PageRenderTime 33ms CodeModel.GetById 19ms app.highlight 11ms RepoModel.GetById 0ms app.codeStats 0ms

/arch/x86/pci/pcbios.c

https://bitbucket.org/ndreys/linux-sunxi
C | 453 lines | 344 code | 51 blank | 58 comment | 39 complexity | 396d2c914393f9ee14485d69b33fcfd1 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1/*
  2 * BIOS32 and PCI BIOS handling.
  3 */
  4
  5#include <linux/pci.h>
  6#include <linux/init.h>
  7#include <linux/slab.h>
  8#include <linux/module.h>
  9#include <linux/uaccess.h>
 10#include <asm/pci_x86.h>
 11#include <asm/pci-functions.h>
 12#include <asm/cacheflush.h>
 13
 14/* BIOS32 signature: "_32_" */
 15#define BIOS32_SIGNATURE	(('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
 16
 17/* PCI signature: "PCI " */
 18#define PCI_SIGNATURE		(('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
 19
 20/* PCI service signature: "$PCI" */
 21#define PCI_SERVICE		(('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
 22
 23/* PCI BIOS hardware mechanism flags */
 24#define PCIBIOS_HW_TYPE1		0x01
 25#define PCIBIOS_HW_TYPE2		0x02
 26#define PCIBIOS_HW_TYPE1_SPEC		0x10
 27#define PCIBIOS_HW_TYPE2_SPEC		0x20
 28
 29int pcibios_enabled;
 30
 31/* According to the BIOS specification at:
 32 * http://members.datafast.net.au/dft0802/specs/bios21.pdf, we could
 33 * restrict the x zone to some pages and make it ro. But this may be
 34 * broken on some bios, complex to handle with static_protections.
 35 * We could make the 0xe0000-0x100000 range rox, but this can break
 36 * some ISA mapping.
 37 *
 38 * So we let's an rw and x hole when pcibios is used. This shouldn't
 39 * happen for modern system with mmconfig, and if you don't want it
 40 * you could disable pcibios...
 41 */
 42static inline void set_bios_x(void)
 43{
 44	pcibios_enabled = 1;
 45	set_memory_x(PAGE_OFFSET + BIOS_BEGIN, (BIOS_END - BIOS_BEGIN) >> PAGE_SHIFT);
 46	if (__supported_pte_mask & _PAGE_NX)
 47		printk(KERN_INFO "PCI : PCI BIOS aera is rw and x. Use pci=nobios if you want it NX.\n");
 48}
 49
 50/*
 51 * This is the standard structure used to identify the entry point
 52 * to the BIOS32 Service Directory, as documented in
 53 * 	Standard BIOS 32-bit Service Directory Proposal
 54 * 	Revision 0.4 May 24, 1993
 55 * 	Phoenix Technologies Ltd.
 56 *	Norwood, MA
 57 * and the PCI BIOS specification.
 58 */
 59
 60union bios32 {
 61	struct {
 62		unsigned long signature;	/* _32_ */
 63		unsigned long entry;		/* 32 bit physical address */
 64		unsigned char revision;		/* Revision level, 0 */
 65		unsigned char length;		/* Length in paragraphs should be 01 */
 66		unsigned char checksum;		/* All bytes must add up to zero */
 67		unsigned char reserved[5]; 	/* Must be zero */
 68	} fields;
 69	char chars[16];
 70};
 71
 72/*
 73 * Physical address of the service directory.  I don't know if we're
 74 * allowed to have more than one of these or not, so just in case
 75 * we'll make pcibios_present() take a memory start parameter and store
 76 * the array there.
 77 */
 78
 79static struct {
 80	unsigned long address;
 81	unsigned short segment;
 82} bios32_indirect = { 0, __KERNEL_CS };
 83
 84/*
 85 * Returns the entry point for the given service, NULL on error
 86 */
 87
 88static unsigned long bios32_service(unsigned long service)
 89{
 90	unsigned char return_code;	/* %al */
 91	unsigned long address;		/* %ebx */
 92	unsigned long length;		/* %ecx */
 93	unsigned long entry;		/* %edx */
 94	unsigned long flags;
 95
 96	local_irq_save(flags);
 97	__asm__("lcall *(%%edi); cld"
 98		: "=a" (return_code),
 99		  "=b" (address),
100		  "=c" (length),
101		  "=d" (entry)
102		: "0" (service),
103		  "1" (0),
104		  "D" (&bios32_indirect));
105	local_irq_restore(flags);
106
107	switch (return_code) {
108		case 0:
109			return address + entry;
110		case 0x80:	/* Not present */
111			printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service);
112			return 0;
113		default: /* Shouldn't happen */
114			printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n",
115				service, return_code);
116			return 0;
117	}
118}
119
120static struct {
121	unsigned long address;
122	unsigned short segment;
123} pci_indirect = { 0, __KERNEL_CS };
124
125static int pci_bios_present;
126
127static int __devinit check_pcibios(void)
128{
129	u32 signature, eax, ebx, ecx;
130	u8 status, major_ver, minor_ver, hw_mech;
131	unsigned long flags, pcibios_entry;
132
133	if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
134		pci_indirect.address = pcibios_entry + PAGE_OFFSET;
135
136		local_irq_save(flags);
137		__asm__(
138			"lcall *(%%edi); cld\n\t"
139			"jc 1f\n\t"
140			"xor %%ah, %%ah\n"
141			"1:"
142			: "=d" (signature),
143			  "=a" (eax),
144			  "=b" (ebx),
145			  "=c" (ecx)
146			: "1" (PCIBIOS_PCI_BIOS_PRESENT),
147			  "D" (&pci_indirect)
148			: "memory");
149		local_irq_restore(flags);
150
151		status = (eax >> 8) & 0xff;
152		hw_mech = eax & 0xff;
153		major_ver = (ebx >> 8) & 0xff;
154		minor_ver = ebx & 0xff;
155		if (pcibios_last_bus < 0)
156			pcibios_last_bus = ecx & 0xff;
157		DBG("PCI: BIOS probe returned s=%02x hw=%02x ver=%02x.%02x l=%02x\n",
158			status, hw_mech, major_ver, minor_ver, pcibios_last_bus);
159		if (status || signature != PCI_SIGNATURE) {
160			printk (KERN_ERR "PCI: BIOS BUG #%x[%08x] found\n",
161				status, signature);
162			return 0;
163		}
164		printk(KERN_INFO "PCI: PCI BIOS revision %x.%02x entry at 0x%lx, last bus=%d\n",
165			major_ver, minor_ver, pcibios_entry, pcibios_last_bus);
166#ifdef CONFIG_PCI_DIRECT
167		if (!(hw_mech & PCIBIOS_HW_TYPE1))
168			pci_probe &= ~PCI_PROBE_CONF1;
169		if (!(hw_mech & PCIBIOS_HW_TYPE2))
170			pci_probe &= ~PCI_PROBE_CONF2;
171#endif
172		return 1;
173	}
174	return 0;
175}
176
177static int pci_bios_read(unsigned int seg, unsigned int bus,
178			 unsigned int devfn, int reg, int len, u32 *value)
179{
180	unsigned long result = 0;
181	unsigned long flags;
182	unsigned long bx = (bus << 8) | devfn;
183
184	if (!value || (bus > 255) || (devfn > 255) || (reg > 255))
185		return -EINVAL;
186
187	raw_spin_lock_irqsave(&pci_config_lock, flags);
188
189	switch (len) {
190	case 1:
191		__asm__("lcall *(%%esi); cld\n\t"
192			"jc 1f\n\t"
193			"xor %%ah, %%ah\n"
194			"1:"
195			: "=c" (*value),
196			  "=a" (result)
197			: "1" (PCIBIOS_READ_CONFIG_BYTE),
198			  "b" (bx),
199			  "D" ((long)reg),
200			  "S" (&pci_indirect));
201		/*
202		 * Zero-extend the result beyond 8 bits, do not trust the
203		 * BIOS having done it:
204		 */
205		*value &= 0xff;
206		break;
207	case 2:
208		__asm__("lcall *(%%esi); cld\n\t"
209			"jc 1f\n\t"
210			"xor %%ah, %%ah\n"
211			"1:"
212			: "=c" (*value),
213			  "=a" (result)
214			: "1" (PCIBIOS_READ_CONFIG_WORD),
215			  "b" (bx),
216			  "D" ((long)reg),
217			  "S" (&pci_indirect));
218		/*
219		 * Zero-extend the result beyond 16 bits, do not trust the
220		 * BIOS having done it:
221		 */
222		*value &= 0xffff;
223		break;
224	case 4:
225		__asm__("lcall *(%%esi); cld\n\t"
226			"jc 1f\n\t"
227			"xor %%ah, %%ah\n"
228			"1:"
229			: "=c" (*value),
230			  "=a" (result)
231			: "1" (PCIBIOS_READ_CONFIG_DWORD),
232			  "b" (bx),
233			  "D" ((long)reg),
234			  "S" (&pci_indirect));
235		break;
236	}
237
238	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
239
240	return (int)((result & 0xff00) >> 8);
241}
242
243static int pci_bios_write(unsigned int seg, unsigned int bus,
244			  unsigned int devfn, int reg, int len, u32 value)
245{
246	unsigned long result = 0;
247	unsigned long flags;
248	unsigned long bx = (bus << 8) | devfn;
249
250	if ((bus > 255) || (devfn > 255) || (reg > 255)) 
251		return -EINVAL;
252
253	raw_spin_lock_irqsave(&pci_config_lock, flags);
254
255	switch (len) {
256	case 1:
257		__asm__("lcall *(%%esi); cld\n\t"
258			"jc 1f\n\t"
259			"xor %%ah, %%ah\n"
260			"1:"
261			: "=a" (result)
262			: "0" (PCIBIOS_WRITE_CONFIG_BYTE),
263			  "c" (value),
264			  "b" (bx),
265			  "D" ((long)reg),
266			  "S" (&pci_indirect));
267		break;
268	case 2:
269		__asm__("lcall *(%%esi); cld\n\t"
270			"jc 1f\n\t"
271			"xor %%ah, %%ah\n"
272			"1:"
273			: "=a" (result)
274			: "0" (PCIBIOS_WRITE_CONFIG_WORD),
275			  "c" (value),
276			  "b" (bx),
277			  "D" ((long)reg),
278			  "S" (&pci_indirect));
279		break;
280	case 4:
281		__asm__("lcall *(%%esi); cld\n\t"
282			"jc 1f\n\t"
283			"xor %%ah, %%ah\n"
284			"1:"
285			: "=a" (result)
286			: "0" (PCIBIOS_WRITE_CONFIG_DWORD),
287			  "c" (value),
288			  "b" (bx),
289			  "D" ((long)reg),
290			  "S" (&pci_indirect));
291		break;
292	}
293
294	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
295
296	return (int)((result & 0xff00) >> 8);
297}
298
299
300/*
301 * Function table for BIOS32 access
302 */
303
304static struct pci_raw_ops pci_bios_access = {
305	.read =		pci_bios_read,
306	.write =	pci_bios_write
307};
308
309/*
310 * Try to find PCI BIOS.
311 */
312
313static struct pci_raw_ops * __devinit pci_find_bios(void)
314{
315	union bios32 *check;
316	unsigned char sum;
317	int i, length;
318
319	/*
320	 * Follow the standard procedure for locating the BIOS32 Service
321	 * directory by scanning the permissible address range from
322	 * 0xe0000 through 0xfffff for a valid BIOS32 structure.
323	 */
324
325	for (check = (union bios32 *) __va(0xe0000);
326	     check <= (union bios32 *) __va(0xffff0);
327	     ++check) {
328		long sig;
329		if (probe_kernel_address(&check->fields.signature, sig))
330			continue;
331
332		if (check->fields.signature != BIOS32_SIGNATURE)
333			continue;
334		length = check->fields.length * 16;
335		if (!length)
336			continue;
337		sum = 0;
338		for (i = 0; i < length ; ++i)
339			sum += check->chars[i];
340		if (sum != 0)
341			continue;
342		if (check->fields.revision != 0) {
343			printk("PCI: unsupported BIOS32 revision %d at 0x%p\n",
344				check->fields.revision, check);
345			continue;
346		}
347		DBG("PCI: BIOS32 Service Directory structure at 0x%p\n", check);
348		if (check->fields.entry >= 0x100000) {
349			printk("PCI: BIOS32 entry (0x%p) in high memory, "
350					"cannot use.\n", check);
351			return NULL;
352		} else {
353			unsigned long bios32_entry = check->fields.entry;
354			DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n",
355					bios32_entry);
356			bios32_indirect.address = bios32_entry + PAGE_OFFSET;
357			set_bios_x();
358			if (check_pcibios())
359				return &pci_bios_access;
360		}
361		break;	/* Hopefully more than one BIOS32 cannot happen... */
362	}
363
364	return NULL;
365}
366
367/*
368 *  BIOS Functions for IRQ Routing
369 */
370
371struct irq_routing_options {
372	u16 size;
373	struct irq_info *table;
374	u16 segment;
375} __attribute__((packed));
376
377struct irq_routing_table * pcibios_get_irq_routing_table(void)
378{
379	struct irq_routing_options opt;
380	struct irq_routing_table *rt = NULL;
381	int ret, map;
382	unsigned long page;
383
384	if (!pci_bios_present)
385		return NULL;
386	page = __get_free_page(GFP_KERNEL);
387	if (!page)
388		return NULL;
389	opt.table = (struct irq_info *) page;
390	opt.size = PAGE_SIZE;
391	opt.segment = __KERNEL_DS;
392
393	DBG("PCI: Fetching IRQ routing table... ");
394	__asm__("push %%es\n\t"
395		"push %%ds\n\t"
396		"pop  %%es\n\t"
397		"lcall *(%%esi); cld\n\t"
398		"pop %%es\n\t"
399		"jc 1f\n\t"
400		"xor %%ah, %%ah\n"
401		"1:"
402		: "=a" (ret),
403		  "=b" (map),
404		  "=m" (opt)
405		: "0" (PCIBIOS_GET_ROUTING_OPTIONS),
406		  "1" (0),
407		  "D" ((long) &opt),
408		  "S" (&pci_indirect),
409		  "m" (opt)
410		: "memory");
411	DBG("OK  ret=%d, size=%d, map=%x\n", ret, opt.size, map);
412	if (ret & 0xff00)
413		printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff);
414	else if (opt.size) {
415		rt = kmalloc(sizeof(struct irq_routing_table) + opt.size, GFP_KERNEL);
416		if (rt) {
417			memset(rt, 0, sizeof(struct irq_routing_table));
418			rt->size = opt.size + sizeof(struct irq_routing_table);
419			rt->exclusive_irqs = map;
420			memcpy(rt->slots, (void *) page, opt.size);
421			printk(KERN_INFO "PCI: Using BIOS Interrupt Routing Table\n");
422		}
423	}
424	free_page(page);
425	return rt;
426}
427EXPORT_SYMBOL(pcibios_get_irq_routing_table);
428
429int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq)
430{
431	int ret;
432
433	__asm__("lcall *(%%esi); cld\n\t"
434		"jc 1f\n\t"
435		"xor %%ah, %%ah\n"
436		"1:"
437		: "=a" (ret)
438		: "0" (PCIBIOS_SET_PCI_HW_INT),
439		  "b" ((dev->bus->number << 8) | dev->devfn),
440		  "c" ((irq << 8) | (pin + 10)),
441		  "S" (&pci_indirect));
442	return !(ret & 0xff00);
443}
444EXPORT_SYMBOL(pcibios_set_irq_routing);
445
446void __init pci_pcbios_init(void)
447{
448	if ((pci_probe & PCI_PROBE_BIOS) 
449		&& ((raw_pci_ops = pci_find_bios()))) {
450		pci_bios_present = 1;
451	}
452}
453