⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pmac_pci.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Support for PCI bridges found on Power Macintoshes. * At present the "bandit" and "chaos" bridges are supported. * Fortunately you access configuration space in the same * way with either bridge. * * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au) * * 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. */#include <linux/kernel.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/string.h>#include <linux/init.h>#include <linux/bootmem.h>#include <asm/init.h>#include <asm/io.h>#include <asm/prom.h>#include <asm/pci-bridge.h>#include <asm/machdep.h>#include "pci.h"struct bridge_data **bridges, *bridge_list;static int max_bus;struct uninorth_data {	struct device_node*	node;	volatile unsigned int*	cfg_addr;	volatile unsigned int*	cfg_data;	void*			iobase;	unsigned long		iobase_phys;};static struct uninorth_data uninorth_bridges[3];static int uninorth_count;static int uninorth_default = -1;static void add_bridges(struct device_node *dev);/* * Magic constants for enabling cache coherency in the bandit/PSX bridge. */#define APPLE_VENDID	0x106b#define BANDIT_DEVID	1#define BANDIT_DEVID_2	8#define BANDIT_REVID	3#define BANDIT_DEVNUM	11#define BANDIT_MAGIC	0x50#define BANDIT_COHERENT	0x40/* Obsolete, should be replaced by pmac_pci_dev_io_base() (below) */__pmacvoid *pci_io_base(unsigned int bus){	struct bridge_data *bp;	if (bus > max_bus || (bp = bridges[bus]) == 0)		return 0;	return bp->io_base;}__pmacint pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,		   unsigned char *devfn_ptr){	unsigned int *reg;	int len;	reg = (unsigned int *) get_property(dev, "reg", &len);	if (reg == 0 || len < 5 * sizeof(unsigned int)) {		/* doesn't look like a PCI device */		*bus_ptr = 0xff;		*devfn_ptr = 0xff;		return -1;	}	*bus_ptr = reg[0] >> 16;	*devfn_ptr = reg[0] >> 8;	return 0;}/* This routines figures out on which root bridge a given PCI device * is attached. */__pmacintpmac_pci_dev_root_bridge(unsigned char bus, unsigned char dev_fn){	struct device_node *node, *bridge_node;	int bridge = uninorth_default;	if (uninorth_count == 0)		return 0;	if (bus == 0 && PCI_SLOT(dev_fn) < 11)		return 0;		/* We look for the OF device corresponding to this bus/devfn pair. If we	 * don't find it, we default to the external PCI */	bridge_node = NULL;	node = find_pci_device_OFnode(bus, dev_fn & 0xf8);	if (node) {	    /* note: we don't stop on the first occurence since we need to go             * up to the root bridge */	    do {		if (node->type && !strcmp(node->type, "pci") 			&& device_is_compatible(node, "uni-north"))			bridge_node = node;		node=node->parent;	    } while (node);	}	if (bridge_node) {	    int i;	    for (i=0;i<uninorth_count;i++)		if (uninorth_bridges[i].node == bridge_node) {		    bridge = i;		    break;		}	}	if (bridge == -1) {		printk(KERN_WARNING "pmac_pci: no default bridge !\n");		return 0;	}	return bridge;	}__pmacvoid *pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical){	int bridge = -1;	if (uninorth_count != 0)		bridge = pmac_pci_dev_root_bridge(bus, devfn);	if (bridge == -1) {		struct bridge_data *bp;		if (bus > max_bus || (bp = bridges[bus]) == 0)			return 0;		return physical ? (void *) bp->io_base_phys : bp->io_base;	}	return physical ? (void *) uninorth_bridges[bridge].iobase_phys		: uninorth_bridges[bridge].iobase;}__pmacvoid *pmac_pci_dev_mem_base(unsigned char bus, unsigned char devfn){	return 0;}/* This function only works for bus 0, uni-N uses a different mecanism for * other busses (see below) */#define UNI_N_CFA0(devfn, off)	\	((1 << (unsigned long)PCI_SLOT(dev_fn)) \	| (((unsigned long)PCI_FUNC(dev_fn)) << 8) \	| (((unsigned long)(off)) & 0xFCUL))/* This one is for type 1 config accesses */#define UNI_N_CFA1(bus, devfn, off)	\	((((unsigned long)(bus)) << 16) \	|(((unsigned long)(devfn)) << 8) \	|(((unsigned long)(off)) & 0xFCUL) \	|1UL)	__pmac staticunsigned intuni_north_access_data(unsigned char bus, unsigned char dev_fn,				unsigned char offset){	int bridge;	unsigned int caddr;	bridge = pmac_pci_dev_root_bridge(bus, dev_fn);	if (bus == 0)		caddr = UNI_N_CFA0(dev_fn, offset);	else		caddr = UNI_N_CFA1(bus, dev_fn, offset);		if (bridge == -1) {		printk(KERN_WARNING "pmac_pci: no default bridge !\n");		return 0;	}			/* Uninorth will return garbage if we don't read back the value ! */	out_le32(uninorth_bridges[bridge].cfg_addr, caddr);	(void)in_le32(uninorth_bridges[bridge].cfg_addr);	/* Yes, offset is & 7, not & 3 ! */	return (unsigned int)(uninorth_bridges[bridge].cfg_data) + (offset & 0x07);}__pmacint uni_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,				  unsigned char offset, unsigned char *val){	unsigned int addr;		*val = 0xff;	addr = uni_north_access_data(bus, dev_fn, offset);	if (!addr)		return PCIBIOS_DEVICE_NOT_FOUND;	*val = in_8((volatile unsigned char*)addr);	return PCIBIOS_SUCCESSFUL;}__pmacint uni_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,				  unsigned char offset, unsigned short *val){	unsigned int addr;		*val = 0xffff;	addr = uni_north_access_data(bus, dev_fn, offset);	if (!addr)		return PCIBIOS_DEVICE_NOT_FOUND;	*val = in_le16((volatile unsigned short*)addr);	return PCIBIOS_SUCCESSFUL;}__pmacint uni_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,				   unsigned char offset, unsigned int *val){	unsigned int addr;		*val = 0xffff;	addr = uni_north_access_data(bus, dev_fn, offset);	if (!addr)		return PCIBIOS_DEVICE_NOT_FOUND;	*val = in_le32((volatile unsigned int*)addr);	return PCIBIOS_SUCCESSFUL;}__pmacint uni_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,				   unsigned char offset, unsigned char val){	unsigned int addr;		addr = uni_north_access_data(bus, dev_fn, offset);	if (!addr)		return PCIBIOS_DEVICE_NOT_FOUND;	out_8((volatile unsigned char *)addr, val);	(void)in_8((volatile unsigned char *)addr);	return PCIBIOS_SUCCESSFUL;}__pmacint uni_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,				   unsigned char offset, unsigned short val){	unsigned int addr;		addr = uni_north_access_data(bus, dev_fn, offset);	if (!addr)		return PCIBIOS_DEVICE_NOT_FOUND;	out_le16((volatile unsigned short *)addr, val);	(void)in_le16((volatile unsigned short *)addr);	return PCIBIOS_SUCCESSFUL;}__pmacint uni_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,				    unsigned char offset, unsigned int val){	unsigned int addr;		addr = uni_north_access_data(bus, dev_fn, offset);	if (!addr)		return PCIBIOS_DEVICE_NOT_FOUND;	out_le32((volatile unsigned int *)addr, val);	(void)in_le32((volatile unsigned int *)addr);	return PCIBIOS_SUCCESSFUL;}__pmacint pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,				  unsigned char offset, unsigned char *val){	struct bridge_data *bp;	*val = 0xff;	if (bus > max_bus || (bp = bridges[bus]) == 0)		return PCIBIOS_DEVICE_NOT_FOUND;	if (bus == bp->bus_number) {		if (dev_fn < (11 << 3))			return PCIBIOS_DEVICE_NOT_FOUND;		out_le32(bp->cfg_addr,			 (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)			 + (offset & ~3));	} else {		/* Bus number once again taken into consideration.		 * Change applied from 2.1.24. This makes devices located		 * behind PCI-PCI bridges visible.		 * -Ranjit Deshpande, 01/20/99		 */		out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);	}	udelay(2);	*val = in_8(bp->cfg_data + (offset & 3));	return PCIBIOS_SUCCESSFUL;}__pmacint pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,				  unsigned char offset, unsigned short *val){	struct bridge_data *bp;	*val = 0xffff;	if (bus > max_bus || (bp = bridges[bus]) == 0)		return PCIBIOS_DEVICE_NOT_FOUND;	if ((offset & 1) != 0)		return PCIBIOS_BAD_REGISTER_NUMBER;	if (bus == bp->bus_number) {		if (dev_fn < (11 << 3))			return PCIBIOS_DEVICE_NOT_FOUND;		out_le32(bp->cfg_addr,			 (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)			 + (offset & ~3));	} else {		/* See pci_read_config_byte */		out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);	}	udelay(2);	*val = in_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)));	return PCIBIOS_SUCCESSFUL;}__pmacint pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,				   unsigned char offset, unsigned int *val){	struct bridge_data *bp;	*val = 0xffffffff;	if (bus > max_bus || (bp = bridges[bus]) == 0)		return PCIBIOS_DEVICE_NOT_FOUND;	if ((offset & 3) != 0)		return PCIBIOS_BAD_REGISTER_NUMBER;	if (bus == bp->bus_number) {		if (dev_fn < (11 << 3))			return PCIBIOS_DEVICE_NOT_FOUND;		out_le32(bp->cfg_addr,			 (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)			 + offset);	} else {		/* See pci_read_config_byte */		out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + offset + 1);	}	udelay(2);	*val = in_le32((volatile unsigned int *)bp->cfg_data);	return PCIBIOS_SUCCESSFUL;}__pmacint pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,				   unsigned char offset, unsigned char val){	struct bridge_data *bp;	if (bus > max_bus || (bp = bridges[bus]) == 0)		return PCIBIOS_DEVICE_NOT_FOUND;	if (bus == bp->bus_number) {		if (dev_fn < (11 << 3))			return PCIBIOS_DEVICE_NOT_FOUND;		out_le32(bp->cfg_addr,			 (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)			 + (offset & ~3));	} else {		/* See pci_read_config_byte */		out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);	}	udelay(2);	out_8(bp->cfg_data + (offset & 3), val);	return PCIBIOS_SUCCESSFUL;}__pmacint pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,				   unsigned char offset, unsigned short val){	struct bridge_data *bp;	if (bus > max_bus || (bp = bridges[bus]) == 0)		return PCIBIOS_DEVICE_NOT_FOUND;	if ((offset & 1) != 0)		return PCIBIOS_BAD_REGISTER_NUMBER;	if (bus == bp->bus_number) {		if (dev_fn < (11 << 3))			return PCIBIOS_DEVICE_NOT_FOUND;		out_le32(bp->cfg_addr,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -