|
1 /* |
|
2 * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 #include "pci-ne.h" |
|
21 #include "../naviengine_pci.h" |
|
22 #include <naviengine.h> |
|
23 #include <naviengine_priv.h> |
|
24 |
|
25 // |
|
26 // Global helper functions |
|
27 // |
|
28 |
|
29 |
|
30 /** |
|
31 Integer log base 2 for power of 2 |
|
32 */ |
|
33 TUint32 Log2(TUint32 aNumber) |
|
34 { |
|
35 __NK_ASSERT_ALWAYS(aNumber>0); |
|
36 __NK_ASSERT_DEBUG((aNumber&(aNumber-1))==0); //assert that size is power of 2 |
|
37 const TUint32 b[] = {0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000}; |
|
38 |
|
39 TUint32 r = (aNumber & b[0]) != 0; |
|
40 r |= ((aNumber & b[4]) != 0) << 4; |
|
41 r |= ((aNumber & b[3]) != 0) << 3; |
|
42 r |= ((aNumber & b[2]) != 0) << 2; |
|
43 r |= ((aNumber & b[1]) != 0) << 1; |
|
44 return r; |
|
45 } |
|
46 |
|
47 /** |
|
48 Ceiling power 2. Round up aNumber to the next power of 2. |
|
49 */ |
|
50 TUint32 Clp2(TUint32 aNumber) |
|
51 { |
|
52 aNumber -= 1; |
|
53 aNumber |= aNumber >> 1; |
|
54 aNumber |= aNumber >> 2; |
|
55 aNumber |= aNumber >> 4; |
|
56 aNumber |= aNumber >> 8; |
|
57 aNumber |= aNumber >> 16; |
|
58 return aNumber+1; |
|
59 } |
|
60 |
|
61 |
|
62 // |
|
63 // TMappingManager |
|
64 // |
|
65 |
|
66 /** |
|
67 Just make sure members are zeroed |
|
68 */ |
|
69 TMappingManager::TMapping::TMapping() |
|
70 :iPciAddr(NULL), iPhysAddr(NULL), iUsed(EFalse) |
|
71 {} |
|
72 |
|
73 /** |
|
74 A compare function so that we can find used/unused mappings in RArray. |
|
75 */ |
|
76 TBool TMappingManager::TMapping::UsedCompare(const TMapping& aKeyMapping, const TMapping& aMapping) |
|
77 { |
|
78 return aKeyMapping.iUsed==aMapping.iUsed; |
|
79 } |
|
80 |
|
81 /** |
|
82 A compare function so that we can find mappings to specific phys addr in RArray. |
|
83 */ |
|
84 TBool TMappingManager::TMapping::PhysAddrCompare(const TUint32* aPhysAddr, const TMapping& aMapping) |
|
85 { |
|
86 return *aPhysAddr==aMapping.iPhysAddr; |
|
87 } |
|
88 |
|
89 TBool TMappingManager::TMapping::ContainsPhysical(const TUint32* aPhysAddr, const TMapping& aMapping) |
|
90 { |
|
91 return aMapping.iUsed && Rng(aMapping.iPhysAddr, *aPhysAddr, aMapping.iPhysAddr+aMapping.iSize-1); |
|
92 } |
|
93 |
|
94 TBool TMappingManager::TMapping::ContainsPci(const TUint32* aPciAddr, const TMapping& aMapping) |
|
95 { |
|
96 return aMapping.iUsed && Rng(aMapping.iPciAddr, *aPciAddr, aMapping.iPciAddr+aMapping.iSize-1); |
|
97 } |
|
98 |
|
99 TUint32 TMappingManager::TMapping::PciAddress(TUint32 aPhysAddress) |
|
100 { |
|
101 __NK_ASSERT_ALWAYS(Rng(iPhysAddr, aPhysAddress, iPhysAddr+iSize-1)); |
|
102 return iPciAddr+(aPhysAddress-iPhysAddr); |
|
103 } |
|
104 |
|
105 TUint32 TMappingManager::TMapping::PhysAddress(TUint32 aPciAddress) |
|
106 { |
|
107 __NK_ASSERT_ALWAYS(Rng(iPciAddr, aPciAddress, iPciAddr+iSize-1)); |
|
108 return iPhysAddr+(aPciAddress-iPciAddr); |
|
109 } |
|
110 |
|
111 TMappingManager::TMappingManager(TInt aNumOfBars, TAddressAllocator& aAllocator, TUint32 aBaseAddress) |
|
112 : iAllocator(aAllocator), iNumOfBars(aNumOfBars), iBaseAddress(aBaseAddress), iMappings(iNumOfBars), iMutex(NULL) |
|
113 { |
|
114 _LIT(KChunkManMutex, "PCI_Map_Man_Mutex"); |
|
115 TInt r=Kern::MutexCreate(iMutex, KChunkManMutex, KMutexOrdGeneral1); |
|
116 __NK_ASSERT_ALWAYS(KErrNone==r); |
|
117 |
|
118 TMapping emptyRecord; |
|
119 for(TInt i=0; i<iNumOfBars; ++i) |
|
120 { |
|
121 r = iMappings.Append(emptyRecord); |
|
122 __NK_ASSERT_ALWAYS(r==KErrNone); |
|
123 } |
|
124 } |
|
125 |
|
126 TMappingManager::~TMappingManager() |
|
127 { |
|
128 iMutex->Close(NULL); |
|
129 iMappings.Reset(); |
|
130 } |
|
131 |
|
132 /** |
|
133 Obtain a block of memory from PCI memory space, and map it to the supplied aPhysicalAddress. |
|
134 @param aPhysicalAddress The system memory address to which window points. |
|
135 Must be naturally aligned in accord with aSize. Eg. a 1MB memory block must be alligned to a 1MB boundary. |
|
136 @param aSize Size of mapping. Must be a power of 2 and greater than 1KB. |
|
137 @param On return Will be set to the PCI address of the window. |
|
138 @return |
|
139 - KErrNone Success |
|
140 - KErrNotSupported aPhysicalAddress was not aligned correctly or aSize was not a power of 2 |
|
141 */ |
|
142 TInt TMappingManager::CreateMapping(TUint32 aPhysicalAddress, TInt aSize, TUint32& aPciAddress) |
|
143 { |
|
144 NKern::ThreadEnterCS(); |
|
145 Kern::MutexWait(*iMutex); |
|
146 |
|
147 if(aSize<KMinOutboundWindow) |
|
148 aSize=KMinOutboundWindow; |
|
149 else |
|
150 aSize=Clp2(aSize); //round up to next Power of 2. |
|
151 |
|
152 __NK_ASSERT_ALWAYS(aSize>=KMinOutboundWindow); //assert that size is greater than minimum window |
|
153 __NK_ASSERT_ALWAYS((aSize&(aSize-1))==0); //assert that size is power of 2 |
|
154 |
|
155 TInt r=KErrNone; |
|
156 const TMapping unusedKey; |
|
157 const TInt barIndex = iMappings.Find(unusedKey, TIdentityRelation<TMapping>(TMapping::UsedCompare)); |
|
158 if(KErrNotFound==barIndex) |
|
159 { |
|
160 r=barIndex; |
|
161 goto End; |
|
162 } |
|
163 |
|
164 //ensure that aPhysicalAddress is aligned correctly for the |
|
165 //window size |
|
166 if(aPhysicalAddress&(aSize-1)) |
|
167 { |
|
168 r=KErrNotSupported; |
|
169 goto End; |
|
170 } |
|
171 |
|
172 r = iAllocator.Allocate(aPciAddress, aSize); |
|
173 if(r!=KErrNone) |
|
174 { |
|
175 goto End; |
|
176 } |
|
177 |
|
178 DoCreateMapping(barIndex, aPhysicalAddress, aSize, aPciAddress); |
|
179 |
|
180 End: |
|
181 Kern::MutexSignal(*iMutex); |
|
182 NKern::ThreadLeaveCS(); |
|
183 return r; |
|
184 } |
|
185 |
|
186 void TMappingManager::DoCreateMapping(TInt aBarIndex, TUint32 aPhysicalAddress, TInt& aSize, TUint32& aPciAddress) |
|
187 { |
|
188 __KTRACE_OPT(KPCI, Kern::Printf("Create PCI window mapping: phys=0x%08x, pci=0x%08x, size=0x%08x, BarIndex=%d ", aPhysicalAddress, aPciAddress, aSize, aBarIndex)); |
|
189 //The bar mask field in the |
|
190 //ACR determines how many of the upper bits |
|
191 //of an accessed PCI address should be converted |
|
192 //before being forwarded to AHB. |
|
193 //This is equivalent to 32-log2(size) |
|
194 const TUint32 log2Size=Log2(aSize); |
|
195 const TUint32 acrBarMask = ((32-log2Size)<<4)&KHmAcr_BarMask; |
|
196 const TUint32 acrValue = aPhysicalAddress|acrBarMask|KHtAcr_P2Ace; |
|
197 const TUint32 barValue = aPciAddress; |
|
198 __KTRACE_OPT(KPCI, Kern::Printf(" calculated bar mask = 0x%08x", acrBarMask)); |
|
199 __KTRACE_OPT(KPCI, Kern::Printf(" writing acrValue = 0x%08x @ os 0x%08x", acrValue, KHoAcr[aBarIndex])); |
|
200 __KTRACE_OPT(KPCI, Kern::Printf(" writing barValue = 0x%08x @ os 0x%08x", barValue, KHoBar[aBarIndex])); |
|
201 |
|
202 AsspRegister::Write32(iBaseAddress+KHoAcr[aBarIndex],acrValue); |
|
203 AsspRegister::Write32(iBaseAddress+KHoBar[aBarIndex],barValue); |
|
204 |
|
205 //set bit for this bar in the bar-enable register |
|
206 AsspRegister::Modify32(iBaseAddress+KHoBarEnable, NULL, (1<<aBarIndex)); |
|
207 //__KTRACE_OPT(KPCI, Kern::Printf("New bar enable register: 0x%08x", AsspRegister::Read32(iBaseAddress+KHoBarEnable))); |
|
208 |
|
209 TMapping& newMapping = iMappings[aBarIndex]; |
|
210 newMapping.iPciAddr=aPciAddress; |
|
211 newMapping.iPhysAddr=aPhysicalAddress; |
|
212 newMapping.iSize=aSize; |
|
213 newMapping.iUsed=ETrue; |
|
214 } |
|
215 |
|
216 TInt TMappingManager::RemoveMapping(TUint32 aPhysicalAddress) |
|
217 { |
|
218 NKern::ThreadEnterCS(); |
|
219 Kern::MutexWait(*iMutex); |
|
220 |
|
221 TInt r=KErrNone; |
|
222 TInt barIndex=iMappings.Find(aPhysicalAddress, TMapping::PhysAddrCompare); |
|
223 |
|
224 if(KErrNotFound==barIndex) |
|
225 { |
|
226 r=barIndex; |
|
227 } |
|
228 else |
|
229 { |
|
230 //clear the bits in the BarMask field of the ACR to invalidate access to Bar. |
|
231 AsspRegister::Modify32(iBaseAddress+KHoAcr[barIndex], KHmAcr_BarMask, NULL); |
|
232 |
|
233 //clear bit for this bar in the bar enable register |
|
234 AsspRegister::Modify32(iBaseAddress+KHoBarEnable, (1<<barIndex), NULL); |
|
235 |
|
236 TMapping& oldMapping = iMappings[barIndex]; |
|
237 r = iAllocator.DeAllocate(oldMapping.iPciAddr); |
|
238 __NK_ASSERT_ALWAYS(KErrNone==r); |
|
239 |
|
240 oldMapping.iUsed=EFalse; |
|
241 } |
|
242 |
|
243 Kern::MutexSignal(*iMutex); |
|
244 NKern::ThreadLeaveCS(); |
|
245 return r; |
|
246 } |
|
247 |
|
248 TInt TMappingManager::GetPciAddress(TUint32 aPhysicalAddress, TUint32& aPciAddress) |
|
249 { |
|
250 NKern::ThreadEnterCS(); |
|
251 Kern::MutexWait(*iMutex); |
|
252 |
|
253 const TInt barIndex=iMappings.Find(aPhysicalAddress, TMapping::ContainsPhysical); |
|
254 TInt r= KErrNotFound; |
|
255 |
|
256 if(barIndex==KErrNotFound) |
|
257 r = KErrNotFound; |
|
258 else |
|
259 { |
|
260 aPciAddress=iMappings[barIndex].PciAddress(aPhysicalAddress); |
|
261 r = KErrNone; |
|
262 } |
|
263 |
|
264 Kern::MutexSignal(*iMutex); |
|
265 NKern::ThreadLeaveCS(); |
|
266 return r; |
|
267 } |
|
268 |
|
269 TInt TMappingManager::GetPhysicalAddress(TUint32 aPciAddress, TUint32& aPhysicalAddress) |
|
270 { |
|
271 NKern::ThreadEnterCS(); |
|
272 Kern::MutexWait(*iMutex); |
|
273 |
|
274 const TInt barIndex=iMappings.Find(aPciAddress, TMapping::ContainsPci); |
|
275 TInt r= KErrNotFound; |
|
276 |
|
277 if(barIndex==KErrNotFound) |
|
278 r = KErrNotFound; |
|
279 else |
|
280 { |
|
281 aPhysicalAddress=iMappings[barIndex].PhysAddress(aPciAddress); |
|
282 r = KErrNone; |
|
283 } |
|
284 |
|
285 Kern::MutexSignal(*iMutex); |
|
286 NKern::ThreadLeaveCS(); |
|
287 return r; |
|
288 } |
|
289 |