]> mj.ucw.cz Git - pciutils.git/blob - lib/darwin.c
libpci: Add constants for Lane Margining at the Receiver Extended Capability
[pciutils.git] / lib / darwin.c
1 /*
2  *      The PCI Library -- Darwin kIOACPI access
3  *
4  *      Copyright (c) 2013 Apple, Inc.
5  *
6  *      Can be freely distributed and used under the terms of the GNU GPL v2+.
7  *
8  *      SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <stdint.h>
17
18 #include "internal.h"
19
20 #include <mach/mach_error.h>
21 #include <CoreFoundation/CoreFoundation.h>
22 #include <IOKit/IOKitLib.h>
23 #include <IOKit/IOKitKeys.h>
24
25 enum {
26     kACPIMethodAddressSpaceRead         = 0,
27     kACPIMethodAddressSpaceWrite        = 1,
28     kACPIMethodDebuggerCommand          = 2,
29     kACPIMethodCount
30 };
31
32 #pragma pack(1)
33
34 typedef UInt32 IOACPIAddressSpaceID;
35
36 enum {
37     kIOACPIAddressSpaceIDSystemMemory       = 0,
38     kIOACPIAddressSpaceIDSystemIO           = 1,
39     kIOACPIAddressSpaceIDPCIConfiguration   = 2,
40     kIOACPIAddressSpaceIDEmbeddedController = 3,
41     kIOACPIAddressSpaceIDSMBus              = 4
42 };
43
44 /*
45  * 64-bit ACPI address
46  */
47 union IOACPIAddress {
48     UInt64 addr64;
49     struct {
50         unsigned int offset     :16;
51         unsigned int function   :3;
52         unsigned int device     :5;
53         unsigned int bus        :8;
54         unsigned int segment    :16;
55         unsigned int reserved   :16;
56     } pci;
57 };
58 typedef union IOACPIAddress IOACPIAddress;
59
60 #pragma pack()
61
62 struct AddressSpaceParam {
63     UInt64                      value;
64     UInt32                      spaceID;
65     IOACPIAddress       address;
66     UInt32                      bitWidth;
67     UInt32                      bitOffset;
68     UInt32                      options;
69 };
70 typedef struct AddressSpaceParam AddressSpaceParam;
71
72 static void
73 darwin_config(struct pci_access *a UNUSED)
74 {
75 }
76
77 static int
78 darwin_detect(struct pci_access *a)
79 {
80   io_registry_entry_t    service;
81   io_connect_t           connect;
82   kern_return_t          status;
83
84   service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleACPIPlatformExpert"));
85   if (service)
86     {
87       status = IOServiceOpen(service, mach_task_self(), 0, &connect);
88       IOObjectRelease(service);
89     }
90
91   if (!service || (kIOReturnSuccess != status))
92     {
93       a->warning("Cannot open AppleACPIPlatformExpert (add boot arg debug=0x144 & run as root)");
94       return 0;
95     }
96   a->debug("...using AppleACPIPlatformExpert");
97   a->fd = connect;
98   return 1;
99 }
100
101 static void
102 darwin_init(struct pci_access *a UNUSED)
103 {
104 }
105
106 static void
107 darwin_cleanup(struct pci_access *a UNUSED)
108 {
109 }
110
111 static int
112 darwin_read(struct pci_dev *d, int pos, byte *buf, int len)
113 {
114   if (!(len == 1 || len == 2 || len == 4))
115     return pci_generic_block_read(d, pos, buf, len);
116
117   AddressSpaceParam param;
118   kern_return_t     status;
119
120   param.spaceID   = kIOACPIAddressSpaceIDPCIConfiguration;
121   param.bitWidth  = len * 8;
122   param.bitOffset = 0;
123   param.options   = 0;
124
125   param.address.pci.offset   = pos;
126   param.address.pci.function = d->func;
127   param.address.pci.device   = d->dev;
128   param.address.pci.bus      = d->bus;
129   param.address.pci.segment  = d->domain;
130   param.address.pci.reserved = 0;
131   param.value                = -1ULL;
132
133   size_t outSize = sizeof(param);
134   status = IOConnectCallStructMethod(d->access->fd, kACPIMethodAddressSpaceRead,
135     &param, sizeof(param),
136     &param, &outSize);
137   if ((kIOReturnSuccess != status))
138     d->access->error("darwin_read: kACPIMethodAddressSpaceRead failed: %s", mach_error_string(status));
139
140   switch (len)
141     {
142     case 1:
143       buf[0] = (u8) param.value;
144       break;
145     case 2:
146       ((u16 *) buf)[0] = cpu_to_le16((u16) param.value);
147       break;
148     case 4:
149       ((u32 *) buf)[0] = cpu_to_le32((u32) param.value);
150       break;
151     }
152   return 1;
153 }
154
155 static int
156 darwin_write(struct pci_dev *d, int pos, byte *buf, int len)
157 {
158   if (!(len == 1 || len == 2 || len == 4))
159     return pci_generic_block_write(d, pos, buf, len);
160
161   AddressSpaceParam param;
162   kern_return_t     status;
163
164   param.spaceID   = kIOACPIAddressSpaceIDPCIConfiguration;
165   param.bitWidth  = len * 8;
166   param.bitOffset = 0;
167   param.options   = 0;
168
169   param.address.pci.offset   = pos;
170   param.address.pci.function = d->func;
171   param.address.pci.device   = d->dev;
172   param.address.pci.bus      = d->bus;
173   param.address.pci.segment  = d->domain;
174   param.address.pci.reserved = 0;
175
176   switch (len)
177     {
178     case 1:
179       param.value = buf[0];
180       break;
181     case 2:
182       param.value = le16_to_cpu(((u16 *) buf)[0]);
183       break;
184     case 4:
185       param.value = le32_to_cpu(((u32 *) buf)[0]);
186       break;
187     }
188
189   size_t outSize = 0;
190   status = IOConnectCallStructMethod(d->access->fd, kACPIMethodAddressSpaceWrite,
191     &param, sizeof(param),
192     NULL, &outSize);
193   if ((kIOReturnSuccess != status))
194     d->access->error("darwin_read: kACPIMethodAddressSpaceWrite failed: %s", mach_error_string(status));
195
196   return 1;
197 }
198
199 struct pci_methods pm_darwin = {
200     "darwin",
201     "Darwin",
202     darwin_config,
203     darwin_detect,
204     darwin_init,
205     darwin_cleanup,
206     pci_generic_scan,
207     pci_generic_fill_info,
208     darwin_read,
209     darwin_write,
210     NULL,                                 /* read_vpd */
211     NULL,                                 /* dev_init */
212     NULL                                  /* dev_cleanup */
213 };