GNU Linux-libre 4.19.286-gnu1
[releases.git] / arch / mips / pci / pci-virtio-guest.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2013 Cavium, Inc.
7  */
8
9 #include <linux/kernel.h>
10 #include <linux/init.h>
11 #include <linux/interrupt.h>
12 #include <linux/pci.h>
13
14 #include <uapi/asm/bitfield.h>
15 #include <asm/byteorder.h>
16 #include <asm/io.h>
17
18 #define PCI_CONFIG_ADDRESS      0xcf8
19 #define PCI_CONFIG_DATA         0xcfc
20
21 union pci_config_address {
22         struct {
23                 __BITFIELD_FIELD(unsigned enable_bit      : 1,  /* 31       */
24                 __BITFIELD_FIELD(unsigned reserved        : 7,  /* 30 .. 24 */
25                 __BITFIELD_FIELD(unsigned bus_number      : 8,  /* 23 .. 16 */
26                 __BITFIELD_FIELD(unsigned devfn_number    : 8,  /* 15 .. 8  */
27                 __BITFIELD_FIELD(unsigned register_number : 8,  /* 7  .. 0  */
28                 )))));
29         };
30         u32 w;
31 };
32
33 int pcibios_plat_dev_init(struct pci_dev *dev)
34 {
35         return 0;
36 }
37
38 int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
39 {
40         return ((pin + slot) % 4)+ MIPS_IRQ_PCIA;
41 }
42
43 static void pci_virtio_guest_write_config_addr(struct pci_bus *bus,
44                                         unsigned int devfn, int reg)
45 {
46         union pci_config_address pca = { .w = 0 };
47
48         pca.register_number = reg;
49         pca.devfn_number = devfn;
50         pca.bus_number = bus->number;
51         pca.enable_bit = 1;
52
53         outl(pca.w, PCI_CONFIG_ADDRESS);
54 }
55
56 static int pci_virtio_guest_write_config(struct pci_bus *bus,
57                 unsigned int devfn, int reg, int size, u32 val)
58 {
59         pci_virtio_guest_write_config_addr(bus, devfn, reg);
60
61         switch (size) {
62         case 1:
63                 outb(val, PCI_CONFIG_DATA + (reg & 3));
64                 break;
65         case 2:
66                 outw(val, PCI_CONFIG_DATA + (reg & 2));
67                 break;
68         case 4:
69                 outl(val, PCI_CONFIG_DATA);
70                 break;
71         }
72
73         return PCIBIOS_SUCCESSFUL;
74 }
75
76 static int pci_virtio_guest_read_config(struct pci_bus *bus, unsigned int devfn,
77                                         int reg, int size, u32 *val)
78 {
79         pci_virtio_guest_write_config_addr(bus, devfn, reg);
80
81         switch (size) {
82         case 1:
83                 *val = inb(PCI_CONFIG_DATA + (reg & 3));
84                 break;
85         case 2:
86                 *val = inw(PCI_CONFIG_DATA + (reg & 2));
87                 break;
88         case 4:
89                 *val = inl(PCI_CONFIG_DATA);
90                 break;
91         }
92         return PCIBIOS_SUCCESSFUL;
93 }
94
95 static struct pci_ops pci_virtio_guest_ops = {
96         .read  = pci_virtio_guest_read_config,
97         .write = pci_virtio_guest_write_config,
98 };
99
100 static struct resource pci_virtio_guest_mem_resource = {
101         .name = "Virtio MEM",
102         .flags = IORESOURCE_MEM,
103         .start  = 0x10000000,
104         .end    = 0x1dffffff
105 };
106
107 static struct resource pci_virtio_guest_io_resource = {
108         .name = "Virtio IO",
109         .flags = IORESOURCE_IO,
110         .start  = 0,
111         .end    = 0xffff
112 };
113
114 static struct pci_controller pci_virtio_guest_controller = {
115         .pci_ops = &pci_virtio_guest_ops,
116         .mem_resource = &pci_virtio_guest_mem_resource,
117         .io_resource = &pci_virtio_guest_io_resource,
118 };
119
120 static int __init pci_virtio_guest_setup(void)
121 {
122         pr_err("pci_virtio_guest_setup\n");
123
124         /* Virtio comes pre-assigned */
125         pci_set_flags(PCI_PROBE_ONLY);
126
127         pci_virtio_guest_controller.io_map_base = mips_io_port_base;
128         register_pci_controller(&pci_virtio_guest_controller);
129         return 0;
130 }
131 arch_initcall(pci_virtio_guest_setup);