1 /************************************************************************/
2 /* This module supports the iSeries I/O Address translation mapping */
3 /* Copyright (C) 20yy <Allan H Trautman> <IBM Corp> */
4 /* */
5 /* This program is free software; you can redistribute it and/or modify */
6 /* it under the terms of the GNU General Public License as published by */
7 /* the Free Software Foundation; either version 2 of the License, or */
8 /* (at your option) any later version. */
9 /* */
10 /* This program is distributed in the hope that it will be useful, */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
13 /* GNU General Public License for more details. */
14 /* */
15 /* You should have received a copy of the GNU General Public License */
16 /* along with this program; if not, write to the: */
17 /* Free Software Foundation, Inc., */
18 /* 59 Temple Place, Suite 330, */
19 /* Boston, MA 02111-1307 USA */
20 /************************************************************************/
21 /* Change Activity: */
22 /* Created, December 14, 2000 */
23 /* Added Bar table for IoMm performance. */
24 /* Ported to ppc64 */
25 /* Added dynamic table allocation */
26 /* End Change Activity */
27 /************************************************************************/
28 #include <asm/types.h>
29 #include <asm/resource.h>
30 #include <linux/pci.h>
31 #include <linux/spinlock.h>
32 #include <asm/ppcdebug.h>
33 #include <asm/flight_recorder.h>
34 #include <asm/iSeries/HvCallPci.h>
35 #include <asm/iSeries/iSeries_pci.h>
36
37 #include "iSeries_IoMmTable.h"
38 #include "pci.h"
39
40 /*******************************************************************/
41 /* Table defines */
42 /* Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space. */
43 /*******************************************************************/
44 #define Max_Entries 1024
45 unsigned long iSeries_IoMmTable_Entry_Size = 0x0000000000400000;
46 unsigned long iSeries_Base_Io_Memory = 0xE000000000000000;
47 unsigned long iSeries_Max_Io_Memory = 0xE000000000000000;
48 static long iSeries_CurrentIndex = 0;
49
50 /*******************************************************************/
51 /* Lookup Tables. */
52 /*******************************************************************/
53 struct iSeries_Device_Node** iSeries_IoMmTable;
54 u8* iSeries_IoBarTable;
55
56 /*******************************************************************/
57 /* Static and Global variables */
58 /*******************************************************************/
59 static char* iSeriesPciIoText = "iSeries PCI I/O";
60 static spinlock_t iSeriesIoMmTableLock = SPIN_LOCK_UNLOCKED;
61
62 /*******************************************************************/
63 /* iSeries_IoMmTable_Initialize */
64 /*******************************************************************/
65 /* Allocates and initalizes the Address Translation Table and Bar */
66 /* Tables to get them ready for use. Must be called before any */
67 /* I/O space is handed out to the device BARs. */
68 /* A follow up method,iSeries_IoMmTable_Status can be called to */
69 /* adjust the table after the device BARs have been assiged to */
70 /* resize the table. */
71 /*******************************************************************/
iSeries_IoMmTable_Initialize(void)72 void iSeries_IoMmTable_Initialize(void)
73 {
74 spin_lock(&iSeriesIoMmTableLock);
75 iSeries_IoMmTable = kmalloc(sizeof(void*)*Max_Entries,GFP_KERNEL);
76 iSeries_IoBarTable = kmalloc(sizeof(u8)*Max_Entries, GFP_KERNEL);
77 spin_unlock(&iSeriesIoMmTableLock);
78 PCIFR("IoMmTable Initialized 0x%p", iSeries_IoMmTable);
79 if(iSeries_IoMmTable == NULL || iSeries_IoBarTable == NULL) {
80 panic("PCI: I/O tables allocation failed.\n");
81 }
82 }
83
84 /*******************************************************************/
85 /* iSeries_IoMmTable_AllocateEntry */
86 /*******************************************************************/
87 /* Adds pci_dev entry in address translation table */
88 /*******************************************************************/
89 /* - Allocates the number of entries required in table base on BAR */
90 /* size. */
91 /* - Allocates starting at iSeries_Base_Io_Memory and increases. */
92 /* - The size is round up to be a multiple of entry size. */
93 /* - CurrentIndex is incremented to keep track of the last entry. */
94 /* - Builds the resource entry for allocated BARs. */
95 /*******************************************************************/
iSeries_IoMmTable_AllocateEntry(struct pci_dev * PciDev,int BarNumber)96 static void iSeries_IoMmTable_AllocateEntry(struct pci_dev* PciDev, int BarNumber)
97 {
98 struct resource* BarResource = &PciDev->resource[BarNumber];
99 long BarSize = pci_resource_len(PciDev,BarNumber);
100 /***********************************************************/
101 /* No space to allocate, quick exit, skip Allocation. */
102 /***********************************************************/
103 if(BarSize == 0) return;
104 /***********************************************************/
105 /* Set Resource values. */
106 /***********************************************************/
107 spin_lock(&iSeriesIoMmTableLock);
108 BarResource->name = iSeriesPciIoText;
109 BarResource->start = iSeries_IoMmTable_Entry_Size*iSeries_CurrentIndex;
110 BarResource->start+= iSeries_Base_Io_Memory;
111 BarResource->end = BarResource->start+BarSize-1;
112 /***********************************************************/
113 /* Allocate the number of table entries needed for BAR. */
114 /***********************************************************/
115 while (BarSize > 0 ) {
116 *(iSeries_IoMmTable +iSeries_CurrentIndex) = (struct iSeries_Device_Node*)PciDev->sysdata;
117 *(iSeries_IoBarTable+iSeries_CurrentIndex) = BarNumber;
118 BarSize -= iSeries_IoMmTable_Entry_Size;
119 ++iSeries_CurrentIndex;
120 }
121 iSeries_Max_Io_Memory = (iSeries_IoMmTable_Entry_Size*iSeries_CurrentIndex)+iSeries_Base_Io_Memory;
122 spin_unlock(&iSeriesIoMmTableLock);
123 }
124
125 /*******************************************************************/
126 /* iSeries_allocateDeviceBars */
127 /*******************************************************************/
128 /* - Allocates ALL pci_dev BAR's and updates the resources with the*/
129 /* BAR value. BARS with zero length will have the resources */
130 /* The HvCallPci_getBarParms is used to get the size of the BAR */
131 /* space. It calls iSeries_IoMmTable_AllocateEntry to allocate */
132 /* each entry. */
133 /* - Loops through The Bar resourses(0 - 5) including the ROM */
134 /* is resource(6). */
135 /*******************************************************************/
iSeries_allocateDeviceBars(struct pci_dev * PciDev)136 void iSeries_allocateDeviceBars(struct pci_dev* PciDev)
137 {
138 struct resource* BarResource;
139 int BarNumber;
140 for(BarNumber = 0; BarNumber <= PCI_ROM_RESOURCE; ++BarNumber) {
141 BarResource = &PciDev->resource[BarNumber];
142 iSeries_IoMmTable_AllocateEntry(PciDev, BarNumber);
143 }
144 }
145
146 /************************************************************************/
147 /* Translates the IoAddress to the device that is mapped to IoSpace. */
148 /* This code is inlined, see the iSeries_pci.c file for the replacement.*/
149 /************************************************************************/
iSeries_xlateIoMmAddress(void * IoAddress)150 struct iSeries_Device_Node* iSeries_xlateIoMmAddress(void* IoAddress)
151 {
152 return NULL;
153 }
154
155 /************************************************************************
156 * Status hook for IoMmTable
157 ************************************************************************/
iSeries_IoMmTable_Status(void)158 void iSeries_IoMmTable_Status(void)
159 {
160 PCIFR("IoMmTable......: 0x%p",iSeries_IoMmTable);
161 PCIFR("IoMmTable Range: 0x%p to 0x%p",iSeries_Base_Io_Memory,iSeries_Max_Io_Memory);
162 return;
163 }
164