ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ppc64 / kernel / iSeries_IoMmTable.c
1 #define PCIFR(...)
2 /************************************************************************/
3 /* This module supports the iSeries I/O Address translation mapping     */
4 /* Copyright (C) 20yy  <Allan H Trautman> <IBM Corp>                    */
5 /*                                                                      */
6 /* This program is free software; you can redistribute it and/or modify */
7 /* it under the terms of the GNU General Public License as published by */
8 /* the Free Software Foundation; either version 2 of the License, or    */
9 /* (at your option) any later version.                                  */
10 /*                                                                      */
11 /* This program is distributed in the hope that it will be useful,      */ 
12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
14 /* GNU General Public License for more details.                         */
15 /*                                                                      */
16 /* You should have received a copy of the GNU General Public License    */ 
17 /* along with this program; if not, write to the:                       */
18 /* Free Software Foundation, Inc.,                                      */ 
19 /* 59 Temple Place, Suite 330,                                          */ 
20 /* Boston, MA  02111-1307  USA                                          */
21 /************************************************************************/
22 /* Change Activity:                                                     */
23 /*   Created, December 14, 2000                                         */
24 /*   Added Bar table for IoMm performance.                              */
25 /*   Ported to ppc64                                                    */
26 /*   Added dynamic table allocation                                     */
27 /* End Change Activity                                                  */
28 /************************************************************************/
29 #include <asm/types.h>
30 #include <asm/resource.h>
31 #include <linux/pci.h>
32 #include <linux/spinlock.h>
33 #include <asm/ppcdebug.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  */
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  * iSeries_IoMmTable_AllocateEntry
85  *
86  * Adds pci_dev entry in address translation table
87  *
88  * - Allocates the number of entries required in table base on BAR
89  *   size.
90  * - Allocates starting at iSeries_Base_Io_Memory and increases.
91  * - The size is round up to be a multiple of entry size.
92  * - CurrentIndex is incremented to keep track of the last entry.
93  * - Builds the resource entry for allocated BARs.
94  */
95 static void iSeries_IoMmTable_AllocateEntry(struct pci_dev *PciDev,
96                 int BarNumber)
97 {
98         struct resource *BarResource = &PciDev->resource[BarNumber];
99         long BarSize = pci_resource_len(PciDev, BarNumber);
100
101         /*
102          * No space to allocate, quick exit, skip Allocation.
103          */
104         if (BarSize == 0)
105                 return;
106         /*
107          * Set Resource values.
108          */
109         spin_lock(&iSeriesIoMmTableLock);
110         BarResource->name = iSeriesPciIoText;
111         BarResource->start =
112                 iSeries_IoMmTable_Entry_Size * iSeries_CurrentIndex;
113         BarResource->start += iSeries_Base_Io_Memory;
114         BarResource->end = BarResource->start+BarSize-1;
115         /*
116          * Allocate the number of table entries needed for BAR.
117          */
118         while (BarSize > 0 ) {
119                 *(iSeries_IoMmTable + iSeries_CurrentIndex) =
120                         (struct iSeries_Device_Node *)PciDev->sysdata;
121                 *(iSeries_IoBarTable + iSeries_CurrentIndex) = BarNumber;
122                 BarSize -= iSeries_IoMmTable_Entry_Size;
123                 ++iSeries_CurrentIndex;
124         }
125         iSeries_Max_Io_Memory = iSeries_Base_Io_Memory +
126                 (iSeries_IoMmTable_Entry_Size * iSeries_CurrentIndex);
127         spin_unlock(&iSeriesIoMmTableLock);
128 }
129
130 /*
131  * iSeries_allocateDeviceBars
132  *
133  * - Allocates ALL pci_dev BAR's and updates the resources with the
134  *   BAR value.  BARS with zero length will have the resources
135  *   The HvCallPci_getBarParms is used to get the size of the BAR
136  *   space.  It calls iSeries_IoMmTable_AllocateEntry to allocate
137  *   each entry.
138  * - Loops through The Bar resources(0 - 5) including the ROM
139  *   is resource(6).
140  */
141 void iSeries_allocateDeviceBars(struct pci_dev *PciDev)
142 {
143         struct resource *BarResource;
144         int BarNumber;
145
146         for (BarNumber = 0; BarNumber <= PCI_ROM_RESOURCE; ++BarNumber) {
147                 BarResource = &PciDev->resource[BarNumber];
148                 iSeries_IoMmTable_AllocateEntry(PciDev, BarNumber);
149         }
150 }
151
152 /*
153  * Translates the IoAddress to the device that is mapped to IoSpace.
154  * This code is inlined, see the iSeries_pci.c file for the replacement.
155  */
156 struct iSeries_Device_Node *iSeries_xlateIoMmAddress(void *IoAddress)
157 {
158         return NULL;       
159 }
160
161 /*
162  * Status hook for IoMmTable
163  */
164 void iSeries_IoMmTable_Status(void)
165 {
166         PCIFR("IoMmTable......: 0x%p", iSeries_IoMmTable);
167         PCIFR("IoMmTable Range: 0x%p to 0x%p", iSeries_Base_Io_Memory,
168                         iSeries_Max_Io_Memory);
169 }