Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.16 271 lines 6.8 kB view raw
1/* 2 * Copyright 2001 MontaVista Software Inc. 3 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net 4 * 5 * arch/mips/ddb5xxx/ddb5476/pci_ops.c 6 * Define the pci_ops for DB5477. 7 * 8 * Much of the code is derived from the original DDB5074 port by 9 * Geert Uytterhoeven <geert@sonycom.com> 10 * 11 * This program is free software; you can redistribute it and/or modify it 12 * under the terms of the GNU General Public License as published by the 13 * Free Software Foundation; either version 2 of the License, or (at your 14 * option) any later version. 15 * 16 */ 17#include <linux/pci.h> 18#include <linux/kernel.h> 19#include <linux/types.h> 20 21#include <asm/addrspace.h> 22#include <asm/debug.h> 23 24#include <asm/ddb5xxx/ddb5xxx.h> 25 26/* 27 * config_swap structure records what set of pdar/pmr are used 28 * to access pci config space. It also provides a place hold the 29 * original values for future restoring. 30 */ 31struct pci_config_swap { 32 u32 pdar; 33 u32 pmr; 34 u32 config_base; 35 u32 config_size; 36 u32 pdar_backup; 37 u32 pmr_backup; 38}; 39 40/* 41 * On DDB5476, we have one set of swap registers 42 */ 43struct pci_config_swap ext_pci_swap = { 44 DDB_PCIW0, 45 DDB_PCIINIT0, 46 DDB_PCI_CONFIG_BASE, 47 DDB_PCI_CONFIG_SIZE 48}; 49 50static int pci_config_workaround = 1; 51 52/* 53 * access config space 54 */ 55static inline u32 ddb_access_config_base(struct pci_config_swap *swap, u32 bus, /* 0 means top level bus */ 56 u32 slot_num) 57{ 58 u32 pci_addr = 0; 59 u32 pciinit_offset = 0; 60 u32 virt_addr = swap->config_base; 61 u32 option; 62 63 if (pci_config_workaround) { 64 if (slot_num == 5) 65 slot_num = 14; 66 } else { 67 if (slot_num == 5) 68 return DDB_BASE + DDB_PCI_BASE; 69 } 70 71 /* minimum pdar (window) size is 2MB */ 72 db_assert(swap->config_size >= (2 << 20)); 73 74 db_assert(slot_num < (1 << 5)); 75 db_assert(bus < (1 << 8)); 76 77 /* backup registers */ 78 swap->pdar_backup = ddb_in32(swap->pdar); 79 swap->pmr_backup = ddb_in32(swap->pmr); 80 81 /* set the pdar (pci window) register */ 82 ddb_set_pdar(swap->pdar, swap->config_base, swap->config_size, 32, /* 32 bit wide */ 83 0, /* not on local memory bus */ 84 0); /* not visible from PCI bus (N/A) */ 85 86 /* 87 * calcuate the absolute pci config addr; 88 * according to the spec, we start scanning from adr:11 (0x800) 89 */ 90 if (bus == 0) { 91 /* type 0 config */ 92 pci_addr = 0x00040000 << slot_num; 93 } else { 94 /* type 1 config */ 95 pci_addr = 0x00040000 << slot_num; 96 panic 97 ("ddb_access_config_base: we don't support type 1 config Yet"); 98 } 99 100 /* 101 * if pci_addr is less than pci config window size, we set 102 * pciinit_offset to 0 and adjust the virt_address. 103 * Otherwise we will try to adjust pciinit_offset. 104 */ 105 if (pci_addr < swap->config_size) { 106 virt_addr = KSEG1ADDR(swap->config_base + pci_addr); 107 pciinit_offset = 0; 108 } else { 109 db_assert((pci_addr & (swap->config_size - 1)) == 0); 110 virt_addr = KSEG1ADDR(swap->config_base); 111 pciinit_offset = pci_addr; 112 } 113 114 /* set the pmr register */ 115 option = DDB_PCI_ACCESS_32; 116 if (bus != 0) 117 option |= DDB_PCI_CFGTYPE1; 118 ddb_set_pmr(swap->pmr, DDB_PCICMD_CFG, pciinit_offset, option); 119 120 return virt_addr; 121} 122 123static inline void ddb_close_config_base(struct pci_config_swap *swap) 124{ 125 ddb_out32(swap->pdar, swap->pdar_backup); 126 ddb_out32(swap->pmr, swap->pmr_backup); 127} 128 129static int read_config_dword(struct pci_config_swap *swap, 130 struct pci_dev *dev, u32 where, u32 * val) 131{ 132 u32 bus, slot_num, func_num; 133 u32 base; 134 135 db_assert((where & 3) == 0); 136 db_assert(where < (1 << 8)); 137 138 /* check if the bus is top-level */ 139 if (dev->bus->parent != NULL) { 140 bus = dev->bus->number; 141 db_assert(bus != 0); 142 } else { 143 bus = 0; 144 } 145 146 slot_num = PCI_SLOT(dev->devfn); 147 func_num = PCI_FUNC(dev->devfn); 148 base = ddb_access_config_base(swap, bus, slot_num); 149 *val = *(volatile u32 *) (base + (func_num << 8) + where); 150 ddb_close_config_base(swap); 151 return PCIBIOS_SUCCESSFUL; 152} 153 154static int read_config_word(struct pci_config_swap *swap, 155 struct pci_dev *dev, u32 where, u16 * val) 156{ 157 int status; 158 u32 result; 159 160 db_assert((where & 1) == 0); 161 162 status = read_config_dword(swap, dev, where & ~3, &result); 163 if (where & 2) 164 result >>= 16; 165 *val = result & 0xffff; 166 return status; 167} 168 169static int read_config_byte(struct pci_config_swap *swap, 170 struct pci_dev *dev, u32 where, u8 * val) 171{ 172 int status; 173 u32 result; 174 175 status = read_config_dword(swap, dev, where & ~3, &result); 176 if (where & 1) 177 result >>= 8; 178 if (where & 2) 179 result >>= 16; 180 *val = result & 0xff; 181 return status; 182} 183 184static int write_config_dword(struct pci_config_swap *swap, 185 struct pci_dev *dev, u32 where, u32 val) 186{ 187 u32 bus, slot_num, func_num; 188 u32 base; 189 190 db_assert((where & 3) == 0); 191 db_assert(where < (1 << 8)); 192 193 /* check if the bus is top-level */ 194 if (dev->bus->parent != NULL) { 195 bus = dev->bus->number; 196 db_assert(bus != 0); 197 } else { 198 bus = 0; 199 } 200 201 slot_num = PCI_SLOT(dev->devfn); 202 func_num = PCI_FUNC(dev->devfn); 203 base = ddb_access_config_base(swap, bus, slot_num); 204 *(volatile u32 *) (base + (func_num << 8) + where) = val; 205 ddb_close_config_base(swap); 206 return PCIBIOS_SUCCESSFUL; 207} 208 209static int write_config_word(struct pci_config_swap *swap, 210 struct pci_dev *dev, u32 where, u16 val) 211{ 212 int status, shift = 0; 213 u32 result; 214 215 db_assert((where & 1) == 0); 216 217 status = read_config_dword(swap, dev, where & ~3, &result); 218 if (status != PCIBIOS_SUCCESSFUL) 219 return status; 220 221 if (where & 2) 222 shift += 16; 223 result &= ~(0xffff << shift); 224 result |= val << shift; 225 return write_config_dword(swap, dev, where & ~3, result); 226} 227 228static int write_config_byte(struct pci_config_swap *swap, 229 struct pci_dev *dev, u32 where, u8 val) 230{ 231 int status, shift = 0; 232 u32 result; 233 234 status = read_config_dword(swap, dev, where & ~3, &result); 235 if (status != PCIBIOS_SUCCESSFUL) 236 return status; 237 238 if (where & 2) 239 shift += 16; 240 if (where & 1) 241 shift += 8; 242 result &= ~(0xff << shift); 243 result |= val << shift; 244 return write_config_dword(swap, dev, where & ~3, result); 245} 246 247#define MAKE_PCI_OPS(prefix, rw, unitname, unittype, pciswap) \ 248static int prefix##_##rw##_config_##unitname(struct pci_dev *dev, int where, unittype val) \ 249{ \ 250 return rw##_config_##unitname(pciswap, \ 251 dev, \ 252 where, \ 253 val); \ 254} 255 256MAKE_PCI_OPS(extpci, read, byte, u8 *, &ext_pci_swap) 257 MAKE_PCI_OPS(extpci, read, word, u16 *, &ext_pci_swap) 258 MAKE_PCI_OPS(extpci, read, dword, u32 *, &ext_pci_swap) 259 260 MAKE_PCI_OPS(extpci, write, byte, u8, &ext_pci_swap) 261 MAKE_PCI_OPS(extpci, write, word, u16, &ext_pci_swap) 262 MAKE_PCI_OPS(extpci, write, dword, u32, &ext_pci_swap) 263 264struct pci_ops ddb5476_ext_pci_ops = { 265 extpci_read_config_byte, 266 extpci_read_config_word, 267 extpci_read_config_dword, 268 extpci_write_config_byte, 269 extpci_write_config_word, 270 extpci_write_config_dword 271};