2 /************************************************************************/
3 /* This module supports the iSeries I/O Address translation mapping */
4 /* Copyright (C) 20yy <Allan H Trautman> <IBM Corp> */
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. */
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. */
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. */
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>
37 #include "iSeries_IoMmTable.h"
42 * Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space.
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;
53 struct iSeries_Device_Node **iSeries_IoMmTable;
54 u8 *iSeries_IoBarTable;
57 * Static and Global variables
59 static char *iSeriesPciIoText = "iSeries PCI I/O";
60 static spinlock_t iSeriesIoMmTableLock = SPIN_LOCK_UNLOCKED;
63 * iSeries_IoMmTable_Initialize
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
72 void iSeries_IoMmTable_Initialize(void)
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");
84 * iSeries_IoMmTable_AllocateEntry
86 * Adds pci_dev entry in address translation table
88 * - Allocates the number of entries required in table base on BAR
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.
95 static void iSeries_IoMmTable_AllocateEntry(struct pci_dev *PciDev,
98 struct resource *BarResource = &PciDev->resource[BarNumber];
99 long BarSize = pci_resource_len(PciDev, BarNumber);
102 * No space to allocate, quick exit, skip Allocation.
107 * Set Resource values.
109 spin_lock(&iSeriesIoMmTableLock);
110 BarResource->name = iSeriesPciIoText;
112 iSeries_IoMmTable_Entry_Size * iSeries_CurrentIndex;
113 BarResource->start += iSeries_Base_Io_Memory;
114 BarResource->end = BarResource->start+BarSize-1;
116 * Allocate the number of table entries needed for BAR.
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;
125 iSeries_Max_Io_Memory = iSeries_Base_Io_Memory +
126 (iSeries_IoMmTable_Entry_Size * iSeries_CurrentIndex);
127 spin_unlock(&iSeriesIoMmTableLock);
131 * iSeries_allocateDeviceBars
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
138 * - Loops through The Bar resources(0 - 5) including the ROM
141 void iSeries_allocateDeviceBars(struct pci_dev *PciDev)
143 struct resource *BarResource;
146 for (BarNumber = 0; BarNumber <= PCI_ROM_RESOURCE; ++BarNumber) {
147 BarResource = &PciDev->resource[BarNumber];
148 iSeries_IoMmTable_AllocateEntry(PciDev, BarNumber);
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.
156 struct iSeries_Device_Node *iSeries_xlateIoMmAddress(void *IoAddress)
162 * Status hook for IoMmTable
164 void iSeries_IoMmTable_Status(void)
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);