|
8 | 8 | */
|
9 | 9 | #include "ecam.h"
|
10 | 10 |
|
11 |
| -#include <lk/debug.h> |
12 |
| -#include <lk/err.h> |
13 | 11 | #include <stdlib.h>
|
14 | 12 | #include <string.h>
|
15 |
| -#include <kernel/thread.h> |
16 |
| -#include <kernel/spinlock.h> |
| 13 | + |
17 | 14 | #include <dev/bus/pci.h>
|
| 15 | +#include <fbl/alloc_checker.h> |
| 16 | +#include <kernel/spinlock.h> |
| 17 | +#include <kernel/thread.h> |
| 18 | +#include <lk/debug.h> |
| 19 | +#include <lk/err.h> |
18 | 20 | #include <lk/trace.h>
|
19 |
| - |
20 |
| -#if WITH_KERNEL_VM |
21 |
| -#include <kernel/vm.h> |
22 |
| -#endif |
| 21 | +#include <vm/vm_aspace.h> |
23 | 22 |
|
24 | 23 | #include "../pci_priv.h"
|
25 | 24 |
|
26 | 25 | #define LOCAL_TRACE 0
|
27 | 26 |
|
28 |
| -pci_ecam::pci_ecam(paddr_t base, uint16_t segment, uint8_t start_bus, uint8_t end_bus) : |
29 |
| - base_(base), segment_(segment), start_bus_(start_bus), end_bus_(end_bus) {} |
| 27 | +pci_ecam::pci_ecam(paddr_t base, uint16_t segment, uint8_t start_bus, uint8_t end_bus) |
| 28 | + : base_(base), segment_(segment), start_bus_(start_bus), end_bus_(end_bus) {} |
30 | 29 |
|
31 | 30 | pci_ecam::~pci_ecam() {
|
32 |
| - LTRACE_ENTRY; |
33 |
| -#if WITH_KERNEL_VM |
34 |
| - if (ecam_ptr_) { |
35 |
| - vmm_free_region(vmm_get_kernel_aspace(), (vaddr_t)ecam_ptr_); |
36 |
| - } |
37 |
| -#endif |
| 31 | + LTRACE_ENTRY; |
| 32 | + if (ecam_ptr_) { |
| 33 | + VmAspace::kernel_aspace()->FreeRegion(reinterpret_cast<vaddr_t>(ecam_ptr_)); |
| 34 | + ecam_ptr_ = nullptr; |
| 35 | + } |
38 | 36 | }
|
39 | 37 |
|
40 | 38 | pci_ecam *pci_ecam::detect(paddr_t base, uint16_t segment, uint8_t start_bus, uint8_t end_bus) {
|
41 |
| - LTRACEF("base %#lx, segment %hu, bus [%hhu...%hhu]\n", base, segment, start_bus, end_bus); |
42 |
| - |
43 |
| - // we only support a limited configuration at the moment |
44 |
| - if (segment != 0 || start_bus != 0) { |
45 |
| - return nullptr; |
46 |
| - } |
47 |
| - |
48 |
| - auto ecam = new pci_ecam(base, segment, start_bus, end_bus); |
49 |
| - |
50 |
| - // initialize the object, which may fail |
51 |
| - status_t err = ecam->initialize(); |
52 |
| - if (err != NO_ERROR) { |
53 |
| - delete ecam; |
54 |
| - return nullptr; |
55 |
| - } |
56 |
| - |
57 |
| - return ecam; |
| 39 | + LTRACEF("base %#lx, segment %hu, bus [%hhu...%hhu]\n", base, segment, start_bus, end_bus); |
| 40 | + |
| 41 | + // we only support a limited configuration at the moment |
| 42 | + if (segment != 0 || start_bus != 0) { |
| 43 | + return nullptr; |
| 44 | + } |
| 45 | + |
| 46 | + fbl::AllocChecker ac; |
| 47 | + auto ecam = new (&ac) pci_ecam(base, segment, start_bus, end_bus); |
| 48 | + if (!ac.check()) { |
| 49 | + return nullptr; |
| 50 | + } |
| 51 | + |
| 52 | + // initialize the object, which may fail |
| 53 | + status_t err = ecam->initialize(); |
| 54 | + if (err != NO_ERROR) { |
| 55 | + delete ecam; |
| 56 | + return nullptr; |
| 57 | + } |
| 58 | + |
| 59 | + return ecam; |
58 | 60 | }
|
59 | 61 |
|
60 | 62 | status_t pci_ecam::initialize() {
|
61 |
| - // compute the aperture size of this |
62 |
| - size_t size = ((size_t)end_bus_ - (size_t)start_bus_ + 1) << 20; // each bus occupies 20 bits of address space |
63 |
| - LTRACEF("aperture size %#zx\n", size); |
64 |
| - |
65 |
| - |
66 |
| -#if WITH_KERNEL_VM |
67 |
| - // try to map the aperture |
68 |
| - // ask for 4MB aligned regions (log2 22) to help with the mmu on most architectures |
69 |
| - //status_t vmm_alloc_physical(vmm_aspace_t *aspace, const char *name, size_t size, void **ptr, uint8_t align_log2, paddr_t paddr, uint vmm_flags, uint arch_mmu_flags) |
70 |
| - status_t err = vmm_alloc_physical(vmm_get_kernel_aspace(), "pci_ecam", size, (void **)&ecam_ptr_, 22, base_, 0, ARCH_MMU_FLAG_UNCACHED_DEVICE); |
71 |
| - LTRACEF("vmm_alloc_physical returns %d, ptr %p\n", err, ecam_ptr_); |
72 |
| - |
73 |
| - if (err != NO_ERROR) { |
74 |
| - ecam_ptr_ = nullptr; |
75 |
| - return err; |
76 |
| - } |
77 |
| -#else |
78 |
| - // no vm, so can directly access the aperture |
79 |
| - ecam_ptr_ = (uint8_t *)base_; |
80 |
| -#endif |
81 |
| - |
82 |
| - set_last_bus(end_bus_); |
83 |
| - |
84 |
| - return NO_ERROR; |
| 63 | + // compute the aperture size of this |
| 64 | + size_t size = ((size_t)end_bus_ - (size_t)start_bus_ + 1) |
| 65 | + << 20; // each bus occupies 20 bits of address space |
| 66 | + LTRACEF("aperture size %#zx\n", size); |
| 67 | + |
| 68 | + // try to map the aperture |
| 69 | + // ask for 4MB aligned regions (log2 22) to help with the mmu on most architectures |
| 70 | + // status_t vmm_alloc_physical(vmm_aspace_t *aspace, const char *name, size_t size, void **ptr, |
| 71 | + // uint8_t align_log2, paddr_t paddr, uint vmm_flags, uint arch_mmu_flags) |
| 72 | + zx_status_t err = VmAspace::kernel_aspace()->AllocPhysical( |
| 73 | + "pci_ecam", size, /* size */ |
| 74 | + (void **)&ecam_ptr_, /* returned virtual address */ |
| 75 | + 22, /* alignment log2 */ |
| 76 | + base_, /* physical address */ |
| 77 | + 0, /* vmm flags */ |
| 78 | + ARCH_MMU_FLAG_UNCACHED_DEVICE | ARCH_MMU_FLAG_PERM_READ | ARCH_MMU_FLAG_PERM_WRITE); |
| 79 | + |
| 80 | + LTRACEF("vmm_alloc_physical returns %d, ptr %p\n", err, ecam_ptr_); |
| 81 | + if (err != ZX_OK) { |
| 82 | + ecam_ptr_ = nullptr; |
| 83 | + return err; |
| 84 | + } |
| 85 | + |
| 86 | + set_last_bus(end_bus_); |
| 87 | + |
| 88 | + return NO_ERROR; |
85 | 89 | }
|
86 | 90 |
|
87 | 91 | // compute the offset into the ecam given the location and register offset
|
88 | 92 | inline size_t location_to_offset(const pci_location_t state, uint32_t reg) {
|
89 |
| - // |
90 |
| - // | 27 - 20 | 19 - 15 | 14 - 12 | 11 - 8 | 7 - 2 | 1 - 0 | |
91 |
| - // | Bus Nr | Dev Nr | Function Nr | Ext. Register Nr | Register Nr | Byte Enable | |
92 |
| - |
93 |
| - // TODO: clamp or assert on invalid offset |
94 |
| - size_t offset = (size_t)state.bus << 20; |
95 |
| - offset += (size_t)state.dev << 15; |
96 |
| - offset += (size_t)state.fn << 12; |
97 |
| - offset += reg; |
98 |
| - return offset; |
| 93 | + // |
| 94 | + // | 27 - 20 | 19 - 15 | 14 - 12 | 11 - 8 | 7 - 2 | 1 - 0 | |
| 95 | + // | Bus Nr | Dev Nr | Function Nr | Ext. Register Nr | Register Nr | Byte Enable | |
| 96 | + |
| 97 | + // TODO: clamp or assert on invalid offset |
| 98 | + size_t offset = (size_t)state.bus << 20; |
| 99 | + offset += (size_t)state.dev << 15; |
| 100 | + offset += (size_t)state.fn << 12; |
| 101 | + offset += reg; |
| 102 | + return offset; |
99 | 103 | }
|
100 | 104 |
|
101 | 105 | // templatized routines to access the pci config space using a specific type
|
102 | 106 | template <typename T>
|
103 |
| -inline int read_config(const pci_location_t state, uint32_t reg, T *value, const uint8_t *ecam_ptr) { |
104 |
| - auto off = location_to_offset(state, reg); |
| 107 | +inline int read_config(const pci_location_t state, uint32_t reg, T *value, |
| 108 | + const uint8_t *ecam_ptr) { |
| 109 | + auto off = location_to_offset(state, reg); |
105 | 110 |
|
106 |
| - *value = *reinterpret_cast<const volatile T *>(&ecam_ptr[off]); |
| 111 | + *value = *reinterpret_cast<const volatile T *>(&ecam_ptr[off]); |
107 | 112 |
|
108 |
| - return NO_ERROR; |
| 113 | + return NO_ERROR; |
109 | 114 | }
|
110 | 115 |
|
111 | 116 | template <typename T>
|
112 | 117 | inline int write_config(const pci_location_t state, uint32_t reg, T value, uint8_t *ecam_ptr) {
|
113 |
| - auto off = location_to_offset(state, reg); |
| 118 | + auto off = location_to_offset(state, reg); |
114 | 119 |
|
115 |
| - *reinterpret_cast<volatile T *>(&ecam_ptr[off]) = value; |
| 120 | + *reinterpret_cast<volatile T *>(&ecam_ptr[off]) = value; |
116 | 121 |
|
117 |
| - return NO_ERROR; |
| 122 | + return NO_ERROR; |
118 | 123 | }
|
119 | 124 |
|
120 | 125 | int pci_ecam::read_config_byte(const pci_location_t state, uint32_t reg, uint8_t *value) {
|
121 |
| - LTRACEF_LEVEL(2, "state bus %#hhx dev %#hhx %#hhx reg %#x\n", state.bus, state.dev, state.fn, reg); |
122 |
| - return read_config(state, reg, value, ecam_ptr_); |
| 126 | + LTRACEF_LEVEL(2, "state bus %#hhx dev %#hhx %#hhx reg %#x\n", state.bus, state.dev, state.fn, |
| 127 | + reg); |
| 128 | + return read_config(state, reg, value, ecam_ptr_); |
123 | 129 | }
|
124 | 130 |
|
125 | 131 | int pci_ecam::read_config_half(const pci_location_t state, uint32_t reg, uint16_t *value) {
|
126 |
| - LTRACEF_LEVEL(2, "state bus %#hhx dev %#hhx %#hhx reg %#x\n", state.bus, state.dev, state.fn, reg); |
127 |
| - return read_config(state, reg, value, ecam_ptr_); |
| 132 | + LTRACEF_LEVEL(2, "state bus %#hhx dev %#hhx %#hhx reg %#x\n", state.bus, state.dev, state.fn, |
| 133 | + reg); |
| 134 | + return read_config(state, reg, value, ecam_ptr_); |
128 | 135 | }
|
129 | 136 |
|
130 | 137 | int pci_ecam::read_config_word(const pci_location_t state, uint32_t reg, uint32_t *value) {
|
131 |
| - LTRACEF_LEVEL(2, "state bus %#hhx dev %#hhx %#hhx reg %#x\n", state.bus, state.dev, state.fn, reg); |
132 |
| - return read_config(state, reg, value, ecam_ptr_); |
| 138 | + LTRACEF_LEVEL(2, "state bus %#hhx dev %#hhx %#hhx reg %#x\n", state.bus, state.dev, state.fn, |
| 139 | + reg); |
| 140 | + return read_config(state, reg, value, ecam_ptr_); |
133 | 141 | }
|
134 | 142 |
|
135 | 143 | int pci_ecam::write_config_byte(const pci_location_t state, uint32_t reg, uint8_t value) {
|
136 |
| - LTRACEF_LEVEL(2, "state bus %#hhx dev %#hhx %#hhx reg %#x\n", state.bus, state.dev, state.fn, reg); |
137 |
| - return write_config(state, reg, value, ecam_ptr_); |
| 144 | + LTRACEF_LEVEL(2, "state bus %#hhx dev %#hhx %#hhx reg %#x\n", state.bus, state.dev, state.fn, |
| 145 | + reg); |
| 146 | + return write_config(state, reg, value, ecam_ptr_); |
138 | 147 | }
|
139 | 148 |
|
140 | 149 | int pci_ecam::write_config_half(const pci_location_t state, uint32_t reg, uint16_t value) {
|
141 |
| - LTRACEF_LEVEL(2, "state bus %#hhx dev %#hhx %#hhx reg %#x\n", state.bus, state.dev, state.fn, reg); |
142 |
| - return write_config(state, reg, value, ecam_ptr_); |
| 150 | + LTRACEF_LEVEL(2, "state bus %#hhx dev %#hhx %#hhx reg %#x\n", state.bus, state.dev, state.fn, |
| 151 | + reg); |
| 152 | + return write_config(state, reg, value, ecam_ptr_); |
143 | 153 | }
|
144 | 154 |
|
145 | 155 | int pci_ecam::write_config_word(const pci_location_t state, uint32_t reg, uint32_t value) {
|
146 |
| - LTRACEF_LEVEL(2, "state bus %#hhx dev %#hhx %#hhx reg %#x\n", state.bus, state.dev, state.fn, reg); |
147 |
| - return write_config(state, reg, value, ecam_ptr_); |
| 156 | + LTRACEF_LEVEL(2, "state bus %#hhx dev %#hhx %#hhx reg %#x\n", state.bus, state.dev, state.fn, |
| 157 | + reg); |
| 158 | + return write_config(state, reg, value, ecam_ptr_); |
148 | 159 | }
|
0 commit comments