Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * IOSF-SB MailBox Interface Driver
4 : : * Copyright (c) 2013, Intel Corporation.
5 : : *
6 : : * The IOSF-SB is a fabric bus available on Atom based SOC's that uses a
7 : : * mailbox interface (MBI) to communicate with multiple devices. This
8 : : * driver implements access to this interface for those platforms that can
9 : : * enumerate the device using PCI.
10 : : */
11 : :
12 : : #include <linux/delay.h>
13 : : #include <linux/module.h>
14 : : #include <linux/init.h>
15 : : #include <linux/spinlock.h>
16 : : #include <linux/pci.h>
17 : : #include <linux/debugfs.h>
18 : : #include <linux/capability.h>
19 : : #include <linux/pm_qos.h>
20 : : #include <linux/wait.h>
21 : :
22 : : #include <asm/iosf_mbi.h>
23 : :
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
28 : :
29 : : static struct pci_dev *mbi_pdev;
30 : : static DEFINE_SPINLOCK(iosf_mbi_lock);
31 : :
32 : : /**************** Generic iosf_mbi access helpers ****************/
33 : :
34 : 0 : static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset)
35 : : {
36 : 0 : return (op << 24) | (port << 16) | (offset << 8) | MBI_ENABLE;
37 : : }
38 : :
39 : 0 : static int iosf_mbi_pci_read_mdr(u32 mcrx, u32 mcr, u32 *mdr)
40 : : {
41 : 0 : int result;
42 : :
43 [ # # ]: 0 : if (!mbi_pdev)
44 : : return -ENODEV;
45 : :
46 [ # # ]: 0 : if (mcrx) {
47 : 0 : result = pci_write_config_dword(mbi_pdev, MBI_MCRX_OFFSET,
48 : : mcrx);
49 [ # # ]: 0 : if (result < 0)
50 : 0 : goto fail_read;
51 : : }
52 : :
53 : 0 : result = pci_write_config_dword(mbi_pdev, MBI_MCR_OFFSET, mcr);
54 [ # # ]: 0 : if (result < 0)
55 : 0 : goto fail_read;
56 : :
57 : 0 : result = pci_read_config_dword(mbi_pdev, MBI_MDR_OFFSET, mdr);
58 [ # # ]: 0 : if (result < 0)
59 : 0 : goto fail_read;
60 : :
61 : : return 0;
62 : :
63 : 0 : fail_read:
64 : 0 : dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result);
65 : 0 : return result;
66 : : }
67 : :
68 : 0 : static int iosf_mbi_pci_write_mdr(u32 mcrx, u32 mcr, u32 mdr)
69 : : {
70 : 0 : int result;
71 : :
72 [ # # ]: 0 : if (!mbi_pdev)
73 : : return -ENODEV;
74 : :
75 : 0 : result = pci_write_config_dword(mbi_pdev, MBI_MDR_OFFSET, mdr);
76 [ # # ]: 0 : if (result < 0)
77 : 0 : goto fail_write;
78 : :
79 [ # # ]: 0 : if (mcrx) {
80 : 0 : result = pci_write_config_dword(mbi_pdev, MBI_MCRX_OFFSET,
81 : : mcrx);
82 [ # # ]: 0 : if (result < 0)
83 : 0 : goto fail_write;
84 : : }
85 : :
86 : 0 : result = pci_write_config_dword(mbi_pdev, MBI_MCR_OFFSET, mcr);
87 [ # # ]: 0 : if (result < 0)
88 : 0 : goto fail_write;
89 : :
90 : : return 0;
91 : :
92 : 0 : fail_write:
93 : 0 : dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result);
94 : 0 : return result;
95 : : }
96 : :
97 : 0 : int iosf_mbi_read(u8 port, u8 opcode, u32 offset, u32 *mdr)
98 : : {
99 : 0 : u32 mcr, mcrx;
100 : 0 : unsigned long flags;
101 : 0 : int ret;
102 : :
103 : : /* Access to the GFX unit is handled by GPU code */
104 [ # # ]: 0 : if (port == BT_MBI_UNIT_GFX) {
105 : 0 : WARN_ON(1);
106 : 0 : return -EPERM;
107 : : }
108 : :
109 : 0 : mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO);
110 : 0 : mcrx = offset & MBI_MASK_HI;
111 : :
112 : 0 : spin_lock_irqsave(&iosf_mbi_lock, flags);
113 : 0 : ret = iosf_mbi_pci_read_mdr(mcrx, mcr, mdr);
114 : 0 : spin_unlock_irqrestore(&iosf_mbi_lock, flags);
115 : :
116 : 0 : return ret;
117 : : }
118 : : EXPORT_SYMBOL(iosf_mbi_read);
119 : :
120 : 0 : int iosf_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr)
121 : : {
122 : 0 : u32 mcr, mcrx;
123 : 0 : unsigned long flags;
124 : 0 : int ret;
125 : :
126 : : /* Access to the GFX unit is handled by GPU code */
127 [ # # ]: 0 : if (port == BT_MBI_UNIT_GFX) {
128 : 0 : WARN_ON(1);
129 : 0 : return -EPERM;
130 : : }
131 : :
132 : 0 : mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO);
133 : 0 : mcrx = offset & MBI_MASK_HI;
134 : :
135 : 0 : spin_lock_irqsave(&iosf_mbi_lock, flags);
136 : 0 : ret = iosf_mbi_pci_write_mdr(mcrx, mcr, mdr);
137 : 0 : spin_unlock_irqrestore(&iosf_mbi_lock, flags);
138 : :
139 : 0 : return ret;
140 : : }
141 : : EXPORT_SYMBOL(iosf_mbi_write);
142 : :
143 : 0 : int iosf_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask)
144 : : {
145 : 0 : u32 mcr, mcrx;
146 : 0 : u32 value;
147 : 0 : unsigned long flags;
148 : 0 : int ret;
149 : :
150 : : /* Access to the GFX unit is handled by GPU code */
151 [ # # ]: 0 : if (port == BT_MBI_UNIT_GFX) {
152 : 0 : WARN_ON(1);
153 : 0 : return -EPERM;
154 : : }
155 : :
156 : 0 : mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO);
157 : 0 : mcrx = offset & MBI_MASK_HI;
158 : :
159 : 0 : spin_lock_irqsave(&iosf_mbi_lock, flags);
160 : :
161 : : /* Read current mdr value */
162 : 0 : ret = iosf_mbi_pci_read_mdr(mcrx, mcr & MBI_RD_MASK, &value);
163 [ # # ]: 0 : if (ret < 0) {
164 : 0 : spin_unlock_irqrestore(&iosf_mbi_lock, flags);
165 : 0 : return ret;
166 : : }
167 : :
168 : : /* Apply mask */
169 : 0 : value &= ~mask;
170 : 0 : mdr &= mask;
171 : 0 : value |= mdr;
172 : :
173 : : /* Write back */
174 : 0 : ret = iosf_mbi_pci_write_mdr(mcrx, mcr | MBI_WR_MASK, value);
175 : :
176 : 0 : spin_unlock_irqrestore(&iosf_mbi_lock, flags);
177 : :
178 : 0 : return ret;
179 : : }
180 : : EXPORT_SYMBOL(iosf_mbi_modify);
181 : :
182 : 0 : bool iosf_mbi_available(void)
183 : : {
184 : : /* Mbi isn't hot-pluggable. No remove routine is provided */
185 : 0 : return mbi_pdev;
186 : : }
187 : : EXPORT_SYMBOL(iosf_mbi_available);
188 : :
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 : :
205 : : static DEFINE_MUTEX(iosf_mbi_pmic_access_mutex);
206 : : static BLOCKING_NOTIFIER_HEAD(iosf_mbi_pmic_bus_access_notifier);
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;
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 : :
214 : 0 : void iosf_mbi_punit_acquire(void)
215 : : {
216 : : /* Wait for any I2C PMIC accesses from in kernel drivers to finish. */
217 : 0 : mutex_lock(&iosf_mbi_pmic_access_mutex);
218 [ # # ]: 0 : while (iosf_mbi_pmic_i2c_access_count != 0) {
219 : 0 : mutex_unlock(&iosf_mbi_pmic_access_mutex);
220 [ # # # # ]: 0 : wait_event(iosf_mbi_pmic_access_waitq,
221 : : iosf_mbi_pmic_i2c_access_count == 0);
222 : 0 : 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 : 0 : iosf_mbi_pmic_punit_access_count++;
229 : 0 : mutex_unlock(&iosf_mbi_pmic_access_mutex);
230 : 0 : }
231 : : EXPORT_SYMBOL(iosf_mbi_punit_acquire);
232 : :
233 : 0 : void iosf_mbi_punit_release(void)
234 : : {
235 : 0 : bool do_wakeup;
236 : :
237 : 0 : mutex_lock(&iosf_mbi_pmic_access_mutex);
238 : 0 : iosf_mbi_pmic_punit_access_count--;
239 : 0 : do_wakeup = iosf_mbi_pmic_punit_access_count == 0;
240 : 0 : mutex_unlock(&iosf_mbi_pmic_access_mutex);
241 : :
242 [ # # ]: 0 : if (do_wakeup)
243 : 0 : wake_up(&iosf_mbi_pmic_access_waitq);
244 : 0 : }
245 : : EXPORT_SYMBOL(iosf_mbi_punit_release);
246 : :
247 : 0 : static int iosf_mbi_get_sem(u32 *sem)
248 : : {
249 : 0 : int ret;
250 : :
251 : 0 : ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
252 : : iosf_mbi_sem_address, sem);
253 [ # # ]: 0 : if (ret) {
254 : 0 : dev_err(&mbi_pdev->dev, "Error P-Unit semaphore read failed\n");
255 : 0 : return ret;
256 : : }
257 : :
258 : 0 : *sem &= PUNIT_SEMAPHORE_BIT;
259 : 0 : return 0;
260 : : }
261 : :
262 : 0 : static void iosf_mbi_reset_semaphore(void)
263 : : {
264 [ # # ]: 0 : if (iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ,
265 : : iosf_mbi_sem_address, 0, PUNIT_SEMAPHORE_BIT))
266 : 0 : dev_err(&mbi_pdev->dev, "Error P-Unit semaphore reset failed\n");
267 : :
268 : 0 : pm_qos_update_request(&iosf_mbi_pm_qos, PM_QOS_DEFAULT_VALUE);
269 : :
270 : 0 : blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier,
271 : : MBI_PMIC_BUS_ACCESS_END, NULL);
272 : 0 : }
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 : : *
282 : : * To allow safe PMIC i2c bus accesses this function takes the following steps:
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
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.
294 : : *
295 : : * 3) Some code makes such P-Unit requests from atomic contexts where it
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 : : *
301 : : * 4) When CPU cores enter C6 or C7 the P-Unit needs to talk to the PMIC
302 : : * if this happens while the kernel itself is accessing the PMIC I2C bus
303 : : * the SoC hangs.
304 : : * As the third step we call pm_qos_update_request() to disallow the CPU
305 : : * to enter C6 or C7.
306 : : *
307 : : * 5) The P-Unit has a PMIC bus semaphore which we can request to stop
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 : 0 : int iosf_mbi_block_punit_i2c_access(void)
313 : : {
314 : 0 : unsigned long start, end;
315 : 0 : int ret = 0;
316 : 0 : u32 sem;
317 : :
318 [ # # # # : 0 : if (WARN_ON(!mbi_pdev || !iosf_mbi_sem_address))
# # # # ]
319 : : return -ENXIO;
320 : :
321 : 0 : mutex_lock(&iosf_mbi_pmic_access_mutex);
322 : :
323 [ # # ]: 0 : while (iosf_mbi_pmic_punit_access_count != 0) {
324 : 0 : mutex_unlock(&iosf_mbi_pmic_access_mutex);
325 [ # # # # ]: 0 : wait_event(iosf_mbi_pmic_access_waitq,
326 : : iosf_mbi_pmic_punit_access_count == 0);
327 : 0 : mutex_lock(&iosf_mbi_pmic_access_mutex);
328 : : }
329 : :
330 [ # # ]: 0 : if (iosf_mbi_pmic_i2c_access_count > 0)
331 : 0 : goto success;
332 : :
333 : 0 : 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 : : */
341 : 0 : pm_qos_update_request(&iosf_mbi_pm_qos, 0);
342 : :
343 : : /* host driver writes to side band semaphore register */
344 : 0 : ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
345 : : iosf_mbi_sem_address, PUNIT_SEMAPHORE_ACQUIRE);
346 [ # # ]: 0 : if (ret) {
347 : 0 : dev_err(&mbi_pdev->dev, "Error P-Unit semaphore request failed\n");
348 : 0 : goto error;
349 : : }
350 : :
351 : : /* host driver waits for bit 0 to be set in semaphore register */
352 : 0 : start = jiffies;
353 : 0 : end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
354 : 0 : do {
355 : 0 : ret = iosf_mbi_get_sem(&sem);
356 [ # # # # ]: 0 : if (!ret && sem) {
357 : 0 : iosf_mbi_sem_acquired = jiffies;
358 : 0 : dev_dbg(&mbi_pdev->dev, "P-Unit semaphore acquired after %ums\n",
359 : : jiffies_to_msecs(jiffies - start));
360 : 0 : goto success;
361 : : }
362 : :
363 : 0 : usleep_range(1000, 2000);
364 [ # # ]: 0 : } while (time_before(jiffies, end));
365 : :
366 : 0 : ret = -ETIMEDOUT;
367 : 0 : dev_err(&mbi_pdev->dev, "Error P-Unit semaphore timed out, resetting\n");
368 : 0 : error:
369 : 0 : iosf_mbi_reset_semaphore();
370 [ # # ]: 0 : if (!iosf_mbi_get_sem(&sem))
371 : 0 : dev_err(&mbi_pdev->dev, "P-Unit semaphore: %d\n", sem);
372 : 0 : success:
373 [ # # # # ]: 0 : if (!WARN_ON(ret))
374 : 0 : iosf_mbi_pmic_i2c_access_count++;
375 : :
376 : 0 : mutex_unlock(&iosf_mbi_pmic_access_mutex);
377 : :
378 : 0 : return ret;
379 : : }
380 : : EXPORT_SYMBOL(iosf_mbi_block_punit_i2c_access);
381 : :
382 : 0 : void iosf_mbi_unblock_punit_i2c_access(void)
383 : : {
384 : 0 : bool do_wakeup = false;
385 : :
386 : 0 : mutex_lock(&iosf_mbi_pmic_access_mutex);
387 : 0 : iosf_mbi_pmic_i2c_access_count--;
388 [ # # ]: 0 : if (iosf_mbi_pmic_i2c_access_count == 0) {
389 : 0 : iosf_mbi_reset_semaphore();
390 : 0 : dev_dbg(&mbi_pdev->dev, "punit semaphore held for %ums\n",
391 : : jiffies_to_msecs(jiffies - iosf_mbi_sem_acquired));
392 : 0 : do_wakeup = true;
393 : : }
394 : 0 : mutex_unlock(&iosf_mbi_pmic_access_mutex);
395 : :
396 [ # # ]: 0 : if (do_wakeup)
397 : 0 : wake_up(&iosf_mbi_pmic_access_waitq);
398 : 0 : }
399 : : EXPORT_SYMBOL(iosf_mbi_unblock_punit_i2c_access);
400 : :
401 : 0 : int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb)
402 : : {
403 : 0 : int ret;
404 : :
405 : : /* Wait for the bus to go inactive before registering */
406 : 0 : iosf_mbi_punit_acquire();
407 : 0 : ret = blocking_notifier_chain_register(
408 : : &iosf_mbi_pmic_bus_access_notifier, nb);
409 : 0 : iosf_mbi_punit_release();
410 : :
411 : 0 : return ret;
412 : : }
413 : : EXPORT_SYMBOL(iosf_mbi_register_pmic_bus_access_notifier);
414 : :
415 : 0 : int iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(
416 : : struct notifier_block *nb)
417 : : {
418 : 0 : iosf_mbi_assert_punit_acquired();
419 : :
420 : 0 : 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 : :
425 : 0 : int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb)
426 : : {
427 : 0 : int ret;
428 : :
429 : : /* Wait for the bus to go inactive before unregistering */
430 : 0 : iosf_mbi_punit_acquire();
431 : 0 : ret = iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(nb);
432 : 0 : iosf_mbi_punit_release();
433 : :
434 : 0 : return ret;
435 : : }
436 : : EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier);
437 : :
438 : 0 : void iosf_mbi_assert_punit_acquired(void)
439 : : {
440 [ # # # # ]: 0 : WARN_ON(iosf_mbi_pmic_punit_access_count == 0);
441 : 0 : }
442 : : EXPORT_SYMBOL(iosf_mbi_assert_punit_acquired);
443 : :
444 : : /**************** iosf_mbi debug code ****************/
445 : :
446 : : #ifdef CONFIG_IOSF_MBI_DEBUG
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;
485 : :
486 : : static void iosf_sideband_debug_init(void)
487 : : {
488 : : iosf_dbg = debugfs_create_dir("iosf_sb", NULL);
489 : :
490 : : /* mdr */
491 : : debugfs_create_x32("mdr", 0660, iosf_dbg, &dbg_mdr);
492 : :
493 : : /* mcrx */
494 : : debugfs_create_x32("mcrx", 0660, iosf_dbg, &dbg_mcrx);
495 : :
496 : : /* mcr - initiates mailbox tranaction */
497 : : debugfs_create_file("mcr", 0660, iosf_dbg, &dbg_mcr, &iosf_mcr_fops);
498 : : }
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 : 28 : static inline void iosf_debugfs_init(void) { }
511 : 0 : static inline void iosf_debugfs_remove(void) { }
512 : : #endif /* CONFIG_IOSF_MBI_DEBUG */
513 : :
514 : 0 : static int iosf_mbi_probe(struct pci_dev *pdev,
515 : : const struct pci_device_id *dev_id)
516 : : {
517 : 0 : int ret;
518 : :
519 : 0 : ret = pci_enable_device(pdev);
520 [ # # ]: 0 : if (ret < 0) {
521 : 0 : dev_err(&pdev->dev, "error: could not enable device\n");
522 : 0 : return ret;
523 : : }
524 : :
525 : 0 : mbi_pdev = pci_dev_get(pdev);
526 : 0 : iosf_mbi_sem_address = dev_id->driver_data;
527 : :
528 : 0 : return 0;
529 : : }
530 : :
531 : : static const struct pci_device_id iosf_mbi_pci_ids[] = {
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) },
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 : 28 : static int __init iosf_mbi_init(void)
547 : : {
548 : 28 : iosf_debugfs_init();
549 : :
550 : 28 : pm_qos_add_request(&iosf_mbi_pm_qos, PM_QOS_CPU_DMA_LATENCY,
551 : : PM_QOS_DEFAULT_VALUE);
552 : :
553 : 28 : return pci_register_driver(&iosf_mbi_pci_driver);
554 : : }
555 : :
556 : 0 : static void __exit iosf_mbi_exit(void)
557 : : {
558 : 0 : iosf_debugfs_remove();
559 : :
560 : 0 : pci_unregister_driver(&iosf_mbi_pci_driver);
561 : 0 : pci_dev_put(mbi_pdev);
562 : 0 : mbi_pdev = NULL;
563 : :
564 : 0 : pm_qos_remove_request(&iosf_mbi_pm_qos);
565 : 0 : }
566 : :
567 : : module_init(iosf_mbi_init);
568 : : module_exit(iosf_mbi_exit);
569 : :
570 : : MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
571 : : MODULE_DESCRIPTION("IOSF Mailbox Interface accessor");
572 : : MODULE_LICENSE("GPL v2");
|