rtas_pci.c 7.1 KB
Newer Older
1 2 3 4 5
/*
 * Copyright (C) 2001 Dave Engebretsen, IBM Corporation
 * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
 *
 * RTAS specific routines for PCI.
6
 *
7 8 9 10 11 12
 * Based on code from pci.c, chrp_pci.c and pSeries_pci.c
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
13
 *
14 15 16 17
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
18
 *
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */

#include <linux/kernel.h>
#include <linux/threads.h>
#include <linux/pci.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/bootmem.h>

#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/pci-bridge.h>
#include <asm/iommu.h>
#include <asm/rtas.h>
39
#include <asm/mpic.h>
40
#include <asm/ppc-pci.h>
41
#include <asm/eeh.h>
42 43 44 45 46 47 48

/* RTAS tokens */
static int read_pci_config;
static int write_pci_config;
static int ibm_read_pci_config;
static int ibm_write_pci_config;

49
static inline int config_access_valid(struct pci_dn *dn, int where)
50 51 52 53 54 55 56 57 58
{
	if (where < 256)
		return 1;
	if (where < 4096 && dn->pci_ext_config_space)
		return 1;

	return 0;
}

59
int rtas_read_config(struct pci_dn *pdn, int where, int size, u32 *val)
60 61 62 63 64
{
	int returnval = -1;
	unsigned long buid, addr;
	int ret;

65
	if (!pdn)
66
		return PCIBIOS_DEVICE_NOT_FOUND;
67
	if (!config_access_valid(pdn, where))
68 69
		return PCIBIOS_BAD_REGISTER_NUMBER;

70
	addr = rtas_config_addr(pdn->busno, pdn->devfn, where);
71
	buid = pdn->phb->buid;
72 73
	if (buid) {
		ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval,
74
				addr, BUID_HI(buid), BUID_LO(buid), size);
75 76 77 78 79 80 81 82
	} else {
		ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size);
	}
	*val = returnval;

	if (ret)
		return PCIBIOS_DEVICE_NOT_FOUND;

83
	if (returnval == EEH_IO_ERROR_VALUE(size) &&
84
	    eeh_dn_check_failure (pdn->node, NULL))
85 86 87 88 89 90 91 92 93 94 95
		return PCIBIOS_DEVICE_NOT_FOUND;

	return PCIBIOS_SUCCESSFUL;
}

static int rtas_pci_read_config(struct pci_bus *bus,
				unsigned int devfn,
				int where, int size, u32 *val)
{
	struct device_node *busdn, *dn;

96
	busdn = pci_bus_to_OF_node(bus);
97 98

	/* Search only direct children of the bus */
99 100 101
	for (dn = busdn->child; dn; dn = dn->sibling) {
		struct pci_dn *pdn = PCI_DN(dn);
		if (pdn && pdn->devfn == devfn
102
		    && of_device_is_available(dn))
103 104
			return rtas_read_config(pdn, where, size, val);
	}
105

106 107 108
	return PCIBIOS_DEVICE_NOT_FOUND;
}

109
int rtas_write_config(struct pci_dn *pdn, int where, int size, u32 val)
110 111 112 113
{
	unsigned long buid, addr;
	int ret;

114
	if (!pdn)
115
		return PCIBIOS_DEVICE_NOT_FOUND;
116
	if (!config_access_valid(pdn, where))
117 118
		return PCIBIOS_BAD_REGISTER_NUMBER;

119
	addr = rtas_config_addr(pdn->busno, pdn->devfn, where);
120
	buid = pdn->phb->buid;
121
	if (buid) {
122 123
		ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr,
			BUID_HI(buid), BUID_LO(buid), size, (ulong) val);
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
	} else {
		ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val);
	}

	if (ret)
		return PCIBIOS_DEVICE_NOT_FOUND;

	return PCIBIOS_SUCCESSFUL;
}

static int rtas_pci_write_config(struct pci_bus *bus,
				 unsigned int devfn,
				 int where, int size, u32 val)
{
	struct device_node *busdn, *dn;

140
	busdn = pci_bus_to_OF_node(bus);
141 142

	/* Search only direct children of the bus */
143 144 145
	for (dn = busdn->child; dn; dn = dn->sibling) {
		struct pci_dn *pdn = PCI_DN(dn);
		if (pdn && pdn->devfn == devfn
146
		    && of_device_is_available(dn))
147 148
			return rtas_write_config(pdn, where, size, val);
	}
149 150 151
	return PCIBIOS_DEVICE_NOT_FOUND;
}

152
static struct pci_ops rtas_pci_ops = {
153 154
	.read = rtas_pci_read_config,
	.write = rtas_pci_write_config,
155 156
};

