Logical Channel Prioritization in LTE 4G
How the UE splits an uplink grant across logical channels using LCP, priority and prioritised bit rate.
When the eNB hands the UE an uplink grant, that grant is a fixed number of bytes — and the UE usually has data waiting on several logical channels at once: a signalling message on SRB1, voice on one DRB, a file download's TCP-ACKs on another. Logical Channel Prioritization (LCP) is the rulebook in the UE's MAC that decides, fairly but with priority, how many of those bytes each logical channel gets to place into the transport block.
Introduction
Logical Channel Prioritization (TS 36.321) is the UE-side MAC procedure that runs every time a new uplink transmission is assembled for a grant. It is the last decision the UE makes before bytes hit the air: the scheduler has already decided how big the transport block is; LCP decides which logical channels fill it and in what order their SDUs are packed into the MAC PDU.
It sits at the heart of the uplink loop. A Scheduling Request (SR) asks for a grant, a Buffer Status Report (BSR) tells the eNB how much is queued, the eNB issues a grant on PDCCH (DCI format 0 / C-RNTI), and LCP is what turns that grant into a concrete set of bytes. Because the algorithm is fully standardised and deterministic, the eNB can predict exactly what the UE will do — which is what keeps buffer reporting and grant sizing in step.
LCP matters because a grant is scarce and shared. High-priority signalling and delay-sensitive flows must go first, yet low-priority bulk data must not starve. When something goes wrong — voice choppy under a big upload, signalling delayed, a channel that never seems to drain — the root cause is almost always one specific parameter or one of the two rounds, so a structured, step-by-step reading of the LCP configuration pays off immediately.
On this page
Why LCP is needed
In plain words: think of one UL grant as a single delivery van with limited space, and each logical channel as a department wanting to ship boxes. Strict "most-important-first" loading would let one busy department fill the whole van every trip and leave the others' boxes on the dock forever. LCP instead gives every department a guaranteed minimum share first (round 1), then fills any leftover space with the most important boxes (round 2) — nobody starves, and the van never leaves half-empty.
LCP (TS 36.321) runs in the UE's MAC every time a new uplink transmission is assembled for a grant. The grant is scarce and shared: high-priority signalling and delay-sensitive flows must go first, but low-priority bulk data must not be starved forever. If MAC simply served channels in strict priority order, a greedy high-priority channel with a full buffer could swallow every grant and block everything below it indefinitely. LCP prevents that with a token-bucket scheme layered under strict-priority tie-breaking.
A MAC procedure that, given the transport-block size of one UL grant, allocates bytes to each configured logical channel and fixes the order in which their MAC SDUs are packed into the MAC PDU.
To guarantee each channel a minimum rate (so nothing starves) while still letting urgent traffic dominate. It is the arbitration layer between "the UE has a grant" and "here are the exact bytes on the air."
Each logical channel owns a token bucket that fills at its prioritisedBitRate. Round 1 serves every channel up to its token balance in priority order; round 2 hands any leftover capacity to channels by strict priority until the grant is full.
The core idea: two passes over the same set of channels. The first pass guarantees fairness (each channel gets up to its PBR share). The second pass rewards priority (whoever is most important mops up the rest). This is exactly why a low-priority channel still makes progress even when a high-priority channel has plenty to send — and why an urgent channel still empties fast when there is spare room.
LCP is a purely UE-side procedure. The eNB never tells the UE how to split a grant; it only sizes the grant (via DCI format 0 on PDCCH, CRC scrambled by the UE's C-RNTI, in the UE-specific search space) and trusts the UE to fill it by the standardised algorithm. Because the algorithm is deterministic, the eNB can nonetheless predict what the UE will do — which is why the BSR the UE reports and the grants the eNB issues stay in step. The whole scheme rests on three per-channel RRC parameters and one state variable, so those come first.
The per-logical-channel parameters
RRC configures each logical channel through the LogicalChannelConfig IE (TS 36.331), carried inside the bearer setup. Three fields drive LCP directly, and a fourth (logicalChannelGroup) ties the channel to buffer reporting, covered later.
| Parameter | Range / unit | Meaning |
|---|---|---|
priority | 1–16 (integer) | The channel's importance. A lower value means higher priority — priority 1 is served before priority 16. Sets the service order in both rounds. SRBs are always configured with lower values (higher priority) than DRBs. |
prioritisedBitRate (PBR) | kB/s, or infinity | The guaranteed minimum rate. Tokens (bytes) accrue into the channel's bucket at this rate. Setting it to infinity means the channel drains everything it can already in round 1 — effectively pure strict priority for that channel. |
bucketSizeDuration (BSD) | ms (e.g. 50, 100, 150…1000) | Caps the bucket. Maximum token balance = PBR × BSD. It bounds how much unused allowance an idle channel can hoard, so it cannot burst without limit after a quiet period. |
logicalChannelGroup | 0–3 | Assigns the channel to one of four Logical Channel Groups (LCG) used for buffer status reporting — see below. |
Where it lives, by RAT/mode: in LTE these fields are delivered in a dedicated RRCConnectionReconfiguration (or RRCConnectionSetup) inside each bearer's logicalChannelConfig — they are never broadcast, because they are per-UE, per-bearer policy. In 5G NR the equivalent is LogicalChannelConfig in TS 38.331 with the same three knobs plus NR-only mapping restrictions.
The token bucket Bj
The state that ties these parameters together is a per-channel variable the spec calls Bj — the current token balance of logical channel j, measured in bytes. Think of it as a bucket that is continuously topped up by a tap running at PBR and drained whenever the channel is served in round 1. Formally, before every LCP run MAC increments Bj by PBR × T, where T is the elapsed time since Bj was last incremented — but never above the ceiling PBR × BSD. Any overflow above the ceiling is simply discarded, which is the whole point of BSD: it stops a channel that has been silent for minutes from accumulating a gigantic entitlement.
When the channel is served in round 1, Bj is decremented by exactly the number of bytes taken, and it may legitimately go negative. A negative balance means the channel has recently drawn more than its long-run PBR entitlement, so it must wait for the tap to refill before it wins round 1 space again. Crucially, Bj is not touched in round 2 — bytes handed out in the second pass are "bonus" capacity that does not count against the channel's guaranteed rate. This asymmetry is what makes the two rounds mean two different things.
Reading the knobs together: PBR is the long-run guaranteed byte rate; BSD is how bursty that guarantee is allowed to be; priority is the tie-breaker whenever two channels want the same byte. A voice bearer gets a modest PBR and short BSD (steady, low-latency, non-bursty); a bulk data bearer might get a small PBR but a large BSD so it can occasionally catch up after being throttled.
The two-round LCP algorithm
When a new UL grant arrives, MAC first refreshes every bucket (the Bj += PBR × T step), then allocates bytes in a defined order. TS 36.321 breaks this into two passes over the channels that have data to send.
Round 1 — serve the guaranteed share. Consider all logical channels with data available, in decreasing priority order (lowest priority value first). Each channel is allocated resources up to the minimum of (its buffered data) and (its current bucket balance Bj). Only channels with Bj > 0 are eligible; a channel sitting at a negative balance is skipped this round. As bytes are taken, Bj is decremented by that amount. When round 1 finishes, every channel has received roughly its PBR worth of the grant, doled out strictly in priority order so that if the bucket shares alone exceed the grant, the important channels are the ones that got served.
✅ Debugging steps — round 1 (fairness pass)
- Dump each channel's
priority,PBR,BSDfrom the activeLogicalChannelConfigand confirm they match the intended bearer policy (SRBs lowestpriorityvalue). - Check the running
Bjfor the starved channel — a persistently negativeBjexplains why it wins no round 1 bytes. - Verify the grant actually reached the UE this TTI (
DCI format 0decoded onPDCCHunderC-RNTI) — no grant means LCP never ran. - Confirm the bucket refresh interval (
T) is being applied: ifBjis not accruing atPBR, a channel never regains eligibility.
⚠ Common causes of failure — round 1
PBRset too low (orBSDtoo small) for a channel, so its guaranteed share is tiny and it lives almost entirely off round 2 leftovers — it stalls whenever higher-priority traffic is heavy.- Two channels mis-configured with the same
priority, making the service order ambiguous/implementation-dependent. PBR = infinityon a channel that should have been rate-limited, letting it drain everything in round 1 and squeeze the others.- Grant never arrives (SR/BSR loop broken upstream), so no LCP pass happens at all.
Round 2 — spend what is left. If the grant still has room after every bucket share is served, MAC does a second pass, again in strict decreasing priority order, but this time ignoring Bj entirely. The highest-priority channel with remaining data takes as much as it can, then the next, and so on, until the transport block is full or all buffers are empty. Because Bj is not decremented here, a channel can be served well above its PBR in a single grant whenever there is spare capacity — the algorithm never wastes grant bytes just to enforce a rate cap.
✅ Debugging steps — round 2 (efficiency pass)
- Confirm the transport block is actually being filled — if it is leaving padding while a channel still has data, round 2 is not running or a mapping/segmentation rule is blocking the channel.
- Check that the highest-priority channel with remaining data is the one absorbing the leftover; if a lower-priority channel wins the surplus, re-check
priorityvalues. - Verify
Bjis not being decremented in this pass (bonus bytes should not count against the guaranteed rate).
⚠ Common causes of failure — round 2
- Grant persistently too small to reach round 2, so a bursty low-priority bearer never catches up (usually a BSR/scheduler sizing issue upstream, not LCP itself).
- A whole SDU cannot fit and the UE (mis)handles segmentation, leaving avoidable padding.
- Priority inversion from a configuration typo, so the surplus goes to the wrong bearer.
Why two rounds: round 1 is the fairness pass — it enforces each channel's minimum rate before anyone gets extra. Round 2 is the efficiency pass — it never leaves the transport block half-empty while a channel still has data, and it gives the leftover to the most important traffic. A channel with PBR = infinity has an effectively unbounded bucket, so it grabs all its data in round 1 and behaves like strict priority.
The packing rules that keep both sides in sync
On top of the two rounds, TS 36.321 fixes a few rules so the UE and eNB always build the same PDU and never waste bytes:
| Rule | Why it exists |
|---|---|
| MAC control elements go first | A MAC CE such as a BSR or PHR is placed ahead of user-data SDUs, because that control information is precisely what lets the eNB size the next grant correctly. A C-RNTI or padding BSR is prioritised above all logical-channel data. |
| Serve highest priority first | Both rounds walk channels from lowest priority value upward, so urgent signalling is never queued behind bulk data. |
| Do not segment if a whole SDU fits | If the remaining grant can hold a whole RLC SDU, the UE sends it whole rather than splitting it; segmentation is a last resort, not a default. |
| Maximise served data, minimise padding | The UE must not leave a channel with data unserved while inserting padding. Padding is used only when no more data can possibly fit. |
LTE vs NR — no mapping restrictions: classic LTE LCP has no logical-channel mapping restrictions. Every configured channel is eligible for every grant, and the two-round token bucket alone decides the split. NR later added per-channel gates — allowedSCS-List, maxPUSCH-Duration, configuredGrantType1Allowed, allowedServingCells — so that a channel can be blocked from a grant whose numerology or duration does not suit it. In LTE none of that exists: the only filters are "has data" and "has a positive Bj (round 1)."
Reading LCP in the UE MAC logs
LCP itself is a UE-internal decision, but modern modem traces expose it: the grant size, each channel's Bj before the pass, and the bytes each channel won across the two rounds. Reading these three together tells you immediately whether a starved channel is starved by design (negative Bj, small grant) or by misconfiguration (wrong priority/PBR).
Representative UE MAC log (QXDM/QCAT-style) — illustrative, values vary by vendor/build:
| Field | Meaning | Example (from log) | Debugging check |
|---|---|---|---|
tbs_bytes | Transport-block size of this UL grant — the total LCP must fill. | 1200 | Compare against the reported BSR; a grant far smaller than the buffer means the loop needs more rounds, not a config bug. |
ce=[shortBSR 2B] | MAC CEs placed first per the packing rules, reducing the round 1 budget. | 2B | Confirm control elements precede data; if a BSR/PHR is missing, the next grant may be mis-sized. |
prio | Per-channel priority driving the service order in both rounds. | 1 / 5 / 12 | Lowest value must be served first; an out-of-order allocation points to a config typo. |
Bj | Token-bucket balance at grant time (PBR × T, capped at PBR × BSD). | +200 / +100 | A negative Bj legitimately excludes a channel from round 1; verify it is refilling at PBR. |
r1_alloc | Bytes won in round 1 = min(data, Bj). | 200 | Should never exceed Bj or buffered data; a mismatch is a bucket-accounting bug. |
r2_alloc | Bytes won in round 2, ignoring Bj, by strict priority. | 598 | Leftover should flow to the highest-priority channel with data; otherwise re-check priority. |
padding | Unused grant bytes. | 0 | Padding > 0 while data remains means a channel was wrongly excluded or a whole SDU could not fit. |
Logical Channel Groups and the BSR
LCP decides how to fill a grant the UE already has. But the eNB can only issue a right-sized grant if it knows how much the UE is holding — and that is reported by the Buffer Status Report (BSR). Reporting per individual logical channel would be far too much overhead, so LTE groups channels into Logical Channel Groups (LCG) and reports buffer occupancy per group.
There are exactly four groups, LCG 0 through LCG 3, and each logical channel is assigned to one via the logicalChannelGroup field at bearer setup. The assignment follows priority: high-priority channels (signalling, voice) are grouped together and lower-priority bulk channels in another, so the eNB can tell "urgent bytes waiting" apart from "background bytes waiting" from the report alone.
BSR format | When used | What it reports |
|---|---|---|
Short BSR | Only one LCG has data to report | The LCG ID (2 bits) plus one 6-bit buffer-size index for that group. |
Truncated BSR | More than one LCG has data but the grant is too small for a long BSR | The single highest-priority LCG with data, same fields as short. |
Long BSR | Two or more LCGs have data | Four 6-bit buffer-size fields, one for every LCG (0–3), in order. |
The 6-bit index does not carry a raw byte count; it points into a standardised buffer-size table, so a value covers a range of bytes. A BSR is triggered by events such as new higher-priority data arriving (Regular BSR), a periodic timer expiring (Periodic BSR), or spare room in a grant that a BSR can usefully fill (Padding BSR). The relationship with LCP is a tight feedback loop: LCP consumes the buffer, the buffer level drives the next BSR, the BSR drives the next grant, and LCP runs again on that grant.
LCG vs LCP priority — two different uses of the same channels: the LCG (4 groups) exists only to compress buffer reporting into a small BSR. The per-channel priority (1–16) is what LCP actually uses to order the split. A channel therefore has both a group (for the report) and a priority (for the fill); they are set together but serve different mechanisms.
How LCP maps onto radio bearers
Every logical channel LCP arbitrates over is the MAC face of a radio bearer. Two families exist: Signalling Radio Bearers (SRBs) carrying RRC and NAS control, and Data Radio Bearers (DRBs) carrying user-plane traffic. LCP does not know or care about that distinction directly — it only sees priority, PBR and Bj — but the network configures those parameters so that the bearer hierarchy falls out naturally.
SRBoverDRB. Signalling bearers are configured with the lowestpriorityvalues (highest priority).SRB0(onCCCH) andSRB1carry the RRC messages that keep the connection alive — measurement reports, reconfiguration, handover signalling — and must never be delayed behind a file upload. They are typically given a small guaranteed rate but sit at the top of the priority order, so in both rounds their bytes go in first.- Among
DRBs, byQCI. EachDRBmaps to a QoS Class Identifier that characterises its traffic (delay budget, loss tolerance, GBR vs non-GBR). The network translatesQCIinto concrete LCP settings: aQCI1 voice bearer (GBR, tight delay) gets a higherpriorityand a matchingPBR; aQCI9 best-effort bearer gets a lowpriorityand often a smallPBRwith a largeBSDso it lives mostly off round 2 leftovers.
The result is a clean ordering: control signalling first, then real-time GBR data, then interactive traffic, then background best-effort — all expressed to MAC purely as priority/PBR/BSD triples. This is why you can reason about a UE's uplink behaviour just from the LogicalChannelConfig table without ever mentioning bearers: the bearer policy has already been baked into those numbers.
One more contrast with NR: because LTE has no mapping restrictions, an SRB and a DRB compete for the very same grant with nothing but priority and buckets separating them. In NR you could additionally forbid a bearer from a particular grant type; in LTE the token bucket is the only throttle, which keeps the model simple and predictable.
Worked example: splitting one grant across SRB1 and two DRBs
Put it together with a concrete grant. The UE holds three channels and receives a UL grant of 1200 bytes (ignoring MAC subheader and short BSR CE overhead for clarity — assume a small BSR is placed first per the packing rules). Their configuration and buffered data at grant time:
| Channel | priority | PBR → Bj at grant | Buffered data |
|---|---|---|---|
SRB1 | 1 (highest) | infinity (unbounded) | 100 B |
DRB1 (QCI 1, voice) | 5 | 200 B | 400 B |
DRB2 (QCI 9, best-effort) | 12 (lowest) | 100 B | 5000 B |
Round 1 walks the channels in priority order, each taking min(data, Bj), decrementing Bj:
SRB1(prio 1):Bjunbounded, only 100 B buffered → takes 100 B. Grant left: 1100 B.DRB1(prio 5): min(400, 200) → takes 200 B,Bj→ 0. Grant left: 900 B. Still 200 B buffered.DRB2(prio 12): min(5000, 100) → takes 100 B,Bj→ 0. Grant left: 800 B. Still 4900 B buffered.
Round 2 walks the same order ignoring Bj, filling the remaining 800 B by strict priority:
SRB1: buffer already empty → skip.DRB1: 200 B left → takes all 200 B. Grant left: 600 B.DRB2: 4900 B left → takes 600 B, filling the grant. Grant left: 0.
| Channel | Round 1 | Round 2 | Total in TB | Left in buffer |
|---|---|---|---|---|
SRB1 | 100 B | — | 100 B | 0 |
DRB1 | 200 B | 200 B | 400 B | 0 |
DRB2 | 100 B | 600 B | 700 B | 4300 B |
| Grant | 400 B | 800 B | 1200 B | — |
Notice the outcome. Signalling and voice are fully cleared; the best-effort bearer got its guaranteed 100 B in round 1 plus whatever room was left over (600 B) in round 2, and still has 4300 B waiting — which will trigger the next BSR and, in turn, the next grant. DRB1's Bj is now 0 and DRB2's is 0, so if a second grant arrived in the very next TTI before the tap refilled, round 1 would allocate them almost nothing and round 2 would again favour the higher-priority channel. That is the token bucket doing its job across grants, not just within one.
LTE ↔ NR: the two-round token-bucket core is identical — NR keeps priority, prioritisedBitRate and bucketSizeDuration, the Bj variable, and the "MAC CE first, minimise padding" packing rules (TS 38.321). What NR adds is logical-channel mapping restrictions: allowedSCS-List, maxPUSCH-Duration, configuredGrantType1Allowed and allowedServingCells can bar a channel from a grant whose numerology, duration, grant type or cell does not suit it — a first eligibility filter applied before the two rounds. LTE has none of these, so in LTE every configured channel competes for every grant. NR also expands buffer reporting to up to eight LCGs, versus LTE's four.
Summary
LCP is the deterministic MAC procedure that turns one UL grant into a concrete, ordered set of bytes. Read it in the order the algorithm runs: refresh every bucket (Bj += PBR × T, capped at PBR × BSD), place MAC CEs (BSR/PHR) first, run round 1 for fairness (each channel up to min(data, Bj) in priority order), then round 2 for efficiency (leftover to the highest-priority channel with data, ignoring Bj).
When a channel misbehaves, the first field to check is almost always one of three: the channel's priority (wrong order), its PBR/BSD (too small a guaranteed share, or a negative Bj excluding it from round 1), or the grant size itself (a BSR/scheduler sizing problem upstream, not LCP). Isolating which of the two rounds the byte was lost in turns a vague "voice choppy under upload" into a specific, testable hypothesis.
Best used config-in-hand: line up the LogicalChannelConfig triples against the LCP allocation trace and the reported BSR, and the first number that does not match the intended bearer policy is your root cause.
Quick Q&A
Q. Why does LCP use two rounds instead of just serving strictly by priority?
A. A single priority pass would let a high-priority channel with a full buffer consume the whole grant and starve everything else. Round 1 caps each channel at its PBR bucket (Bj) to guarantee a minimum rate; round 2 then gives any leftover to the highest-priority channel with data so no grant space is wasted. Fairness first, efficiency second.
Q. What do prioritisedBitRate and bucketSizeDuration together define?
A. PBR is the fill rate of the token bucket (the guaranteed byte rate). BSD sets the ceiling: max balance Bj = PBR × BSD. BSD bounds how much unused allowance an idle channel can hoard, so it cannot burst without limit after a quiet period.
Q. What is a Logical Channel Group and how many are there?
A. An LCG is a grouping of logical channels used only for buffer reporting. There are four (LCG 0–3), assigned via logicalChannelGroup. The BSR reports buffered bytes per group, not per channel, to keep control overhead small. It is separate from the per-channel priority that LCP uses to order the split.
Q. How does LTE LCP differ from NR LCP?
A. LTE has no logical-channel mapping restrictions — every channel is eligible for every grant and only the token bucket and priority decide the split. NR added per-channel gates such as allowedSCS-List and maxPUSCH-Duration that can bar a channel from an unsuitable grant, and expands buffer reporting to up to eight LCGs. Otherwise the two-round token-bucket core is the same.
Q. Does Bj change during round 2, and can it go negative?
A. Bj is decremented only in round 1, by the bytes taken, and it may legitimately go negative (the channel then waits for the PBR tap to refill before it wins round 1 space again). Round 2 bytes are bonus capacity and do not touch Bj.
Q. Why is an SRB served before a DRB, and how is that enforced?
A. Signalling must never wait behind bulk data. It is enforced purely through configuration: SRBs get the lowest priority values (highest priority), so both LCP rounds serve them first. Among DRBs the ordering follows QCI, mapped by the network into priority/PBR/BSD values.
Where this fits
LCP is the bridge between "the UE has a grant" and "here are the exact bytes in the transport block." The buffer occupancy it works from is reported by the BSR (per LCG), the grant itself is requested via SR and shaped by PHR, and the finished bytes are packaged as a MAC PDU with its control elements first.