arch/powerpc/sysdev/tsi108_pci.c

Source file repositories/reference/linux-study-clean/arch/powerpc/sysdev/tsi108_pci.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/sysdev/tsi108_pci.c
Extension
.c
Size
10707 bytes
Lines
427
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if ((err_addr & 0xFF000000) == pci_cfg_base) {
			pci_stat =
			    tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_CSR);
			tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_CSR,
					 pci_stat);
		}
	}

	return;
}

#define __tsi108_read_pci_config(x, addr, op)		\
	__asm__ __volatile__(				\
		"	"op" %0,0,%1\n"		\
		"1:	eieio\n"			\
		"2:\n"					\
		".section .fixup,\"ax\"\n"		\
		"3:	li %0,-1\n"			\
		"	b 2b\n"				\
		".previous\n"				\
		EX_TABLE(1b, 3b)			\
		: "=r"(x) : "r"(addr))

int
tsi108_direct_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
			  int len, u32 * val)
{
	volatile unsigned char *cfg_addr;
	struct pci_controller *hose = pci_bus_to_host(bus);
	u32 temp;

	if (ppc_md.pci_exclude_device)
		if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
			return PCIBIOS_DEVICE_NOT_FOUND;

	cfg_addr = (unsigned char *)(tsi_mk_config_addr(bus->number,
							devfn,
							offset) | (offset &
								   0x03));

	switch (len) {
	case 1:
		__tsi108_read_pci_config(temp, cfg_addr, "lbzx");
		break;
	case 2:
		__tsi108_read_pci_config(temp, cfg_addr, "lhbrx");
		break;
	default:
		__tsi108_read_pci_config(temp, cfg_addr, "lwbrx");
		break;
	}

	*val = temp;

#ifdef DEBUG
	if ((0xFFFFFFFF != temp) && (0xFFFF != temp) && (0xFF != temp)) {
		printk("PCI CFG read : ");
		printk("%d:0x%x:0x%x ", bus->number, devfn, offset);
		printk("%d ADDR=0x%08x ", len, (uint) cfg_addr);
		printk("data = 0x%x\n", *val);
	}
#endif
	return PCIBIOS_SUCCESSFUL;
}

void tsi108_clear_pci_cfg_error(void)
{
	tsi108_clear_pci_error(tsi108_pci_cfg_phys);
}

static struct pci_ops tsi108_direct_pci_ops = {
	.read = tsi108_direct_read_config,
	.write = tsi108_direct_write_config,
};

int __init tsi108_setup_pci(struct device_node *dev, u32 cfg_phys, int primary)
{
	int len;
	struct pci_controller *hose;
	struct resource rsrc;
	const int *bus_range;
	int has_address = 0;

	/* PCI Config mapping */
	tsi108_pci_cfg_base = (u32)ioremap(cfg_phys, TSI108_PCI_CFG_SIZE);
	tsi108_pci_cfg_phys = cfg_phys;
	DBG("TSI_PCI: %s tsi108_pci_cfg_base=0x%x\n", __func__,
	    tsi108_pci_cfg_base);

	/* Fetch host bridge registers address */

Annotation

Implementation Notes