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