| 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 | |
| 44 | function Hex (Val : Natural) return Character |
| 45 | with |
| 46 | Pre => Val < 16 |
| 47 | is |
| 48 | begin |
| 49 | if Val < 10 then |
| 50 | return Character'Val (Character'Pos ('0') + Val); |
| 51 | else |
| 52 | return Character'Val (Character'Pos ('a') + Val - 10); |
| 53 | end if; |
| 54 | end Hex; |
| 55 | |
| 56 | subtype String2 is String (1 .. 2); |
| 57 | function Hex2 (Val : Natural) return String2 |
| 58 | with |
| 59 | Pre => Val < 256 |
| 60 | is |
| 61 | Res : constant String (1 .. 2) := (Hex (Val / 16), Hex (Val mod 16)); |
| 62 | begin |
| 63 | return Res; |
| 64 | end Hex2; |
| 65 | |
| 66 | procedure Patch_Sysfs_Path (Path : in out String) |
| 67 | with |
| 68 | Pre => Path'Length >= 36 |
| 69 | is |
| 70 | begin |
| 71 | Path (Path'First + 21 .. Path'First + 22) := Hex2 (Natural (Dev.Bus)); |
| 72 | Path (Path'First + 29 .. Path'First + 30) := Hex2 (Natural (Dev.Bus)); |
| 73 | Path (Path'First + 32 .. Path'First + 33) := Hex2 (Natural (Dev.Slot)); |
| 74 | Path (Path'First + 35) := Hex (Natural (Dev.Func)); |
| 75 | end Patch_Sysfs_Path; |
| 76 | |
| 77 | procedure Map |
| 78 | (Addr : out Word64; |
| 79 | Res : in Resource; |
| 80 | Length : in Natural := 0; |
| 81 | Offset : in Natural := 0; |
| 82 | WC : in Boolean := False) |
| 83 | is |
| 84 | Success : Boolean; |
| 85 | Path : String (1 .. 49) := |
| 86 | "/sys/devices/pci0000:xx/0000:xx:xx.x/resourcex_wc"; |
| 87 | begin |
| 88 | Patch_Sysfs_Path (Path); |
| 89 | Path (46) := Character'Val (Character'Pos ('0') + Resource'Pos (Res)); |
| 90 | if not WC then |
| 91 | Path (47) := Character'Val (0); |
| 92 | end if; |
| 93 | |
| 94 | File.Map |
| 95 | (Addr => Addr, |
| 96 | Path => Path, |
| 97 | Len => Length, |
| 98 | Offset => Offset, |
| 99 | Readable => True, |
| 100 | Writable => True, |
| 101 | Success => Success); |
| 102 | |
| 103 | if not Success and WC then -- try again without write-combining |
| 104 | Path (47) := Character'Val (0); |
| 105 | |
| 106 | File.Map |
| 107 | (Addr => Addr, |
| 108 | Path => Path, |
| 109 | Len => Length, |
| 110 | Offset => Offset, |
| 111 | Readable => True, |
| 112 | Writable => True, |
| 113 | Success => Success); |
| 114 | end if; |
| 115 | |
| 116 | if not Success then |
| 117 | Addr := 0; |
| 118 | end if; |
| 119 | end Map; |
| 120 | |
| 121 | procedure Resource_Size (Length : out Natural; Res : Resource) |
| 122 | is |
| 123 | Path : String (1 .. 46) := |
| 124 | "/sys/devices/pci0000:xx/0000:xx:xx.x/resourcex"; |
| 125 | begin |
| 126 | Patch_Sysfs_Path (Path); |
| 127 | Path (46) := Character'Val (Character'Pos ('0') + Resource'Pos (Res)); |
| 128 | |
| 129 | File.Size (Length, Path); |
| 130 | end Resource_Size; |
| 131 | |
| 132 | procedure Initialize (Success : out Boolean; MMConf_Base : Word64 := 0) |
| 133 | is |
| 134 | Addr : Word64; |
| 135 | Path : String (1 .. 43) := "/sys/devices/pci0000:xx/0000:xx:xx.x/config"; |
| 136 | begin |
| 137 | Patch_Sysfs_Path (Path); |
| 138 | |
| 139 | File.Map |
| 140 | (Addr => Addr, |
| 141 | Path => Path, |
| 142 | Readable => True, |
| 143 | Map_Copy => True, |
| 144 | Success => Success); |
| 145 | MM.Set_Base_Address (Addr); |
| 146 | end Initialize; |
| 147 | |
| 148 | end HW.PCI.Dev; |