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