| Nico Huber | ff3240b | 2017-07-09 16:23:04 +0200 | [diff] [blame] | 1 | -- |
| 2 | -- Copyright (C) 2017 Nico Huber <nico.h@gmx.de> |
| 3 | -- |
| 4 | -- This program is free software; you can redistribute it and/or modify |
| 5 | -- it under the terms of the GNU General Public License as published by |
| 6 | -- the Free Software Foundation; either version 2 of the License, or |
| 7 | -- (at your option) any later version. |
| 8 | -- |
| 9 | -- This program is distributed in the hope that it will be useful, |
| 10 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | -- GNU General Public License for more details. |
| 13 | -- |
| 14 | |
| 15 | with Ada.Text_IO; |
| 16 | with Ada.Strings.Fixed; |
| 17 | |
| 18 | with HW.File; |
| 19 | with HW.PCI.MMConf; |
| 20 | |
| 21 | with HW.MMIO_Range; |
| 22 | pragma Elaborate_All (HW.MMIO_Range); |
| 23 | |
| 24 | use Ada.Strings.Fixed; |
| 25 | |
| 26 | package body HW.PCI.Dev |
| 27 | with |
| 28 | Refined_State => |
| 29 | (Address_State => MM.Address_State, |
| 30 | PCI_State => MM.PCI_State) |
| 31 | is |
| 32 | |
| 33 | -- We map each device's config space individually, hence Address'(0, 0, 0). |
| 34 | package MM is new HW.PCI.MMConf (Address'(0, 0, 0)); |
| 35 | |
| 36 | procedure Read8 (Value : out Word8; Offset : Index) renames MM.Read8; |
| 37 | procedure Read16 (Value : out Word16; Offset : Index) renames MM.Read16; |
| 38 | procedure Read32 (Value : out Word32; Offset : Index) renames MM.Read32; |
| 39 | |
| 40 | procedure Write8 (Offset : Index; Value : Word8) renames MM.Write8; |
| 41 | procedure Write16 (Offset : Index; Value : Word16) renames MM.Write16; |
| 42 | procedure Write32 (Offset : Index; Value : Word32) renames MM.Write32; |
| 43 | |
| Nico Huber | 6685971 | 2017-08-25 20:04:30 +0200 | [diff] [blame^] | 44 | -- No-op PCI config update to share contracts |
| 45 | -- with implementations that do actual updates. |
| 46 | procedure Dummy_PCI_Update |
| 47 | with |
| 48 | Global => (In_Out => MM.PCI_State); |
| 49 | procedure Dummy_PCI_Update is null |
| 50 | with |
| 51 | SPARK_Mode => Off; |
| 52 | |
| Nico Huber | ff3240b | 2017-07-09 16:23:04 +0200 | [diff] [blame] | 53 | function Hex (Val : Natural) return Character |
| 54 | with |
| 55 | Pre => Val < 16 |
| 56 | is |
| 57 | begin |
| 58 | if Val < 10 then |
| 59 | return Character'Val (Character'Pos ('0') + Val); |
| 60 | else |
| 61 | return Character'Val (Character'Pos ('a') + Val - 10); |
| 62 | end if; |
| 63 | end Hex; |
| 64 | |
| 65 | subtype String2 is String (1 .. 2); |
| 66 | function Hex2 (Val : Natural) return String2 |
| 67 | with |
| 68 | Pre => Val < 256 |
| 69 | is |
| 70 | Res : constant String (1 .. 2) := (Hex (Val / 16), Hex (Val mod 16)); |
| 71 | begin |
| 72 | return Res; |
| 73 | end Hex2; |
| 74 | |
| 75 | procedure Patch_Sysfs_Path (Path : in out String) |
| 76 | with |
| 77 | Pre => Path'Length >= 36 |
| 78 | is |
| 79 | begin |
| 80 | Path (Path'First + 21 .. Path'First + 22) := Hex2 (Natural (Dev.Bus)); |
| 81 | Path (Path'First + 29 .. Path'First + 30) := Hex2 (Natural (Dev.Bus)); |
| 82 | Path (Path'First + 32 .. Path'First + 33) := Hex2 (Natural (Dev.Slot)); |
| 83 | Path (Path'First + 35) := Hex (Natural (Dev.Func)); |
| 84 | end Patch_Sysfs_Path; |
| 85 | |
| 86 | procedure Map |
| 87 | (Addr : out Word64; |
| 88 | Res : in Resource; |
| 89 | Length : in Natural := 0; |
| 90 | Offset : in Natural := 0; |
| 91 | WC : in Boolean := False) |
| 92 | is |
| 93 | Success : Boolean; |
| 94 | Path : String (1 .. 49) := |
| 95 | "/sys/devices/pci0000:xx/0000:xx:xx.x/resourcex_wc"; |
| 96 | begin |
| Nico Huber | 6685971 | 2017-08-25 20:04:30 +0200 | [diff] [blame^] | 97 | Dummy_PCI_Update; |
| 98 | |
| Nico Huber | ff3240b | 2017-07-09 16:23:04 +0200 | [diff] [blame] | 99 | Patch_Sysfs_Path (Path); |
| 100 | Path (46) := Character'Val (Character'Pos ('0') + Resource'Pos (Res)); |
| 101 | if not WC then |
| 102 | Path (47) := Character'Val (0); |
| 103 | end if; |
| 104 | |
| 105 | File.Map |
| 106 | (Addr => Addr, |
| 107 | Path => Path, |
| 108 | Len => Length, |
| 109 | Offset => Offset, |
| 110 | Readable => True, |
| 111 | Writable => True, |
| 112 | Success => Success); |
| 113 | |
| 114 | if not Success and WC then -- try again without write-combining |
| 115 | Path (47) := Character'Val (0); |
| 116 | |
| 117 | File.Map |
| 118 | (Addr => Addr, |
| 119 | Path => Path, |
| 120 | Len => Length, |
| 121 | Offset => Offset, |
| 122 | Readable => True, |
| 123 | Writable => True, |
| 124 | Success => Success); |
| 125 | end if; |
| 126 | |
| 127 | if not Success then |
| 128 | Addr := 0; |
| 129 | end if; |
| 130 | end Map; |
| 131 | |
| 132 | procedure Resource_Size (Length : out Natural; Res : Resource) |
| 133 | is |
| 134 | Path : String (1 .. 46) := |
| 135 | "/sys/devices/pci0000:xx/0000:xx:xx.x/resourcex"; |
| 136 | begin |
| Nico Huber | 6685971 | 2017-08-25 20:04:30 +0200 | [diff] [blame^] | 137 | Dummy_PCI_Update; |
| 138 | |
| Nico Huber | ff3240b | 2017-07-09 16:23:04 +0200 | [diff] [blame] | 139 | Patch_Sysfs_Path (Path); |
| 140 | Path (46) := Character'Val (Character'Pos ('0') + Resource'Pos (Res)); |
| 141 | |
| 142 | File.Size (Length, Path); |
| 143 | end Resource_Size; |
| 144 | |
| 145 | procedure Initialize (Success : out Boolean; MMConf_Base : Word64 := 0) |
| 146 | is |
| 147 | Addr : Word64; |
| 148 | Path : String (1 .. 43) := "/sys/devices/pci0000:xx/0000:xx:xx.x/config"; |
| 149 | begin |
| 150 | Patch_Sysfs_Path (Path); |
| 151 | |
| 152 | File.Map |
| 153 | (Addr => Addr, |
| 154 | Path => Path, |
| 155 | Readable => True, |
| 156 | Map_Copy => True, |
| 157 | Success => Success); |
| 158 | MM.Set_Base_Address (Addr); |
| 159 | end Initialize; |
| 160 | |
| 161 | end HW.PCI.Dev; |