1 /*
2 * Copyright (c) 2021 Travis Geiseblrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8 #include "resource.h"
9
10 #include <dev/bus/pci.h>
11 #include <lk/err.h>
12 #include <lk/trace.h>
13 #include <stdint.h>
14
15 #define LOCAL_TRACE 0
16
17 namespace pci {
18
type_to_range(pci_resource_type type,bool prefetchable)19 resource_range &resource_allocator::type_to_range(pci_resource_type type, bool prefetchable) {
20 if (prefetchable) {
21 switch (type) {
22 case PCI_RESOURCE_MMIO_RANGE:
23 return ranges_.mmio_prefetchable;
24 case PCI_RESOURCE_MMIO64_RANGE:
25 return ranges_.mmio64_prefetchable;
26 default:
27 DEBUG_ASSERT_MSG(0, "uhandled prefetchable pci resource type %d\n", type);
28 }
29 } else {
30 switch (type) {
31 case PCI_RESOURCE_IO_RANGE:
32 return ranges_.io;
33 case PCI_RESOURCE_MMIO_RANGE:
34 return ranges_.mmio;
35 case PCI_RESOURCE_MMIO64_RANGE:
36 return ranges_.mmio64;
37 default:
38 DEBUG_ASSERT_MSG(0, "uhandled pci resource type %d\n", type);
39 }
40 }
41 static resource_range zero = {};
42 return zero;
43 }
44
set_range(const resource_range & range,bool prefetchable)45 status_t resource_allocator::set_range(const resource_range &range, bool prefetchable) {
46 LTRACEF("range base %#llx size %#llx type %d prefetchable %d\n", range.base, range.size, range.type, prefetchable);
47 type_to_range(range.type, prefetchable) = range;
48 return NO_ERROR;
49 }
50
allocate_mmio(bool can_be_64bit,bool prefetchable,uint64_t size,uint8_t align,uint64_t * out)51 status_t resource_allocator::allocate_mmio(bool can_be_64bit, bool prefetchable, uint64_t size, uint8_t align, uint64_t *out) {
52 pci_resource_type type;
53
54 for (;;) {
55 if (can_be_64bit) {
56 type = PCI_RESOURCE_MMIO64_RANGE;
57 } else {
58 type = PCI_RESOURCE_MMIO_RANGE;
59 }
60
61 auto &range = type_to_range(type, prefetchable);
62
63 LTRACEF("range base %#llx size %#llx. request size %#llx align %u prefetchable %d can_be_64 %d\n",
64 range.base, range.size, size, align, prefetchable, can_be_64bit);
65
66 // TODO: make sure align is honored or removed
67 if (range.base + size <= range.base + range.size) {
68 *out = range.base;
69 range.base += size;
70 range.size -= size;
71 return NO_ERROR;
72 }
73
74 // after trying once to allocate in a 64bit range, drop to 32bit and try again
75 if (can_be_64bit) {
76 can_be_64bit = false;
77 continue;
78 }
79 break;
80 }
81
82 return ERR_NO_RESOURCES;
83 }
84
allocate_io(uint32_t size,uint8_t align,uint32_t * out)85 status_t resource_allocator::allocate_io(uint32_t size, uint8_t align, uint32_t *out) {
86 auto &range = type_to_range(PCI_RESOURCE_IO_RANGE, false);
87
88 LTRACEF("range base %#llx size %#llx. request size %#x align %u\n", range.base, range.size, size, align);
89
90 // TODO: make sure align is honored or removed
91 if (range.base + size <= range.base + range.size) {
92 *out = range.base;
93 range.base += size;
94 range.size -= size;
95 return NO_ERROR;
96 }
97
98 return ERR_NO_RESOURCES;
99 }
100
101 } // namespace pci
102