Commit | Line | Data |
---|---|---|
2025cf9e | 1 | // SPDX-License-Identifier: GPL-2.0-only |
46184415 DB |
2 | /* |
3 | * IOSF-SB MailBox Interface Driver | |
4 | * Copyright (c) 2013, Intel Corporation. | |
5 | * | |
46184415 | 6 | * The IOSF-SB is a fabric bus available on Atom based SOC's that uses a |
a97673a1 | 7 | * mailbox interface (MBI) to communicate with multiple devices. This |
46184415 DB |
8 | * driver implements access to this interface for those platforms that can |
9 | * enumerate the device using PCI. | |
10 | */ | |
11 | ||
e09db3d2 | 12 | #include <linux/delay.h> |
46184415 DB |
13 | #include <linux/module.h> |
14 | #include <linux/init.h> | |
15 | #include <linux/spinlock.h> | |
16 | #include <linux/pci.h> | |
8dc12f93 DB |
17 | #include <linux/debugfs.h> |
18 | #include <linux/capability.h> | |
e09db3d2 | 19 | #include <linux/pm_qos.h> |
00452ba9 | 20 | #include <linux/wait.h> |
46184415 DB |
21 | |
22 | #include <asm/iosf_mbi.h> | |
23 | ||
e09db3d2 HG |
24 | #define PCI_DEVICE_ID_INTEL_BAYTRAIL 0x0F00 |
25 | #define PCI_DEVICE_ID_INTEL_BRASWELL 0x2280 | |
26 | #define PCI_DEVICE_ID_INTEL_QUARK_X1000 0x0958 | |
27 | #define PCI_DEVICE_ID_INTEL_TANGIER 0x1170 | |
04725ad5 | 28 | |
7e1ff15b | 29 | static struct pci_dev *mbi_pdev; |
46184415 | 30 | static DEFINE_SPINLOCK(iosf_mbi_lock); |
e09db3d2 HG |
31 | |
32 | /**************** Generic iosf_mbi access helpers ****************/ | |
46184415 DB |
33 | |
34 | static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset) | |
35 | { | |
36 | return (op << 24) | (port << 16) | (offset << 8) | MBI_ENABLE; | |
37 | } | |
38 | ||
46184415 DB |
39 | static int iosf_mbi_pci_read_mdr(u32 mcrx, u32 mcr, u32 *mdr) |
40 | { | |
41 | int result; | |
42 | ||
43 | if (!mbi_pdev) | |
44 | return -ENODEV; | |
45 | ||
46 | if (mcrx) { | |
47 | result = pci_write_config_dword(mbi_pdev, MBI_MCRX_OFFSET, | |
48 | mcrx); | |
49 | if (result < 0) | |
50 | goto fail_read; | |
51 | } | |
52 | ||
53 | result = pci_write_config_dword(mbi_pdev, MBI_MCR_OFFSET, mcr); | |
54 | if (result < 0) | |
55 | goto fail_read; | |
56 | ||
57 | result = pci_read_config_dword(mbi_pdev, MBI_MDR_OFFSET, mdr); | |
58 | if (result < 0) | |
59 | goto fail_read; | |
60 | ||
61 | return 0; | |
62 | ||
63 | fail_read: | |
64 | dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result); | |
65 | return result; | |
66 | } | |
67 | ||
68 | static int iosf_mbi_pci_write_mdr(u32 mcrx, u32 mcr, u32 mdr) | |
69 | { | |
70 | int result; | |
71 | ||
72 | if (!mbi_pdev) | |
73 | return -ENODEV; | |
74 | ||
75 | result = pci_write_config_dword(mbi_pdev, MBI_MDR_OFFSET, mdr); | |
76 | if (result < 0) | |
77 | goto fail_write; | |
78 | ||
79 | if (mcrx) { | |
80 | result = pci_write_config_dword(mbi_pdev, MBI_MCRX_OFFSET, | |
81 | mcrx); | |
82 | if (result < 0) | |
83 | goto fail_write; | |
84 | } | |
85 | ||
86 | result = pci_write_config_dword(mbi_pdev, MBI_MCR_OFFSET, mcr); | |
87 | if (result < 0) | |
88 | goto fail_write; | |
89 | ||
90 | return 0; | |
91 | ||
92 | fail_write: | |
93 | dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result); | |
94 | return result; | |
95 | } | |
96 | ||
97 | int iosf_mbi_read(u8 port, u8 opcode, u32 offset, u32 *mdr) | |
98 | { | |
99 | u32 mcr, mcrx; | |
100 | unsigned long flags; | |
101 | int ret; | |
102 | ||
7e1ff15b | 103 | /* Access to the GFX unit is handled by GPU code */ |
46184415 DB |
104 | if (port == BT_MBI_UNIT_GFX) { |
105 | WARN_ON(1); | |
106 | return -EPERM; | |
107 | } | |
108 | ||
109 | mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO); | |
110 | mcrx = offset & MBI_MASK_HI; | |
111 | ||
112 | spin_lock_irqsave(&iosf_mbi_lock, flags); | |
113 | ret = iosf_mbi_pci_read_mdr(mcrx, mcr, mdr); | |
114 | spin_unlock_irqrestore(&iosf_mbi_lock, flags); | |
115 | ||
116 | return ret; | |
117 | } | |
118 | EXPORT_SYMBOL(iosf_mbi_read); | |
119 | ||
120 | int iosf_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr) | |
121 | { | |
122 | u32 mcr, mcrx; | |
123 | unsigned long flags; | |
124 | int ret; | |
125 | ||
7e1ff15b | 126 | /* Access to the GFX unit is handled by GPU code */ |
46184415 DB |
127 | if (port == BT_MBI_UNIT_GFX) { |
128 | WARN_ON(1); | |
129 | return -EPERM; | |
130 | } | |
131 | ||
132 | mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO); | |
133 | mcrx = offset & MBI_MASK_HI; | |
134 | ||
135 | spin_lock_irqsave(&iosf_mbi_lock, flags); | |
136 | ret = iosf_mbi_pci_write_mdr(mcrx, mcr, mdr); | |
137 | spin_unlock_irqrestore(&iosf_mbi_lock, flags); | |
138 | ||
139 | return ret; | |
140 | } | |
141 | EXPORT_SYMBOL(iosf_mbi_write); | |
142 | ||
143 | int iosf_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask) | |
144 | { | |
145 | u32 mcr, mcrx; | |
146 | u32 value; | |
147 | unsigned long flags; | |
148 | int ret; | |
149 | ||
7e1ff15b | 150 | /* Access to the GFX unit is handled by GPU code */ |
46184415 DB |
151 | if (port == BT_MBI_UNIT_GFX) { |
152 | WARN_ON(1); | |
153 | return -EPERM; | |
154 | } | |
155 | ||
156 | mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO); | |
157 | mcrx = offset & MBI_MASK_HI; | |
158 | ||
159 | spin_lock_irqsave(&iosf_mbi_lock, flags); | |
160 | ||
161 | /* Read current mdr value */ | |
162 | ret = iosf_mbi_pci_read_mdr(mcrx, mcr & MBI_RD_MASK, &value); | |
163 | if (ret < 0) { | |
164 | spin_unlock_irqrestore(&iosf_mbi_lock, flags); | |
165 | return ret; | |
166 | } | |
167 | ||
168 | /* Apply mask */ | |
169 | value &= ~mask; | |
170 | mdr &= mask; | |
171 | value |= mdr; | |
172 | ||
173 | /* Write back */ | |
174 | ret = iosf_mbi_pci_write_mdr(mcrx, mcr | MBI_WR_MASK, value); | |
175 | ||
176 | spin_unlock_irqrestore(&iosf_mbi_lock, flags); | |
177 | ||
178 | return ret; | |
179 | } | |
180 | EXPORT_SYMBOL(iosf_mbi_modify); | |
181 | ||
6b8f0c87 DB |
182 | bool iosf_mbi_available(void) |
183 | { | |
184 | /* Mbi isn't hot-pluggable. No remove routine is provided */ | |
185 | return mbi_pdev; | |
186 | } | |
187 | EXPORT_SYMBOL(iosf_mbi_available); | |
188 | ||
e09db3d2 HG |
189 | /* |
190 | **************** P-Unit/kernel shared I2C bus arbritration **************** | |
191 | * | |
192 | * Some Bay Trail and Cherry Trail devices have the P-Unit and us (the kernel) | |
193 | * share a single I2C bus to the PMIC. Below are helpers to arbitrate the | |
194 | * accesses between the kernel and the P-Unit. | |
195 | * | |
196 | * See arch/x86/include/asm/iosf_mbi.h for kernel-doc text for each function. | |
197 | */ | |
198 | ||
199 | #define SEMAPHORE_TIMEOUT 500 | |
200 | #define PUNIT_SEMAPHORE_BYT 0x7 | |
201 | #define PUNIT_SEMAPHORE_CHT 0x10e | |
202 | #define PUNIT_SEMAPHORE_BIT BIT(0) | |
203 | #define PUNIT_SEMAPHORE_ACQUIRE BIT(1) | |
204 | ||
00452ba9 | 205 | static DEFINE_MUTEX(iosf_mbi_pmic_access_mutex); |
e09db3d2 | 206 | static BLOCKING_NOTIFIER_HEAD(iosf_mbi_pmic_bus_access_notifier); |
00452ba9 HG |
207 | static DECLARE_WAIT_QUEUE_HEAD(iosf_mbi_pmic_access_waitq); |
208 | static u32 iosf_mbi_pmic_punit_access_count; | |
209 | static u32 iosf_mbi_pmic_i2c_access_count; | |
e09db3d2 HG |
210 | static u32 iosf_mbi_sem_address; |
211 | static unsigned long iosf_mbi_sem_acquired; | |
212 | static struct pm_qos_request iosf_mbi_pm_qos; | |
213 | ||
9260a040 HG |
214 | void iosf_mbi_punit_acquire(void) |
215 | { | |
00452ba9 HG |
216 | /* Wait for any I2C PMIC accesses from in kernel drivers to finish. */ |
217 | mutex_lock(&iosf_mbi_pmic_access_mutex); | |
218 | while (iosf_mbi_pmic_i2c_access_count != 0) { | |
219 | mutex_unlock(&iosf_mbi_pmic_access_mutex); | |
220 | wait_event(iosf_mbi_pmic_access_waitq, | |
221 | iosf_mbi_pmic_i2c_access_count == 0); | |
222 | mutex_lock(&iosf_mbi_pmic_access_mutex); | |
223 | } | |
224 | /* | |
225 | * We do not need to do anything to allow the PUNIT to safely access | |
226 | * the PMIC, other then block in kernel accesses to the PMIC. | |
227 | */ | |
228 | iosf_mbi_pmic_punit_access_count++; | |
229 | mutex_unlock(&iosf_mbi_pmic_access_mutex); | |
9260a040 HG |
230 | } |
231 | EXPORT_SYMBOL(iosf_mbi_punit_acquire); | |
232 | ||
233 | void iosf_mbi_punit_release(void) | |
234 | { | |
00452ba9 HG |
235 | bool do_wakeup; |
236 | ||
237 | mutex_lock(&iosf_mbi_pmic_access_mutex); | |
238 | iosf_mbi_pmic_punit_access_count--; | |
239 | do_wakeup = iosf_mbi_pmic_punit_access_count == 0; | |
240 | mutex_unlock(&iosf_mbi_pmic_access_mutex); | |
241 | ||
242 | if (do_wakeup) | |
243 | wake_up(&iosf_mbi_pmic_access_waitq); | |
9260a040 HG |
244 | } |
245 | EXPORT_SYMBOL(iosf_mbi_punit_release); | |
246 | ||
e09db3d2 HG |
247 | static int iosf_mbi_get_sem(u32 *sem) |
248 | { | |
249 | int ret; | |
250 | ||
251 | ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, | |
252 | iosf_mbi_sem_address, sem); | |
253 | if (ret) { | |
254 | dev_err(&mbi_pdev->dev, "Error P-Unit semaphore read failed\n"); | |
255 | return ret; | |
256 | } | |
257 | ||
258 | *sem &= PUNIT_SEMAPHORE_BIT; | |
259 | return 0; | |
260 | } | |
261 | ||
262 | static void iosf_mbi_reset_semaphore(void) | |
263 | { | |
264 | if (iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, | |
265 | iosf_mbi_sem_address, 0, PUNIT_SEMAPHORE_BIT)) | |
266 | dev_err(&mbi_pdev->dev, "Error P-Unit semaphore reset failed\n"); | |
267 | ||
fe66a17e | 268 | cpu_latency_qos_update_request(&iosf_mbi_pm_qos, PM_QOS_DEFAULT_VALUE); |
e09db3d2 HG |
269 | |
270 | blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier, | |
271 | MBI_PMIC_BUS_ACCESS_END, NULL); | |
272 | } | |
273 | ||
274 | /* | |
275 | * This function blocks P-Unit accesses to the PMIC I2C bus, so that kernel | |
276 | * I2C code, such as e.g. a fuel-gauge driver, can access it safely. | |
277 | * | |
278 | * This function may be called by I2C controller code while an I2C driver has | |
279 | * already blocked P-Unit accesses because it wants them blocked over multiple | |
280 | * i2c-transfers, for e.g. read-modify-write of an I2C client register. | |
281 | * | |
00452ba9 | 282 | * To allow safe PMIC i2c bus accesses this function takes the following steps: |
e09db3d2 HG |
283 | * |
284 | * 1) Some code sends request to the P-Unit which make it access the PMIC | |
285 | * I2C bus. Testing has shown that the P-Unit does not check its internal | |
286 | * PMIC bus semaphore for these requests. Callers of these requests call | |
287 | * iosf_mbi_punit_acquire()/_release() around their P-Unit accesses, these | |
00452ba9 HG |
288 | * functions increase/decrease iosf_mbi_pmic_punit_access_count, so first |
289 | * we wait for iosf_mbi_pmic_punit_access_count to become 0. | |
290 | * | |
291 | * 2) Check iosf_mbi_pmic_i2c_access_count, if access has already | |
292 | * been blocked by another caller, we only need to increment | |
293 | * iosf_mbi_pmic_i2c_access_count and we can skip the other steps. | |
e09db3d2 | 294 | * |
00452ba9 | 295 | * 3) Some code makes such P-Unit requests from atomic contexts where it |
e09db3d2 HG |
296 | * cannot call iosf_mbi_punit_acquire() as that may sleep. |
297 | * As the second step we call a notifier chain which allows any code | |
298 | * needing P-Unit resources from atomic context to acquire them before | |
299 | * we take control over the PMIC I2C bus. | |
300 | * | |
00452ba9 | 301 | * 4) When CPU cores enter C6 or C7 the P-Unit needs to talk to the PMIC |
e09db3d2 HG |
302 | * if this happens while the kernel itself is accessing the PMIC I2C bus |
303 | * the SoC hangs. | |
fe66a17e RW |
304 | * As the third step we call cpu_latency_qos_update_request() to disallow the |
305 | * CPU to enter C6 or C7. | |
e09db3d2 | 306 | * |
00452ba9 | 307 | * 5) The P-Unit has a PMIC bus semaphore which we can request to stop |
e09db3d2 HG |
308 | * autonomous P-Unit tasks from accessing the PMIC I2C bus while we hold it. |
309 | * As the fourth and final step we request this semaphore and wait for our | |
310 | * request to be acknowledged. | |
311 | */ | |
312 | int iosf_mbi_block_punit_i2c_access(void) | |
313 | { | |
314 | unsigned long start, end; | |
315 | int ret = 0; | |
316 | u32 sem; | |
317 | ||
318 | if (WARN_ON(!mbi_pdev || !iosf_mbi_sem_address)) | |
319 | return -ENXIO; | |
320 | ||
00452ba9 | 321 | mutex_lock(&iosf_mbi_pmic_access_mutex); |
e09db3d2 | 322 | |
00452ba9 HG |
323 | while (iosf_mbi_pmic_punit_access_count != 0) { |
324 | mutex_unlock(&iosf_mbi_pmic_access_mutex); | |
325 | wait_event(iosf_mbi_pmic_access_waitq, | |
326 | iosf_mbi_pmic_punit_access_count == 0); | |
327 | mutex_lock(&iosf_mbi_pmic_access_mutex); | |
328 | } | |
329 | ||
330 | if (iosf_mbi_pmic_i2c_access_count > 0) | |
e09db3d2 HG |
331 | goto success; |
332 | ||
e09db3d2 HG |
333 | blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier, |
334 | MBI_PMIC_BUS_ACCESS_BEGIN, NULL); | |
335 | ||
336 | /* | |
337 | * Disallow the CPU to enter C6 or C7 state, entering these states | |
338 | * requires the P-Unit to talk to the PMIC and if this happens while | |
339 | * we're holding the semaphore, the SoC hangs. | |
340 | */ | |
fe66a17e | 341 | cpu_latency_qos_update_request(&iosf_mbi_pm_qos, 0); |
e09db3d2 HG |
342 | |
343 | /* host driver writes to side band semaphore register */ | |
344 | ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, | |
345 | iosf_mbi_sem_address, PUNIT_SEMAPHORE_ACQUIRE); | |
346 | if (ret) { | |
347 | dev_err(&mbi_pdev->dev, "Error P-Unit semaphore request failed\n"); | |
348 | goto error; | |
349 | } | |
350 | ||
351 | /* host driver waits for bit 0 to be set in semaphore register */ | |
352 | start = jiffies; | |
353 | end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT); | |
354 | do { | |
355 | ret = iosf_mbi_get_sem(&sem); | |
356 | if (!ret && sem) { | |
357 | iosf_mbi_sem_acquired = jiffies; | |
358 | dev_dbg(&mbi_pdev->dev, "P-Unit semaphore acquired after %ums\n", | |
359 | jiffies_to_msecs(jiffies - start)); | |
e09db3d2 HG |
360 | goto success; |
361 | } | |
362 | ||
363 | usleep_range(1000, 2000); | |
364 | } while (time_before(jiffies, end)); | |
365 | ||
366 | ret = -ETIMEDOUT; | |
367 | dev_err(&mbi_pdev->dev, "Error P-Unit semaphore timed out, resetting\n"); | |
368 | error: | |
369 | iosf_mbi_reset_semaphore(); | |
e09db3d2 HG |
370 | if (!iosf_mbi_get_sem(&sem)) |
371 | dev_err(&mbi_pdev->dev, "P-Unit semaphore: %d\n", sem); | |
372 | success: | |
373 | if (!WARN_ON(ret)) | |
00452ba9 | 374 | iosf_mbi_pmic_i2c_access_count++; |
e09db3d2 | 375 | |
00452ba9 | 376 | mutex_unlock(&iosf_mbi_pmic_access_mutex); |
e09db3d2 HG |
377 | |
378 | return ret; | |
379 | } | |
380 | EXPORT_SYMBOL(iosf_mbi_block_punit_i2c_access); | |
381 | ||
382 | void iosf_mbi_unblock_punit_i2c_access(void) | |
383 | { | |
00452ba9 | 384 | bool do_wakeup = false; |
e09db3d2 | 385 | |
00452ba9 HG |
386 | mutex_lock(&iosf_mbi_pmic_access_mutex); |
387 | iosf_mbi_pmic_i2c_access_count--; | |
388 | if (iosf_mbi_pmic_i2c_access_count == 0) { | |
e09db3d2 | 389 | iosf_mbi_reset_semaphore(); |
e09db3d2 HG |
390 | dev_dbg(&mbi_pdev->dev, "punit semaphore held for %ums\n", |
391 | jiffies_to_msecs(jiffies - iosf_mbi_sem_acquired)); | |
00452ba9 | 392 | do_wakeup = true; |
e09db3d2 | 393 | } |
00452ba9 | 394 | mutex_unlock(&iosf_mbi_pmic_access_mutex); |
e09db3d2 | 395 | |
00452ba9 HG |
396 | if (do_wakeup) |
397 | wake_up(&iosf_mbi_pmic_access_waitq); | |
e09db3d2 HG |
398 | } |
399 | EXPORT_SYMBOL(iosf_mbi_unblock_punit_i2c_access); | |
400 | ||
528e649b HG |
401 | int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb) |
402 | { | |
403 | int ret; | |
404 | ||
405 | /* Wait for the bus to go inactive before registering */ | |
00452ba9 | 406 | iosf_mbi_punit_acquire(); |
528e649b HG |
407 | ret = blocking_notifier_chain_register( |
408 | &iosf_mbi_pmic_bus_access_notifier, nb); | |
00452ba9 | 409 | iosf_mbi_punit_release(); |
528e649b HG |
410 | |
411 | return ret; | |
412 | } | |
413 | EXPORT_SYMBOL(iosf_mbi_register_pmic_bus_access_notifier); | |
414 | ||
af0ab55f HG |
415 | int iosf_mbi_unregister_pmic_bus_access_notifier_unlocked( |
416 | struct notifier_block *nb) | |
417 | { | |
418 | iosf_mbi_assert_punit_acquired(); | |
419 | ||
420 | return blocking_notifier_chain_unregister( | |
421 | &iosf_mbi_pmic_bus_access_notifier, nb); | |
422 | } | |
423 | EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier_unlocked); | |
424 | ||
528e649b HG |
425 | int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb) |
426 | { | |
427 | int ret; | |
428 | ||
429 | /* Wait for the bus to go inactive before unregistering */ | |
00452ba9 | 430 | iosf_mbi_punit_acquire(); |
af0ab55f | 431 | ret = iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(nb); |
00452ba9 | 432 | iosf_mbi_punit_release(); |
528e649b HG |
433 | |
434 | return ret; | |
435 | } | |
436 | EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier); | |
437 | ||
af0ab55f HG |
438 | void iosf_mbi_assert_punit_acquired(void) |
439 | { | |
00452ba9 | 440 | WARN_ON(iosf_mbi_pmic_punit_access_count == 0); |
af0ab55f HG |
441 | } |
442 | EXPORT_SYMBOL(iosf_mbi_assert_punit_acquired); | |
443 | ||
e09db3d2 HG |
444 | /**************** iosf_mbi debug code ****************/ |
445 | ||
ed2226bd | 446 | #ifdef CONFIG_IOSF_MBI_DEBUG |
8dc12f93 DB |
447 | static u32 dbg_mdr; |
448 | static u32 dbg_mcr; | |
449 | static u32 dbg_mcrx; | |
450 | ||
451 | static int mcr_get(void *data, u64 *val) | |
452 | { | |
453 | *val = *(u32 *)data; | |
454 | return 0; | |
455 | } | |
456 | ||
457 | static int mcr_set(void *data, u64 val) | |
458 | { | |
459 | u8 command = ((u32)val & 0xFF000000) >> 24, | |
460 | port = ((u32)val & 0x00FF0000) >> 16, | |
461 | offset = ((u32)val & 0x0000FF00) >> 8; | |
462 | int err; | |
463 | ||
464 | *(u32 *)data = val; | |
465 | ||
466 | if (!capable(CAP_SYS_RAWIO)) | |
467 | return -EACCES; | |
468 | ||
469 | if (command & 1u) | |
470 | err = iosf_mbi_write(port, | |
471 | command, | |
472 | dbg_mcrx | offset, | |
473 | dbg_mdr); | |
474 | else | |
475 | err = iosf_mbi_read(port, | |
476 | command, | |
477 | dbg_mcrx | offset, | |
478 | &dbg_mdr); | |
479 | ||
480 | return err; | |
481 | } | |
482 | DEFINE_SIMPLE_ATTRIBUTE(iosf_mcr_fops, mcr_get, mcr_set , "%llx\n"); | |
483 | ||
484 | static struct dentry *iosf_dbg; | |
ed2226bd | 485 | |
8dc12f93 DB |
486 | static void iosf_sideband_debug_init(void) |
487 | { | |
8dc12f93 | 488 | iosf_dbg = debugfs_create_dir("iosf_sb", NULL); |
8dc12f93 DB |
489 | |
490 | /* mdr */ | |
519e96ee | 491 | debugfs_create_x32("mdr", 0660, iosf_dbg, &dbg_mdr); |
8dc12f93 DB |
492 | |
493 | /* mcrx */ | |
519e96ee | 494 | debugfs_create_x32("mcrx", 0660, iosf_dbg, &dbg_mcrx); |
8dc12f93 DB |
495 | |
496 | /* mcr - initiates mailbox tranaction */ | |
519e96ee | 497 | debugfs_create_file("mcr", 0660, iosf_dbg, &dbg_mcr, &iosf_mcr_fops); |
8dc12f93 | 498 | } |
ed2226bd DB |
499 | |
500 | static void iosf_debugfs_init(void) | |
501 | { | |
502 | iosf_sideband_debug_init(); | |
503 | } | |
504 | ||
505 | static void iosf_debugfs_remove(void) | |
506 | { | |
507 | debugfs_remove_recursive(iosf_dbg); | |
508 | } | |
509 | #else | |
510 | static inline void iosf_debugfs_init(void) { } | |
511 | static inline void iosf_debugfs_remove(void) { } | |
512 | #endif /* CONFIG_IOSF_MBI_DEBUG */ | |
8dc12f93 | 513 | |
46184415 | 514 | static int iosf_mbi_probe(struct pci_dev *pdev, |
e09db3d2 | 515 | const struct pci_device_id *dev_id) |
46184415 DB |
516 | { |
517 | int ret; | |
518 | ||
519 | ret = pci_enable_device(pdev); | |
520 | if (ret < 0) { | |
521 | dev_err(&pdev->dev, "error: could not enable device\n"); | |
522 | return ret; | |
523 | } | |
524 | ||
525 | mbi_pdev = pci_dev_get(pdev); | |
e09db3d2 HG |
526 | iosf_mbi_sem_address = dev_id->driver_data; |
527 | ||
46184415 DB |
528 | return 0; |
529 | } | |
530 | ||
9baa3c34 | 531 | static const struct pci_device_id iosf_mbi_pci_ids[] = { |
e09db3d2 HG |
532 | { PCI_DEVICE_DATA(INTEL, BAYTRAIL, PUNIT_SEMAPHORE_BYT) }, |
533 | { PCI_DEVICE_DATA(INTEL, BRASWELL, PUNIT_SEMAPHORE_CHT) }, | |
534 | { PCI_DEVICE_DATA(INTEL, QUARK_X1000, 0) }, | |
535 | { PCI_DEVICE_DATA(INTEL, TANGIER, 0) }, | |
46184415 DB |
536 | { 0, }, |
537 | }; | |
538 | MODULE_DEVICE_TABLE(pci, iosf_mbi_pci_ids); | |
539 | ||
540 | static struct pci_driver iosf_mbi_pci_driver = { | |
541 | .name = "iosf_mbi_pci", | |
542 | .probe = iosf_mbi_probe, | |
543 | .id_table = iosf_mbi_pci_ids, | |
544 | }; | |
545 | ||
546 | static int __init iosf_mbi_init(void) | |
547 | { | |
ed2226bd DB |
548 | iosf_debugfs_init(); |
549 | ||
fe66a17e | 550 | cpu_latency_qos_add_request(&iosf_mbi_pm_qos, PM_QOS_DEFAULT_VALUE); |
e09db3d2 | 551 | |
46184415 DB |
552 | return pci_register_driver(&iosf_mbi_pci_driver); |
553 | } | |
554 | ||
555 | static void __exit iosf_mbi_exit(void) | |
556 | { | |
ed2226bd | 557 | iosf_debugfs_remove(); |
8dc12f93 | 558 | |
46184415 | 559 | pci_unregister_driver(&iosf_mbi_pci_driver); |
b93fb9f6 AS |
560 | pci_dev_put(mbi_pdev); |
561 | mbi_pdev = NULL; | |
e09db3d2 | 562 | |
fe66a17e | 563 | cpu_latency_qos_remove_request(&iosf_mbi_pm_qos); |
46184415 DB |
564 | } |
565 | ||
566 | module_init(iosf_mbi_init); | |
567 | module_exit(iosf_mbi_exit); | |
568 | ||
569 | MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>"); | |
570 | MODULE_DESCRIPTION("IOSF Mailbox Interface accessor"); | |
571 | MODULE_LICENSE("GPL v2"); |