157
static int is_python(struct device_node *dev)
158
{
159
	const char *model = of_get_property(dev, "model", NULL);
160 161 162 163 164 165 166

	if (model && strstr(model, "Python"))
		return 1;

	return 0;
}

167
static void python_countermeasures(struct device_node *dev)
168
{
169
	struct resource registers;
170 171 172
	void __iomem *chip_regs;
	volatile u32 val;

173 174
	if (of_address_to_resource(dev, 0, &registers)) {
		printk(KERN_ERR "Can't get address for Python workarounds !\n");
175
		return;
176
	}
177 178

	/* Python's register file is 1 MB in size. */
179
	chip_regs = ioremap(registers.start & ~(0xfffffUL), 0x100000);
180

181
	/*
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
	 * Firmware doesn't always clear this bit which is critical
	 * for good performance - Anton
	 */

#define PRG_CL_RESET_VALID 0x00010000

	val = in_be32(chip_regs + 0xf6030);
	if (val & PRG_CL_RESET_VALID) {
		printk(KERN_INFO "Python workaround: ");
		val &= ~PRG_CL_RESET_VALID;
		out_be32(chip_regs + 0xf6030, val);
		/*
		 * We must read it back for changes to
		 * take effect
		 */
		val = in_be32(chip_regs + 0xf6030);
		printk("reg0: %x\n", val);
	}

	iounmap(chip_regs);
}

void __init init_pci_config_tokens (void)
{
	read_pci_config = rtas_token("read-pci-config");
	write_pci_config = rtas_token("write-pci-config");
	ibm_read_pci_config = rtas_token("ibm,read-pci-config");
	ibm_write_pci_config = rtas_token("ibm,write-pci-config");
}

unsigned long __devinit get_phb_buid (struct device_node *phb)
{
214
	struct resource r;
215

216
	if (ibm_read_pci_config == -1)
217
		return 0;
218
	if (of_address_to_resource(phb, 0, &r))
219
		return 0;
220
	return r.start;
221 222 223 224 225
}

static int phb_set_bus_ranges(struct device_node *dev,
			      struct pci_controller *phb)
{
226
	const int *bus_range;
227 228
	unsigned int len;

229
	bus_range = of_get_property(dev, "bus-range", &len);
230 231 232
	if (bus_range == NULL || len < 2 * sizeof(int)) {
		return 1;
 	}
233

234 235 236 237 238 239
	phb->first_busno =  bus_range[0];
	phb->last_busno  =  bus_range[1];

	return 0;
}

240
int __devinit rtas_setup_phb(struct pci_controller *phb)
241
{
242
	struct device_node *dev = phb->dn;
243

244
	if (is_python(dev))
245
		python_countermeasures(dev);
246 247 248 249 250 251 252 253 254 255

	if (phb_set_bus_ranges(dev, phb))
		return 1;

	phb->ops = &rtas_pci_ops;
	phb->buid = get_phb_buid(dev);

	return 0;
}

256
void __init find_and_init_phbs(void)
257 258 259 260 261
{
	struct device_node *node;
	struct pci_controller *phb;
	struct device_node *root = of_find_node_by_path("/");

262
	for_each_child_of_node(root, node) {
263 264
		if (node->type == NULL || (strcmp(node->type, "pci") != 0 &&
					   strcmp(node->type, "pciex") != 0))
265 266
			continue;

267
		phb = pcibios_alloc_controller(node);
268 269
		if (!phb)
			continue;
270
		rtas_setup_phb(phb);
271
		pci_process_bridge_OF_ranges(phb, node, 0);
272
		isa_bridge_find_early(phb);
273 274 275 276 277 278
	}

	of_node_put(root);
	pci_devs_phb_init();

	/*
279
	 * PCI_PROBE_ONLY and PCI_REASSIGN_ALL_BUS can be set via properties
280 281 282
	 * in chosen.
	 */
	if (of_chosen) {
283
		const int *prop;
284

285
		prop = of_get_property(of_chosen,
286
				"linux,pci-probe-only", NULL);
287 288 289 290 291 292
		if (prop) {
			if (*prop)
				pci_add_flags(PCI_PROBE_ONLY);
			else
				pci_clear_flags(PCI_PROBE_ONLY);
		}
293

294
#ifdef CONFIG_PPC32 /* Will be made generic soon */
295
		prop = of_get_property(of_chosen,
296
				"linux,pci-assign-all-buses", NULL);
297
		if (prop && *prop)
298
			pci_add_flags(PCI_REASSIGN_ALL_BUS);
299
#endif /* CONFIG_PPC32 */
300 301
	}
}