// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: N2_TrieTlb.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
// The above named program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
// ========== Copyright Header End ============================================
N2_TrieTlb::N2_TrieTlb( N2_Tlb
* _tlb
)/*{{{*/
fail_page1
= new Page1(0);
fail_page3
= new Page3(fail_page1
);
fail_page5
= new Page5(fail_page3
);
fail_node3
= new Node3(fail_page5
);
fail_node2
= new Node2(fail_node3
);
fail_node1
= new Node1(fail_node2
);
for (uint_t p
=0; p
< PID_SIZE
; p
++)
for (uint_t c
=0; c
< CTX_SIZE
; c
++)
N2_TrieTlb::N2_TrieTlb( N2_TrieTlb
& trie
, N2_Tlb
* _tlb
)/*{{{*/
fail_node1(trie
.fail_node1
),
fail_node2(trie
.fail_node2
),
fail_node3(trie
.fail_node3
),
fail_page5(trie
.fail_page5
),
fail_page3(trie
.fail_page3
),
fail_page1(trie
.fail_page1
),
free_node1(trie
.free_node1
),
free_node2(trie
.free_node2
),
free_node3(trie
.free_node3
),
free_page5(trie
.free_page5
),
free_page3(trie
.free_page3
),
free_page1(trie
.free_page1
)
for (uint_t p
=0; p
< PID_SIZE
; p
++)
real
[p
] = trie
.copy(trie
.real
[p
]);
for (uint_t c
=0; c
< CTX_SIZE
; c
++)
virt
[p
][c
] = trie
.copy(trie
.virt
[p
][c
]);
N2_TrieTlb::~N2_TrieTlb()/*{{{*/
for (uint_t p
=0; p
< PID_SIZE
; p
++)
Node1
* help
= free_node1
;
free_node1
= free_node1
->next
;
Node2
* help
= free_node2
;
free_node2
= free_node2
->next
;
Node3
* help
= free_node3
;
free_node3
= free_node3
->next
;
Page5
* help
= free_page5
;
free_page5
= free_page5
->next
;
Page3
* help
= free_page3
;
free_page3
= free_page3
->next
;
Page1
* help
= free_page1
;
free_page1
= free_page1
->next
;
N2_TrieTlb::Node1
* N2_TrieTlb::copy( Node1
* r_n1
)/*{{{*/
Node1
* l_n1
= new_node1();
for (uint_t i0
=0; i0
< Node1::SIZE
; i0
++)
Node2
* r_n2
= r_n1
->idx(i0
);
Node2
* l_n2
= new_node2();
for (uint_t i1
=0; i1
< Node2::SIZE
; i1
++)
Node3
* r_n3
= r_n2
->idx(i1
);
Node3
* l_n3
= new_node3();
for (uint_t i2
=0; i2
< Node3::SIZE
; i2
++)
Page5
* r_p5
= r_n3
->idx(i2
);
Page5
* l_p5
= new_page5();
for (uint_t i3
=0; i3
< Page5::SIZE
; i3
++)
Page3
* r_p3
= r_p5
->idx(i3
);
Page3
* l_p3
= new_page3();
for (uint_t i4
=0; i4
< Page3::SIZE
; i4
++)
Page1
* r_p1
= r_p3
->idx(i4
);
Page1
* l_p1
= new_page1();
for (uint_t i5
=0; i5
< Page1::SIZE
; i5
++)
SS_Tte
* tte
= r_p1
->idx(i5
);
void N2_TrieTlb::insert( SS_Strand
* strand
, SS_Tte
* tte
, SS_Tte
* rem_tte
)/*{{{*/
n1
= virt
[tte
->pid()][tte
->context()];
virt
[tte
->pid()][tte
->context()] = n1
;
// For the va we use the non aligned tag value, e.g we don't
// use tte->virt_page. We do this so we auto demap the
// correct smaller page(s).
SS_Vaddr va
= tte
->tag();
uint_t ps
= tte
->page_size();
SS_Tte
* p5_tte
= p5
->tte
;
SS_Tte
* p3_tte
= p3
->tte
;
SS_Tte
* p1_tte
= p1
->tte
;
SS_Tte
* p0_tte
= p1
->at(va
);
// Inserts the TTE and auto demap the overlapping TTEs. E.g. demap
// p0_tte, p1_tte, p3_tte, and p5_tte is they are valid TTEs (!= 0).
// This insert and demap has to be (like in hardware) an atomic operation.
// We do this by creating a new path with the TTEs that are to be
// demapped removed and the new TTE inserted.
// We have a full path: p5, p3, p1 and the have to demap a p0 TTE.
// Optimise for a simple case: replace p0_tte, as Solaris often
// changes readonly TTEs into readwrite TTEs: a result from fork().
// The unoptimised case creates a new path and updates the TTEs and
// inserts the path in the trie as the last operation.
if ((ps
== 0) && (p1_tte
== 0) && (p3_tte
== 0) && (p5_tte
== 0))
tlb
->clr_used(p0_tte
->index
);
tlb
->invalidate_tte(strand
,p0_tte
);
p5_new
->tte
= (ps
== 5) ? tte
: 0;
p3_new
->tte
= (ps
== 3) ? tte
: 0;
p1_new
->tte
= (ps
== 1) ? tte
: 0;
p3_new
->remove(va
,fail_page1
);
p5_new
->remove(va
,fail_page3
);
// Again we have a full path: p5, p3, p1 and the smallest TTE we have
// to demap is p1 TTE. Optimise for a trivial case. Otherwise create
// a new path with the TTEs updated and insert in the trie at the end.
if ((ps
== 1) && (p3_tte
== 0) && (p5_tte
== 0))
tlb
->clr_used(p1_tte
->index
);
tlb
->invalidate_tte(strand
,p1_tte
);
p5_new
->tte
= (ps
== 5) ? tte
: 0;
p3_new
->tte
= (ps
== 3) ? tte
: 0;
p1_new
->tte
= (ps
== 1) ? tte
: 0;
p3_new
->remove(va
,fail_page1
);
p5_new
->remove(va
,fail_page3
);
// We have at least a p5 and p3 node. Select the trivial case for
// optimisation. Else switch between possibly shrinking the path
// (ps >= 3) or extending the path.
if ((ps
== 3) && (p5_tte
== 0))
tlb
->clr_used(p3_tte
->index
);
tlb
->invalidate_tte(strand
,p3_tte
);
p5_new
->tte
= (ps
== 5) ? tte
: 0;
p3_new
->tte
= (ps
== 3) ? tte
: 0;
p5_new
->remove(va
,fail_page3
);
p1_tmp
->tte
= (ps
== 1) ? tte
: 0;
// We have a p5 node. Optimise the simple case. Otherwise
// insert and create missing path.
tlb
->clr_used(p5_tte
->index
);
tlb
->invalidate_tte(strand
,p5_tte
);
else if (p1
!= fail_page1
)
// We have no overlapping TTEs and the path p5, p3, p1 is there.
// This is a simple case, likely to happen often. We can just set
// the new TTE, remove the replaced TTE and return.
// The path is partial there. Create as much as we need, based on
// the page size (ps) of the TTE to be inserted.
// Now invalidate all the TTEs that got autodemapped.
// However, don't invalidate the TTE that is selected
// by the replacement algorithm to make place for the
tlb
->clr_used(p0_tte
->index
);
tlb
->invalidate_tte(strand
,p0_tte
);
tlb
->clr_used(p1_tte
->index
);
tlb
->invalidate_tte(strand
,p1_tte
);
tlb
->clr_used(p3_tte
->index
);
tlb
->invalidate_tte(strand
,p3_tte
);
tlb
->clr_used(p5_tte
->index
);
tlb
->invalidate_tte(strand
,p5_tte
);
// Free up the pages that got copied to make auto-demap
// an atomic operation. Note we don;t clear the tte pointers
// and we don't demolish the p5 to p3 to p1 path. We
// do this so that lookup can detect multi hits properly.
void N2_TrieTlb::remove( SS_Tte
* tte
)/*{{{*/
n1
= virt
[tte
->pid()][tte
->context()];
SS_Vaddr va
= tte
->virt_page
;
uint_t ps
= tte
->page_size();
assert(n1
!= fail_node1
);
assert(n2
!= fail_node2
);
assert(n3
!= fail_node3
);
assert(p5
!= fail_page5
);
assert((p5
->tte
== tte
) || (p5
->tte
== 0));
assert(p3
!= fail_page3
);
assert((p3
->tte
== tte
) || (p3
->tte
== 0));
assert(p1
!= fail_page1
);
assert((p1
->tte
== tte
) || (p1
->tte
== 0));
assert((p1
->at(va
) == tte
) || (p1
->at(va
) == 0));
p3
->remove(va
,fail_page1
);
p5
->remove(va
,fail_page3
);
n3
->remove(va
,fail_page5
);
n2
->remove(va
,fail_node3
);
n1
->remove(va
,fail_node2
);
real
[tte
->pid()] = fail_node1
;
virt
[tte
->pid()][tte
->context()] = fail_node1
;
// demap_trie() remove TTEs from a Trie in an atomic fashion.
// Lookup searches with va from largest TTE to smaller TTE.
// When demapping we remove TTEs from smaller to largest.
// This way the TTE found by lookup is always the largest or
// one that persist after the demap, e.g. it makes the demap
bool N2_TrieTlb::demap_trie( SS_Strand
* strand
, Node1
* n1
, SS_Vaddr va
)/*{{{*/
tlb
->clr_used(tte
->index
);
tlb
->invalidate_tte(strand
,tte
);
tlb
->clr_used(tte
->index
);
tlb
->invalidate_tte(strand
,tte
);
p3
->remove(va
,fail_page1
);
tlb
->clr_used(tte
->index
);
tlb
->invalidate_tte(strand
,tte
);
p5
->remove(va
,fail_page3
);
tlb
->clr_used(tte
->index
);
tlb
->invalidate_tte(strand
,tte
);
n3
->remove(va
,fail_page5
);
n2
->remove(va
,fail_node3
);
n1
->remove(va
,fail_node2
);
void N2_TrieTlb::demap_trie( SS_Strand
* strand
, Node1
* n1
)/*{{{*/
assert(n1
!= fail_node1
);
if (!n1
->is_empty_trie())
for (uint_t i
=0; i
< Node1::SIZE
; i
++)
n1
->remove(i
,fail_node2
);
void N2_TrieTlb::demap_trie( SS_Strand
* strand
, Node2
* n2
)/*{{{*/
assert(n2
!= fail_node2
);
if (!n2
->is_empty_trie())
for (uint_t i
=0; i
< Node2::SIZE
; i
++)
n2
->remove(i
,fail_node3
);
void N2_TrieTlb::demap_trie( SS_Strand
* strand
, Node3
* n3
)/*{{{*/
assert(n3
!= fail_node3
);
if (!n3
->is_empty_trie())
for (uint_t i
=0; i
< Node3::SIZE
; i
++)
n3
->remove(i
,fail_page5
);
void N2_TrieTlb::demap_trie( SS_Strand
* strand
, Page5
* p5
)/*{{{*/
assert(p5
!= fail_page5
);
if (!p5
->is_empty_trie())
for (uint_t i
=0; i
< Page5::SIZE
; i
++)
p5
->remove(i
,fail_page3
);
tlb
->clr_used(tte
->index
);
tlb
->invalidate_tte(strand
,tte
);
void N2_TrieTlb::demap_trie( SS_Strand
* strand
, Page3
* p3
)/*{{{*/
assert(p3
!= fail_page3
);
if (!p3
->is_empty_trie())
for (uint_t i
=0; i
< Page3::SIZE
; i
++)
p3
->remove(i
,fail_page1
);
tlb
->clr_used(tte
->index
);
tlb
->invalidate_tte(strand
,tte
);
void N2_TrieTlb::demap_trie( SS_Strand
* strand
, Page1
* p1
)/*{{{*/
assert(p1
!= fail_page1
);
if (!p1
->is_empty_trie())
for (uint_t i
=0; i
< Page1::SIZE
; i
++)
tlb
->clr_used(tte
->index
);
tlb
->invalidate_tte(strand
,tte
);
tlb
->clr_used(tte
->index
);
tlb
->invalidate_tte(strand
,tte
);
void N2_TrieTlb::demap_virt( SS_Strand
* strand
, uint_t pid
, uint_t ctx
, SS_Vaddr va
)/*{{{*/
Node1
* n1
= virt
[pid
][ctx
];
if (demap_trie(strand
,n1
,va
))
virt
[pid
][ctx
] = fail_node1
;
void N2_TrieTlb::demap_virt( SS_Strand
* strand
, uint_t pid
, uint_t ctx
)/*{{{*/
Node1
* n1
= virt
[pid
][ctx
];
virt
[pid
][ctx
] = fail_node1
;
void N2_TrieTlb::demap_virt( SS_Strand
* strand
, uint_t pid
)/*{{{*/
for (uint_t ctx
=0; ctx
< CTX_SIZE
; ctx
++)
demap_virt(strand
,pid
,ctx
);
void N2_TrieTlb::demap_real( SS_Strand
* strand
, uint_t pid
, SS_Vaddr ra
)/*{{{*/
if (demap_trie(strand
,n1
,ra
))
void N2_TrieTlb::demap_real( SS_Strand
* strand
, uint_t pid
)/*{{{*/
void N2_TrieTlb::demap_all( SS_Strand
* strand
, uint_t pid
)/*{{{*/