1 // Copyright 2018 The Fuchsia Authors
2 // Copyright (c) 2016, Google, Inc. All rights reserved
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 #pragma once
9 
10 #include <dev/address_provider/ecam_region.h>
11 #include <dev/pci_config.h>
12 #include <fbl/intrusive_wavl_tree.h>
13 #include <fbl/mutex.h>
14 #include <sys/types.h>
15 #include <zircon/types.h>
16 
17 // PcieAddressProvider is an interface that implements translation from a BDF to
18 // a PCI ECAM address.
19 class PcieAddressProvider {
20 public:
~PcieAddressProvider()21     virtual ~PcieAddressProvider() {}
22 
23     // Accepts a PCI BDF triple and returns ZX_OK if it is able to translate it
24     // into an ECAM address.
25     // Upon success, virt will contain the ECAM address provided by the
26     // translation. phys will optionally contain the corresponding physical
27     // address.
28     // On failure, result must not be touched by the implementation.
29     virtual zx_status_t Translate(uint8_t bus_id, uint8_t device_id, uint8_t function_id,
30                                   vaddr_t* virt, paddr_t* phys) = 0;
31 
32     // Creates a config that corresponds to the type of the PcieAddressProvider.
33     // For example, a PioAddressProvider will return a PioConfig whereas an
34     // MmioAddressProvider will return an MmioConfig.
35     virtual fbl::RefPtr<PciConfig> CreateConfig(const uintptr_t addr) = 0;
36 
37 protected:
PcieAddressProvider()38     PcieAddressProvider() {}
39 };
40 
41 // Concrete implementations.
42 
43 // Systems that have memory mapped Config Spaces
44 class MmioPcieAddressProvider : public PcieAddressProvider {
45 public:
MmioPcieAddressProvider()46     MmioPcieAddressProvider() {}
47     ~MmioPcieAddressProvider();
48 
49     zx_status_t Translate(uint8_t bus_id, uint8_t device_id, uint8_t function_id,
50                           vaddr_t* virt, paddr_t* phys) override;
51     fbl::RefPtr<PciConfig> CreateConfig(const uintptr_t addr) override;
52 
53     zx_status_t AddEcamRegion(const PciEcamRegion& ecam);
54 
55 private:
56     mutable fbl::Mutex ecam_region_lock_;
57     fbl::WAVLTree<uint8_t, ktl::unique_ptr<MappedEcamRegion>> ecam_regions_;
58 };
59 
60 // Systems that have PIO mapped Config Spaces
61 class PioPcieAddressProvider : public PcieAddressProvider {
62 public:
PioPcieAddressProvider()63     PioPcieAddressProvider() {}
64 
65     zx_status_t Translate(uint8_t bus_id, uint8_t device_id, uint8_t function_id,
66                           vaddr_t* virt, paddr_t* phys) override;
67     fbl::RefPtr<PciConfig> CreateConfig(const uintptr_t addr) override;
68 };
69 
70 
71 class DesignWarePcieAddressProvider : public PcieAddressProvider {
72   public:
DesignWarePcieAddressProvider()73     DesignWarePcieAddressProvider() {}
~DesignWarePcieAddressProvider()74     ~DesignWarePcieAddressProvider() {}
75 
76     zx_status_t Init(const PciEcamRegion& root_bridge,
77                      const PciEcamRegion& downstream_device);
78 
79     zx_status_t Translate(uint8_t bus_id, uint8_t device_id, uint8_t function_id,
80                           vaddr_t* virt, paddr_t* phys) override;
81     fbl::RefPtr<PciConfig> CreateConfig(const uintptr_t addr) override;
82 
83   private:
84     ktl::unique_ptr<MappedEcamRegion> root_bridge_region_;
85     ktl::unique_ptr<MappedEcamRegion> downstream_region_;
86 };
87