aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-11-06 19:06:55 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-06 19:56:47 -0500
commit3c726f8dee6f55e96475574e9f645327e461884c (patch)
treef67c381e8f57959aa4a94bda4c68e24253cd8171 /arch/powerpc/platforms
parentf912696ab330bf539231d1f8032320f2a08b850f (diff)
[PATCH] ppc64: support 64k pages
Adds a new CONFIG_PPC_64K_PAGES which, when enabled, changes the kernel base page size to 64K. The resulting kernel still boots on any hardware. On current machines with 4K pages support only, the kernel will maintain 16 "subpages" for each 64K page transparently. Note that while real 64K capable HW has been tested, the current patch will not enable it yet as such hardware is not released yet, and I'm still verifying with the firmware architects the proper to get the information from the newer hypervisors. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/iseries/htab.c65
-rw-r--r--arch/powerpc/platforms/iseries/hvlog.c4
-rw-r--r--arch/powerpc/platforms/iseries/iommu.c74
-rw-r--r--arch/powerpc/platforms/iseries/setup.c13
-rw-r--r--arch/powerpc/platforms/iseries/vio.c39
-rw-r--r--arch/powerpc/platforms/iseries/viopath.c16
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c115
7 files changed, 170 insertions, 156 deletions
diff --git a/arch/powerpc/platforms/iseries/htab.c b/arch/powerpc/platforms/iseries/htab.c
index b3c6c3374ca6..30bdcf3925d9 100644
--- a/arch/powerpc/platforms/iseries/htab.c
+++ b/arch/powerpc/platforms/iseries/htab.c
@@ -39,15 +39,16 @@ static inline void iSeries_hunlock(unsigned long slot)
39 spin_unlock(&iSeries_hlocks[(slot >> 4) & 0x3f]); 39 spin_unlock(&iSeries_hlocks[(slot >> 4) & 0x3f]);
40} 40}
41 41
42static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, 42long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
43 unsigned long prpn, unsigned long vflags, 43 unsigned long pa, unsigned long rflags,
44 unsigned long rflags) 44 unsigned long vflags, int psize)
45{ 45{
46 unsigned long arpn;
47 long slot; 46 long slot;
48 hpte_t lhpte; 47 hpte_t lhpte;
49 int secondary = 0; 48 int secondary = 0;
50 49
50 BUG_ON(psize != MMU_PAGE_4K);
51
51 /* 52 /*
52 * The hypervisor tries both primary and secondary. 53 * The hypervisor tries both primary and secondary.
53 * If we are being called to insert in the secondary, 54 * If we are being called to insert in the secondary,
@@ -59,8 +60,19 @@ static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
59 60
60 iSeries_hlock(hpte_group); 61 iSeries_hlock(hpte_group);
61 62
62 slot = HvCallHpt_findValid(&lhpte, va >> PAGE_SHIFT); 63 slot = HvCallHpt_findValid(&lhpte, va >> HW_PAGE_SHIFT);
63 BUG_ON(lhpte.v & HPTE_V_VALID); 64 if (unlikely(lhpte.v & HPTE_V_VALID)) {
65 if (vflags & HPTE_V_BOLTED) {
66 HvCallHpt_setSwBits(slot, 0x10, 0);
67 HvCallHpt_setPp(slot, PP_RWXX);
68 iSeries_hunlock(hpte_group);
69 if (slot < 0)
70 return 0x8 | (slot & 7);
71 else
72 return slot & 7;
73 }
74 BUG();
75 }
64 76
65 if (slot == -1) { /* No available entry found in either group */ 77 if (slot == -1) { /* No available entry found in either group */
66 iSeries_hunlock(hpte_group); 78 iSeries_hunlock(hpte_group);
@@ -73,10 +85,9 @@ static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
73 slot &= 0x7fffffffffffffff; 85 slot &= 0x7fffffffffffffff;
74 } 86 }
75 87
76 arpn = phys_to_abs(prpn << PAGE_SHIFT) >> PAGE_SHIFT;
77 88
78 lhpte.v = (va >> 23) << HPTE_V_AVPN_SHIFT | vflags | HPTE_V_VALID; 89 lhpte.v = hpte_encode_v(va, MMU_PAGE_4K) | vflags | HPTE_V_VALID;
79 lhpte.r = (arpn << HPTE_R_RPN_SHIFT) | rflags; 90 lhpte.r = hpte_encode_r(phys_to_abs(pa), MMU_PAGE_4K) | rflags;
80 91
81 /* Now fill in the actual HPTE */ 92 /* Now fill in the actual HPTE */
82 HvCallHpt_addValidate(slot, secondary, &lhpte); 93 HvCallHpt_addValidate(slot, secondary, &lhpte);
@@ -86,25 +97,6 @@ static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
86 return (secondary << 3) | (slot & 7); 97 return (secondary << 3) | (slot & 7);
87} 98}
88 99
89long iSeries_hpte_bolt_or_insert(unsigned long hpte_group,
90 unsigned long va, unsigned long prpn, unsigned long vflags,
91 unsigned long rflags)
92{
93 long slot;
94 hpte_t lhpte;
95
96 slot = HvCallHpt_findValid(&lhpte, va >> PAGE_SHIFT);
97
98 if (lhpte.v & HPTE_V_VALID) {
99 /* Bolt the existing HPTE */
100 HvCallHpt_setSwBits(slot, 0x10, 0);
101 HvCallHpt_setPp(slot, PP_RWXX);
102 return 0;
103 }
104
105 return iSeries_hpte_insert(hpte_group, va, prpn, vflags, rflags);
106}
107
108static unsigned long iSeries_hpte_getword0(unsigned long slot) 100static unsigned long iSeries_hpte_getword0(unsigned long slot)
109{ 101{
110 hpte_t hpte; 102 hpte_t hpte;
@@ -150,15 +142,17 @@ static long iSeries_hpte_remove(unsigned long hpte_group)
150 * bits 61..63 : PP2,PP1,PP0 142 * bits 61..63 : PP2,PP1,PP0
151 */ 143 */
152static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, 144static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp,
153 unsigned long va, int large, int local) 145 unsigned long va, int psize, int local)
154{ 146{
155 hpte_t hpte; 147 hpte_t hpte;
156 unsigned long avpn = va >> 23; 148 unsigned long want_v;
157 149
158 iSeries_hlock(slot); 150 iSeries_hlock(slot);
159 151
160 HvCallHpt_get(&hpte, slot); 152 HvCallHpt_get(&hpte, slot);
161 if ((HPTE_V_AVPN_VAL(hpte.v) == avpn) && (hpte.v & HPTE_V_VALID)) { 153 want_v = hpte_encode_v(va, MMU_PAGE_4K);
154
155 if (HPTE_V_COMPARE(hpte.v, want_v) && (hpte.v & HPTE_V_VALID)) {
162 /* 156 /*
163 * Hypervisor expects bits as NPPP, which is 157 * Hypervisor expects bits as NPPP, which is
164 * different from how they are mapped in our PP. 158 * different from how they are mapped in our PP.
@@ -210,14 +204,17 @@ static long iSeries_hpte_find(unsigned long vpn)
210 * 204 *
211 * No need to lock here because we should be the only user. 205 * No need to lock here because we should be the only user.
212 */ 206 */
213static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea) 207static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
208 int psize)
214{ 209{
215 unsigned long vsid,va,vpn; 210 unsigned long vsid,va,vpn;
216 long slot; 211 long slot;
217 212
213 BUG_ON(psize != MMU_PAGE_4K);
214
218 vsid = get_kernel_vsid(ea); 215 vsid = get_kernel_vsid(ea);
219 va = (vsid << 28) | (ea & 0x0fffffff); 216 va = (vsid << 28) | (ea & 0x0fffffff);
220 vpn = va >> PAGE_SHIFT; 217 vpn = va >> HW_PAGE_SHIFT;
221 slot = iSeries_hpte_find(vpn); 218 slot = iSeries_hpte_find(vpn);
222 if (slot == -1) 219 if (slot == -1)
223 panic("updateboltedpp: Could not find page to bolt\n"); 220 panic("updateboltedpp: Could not find page to bolt\n");
@@ -225,7 +222,7 @@ static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea)
225} 222}
226 223
227static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va, 224static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va,
228 int large, int local) 225 int psize, int local)
229{ 226{
230 unsigned long hpte_v; 227 unsigned long hpte_v;
231 unsigned long avpn = va >> 23; 228 unsigned long avpn = va >> 23;
diff --git a/arch/powerpc/platforms/iseries/hvlog.c b/arch/powerpc/platforms/iseries/hvlog.c
index 62ec73479687..f476d71194fa 100644
--- a/arch/powerpc/platforms/iseries/hvlog.c
+++ b/arch/powerpc/platforms/iseries/hvlog.c
@@ -22,7 +22,7 @@ void HvCall_writeLogBuffer(const void *buffer, u64 len)
22 22
23 while (len) { 23 while (len) {
24 hv_buf.addr = cur; 24 hv_buf.addr = cur;
25 left_this_page = ((cur & PAGE_MASK) + PAGE_SIZE) - cur; 25 left_this_page = ((cur & HW_PAGE_MASK) + HW_PAGE_SIZE) - cur;
26 if (left_this_page > len) 26 if (left_this_page > len)
27 left_this_page = len; 27 left_this_page = len;
28 hv_buf.len = left_this_page; 28 hv_buf.len = left_this_page;
@@ -30,6 +30,6 @@ void HvCall_writeLogBuffer(const void *buffer, u64 len)
30 HvCall2(HvCallBaseWriteLogBuffer, 30 HvCall2(HvCallBaseWriteLogBuffer,
31 virt_to_abs(&hv_buf), 31 virt_to_abs(&hv_buf),
32 left_this_page); 32 left_this_page);
33 cur = (cur & PAGE_MASK) + PAGE_SIZE; 33 cur = (cur & HW_PAGE_MASK) + HW_PAGE_SIZE;
34 } 34 }
35} 35}
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c
index 1a6845b5c5a4..bf081b345820 100644
--- a/arch/powerpc/platforms/iseries/iommu.c
+++ b/arch/powerpc/platforms/iseries/iommu.c
@@ -43,9 +43,12 @@ static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
43 u64 rc; 43 u64 rc;
44 union tce_entry tce; 44 union tce_entry tce;
45 45
46 index <<= TCE_PAGE_FACTOR;
47 npages <<= TCE_PAGE_FACTOR;
48
46 while (npages--) { 49 while (npages--) {
47 tce.te_word = 0; 50 tce.te_word = 0;
48 tce.te_bits.tb_rpn = virt_to_abs(uaddr) >> PAGE_SHIFT; 51 tce.te_bits.tb_rpn = virt_to_abs(uaddr) >> TCE_SHIFT;
49 52
50 if (tbl->it_type == TCE_VB) { 53 if (tbl->it_type == TCE_VB) {
51 /* Virtual Bus */ 54 /* Virtual Bus */
@@ -66,7 +69,7 @@ static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
66 panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", 69 panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n",
67 rc); 70 rc);
68 index++; 71 index++;
69 uaddr += PAGE_SIZE; 72 uaddr += TCE_PAGE_SIZE;
70 } 73 }
71} 74}
72 75
@@ -74,6 +77,9 @@ static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages)
74{ 77{
75 u64 rc; 78 u64 rc;
76 79
80 npages <<= TCE_PAGE_FACTOR;
81 index <<= TCE_PAGE_FACTOR;
82
77 while (npages--) { 83 while (npages--) {
78 rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, 0); 84 rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, 0);
79 if (rc) 85 if (rc)
@@ -83,27 +89,6 @@ static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages)
83 } 89 }
84} 90}
85 91
86#ifdef CONFIG_PCI
87/*
88 * This function compares the known tables to find an iommu_table
89 * that has already been built for hardware TCEs.
90 */
91static struct iommu_table *iommu_table_find(struct iommu_table * tbl)
92{
93 struct pci_dn *pdn;
94
95 list_for_each_entry(pdn, &iSeries_Global_Device_List, Device_List) {
96 struct iommu_table *it = pdn->iommu_table;
97 if ((it != NULL) &&
98 (it->it_type == TCE_PCI) &&
99 (it->it_offset == tbl->it_offset) &&
100 (it->it_index == tbl->it_index) &&
101 (it->it_size == tbl->it_size))
102 return it;
103 }
104 return NULL;
105}
106
107/* 92/*
108 * Call Hv with the architected data structure to get TCE table info. 93 * Call Hv with the architected data structure to get TCE table info.
109 * info. Put the returned data into the Linux representation of the 94 * info. Put the returned data into the Linux representation of the
@@ -113,8 +98,10 @@ static struct iommu_table *iommu_table_find(struct iommu_table * tbl)
113 * 2. TCE table per Bus. 98 * 2. TCE table per Bus.
114 * 3. TCE Table per IOA. 99 * 3. TCE Table per IOA.
115 */ 100 */
116static void iommu_table_getparms(struct pci_dn *pdn, 101void iommu_table_getparms_iSeries(unsigned long busno,
117 struct iommu_table* tbl) 102 unsigned char slotno,
103 unsigned char virtbus,
104 struct iommu_table* tbl)
118{ 105{
119 struct iommu_table_cb *parms; 106 struct iommu_table_cb *parms;
120 107
@@ -124,9 +111,9 @@ static void iommu_table_getparms(struct pci_dn *pdn,
124 111
125 memset(parms, 0, sizeof(*parms)); 112 memset(parms, 0, sizeof(*parms));
126 113
127 parms->itc_busno = pdn->busno; 114 parms->itc_busno = busno;
128 parms->itc_slotno = pdn->LogicalSlot; 115 parms->itc_slotno = slotno;
129 parms->itc_virtbus = 0; 116 parms->itc_virtbus = virtbus;
130 117
131 HvCallXm_getTceTableParms(iseries_hv_addr(parms)); 118 HvCallXm_getTceTableParms(iseries_hv_addr(parms));
132 119
@@ -134,17 +121,40 @@ static void iommu_table_getparms(struct pci_dn *pdn,
134 panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms); 121 panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms);
135 122
136 /* itc_size is in pages worth of table, it_size is in # of entries */ 123 /* itc_size is in pages worth of table, it_size is in # of entries */
137 tbl->it_size = (parms->itc_size * PAGE_SIZE) / sizeof(union tce_entry); 124 tbl->it_size = ((parms->itc_size * TCE_PAGE_SIZE) /
125 sizeof(union tce_entry)) >> TCE_PAGE_FACTOR;
138 tbl->it_busno = parms->itc_busno; 126 tbl->it_busno = parms->itc_busno;
139 tbl->it_offset = parms->itc_offset; 127 tbl->it_offset = parms->itc_offset >> TCE_PAGE_FACTOR;
140 tbl->it_index = parms->itc_index; 128 tbl->it_index = parms->itc_index;
141 tbl->it_blocksize = 1; 129 tbl->it_blocksize = 1;
142 tbl->it_type = TCE_PCI; 130 tbl->it_type = virtbus ? TCE_VB : TCE_PCI;
143 131
144 kfree(parms); 132 kfree(parms);
145} 133}
146 134
147 135
136#ifdef CONFIG_PCI
137/*
138 * This function compares the known tables to find an iommu_table
139 * that has already been built for hardware TCEs.
140 */
141static struct iommu_table *iommu_table_find(struct iommu_table * tbl)
142{
143 struct pci_dn *pdn;
144
145 list_for_each_entry(pdn, &iSeries_Global_Device_List, Device_List) {
146 struct iommu_table *it = pdn->iommu_table;
147 if ((it != NULL) &&
148 (it->it_type == TCE_PCI) &&
149 (it->it_offset == tbl->it_offset) &&
150 (it->it_index == tbl->it_index) &&
151 (it->it_size == tbl->it_size))
152 return it;
153 }
154 return NULL;
155}
156
157
148void iommu_devnode_init_iSeries(struct device_node *dn) 158void iommu_devnode_init_iSeries(struct device_node *dn)
149{ 159{
150 struct iommu_table *tbl; 160 struct iommu_table *tbl;
@@ -152,7 +162,7 @@ void iommu_devnode_init_iSeries(struct device_node *dn)
152 162
153 tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); 163 tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
154 164
155 iommu_table_getparms(pdn, tbl); 165 iommu_table_getparms_iSeries(pdn->busno, pdn->LogicalSlot, 0, tbl);
156 166
157 /* Look for existing tce table */ 167 /* Look for existing tce table */
158 pdn->iommu_table = iommu_table_find(tbl); 168 pdn->iommu_table = iommu_table_find(tbl);
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index fda712b42168..c5207064977d 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -320,11 +320,11 @@ static void __init iSeries_init_early(void)
320 */ 320 */
321 if (naca.xRamDisk) { 321 if (naca.xRamDisk) {
322 initrd_start = (unsigned long)__va(naca.xRamDisk); 322 initrd_start = (unsigned long)__va(naca.xRamDisk);
323 initrd_end = initrd_start + naca.xRamDiskSize * PAGE_SIZE; 323 initrd_end = initrd_start + naca.xRamDiskSize * HW_PAGE_SIZE;
324 initrd_below_start_ok = 1; // ramdisk in kernel space 324 initrd_below_start_ok = 1; // ramdisk in kernel space
325 ROOT_DEV = Root_RAM0; 325 ROOT_DEV = Root_RAM0;
326 if (((rd_size * 1024) / PAGE_SIZE) < naca.xRamDiskSize) 326 if (((rd_size * 1024) / HW_PAGE_SIZE) < naca.xRamDiskSize)
327 rd_size = (naca.xRamDiskSize * PAGE_SIZE) / 1024; 327 rd_size = (naca.xRamDiskSize * HW_PAGE_SIZE) / 1024;
328 } else 328 } else
329#endif /* CONFIG_BLK_DEV_INITRD */ 329#endif /* CONFIG_BLK_DEV_INITRD */
330 { 330 {
@@ -470,13 +470,14 @@ static void __init build_iSeries_Memory_Map(void)
470 */ 470 */
471 hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress()); 471 hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress());
472 hptSizePages = (u32)HvCallHpt_getHptPages(); 472 hptSizePages = (u32)HvCallHpt_getHptPages();
473 hptSizeChunks = hptSizePages >> (MSCHUNKS_CHUNK_SHIFT - PAGE_SHIFT); 473 hptSizeChunks = hptSizePages >>
474 (MSCHUNKS_CHUNK_SHIFT - HW_PAGE_SHIFT);
474 hptLastChunk = hptFirstChunk + hptSizeChunks - 1; 475 hptLastChunk = hptFirstChunk + hptSizeChunks - 1;
475 476
476 printk("HPT absolute addr = %016lx, size = %dK\n", 477 printk("HPT absolute addr = %016lx, size = %dK\n",
477 chunk_to_addr(hptFirstChunk), hptSizeChunks * 256); 478 chunk_to_addr(hptFirstChunk), hptSizeChunks * 256);
478 479
479 ppc64_pft_size = __ilog2(hptSizePages * PAGE_SIZE); 480 ppc64_pft_size = __ilog2(hptSizePages * HW_PAGE_SIZE);
480 481
481 /* 482 /*
482 * The actual hashed page table is in the hypervisor, 483 * The actual hashed page table is in the hypervisor,
@@ -629,7 +630,7 @@ static void __init iSeries_fixup_klimit(void)
629 */ 630 */
630 if (naca.xRamDisk) 631 if (naca.xRamDisk)
631 klimit = KERNELBASE + (u64)naca.xRamDisk + 632 klimit = KERNELBASE + (u64)naca.xRamDisk +
632 (naca.xRamDiskSize * PAGE_SIZE); 633 (naca.xRamDiskSize * HW_PAGE_SIZE);
633 else { 634 else {
634 /* 635 /*
635 * No ram disk was included - check and see if there 636 * No ram disk was included - check and see if there
diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c
index c27a66876c2c..384360ee06ec 100644
--- a/arch/powerpc/platforms/iseries/vio.c
+++ b/arch/powerpc/platforms/iseries/vio.c
@@ -30,41 +30,14 @@ static struct iommu_table vio_iommu_table;
30 30
31static void __init iommu_vio_init(void) 31static void __init iommu_vio_init(void)
32{ 32{
33 struct iommu_table *t; 33 iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table);
34 struct iommu_table_cb cb; 34 veth_iommu_table.it_size /= 2;
35 unsigned long cbp; 35 vio_iommu_table = veth_iommu_table;
36 unsigned long itc_entries; 36 vio_iommu_table.it_offset += veth_iommu_table.it_size;
37 37
38 cb.itc_busno = 255; /* Bus 255 is the virtual bus */ 38 if (!iommu_init_table(&veth_iommu_table))
39 cb.itc_virtbus = 0xff; /* Ask for virtual bus */
40
41 cbp = virt_to_abs(&cb);
42 HvCallXm_getTceTableParms(cbp);
43
44 itc_entries = cb.itc_size * PAGE_SIZE / sizeof(union tce_entry);
45 veth_iommu_table.it_size = itc_entries / 2;
46 veth_iommu_table.it_busno = cb.itc_busno;
47 veth_iommu_table.it_offset = cb.itc_offset;
48 veth_iommu_table.it_index = cb.itc_index;
49 veth_iommu_table.it_type = TCE_VB;
50 veth_iommu_table.it_blocksize = 1;
51
52 t = iommu_init_table(&veth_iommu_table);
53
54 if (!t)
55 printk("Virtual Bus VETH TCE table failed.\n"); 39 printk("Virtual Bus VETH TCE table failed.\n");
56 40 if (!iommu_init_table(&vio_iommu_table))
57 vio_iommu_table.it_size = itc_entries - veth_iommu_table.it_size;
58 vio_iommu_table.it_busno = cb.itc_busno;
59 vio_iommu_table.it_offset = cb.itc_offset +
60 veth_iommu_table.it_size;
61 vio_iommu_table.it_index = cb.itc_index;
62 vio_iommu_table.it_type = TCE_VB;
63 vio_iommu_table.it_blocksize = 1;
64
65 t = iommu_init_table(&vio_iommu_table);
66
67 if (!t)
68 printk("Virtual Bus VIO TCE table failed.\n"); 41 printk("Virtual Bus VIO TCE table failed.\n");
69} 42}
70 43
diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c
index fe97bfbf7463..842672695598 100644
--- a/arch/powerpc/platforms/iseries/viopath.c
+++ b/arch/powerpc/platforms/iseries/viopath.c
@@ -68,7 +68,8 @@ static DEFINE_SPINLOCK(statuslock);
68 * For each kind of event we allocate a buffer that is 68 * For each kind of event we allocate a buffer that is
69 * guaranteed not to cross a page boundary 69 * guaranteed not to cross a page boundary
70 */ 70 */
71static unsigned char event_buffer[VIO_MAX_SUBTYPES * 256] __page_aligned; 71static unsigned char event_buffer[VIO_MAX_SUBTYPES * 256]
72 __attribute__((__aligned__(4096)));
72static atomic_t event_buffer_available[VIO_MAX_SUBTYPES]; 73static atomic_t event_buffer_available[VIO_MAX_SUBTYPES];
73static int event_buffer_initialised; 74static int event_buffer_initialised;
74 75
@@ -116,12 +117,12 @@ static int proc_viopath_show(struct seq_file *m, void *v)
116 HvLpEvent_Rc hvrc; 117 HvLpEvent_Rc hvrc;
117 DECLARE_MUTEX_LOCKED(Semaphore); 118 DECLARE_MUTEX_LOCKED(Semaphore);
118 119
119 buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 120 buf = kmalloc(HW_PAGE_SIZE, GFP_KERNEL);
120 if (!buf) 121 if (!buf)
121 return 0; 122 return 0;
122 memset(buf, 0, PAGE_SIZE); 123 memset(buf, 0, HW_PAGE_SIZE);
123 124
124 handle = dma_map_single(iSeries_vio_dev, buf, PAGE_SIZE, 125 handle = dma_map_single(iSeries_vio_dev, buf, HW_PAGE_SIZE,
125 DMA_FROM_DEVICE); 126 DMA_FROM_DEVICE);
126 127
127 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, 128 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
@@ -131,7 +132,7 @@ static int proc_viopath_show(struct seq_file *m, void *v)
131 viopath_sourceinst(viopath_hostLp), 132 viopath_sourceinst(viopath_hostLp),
132 viopath_targetinst(viopath_hostLp), 133 viopath_targetinst(viopath_hostLp),
133 (u64)(unsigned long)&Semaphore, VIOVERSION << 16, 134 (u64)(unsigned long)&Semaphore, VIOVERSION << 16,
134 ((u64)handle) << 32, PAGE_SIZE, 0, 0); 135 ((u64)handle) << 32, HW_PAGE_SIZE, 0, 0);
135 136
136 if (hvrc != HvLpEvent_Rc_Good) 137 if (hvrc != HvLpEvent_Rc_Good)
137 printk(VIOPATH_KERN_WARN "hv error on op %d\n", (int)hvrc); 138 printk(VIOPATH_KERN_WARN "hv error on op %d\n", (int)hvrc);
@@ -140,7 +141,7 @@ static int proc_viopath_show(struct seq_file *m, void *v)
140 141
141 vlanMap = HvLpConfig_getVirtualLanIndexMap(); 142 vlanMap = HvLpConfig_getVirtualLanIndexMap();
142 143
143 buf[PAGE_SIZE-1] = '\0'; 144 buf[HW_PAGE_SIZE-1] = '\0';
144 seq_printf(m, "%s", buf); 145 seq_printf(m, "%s", buf);
145 seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap); 146 seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap);
146 seq_printf(m, "SRLNBR=%c%c%c%c%c%c%c\n", 147 seq_printf(m, "SRLNBR=%c%c%c%c%c%c%c\n",
@@ -152,7 +153,8 @@ static int proc_viopath_show(struct seq_file *m, void *v)
152 e2a(xItExtVpdPanel.systemSerial[4]), 153 e2a(xItExtVpdPanel.systemSerial[4]),
153 e2a(xItExtVpdPanel.systemSerial[5])); 154 e2a(xItExtVpdPanel.systemSerial[5]));
154 155
155 dma_unmap_single(iSeries_vio_dev, handle, PAGE_SIZE, DMA_FROM_DEVICE); 156 dma_unmap_single(iSeries_vio_dev, handle, HW_PAGE_SIZE,
157 DMA_FROM_DEVICE);
156 kfree(buf); 158 kfree(buf);
157 159
158 return 0; 160 return 0;
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index e384a5a91796..ab0c6dd6ec94 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -19,7 +19,7 @@
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */ 20 */
21 21
22#define DEBUG 22#undef DEBUG_LOW
23 23
24#include <linux/config.h> 24#include <linux/config.h>
25#include <linux/kernel.h> 25#include <linux/kernel.h>
@@ -41,10 +41,10 @@
41 41
42#include "plpar_wrappers.h" 42#include "plpar_wrappers.h"
43 43
44#ifdef DEBUG 44#ifdef DEBUG_LOW
45#define DBG(fmt...) udbg_printf(fmt) 45#define DBG_LOW(fmt...) do { udbg_printf(fmt); } while(0)
46#else 46#else
47#define DBG(fmt...) 47#define DBG_LOW(fmt...) do { } while(0)
48#endif 48#endif
49 49
50/* in pSeries_hvCall.S */ 50/* in pSeries_hvCall.S */
@@ -276,8 +276,9 @@ void vpa_init(int cpu)
276} 276}
277 277
278long pSeries_lpar_hpte_insert(unsigned long hpte_group, 278long pSeries_lpar_hpte_insert(unsigned long hpte_group,
279 unsigned long va, unsigned long prpn, 279 unsigned long va, unsigned long pa,
280 unsigned long vflags, unsigned long rflags) 280 unsigned long rflags, unsigned long vflags,
281 int psize)
281{ 282{
282 unsigned long lpar_rc; 283 unsigned long lpar_rc;
283 unsigned long flags; 284 unsigned long flags;
@@ -285,11 +286,28 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group,
285 unsigned long hpte_v, hpte_r; 286 unsigned long hpte_v, hpte_r;
286 unsigned long dummy0, dummy1; 287 unsigned long dummy0, dummy1;
287 288
288 hpte_v = ((va >> 23) << HPTE_V_AVPN_SHIFT) | vflags | HPTE_V_VALID; 289 if (!(vflags & HPTE_V_BOLTED))
289 if (vflags & HPTE_V_LARGE) 290 DBG_LOW("hpte_insert(group=%lx, va=%016lx, pa=%016lx, "
290 hpte_v &= ~(1UL << HPTE_V_AVPN_SHIFT); 291 "rflags=%lx, vflags=%lx, psize=%d)\n",
291 292 hpte_group, va, pa, rflags, vflags, psize);
292 hpte_r = (prpn << HPTE_R_RPN_SHIFT) | rflags; 293
294 hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID;
295 hpte_r = hpte_encode_r(pa, psize) | rflags;
296
297 if (!(vflags & HPTE_V_BOLTED))
298 DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r);
299
300#if 1
301 {
302 int i;
303 for (i=0;i<8;i++) {
304 unsigned long w0, w1;
305 plpar_pte_read(0, hpte_group, &w0, &w1);
306 BUG_ON (HPTE_V_COMPARE(hpte_v, w0)
307 && (w0 & HPTE_V_VALID));
308 }
309 }
310#endif
293 311
294 /* Now fill in the actual HPTE */ 312 /* Now fill in the actual HPTE */
295 /* Set CEC cookie to 0 */ 313 /* Set CEC cookie to 0 */
@@ -299,23 +317,30 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group,
299 /* Exact = 0 */ 317 /* Exact = 0 */
300 flags = 0; 318 flags = 0;
301 319
302 /* XXX why is this here? - Anton */ 320 /* Make pHyp happy */
303 if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) 321 if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE))
304 hpte_r &= ~_PAGE_COHERENT; 322 hpte_r &= ~_PAGE_COHERENT;
305 323
306 lpar_rc = plpar_hcall(H_ENTER, flags, hpte_group, hpte_v, 324 lpar_rc = plpar_hcall(H_ENTER, flags, hpte_group, hpte_v,
307 hpte_r, &slot, &dummy0, &dummy1); 325 hpte_r, &slot, &dummy0, &dummy1);
308 326 if (unlikely(lpar_rc == H_PTEG_Full)) {
309 if (unlikely(lpar_rc == H_PTEG_Full)) 327 if (!(vflags & HPTE_V_BOLTED))
328 DBG_LOW(" full\n");
310 return -1; 329 return -1;
330 }
311 331
312 /* 332 /*
313 * Since we try and ioremap PHBs we don't own, the pte insert 333 * Since we try and ioremap PHBs we don't own, the pte insert
314 * will fail. However we must catch the failure in hash_page 334 * will fail. However we must catch the failure in hash_page
315 * or we will loop forever, so return -2 in this case. 335 * or we will loop forever, so return -2 in this case.
316 */ 336 */
317 if (unlikely(lpar_rc != H_Success)) 337 if (unlikely(lpar_rc != H_Success)) {
338 if (!(vflags & HPTE_V_BOLTED))
339 DBG_LOW(" lpar err %d\n", lpar_rc);
318 return -2; 340 return -2;
341 }
342 if (!(vflags & HPTE_V_BOLTED))
343 DBG_LOW(" -> slot: %d\n", slot & 7);
319 344
320 /* Because of iSeries, we have to pass down the secondary 345 /* Because of iSeries, we have to pass down the secondary
321 * bucket bit here as well 346 * bucket bit here as well
@@ -340,10 +365,8 @@ static long pSeries_lpar_hpte_remove(unsigned long hpte_group)
340 /* don't remove a bolted entry */ 365 /* don't remove a bolted entry */
341 lpar_rc = plpar_pte_remove(H_ANDCOND, hpte_group + slot_offset, 366 lpar_rc = plpar_pte_remove(H_ANDCOND, hpte_group + slot_offset,
342 (0x1UL << 4), &dummy1, &dummy2); 367 (0x1UL << 4), &dummy1, &dummy2);
343
344 if (lpar_rc == H_Success) 368 if (lpar_rc == H_Success)
345 return i; 369 return i;
346
347 BUG_ON(lpar_rc != H_Not_Found); 370 BUG_ON(lpar_rc != H_Not_Found);
348 371
349 slot_offset++; 372 slot_offset++;
@@ -371,20 +394,28 @@ static void pSeries_lpar_hptab_clear(void)
371 * We can probably optimize here and assume the high bits of newpp are 394 * We can probably optimize here and assume the high bits of newpp are
372 * already zero. For now I am paranoid. 395 * already zero. For now I am paranoid.
373 */ 396 */
374static long pSeries_lpar_hpte_updatepp(unsigned long slot, unsigned long newpp, 397static long pSeries_lpar_hpte_updatepp(unsigned long slot,
375 unsigned long va, int large, int local) 398 unsigned long newpp,
399 unsigned long va,
400 int psize, int local)
376{ 401{
377 unsigned long lpar_rc; 402 unsigned long lpar_rc;
378 unsigned long flags = (newpp & 7) | H_AVPN; 403 unsigned long flags = (newpp & 7) | H_AVPN;
379 unsigned long avpn = va >> 23; 404 unsigned long want_v;
380 405
381 if (large) 406 want_v = hpte_encode_v(va, psize);
382 avpn &= ~0x1UL;
383 407
384 lpar_rc = plpar_pte_protect(flags, slot, (avpn << 7)); 408 DBG_LOW(" update: avpnv=%016lx, hash=%016lx, f=%x, psize: %d ... ",
409 want_v & HPTE_V_AVPN, slot, flags, psize);
385 410
386 if (lpar_rc == H_Not_Found) 411 lpar_rc = plpar_pte_protect(flags, slot, want_v & HPTE_V_AVPN);
412
413 if (lpar_rc == H_Not_Found) {
414 DBG_LOW("not found !\n");
387 return -1; 415 return -1;
416 }
417
418 DBG_LOW("ok\n");
388 419
389 BUG_ON(lpar_rc != H_Success); 420 BUG_ON(lpar_rc != H_Success);
390 421
@@ -410,21 +441,22 @@ static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot)
410 return dword0; 441 return dword0;
411} 442}
412 443
413static long pSeries_lpar_hpte_find(unsigned long vpn) 444static long pSeries_lpar_hpte_find(unsigned long va, int psize)
414{ 445{
415 unsigned long hash; 446 unsigned long hash;
416 unsigned long i, j; 447 unsigned long i, j;
417 long slot; 448 long slot;
418 unsigned long hpte_v; 449 unsigned long want_v, hpte_v;
419 450
420 hash = hpt_hash(vpn, 0); 451 hash = hpt_hash(va, mmu_psize_defs[psize].shift);
452 want_v = hpte_encode_v(va, psize);
421 453
422 for (j = 0; j < 2; j++) { 454 for (j = 0; j < 2; j++) {
423 slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; 455 slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
424 for (i = 0; i < HPTES_PER_GROUP; i++) { 456 for (i = 0; i < HPTES_PER_GROUP; i++) {
425 hpte_v = pSeries_lpar_hpte_getword0(slot); 457 hpte_v = pSeries_lpar_hpte_getword0(slot);
426 458
427 if ((HPTE_V_AVPN_VAL(hpte_v) == (vpn >> 11)) 459 if (HPTE_V_COMPARE(hpte_v, want_v)
428 && (hpte_v & HPTE_V_VALID) 460 && (hpte_v & HPTE_V_VALID)
429 && (!!(hpte_v & HPTE_V_SECONDARY) == j)) { 461 && (!!(hpte_v & HPTE_V_SECONDARY) == j)) {
430 /* HPTE matches */ 462 /* HPTE matches */
@@ -441,17 +473,15 @@ static long pSeries_lpar_hpte_find(unsigned long vpn)
441} 473}
442 474
443static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, 475static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp,
444 unsigned long ea) 476 unsigned long ea,
477 int psize)
445{ 478{
446 unsigned long lpar_rc; 479 unsigned long lpar_rc, slot, vsid, va, flags;
447 unsigned long vsid, va, vpn, flags;
448 long slot;
449 480
450 vsid = get_kernel_vsid(ea); 481 vsid = get_kernel_vsid(ea);
451 va = (vsid << 28) | (ea & 0x0fffffff); 482 va = (vsid << 28) | (ea & 0x0fffffff);
452 vpn = va >> PAGE_SHIFT;
453 483
454 slot = pSeries_lpar_hpte_find(vpn); 484 slot = pSeries_lpar_hpte_find(va, psize);
455 BUG_ON(slot == -1); 485 BUG_ON(slot == -1);
456 486
457 flags = newpp & 7; 487 flags = newpp & 7;
@@ -461,18 +491,18 @@ static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp,
461} 491}
462 492
463static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, 493static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
464 int large, int local) 494 int psize, int local)
465{ 495{
466 unsigned long avpn = va >> 23; 496 unsigned long want_v;
467 unsigned long lpar_rc; 497 unsigned long lpar_rc;
468 unsigned long dummy1, dummy2; 498 unsigned long dummy1, dummy2;
469 499
470 if (large) 500 DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d",
471 avpn &= ~0x1UL; 501 slot, va, psize, local);
472
473 lpar_rc = plpar_pte_remove(H_AVPN, slot, (avpn << 7), &dummy1,
474 &dummy2);
475 502
503 want_v = hpte_encode_v(va, psize);
504 lpar_rc = plpar_pte_remove(H_AVPN, slot, want_v & HPTE_V_AVPN,
505 &dummy1, &dummy2);
476 if (lpar_rc == H_Not_Found) 506 if (lpar_rc == H_Not_Found)
477 return; 507 return;
478 508
@@ -494,7 +524,8 @@ void pSeries_lpar_flush_hash_range(unsigned long number, int local)
494 spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); 524 spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags);
495 525
496 for (i = 0; i < number; i++) 526 for (i = 0; i < number; i++)
497 flush_hash_page(batch->vaddr[i], batch->pte[i], local); 527 flush_hash_page(batch->vaddr[i], batch->pte[i],
528 batch->psize, local);
498 529
499 if (lock_tlbie) 530 if (lock_tlbie)
500 spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); 531 spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags);