1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * linux/arch/alpha/kernel/core_polaris.c 4 * 5 * POLARIS chip-specific code 6 */ 7 8 #define __EXTERN_INLINE inline 9 #include <asm/io.h> 10 #include <asm/core_polaris.h> 11 #undef __EXTERN_INLINE 12 13 #include <linux/types.h> 14 #include <linux/pci.h> 15 #include <linux/sched.h> 16 #include <linux/init.h> 17 18 #include <asm/ptrace.h> 19 20 #include "proto.h" 21 #include "pci_impl.h" 22 23 /* 24 * BIOS32-style PCI interface: 25 */ 26 27 #define DEBUG_CONFIG 0 28 29 #if DEBUG_CONFIG 30 # define DBG_CFG(args) printk args 31 #else 32 # define DBG_CFG(args) 33 #endif 34 35 36 /* 37 * Given a bus, device, and function number, compute resulting 38 * configuration space address. This is fairly straightforward 39 * on POLARIS, since the chip itself generates Type 0 or Type 1 40 * cycles automatically depending on the bus number (Bus 0 is 41 * hardwired to Type 0, all others are Type 1. Peer bridges 42 * are not supported). 43 * 44 * All types: 45 * 46 * 3 3 3 3|3 3 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 47 * 9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 48 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 49 * |1|1|1|1|1|0|0|1|1|1|1|1|1|1|1|0|B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|x|x| 50 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 51 * 52 * 23:16 bus number (8 bits = 128 possible buses) 53 * 15:11 Device number (5 bits) 54 * 10:8 function number 55 * 7:2 register number 56 * 57 * Notes: 58 * The function number selects which function of a multi-function device 59 * (e.g., scsi and ethernet). 60 * 61 * The register selects a DWORD (32 bit) register offset. Hence it 62 * doesn't get shifted by 2 bits as we want to "drop" the bottom two 63 * bits. 64 */ 65 66 static int 67 mk_conf_addr(struct pci_bus *pbus, unsigned int device_fn, int where, 68 unsigned long *pci_addr, u8 *type1) 69 { 70 u8 bus = pbus->number; 71 72 *type1 = (bus == 0) ? 0 : 1; 73 *pci_addr = (bus << 16) | (device_fn << 8) | (where) | 74 POLARIS_DENSE_CONFIG_BASE; 75 76 DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x," 77 " returning address 0x%p\n" 78 bus, device_fn, where, *pci_addr)); 79 80 return 0; 81 } 82 83 static int 84 polaris_read_config(struct pci_bus *bus, unsigned int devfn, int where, 85 int size, u32 *value) 86 { 87 unsigned long addr; 88 unsigned char type1; 89 90 if (mk_conf_addr(bus, devfn, where, &addr, &type1)) 91 return PCIBIOS_DEVICE_NOT_FOUND; 92 93 switch (size) { 94 case 1: 95 *value = __kernel_ldbu(*(vucp)addr); 96 break; 97 case 2: 98 *value = __kernel_ldwu(*(vusp)addr); 99 break; 100 case 4: 101 *value = *(vuip)addr; 102 break; 103 } 104 105 return PCIBIOS_SUCCESSFUL; 106 } 107 108 109 static int 110 polaris_write_config(struct pci_bus *bus, unsigned int devfn, int where, 111 int size, u32 value) 112 { 113 unsigned long addr; 114 unsigned char type1; 115 116 if (mk_conf_addr(bus, devfn, where, &addr, &type1)) 117 return PCIBIOS_DEVICE_NOT_FOUND; 118 119 switch (size) { 120 case 1: 121 __kernel_stb(value, *(vucp)addr); 122 mb(); 123 __kernel_ldbu(*(vucp)addr); 124 break; 125 case 2: 126 __kernel_stw(value, *(vusp)addr); 127 mb(); 128 __kernel_ldwu(*(vusp)addr); 129 break; 130 case 4: 131 *(vuip)addr = value; 132 mb(); 133 *(vuip)addr; 134 break; 135 } 136 137 return PCIBIOS_SUCCESSFUL; 138 } 139 140 struct pci_ops polaris_pci_ops = 141 { 142 .read = polaris_read_config, 143 .write = polaris_write_config, 144 }; 145 146 void __init 147 polaris_init_arch(void) 148 { 149 struct pci_controller *hose; 150 151 /* May need to initialize error reporting (see PCICTL0/1), but 152 * for now assume that the firmware has done the right thing 153 * already. 154 */ 155 #if 0 156 printk("polaris_init_arch(): trusting firmware for setup\n"); 157 #endif 158 159 /* 160 * Create our single hose. 161 */ 162 163 pci_isa_hose = hose = alloc_pci_controller(); 164 hose->io_space = &ioport_resource; 165 hose->mem_space = &iomem_resource; 166 hose->index = 0; 167 168 hose->sparse_mem_base = 0; 169 hose->dense_mem_base = POLARIS_DENSE_MEM_BASE - IDENT_ADDR; 170 hose->sparse_io_base = 0; 171 hose->dense_io_base = POLARIS_DENSE_IO_BASE - IDENT_ADDR; 172 173 hose->sg_isa = hose->sg_pci = NULL; 174 175 /* The I/O window is fixed at 2G @ 2G. */ 176 __direct_map_base = 0x80000000; 177 __direct_map_size = 0x80000000; 178 } 179 180 static inline void 181 polaris_pci_clr_err(void) 182 { 183 *(vusp)POLARIS_W_STATUS; 184 /* Write 1's to settable bits to clear errors */ 185 *(vusp)POLARIS_W_STATUS = 0x7800; 186 mb(); 187 *(vusp)POLARIS_W_STATUS; 188 } 189 190 void 191 polaris_machine_check(unsigned long vector, unsigned long la_ptr) 192 { 193 /* Clear the error before any reporting. */ 194 mb(); 195 mb(); 196 draina(); 197 polaris_pci_clr_err(); 198 wrmces(0x7); 199 mb(); 200 201 process_mcheck_info(vector, la_ptr, "POLARIS", 202 mcheck_expected(0)); 203 } 204
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.