1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
Partial Array Self-Refresh Framework
(C) 2012 Maxime Coquelin <maxime.coquelin@stericsson.com>, ST-Ericsson.
CONTENT
1. Introduction
2. Command-line parameters
3. Allocators patching
4. PASR platform drivers
1. Introduction
PASR Frameworks brings support for the Partial Array Self-Refresh DDR power
management feature. PASR has been introduced in LP-DDR2, and is also present
in DDR3.
PASR provides 4 modes:
* Single-Ended: Only 1/1, 1/2, 1/4 or 1/8 are refreshed, masking starting at
the end of the DDR die.
* Double-Ended: Same as Single-Ended, but refresh-masking does not start
necessairly at the end of the DDR die.
* Bank-Selective: Refresh of each bank of a die can be masked or unmasked via
a dedicated DDR register (MR16). This mode is convenient for DDR configured
in BRC (Bank-Row-Column) mode.
* Segment-Selective: Refresh of each segment of a die can be masked or unmasked
via a dedicated DDR register (MR17). This mode is convenient for DDR configured
in RBC (Row-Bank-Column) mode.
The role of this framework is to stop the refresh of unused memory to enhance
DDR power consumption.
It supports Bank-Selective and Segment-Selective modes, as the more adapted to
modern OSes.
At early boot stage, a representation of the physical DDR layout is built:
Die 0
_______________________________
| I--------------------------I |
| I Bank or Segment 0 I |
| I--------------------------I |
| I--------------------------I |
| I Bank or Segment 1 I |
| I--------------------------I |
| I--------------------------I |
| I Bank or Segment ... I |
| I--------------------------I |
| I--------------------------I |
| I Bank or Segment n I |
| I--------------------------I |
|______________________________|
...
Die n
_______________________________
| I--------------------------I |
| I Bank or Segment 0 I |
| I--------------------------I |
| I--------------------------I |
| I Bank or Segment 1 I |
| I--------------------------I |
| I--------------------------I |
| I Bank or Segment ... I |
| I--------------------------I |
| I--------------------------I |
| I Bank or Segment n I |
| I--------------------------I |
|______________________________|
The first level is a table where elements represent a die:
* Base address,
* Number of segments,
* Table representing banks/segments,
* MR16/MR17 refresh mask,
* DDR Controller callback to update MR16/MR17 refresh mask.
The second level is the section tables representing the banks or segments,
depending on hardware configuration:
* Base address,
* Unused memory size counter,
* Possible pointer to another section it depends on (E.g. Interleaving)
When some memory becomes unused, the allocator owning this memory calls the PASR
Framework's pasr_put(phys_addr, size) function. The framework finds the
sections impacted and updates their counters accordingly.
If a section counter reach the section size, the refresh of the section is
masked. If the corresponding section has a dependency with another section
(E.g. because of DDR interleaving, see figure below), it checks the "paired" section is also
unused before updating the refresh mask.
When some unused memory is requested by the allocator, the allocator owning
this memory calls the PASR Framework's pasr_get(phys_addr, size) function. The
framework find the section impacted and updates their counters accordingly.
If before the update, the section counter was to the section size, the refrewh
of the section is unmasked. If the corresponding section has a dependency with
another section, it also unmask the refresh of the other section.
Interleaving example:
Die 0
_______________________________
| I--------------------------I |
| I Bank or Segment 0 I |<----|
| I--------------------------I | |
| I--------------------------I | |
| I Bank or Segment 1 I | |
| I--------------------------I | |
| I--------------------------I | |
| I Bank or Segment ... I | |
| I--------------------------I | |
| I--------------------------I | |
| I Bank or Segment n I | |
| I--------------------------I | |
|______________________________| |
|
Die 1 |
_______________________________ |
| I--------------------------I | |
| I Bank or Segment 0 I |<----|
| I--------------------------I |
| I--------------------------I |
| I Bank or Segment 1 I |
| I--------------------------I |
| I--------------------------I |
| I Bank or Segment ... I |
| I--------------------------I |
| I--------------------------I |
| I Bank or Segment n I |
| I--------------------------I |
|______________________________|
In the above example, bank 0 of die 0 is interleaved with bank0 of die 0.
The interleaving is done in HW by inverting some addresses lines. The goal is
to improve DDR bandwidth.
Practically, one buffer seen as contiguous by the kernel might be spread
into two DDR dies physically.
2. Command-line parameters
To buid the DDR physical layout representation, two parameters are requested:
* ddr_die (mandatory): Should be added for every DDR dies present in the system.
- Usage: ddr_die=xxx[M|G]@yyy[M|G] where xxx represents the size and yyy
the base address of the die. E.g.: ddr_die=512M@0 ddr_die=512M@512M
* interleaved (optionnal): Should be added for every interleaved dependencies.
- Usage: interleaved=xxx[M|G]@yyy[M|G]:zzz[M|G] where xxx is the size of
the interleaved area between the adresses yyy and zzz. E.g
interleaved=256M@0:512M
3. Allocator patching
Any allocators might call the PASR Framework for DDR power savings. Currently,
only Linux Buddy allocator is patched, but HWMEM and PMEM physically
contiguous memory allocators will follow.
Linux Buddy allocator porting uses Buddy specificities to reduce the overhead
induced by the PASR Framework counter updates. Indeed, the PASR Framework is
called only when MAX_ORDER (4MB page blocs by default) buddies are
inserted/removed from the free lists.
To port PASR FW into a new allocator:
* Call pasr_put(phys_addr, size) each time a memory chunk becomes unused.
* Call pasr_get(phys_addr, size) each time a memory chunk becomes used.
4. PASR platform drivers
The MR16/MR17 PASR mask registers are generally accessible through the DDR
controller. At probe time, the DDR controller driver should register the
callback used by PASR Framework to apply the refresh mask for every DDR die
using pasr_register_mask_function(die_addr, callback, cookie).
The callback passed to apply mask must not sleep since it can me called in
interrupt contexts.
|