| /* | 
 |  * This file is subject to the terms and conditions of the GNU General Public | 
 |  * License.  See the file "COPYING" in the main directory of this archive | 
 |  * for more details. | 
 |  * | 
 |  * Copyright (C) 2013 Cavium, Inc. | 
 |  */ | 
 |  | 
 | #include <linux/kernel.h> | 
 | #include <linux/init.h> | 
 | #include <linux/interrupt.h> | 
 | #include <linux/pci.h> | 
 |  | 
 | #include <uapi/asm/bitfield.h> | 
 | #include <asm/byteorder.h> | 
 | #include <asm/io.h> | 
 |  | 
 | #define PCI_CONFIG_ADDRESS	0xcf8 | 
 | #define PCI_CONFIG_DATA		0xcfc | 
 |  | 
 | union pci_config_address { | 
 | 	struct { | 
 | 		__BITFIELD_FIELD(unsigned enable_bit	  : 1,	/* 31       */ | 
 | 		__BITFIELD_FIELD(unsigned reserved	  : 7,	/* 30 .. 24 */ | 
 | 		__BITFIELD_FIELD(unsigned bus_number	  : 8,	/* 23 .. 16 */ | 
 | 		__BITFIELD_FIELD(unsigned devfn_number	  : 8,	/* 15 .. 8  */ | 
 | 		__BITFIELD_FIELD(unsigned register_number : 8,	/* 7  .. 0  */ | 
 | 		))))); | 
 | 	}; | 
 | 	u32 w; | 
 | }; | 
 |  | 
 | int pcibios_plat_dev_init(struct pci_dev *dev) | 
 | { | 
 | 	return 0; | 
 | } | 
 |  | 
 | int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | 
 | { | 
 | 	return ((pin + slot) % 4)+ MIPS_IRQ_PCIA; | 
 | } | 
 |  | 
 | static void pci_virtio_guest_write_config_addr(struct pci_bus *bus, | 
 | 					unsigned int devfn, int reg) | 
 | { | 
 | 	union pci_config_address pca = { .w = 0 }; | 
 |  | 
 | 	pca.register_number = reg; | 
 | 	pca.devfn_number = devfn; | 
 | 	pca.bus_number = bus->number; | 
 | 	pca.enable_bit = 1; | 
 |  | 
 | 	outl(pca.w, PCI_CONFIG_ADDRESS); | 
 | } | 
 |  | 
 | static int pci_virtio_guest_write_config(struct pci_bus *bus, | 
 | 		unsigned int devfn, int reg, int size, u32 val) | 
 | { | 
 | 	pci_virtio_guest_write_config_addr(bus, devfn, reg); | 
 |  | 
 | 	switch (size) { | 
 | 	case 1: | 
 | 		outb(val, PCI_CONFIG_DATA + (reg & 3)); | 
 | 		break; | 
 | 	case 2: | 
 | 		outw(val, PCI_CONFIG_DATA + (reg & 2)); | 
 | 		break; | 
 | 	case 4: | 
 | 		outl(val, PCI_CONFIG_DATA); | 
 | 		break; | 
 | 	} | 
 |  | 
 | 	return PCIBIOS_SUCCESSFUL; | 
 | } | 
 |  | 
 | static int pci_virtio_guest_read_config(struct pci_bus *bus, unsigned int devfn, | 
 | 					int reg, int size, u32 *val) | 
 | { | 
 | 	pci_virtio_guest_write_config_addr(bus, devfn, reg); | 
 |  | 
 | 	switch (size) { | 
 | 	case 1: | 
 | 		*val = inb(PCI_CONFIG_DATA + (reg & 3)); | 
 | 		break; | 
 | 	case 2: | 
 | 		*val = inw(PCI_CONFIG_DATA + (reg & 2)); | 
 | 		break; | 
 | 	case 4: | 
 | 		*val = inl(PCI_CONFIG_DATA); | 
 | 		break; | 
 | 	} | 
 | 	return PCIBIOS_SUCCESSFUL; | 
 | } | 
 |  | 
 | static struct pci_ops pci_virtio_guest_ops = { | 
 | 	.read  = pci_virtio_guest_read_config, | 
 | 	.write = pci_virtio_guest_write_config, | 
 | }; | 
 |  | 
 | static struct resource pci_virtio_guest_mem_resource = { | 
 | 	.name = "Virtio MEM", | 
 | 	.flags = IORESOURCE_MEM, | 
 | 	.start	= 0x10000000, | 
 | 	.end	= 0x1dffffff | 
 | }; | 
 |  | 
 | static struct resource pci_virtio_guest_io_resource = { | 
 | 	.name = "Virtio IO", | 
 | 	.flags = IORESOURCE_IO, | 
 | 	.start	= 0, | 
 | 	.end	= 0xffff | 
 | }; | 
 |  | 
 | static struct pci_controller pci_virtio_guest_controller = { | 
 | 	.pci_ops = &pci_virtio_guest_ops, | 
 | 	.mem_resource = &pci_virtio_guest_mem_resource, | 
 | 	.io_resource = &pci_virtio_guest_io_resource, | 
 | }; | 
 |  | 
 | static int __init pci_virtio_guest_setup(void) | 
 | { | 
 | 	pr_err("pci_virtio_guest_setup\n"); | 
 |  | 
 | 	/* Virtio comes pre-assigned */ | 
 | 	pci_set_flags(PCI_PROBE_ONLY); | 
 |  | 
 | 	pci_virtio_guest_controller.io_map_base = mips_io_port_base; | 
 | 	register_pci_controller(&pci_virtio_guest_controller); | 
 | 	return 0; | 
 | } | 
 | arch_initcall(pci_virtio_guest_setup); |