PageRenderTime 26ms CodeModel.GetById 9ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/frv/mb93090-mb00/pci-frv.c

https://bitbucket.org/evzijst/gittest
C | 288 lines | 188 code | 26 blank | 74 comment | 54 complexity | 5b4ac5afdd33223bc09a9390e3ca5e03 MD5 | raw file
  1/* pci-frv.c: low-level PCI access routines
  2 *
  3 * Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved.
  4 * Written by David Howells (dhowells@redhat.com)
  5 * - Derived from the i386 equivalent stuff
  6 *
  7 * This program is free software; you can redistribute it and/or
  8 * modify it under the terms of the GNU General Public License
  9 * as published by the Free Software Foundation; either version
 10 * 2 of the License, or (at your option) any later version.
 11 */
 12
 13#include <linux/types.h>
 14#include <linux/kernel.h>
 15#include <linux/pci.h>
 16#include <linux/init.h>
 17#include <linux/ioport.h>
 18#include <linux/errno.h>
 19
 20#include "pci-frv.h"
 21
 22#if 0
 23void
 24pcibios_update_resource(struct pci_dev *dev, struct resource *root,
 25			struct resource *res, int resource)
 26{
 27	u32 new, check;
 28	int reg;
 29
 30	new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
 31	if (resource < 6) {
 32		reg = PCI_BASE_ADDRESS_0 + 4*resource;
 33	} else if (resource == PCI_ROM_RESOURCE) {
 34		res->flags |= IORESOURCE_ROM_ENABLE;
 35		new |= PCI_ROM_ADDRESS_ENABLE;
 36		reg = dev->rom_base_reg;
 37	} else {
 38		/* Somebody might have asked allocation of a non-standard resource */
 39		return;
 40	}
 41
 42	pci_write_config_dword(dev, reg, new);
 43	pci_read_config_dword(dev, reg, &check);
 44	if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
 45		printk(KERN_ERR "PCI: Error while updating region "
 46		       "%s/%d (%08x != %08x)\n", pci_name(dev), resource,
 47		       new, check);
 48	}
 49}
 50#endif
 51
 52/*
 53 * We need to avoid collisions with `mirrored' VGA ports
 54 * and other strange ISA hardware, so we always want the
 55 * addresses to be allocated in the 0x000-0x0ff region
 56 * modulo 0x400.
 57 *
 58 * Why? Because some silly external IO cards only decode
 59 * the low 10 bits of the IO address. The 0x00-0xff region
 60 * is reserved for motherboard devices that decode all 16
 61 * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
 62 * but we want to try to avoid allocating at 0x2900-0x2bff
 63 * which might have be mirrored at 0x0100-0x03ff..
 64 */
 65void
 66pcibios_align_resource(void *data, struct resource *res,
 67		       unsigned long size, unsigned long align)
 68{
 69	if (res->flags & IORESOURCE_IO) {
 70		unsigned long start = res->start;
 71
 72		if (start & 0x300) {
 73			start = (start + 0x3ff) & ~0x3ff;
 74			res->start = start;
 75		}
 76	}
 77}
 78
 79
 80/*
 81 *  Handle resources of PCI devices.  If the world were perfect, we could
 82 *  just allocate all the resource regions and do nothing more.  It isn't.
 83 *  On the other hand, we cannot just re-allocate all devices, as it would
 84 *  require us to know lots of host bridge internals.  So we attempt to
 85 *  keep as much of the original configuration as possible, but tweak it
 86 *  when it's found to be wrong.
 87 *
 88 *  Known BIOS problems we have to work around:
 89 *	- I/O or memory regions not configured
 90 *	- regions configured, but not enabled in the command register
 91 *	- bogus I/O addresses above 64K used
 92 *	- expansion ROMs left enabled (this may sound harmless, but given
 93 *	  the fact the PCI specs explicitly allow address decoders to be
 94 *	  shared between expansion ROMs and other resource regions, it's
 95 *	  at least dangerous)
 96 *
 97 *  Our solution:
 98 *	(1) Allocate resources for all buses behind PCI-to-PCI bridges.
 99 *	    This gives us fixed barriers on where we can allocate.
100 *	(2) Allocate resources for all enabled devices.  If there is
101 *	    a collision, just mark the resource as unallocated. Also
102 *	    disable expansion ROMs during this step.
103 *	(3) Try to allocate resources for disabled devices.  If the
104 *	    resources were assigned correctly, everything goes well,
105 *	    if they weren't, they won't disturb allocation of other
106 *	    resources.
107 *	(4) Assign new addresses to resources which were either
108 *	    not configured at all or misconfigured.  If explicitly
109 *	    requested by the user, configure expansion ROM address
110 *	    as well.
111 */
112
113static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
114{
115	struct list_head *ln;
116	struct pci_bus *bus;
117	struct pci_dev *dev;
118	int idx;
119	struct resource *r, *pr;
120
121	/* Depth-First Search on bus tree */
122	for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
123		bus = pci_bus_b(ln);
124		if ((dev = bus->self)) {
125			for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
126				r = &dev->resource[idx];
127				if (!r->start)
128					continue;
129				pr = pci_find_parent_resource(dev, r);
130				if (!pr || request_resource(pr, r) < 0)
131					printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, pci_name(dev));
132			}
133		}
134		pcibios_allocate_bus_resources(&bus->children);
135	}
136}
137
138static void __init pcibios_allocate_resources(int pass)
139{
140	struct pci_dev *dev = NULL;
141	int idx, disabled;
142	u16 command;
143	struct resource *r, *pr;
144
145	while (dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev),
146	       dev != NULL
147	       ) {
148		pci_read_config_word(dev, PCI_COMMAND, &command);
149		for(idx = 0; idx < 6; idx++) {
150			r = &dev->resource[idx];
151			if (r->parent)		/* Already allocated */
152				continue;
153			if (!r->start)		/* Address not assigned at all */
154				continue;
155			if (r->flags & IORESOURCE_IO)
156				disabled = !(command & PCI_COMMAND_IO);
157			else
158				disabled = !(command & PCI_COMMAND_MEMORY);
159			if (pass == disabled) {
160				DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
161				    r->start, r->end, r->flags, disabled, pass);
162				pr = pci_find_parent_resource(dev, r);
163				if (!pr || request_resource(pr, r) < 0) {
164					printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, pci_name(dev));
165					/* We'll assign a new address later */
166					r->end -= r->start;
167					r->start = 0;
168				}
169			}
170		}
171		if (!pass) {
172			r = &dev->resource[PCI_ROM_RESOURCE];
173			if (r->flags & IORESOURCE_ROM_ENABLE) {
174				/* Turn the ROM off, leave the resource region, but keep it unregistered. */
175				u32 reg;
176				DBG("PCI: Switching off ROM of %s\n", pci_name(dev));
177				r->flags &= ~IORESOURCE_ROM_ENABLE;
178				pci_read_config_dword(dev, dev->rom_base_reg, &reg);
179				pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
180			}
181		}
182	}
183}
184
185static void __init pcibios_assign_resources(void)
186{
187	struct pci_dev *dev = NULL;
188	int idx;
189	struct resource *r;
190
191	while (dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev),
192	       dev != NULL
193	       ) {
194		int class = dev->class >> 8;
195
196		/* Don't touch classless devices and host bridges */
197		if (!class || class == PCI_CLASS_BRIDGE_HOST)
198			continue;
199
200		for(idx=0; idx<6; idx++) {
201			r = &dev->resource[idx];
202
203			/*
204			 *  Don't touch IDE controllers and I/O ports of video cards!
205			 */
206			if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
207			    (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
208				continue;
209
210			/*
211			 *  We shall assign a new address to this resource, either because
212			 *  the BIOS forgot to do so or because we have decided the old
213			 *  address was unusable for some reason.
214			 */
215			if (!r->start && r->end)
216				pci_assign_resource(dev, idx);
217		}
218
219		if (pci_probe & PCI_ASSIGN_ROMS) {
220			r = &dev->resource[PCI_ROM_RESOURCE];
221			r->end -= r->start;
222			r->start = 0;
223			if (r->end)
224				pci_assign_resource(dev, PCI_ROM_RESOURCE);
225		}
226	}
227}
228
229void __init pcibios_resource_survey(void)
230{
231	DBG("PCI: Allocating resources\n");
232	pcibios_allocate_bus_resources(&pci_root_buses);
233	pcibios_allocate_resources(0);
234	pcibios_allocate_resources(1);
235	pcibios_assign_resources();
236}
237
238int pcibios_enable_resources(struct pci_dev *dev, int mask)
239{
240	u16 cmd, old_cmd;
241	int idx;
242	struct resource *r;
243
244	pci_read_config_word(dev, PCI_COMMAND, &cmd);
245	old_cmd = cmd;
246	for(idx=0; idx<6; idx++) {
247		/* Only set up the requested stuff */
248		if (!(mask & (1<<idx)))
249			continue;
250
251		r = &dev->resource[idx];
252		if (!r->start && r->end) {
253			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev));
254			return -EINVAL;
255		}
256		if (r->flags & IORESOURCE_IO)
257			cmd |= PCI_COMMAND_IO;
258		if (r->flags & IORESOURCE_MEM)
259			cmd |= PCI_COMMAND_MEMORY;
260	}
261	if (dev->resource[PCI_ROM_RESOURCE].start)
262		cmd |= PCI_COMMAND_MEMORY;
263	if (cmd != old_cmd) {
264		printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd);
265		pci_write_config_word(dev, PCI_COMMAND, cmd);
266	}
267	return 0;
268}
269
270/*
271 *  If we set up a device for bus mastering, we need to check the latency
272 *  timer as certain crappy BIOSes forget to set it properly.
273 */
274unsigned int pcibios_max_latency = 255;
275
276void pcibios_set_master(struct pci_dev *dev)
277{
278	u8 lat;
279	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
280	if (lat < 16)
281		lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
282	else if (lat > pcibios_max_latency)
283		lat = pcibios_max_latency;
284	else
285		return;
286	printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat);
287	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
288}