Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
b93fb9f
Documentation
arch
alpha
arc
arm
arm64
avr32
blackfin
c6x
cris
frv
h8300
hexagon
ia64
m32r
m68k
metag
microblaze
mips
mn10300
nios2
openrisc
parisc
powerpc
s390
score
sh
sparc
tile
um
unicore32
x86
boot
configs
crypto
entry
ia32
include
kernel
kvm
lguest
lib
math-emu
mm
net
oprofile
pci
platform
atom
ce4100
efi
geode
goldfish
intel-mid
intel-quark
intel
Makefile
iosf_mbi.c
iris
olpc
scx200
sfi
ts5500
uv
Makefile
power
purgatory
realmode
tools
um
video
xen
.gitignore
Kbuild
Kconfig
Kconfig.cpu
Kconfig.debug
Makefile
Makefile.um
Makefile_32.cpu
xtensa
.gitignore
Kconfig
block
crypto
drivers
firmware
fs
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
tools
usr
virt
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
REPORTING-BUGS
Breadcrumbs
linux
/
arch
/
x86
/
platform
/
intel
/
iosf_mbi.c
Blame
Blame
Latest commit
History
History
326 lines (258 loc) · 7.03 KB
Breadcrumbs
linux
/
arch
/
x86
/
platform
/
intel
/
iosf_mbi.c
Top
File metadata and controls
Code
Blame
326 lines (258 loc) · 7.03 KB
Raw
/* * IOSF-SB MailBox Interface Driver * Copyright (c) 2013, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * * The IOSF-SB is a fabric bus available on Atom based SOC's that uses a * mailbox interface (MBI) to communicate with mutiple devices. This * driver implements access to this interface for those platforms that can * enumerate the device using PCI. */ #include <linux/module.h> #include <linux/init.h> #include <linux/spinlock.h> #include <linux/pci.h> #include <linux/debugfs.h> #include <linux/capability.h> #include <asm/iosf_mbi.h> #define PCI_DEVICE_ID_BAYTRAIL 0x0F00 #define PCI_DEVICE_ID_BRASWELL 0x2280 #define PCI_DEVICE_ID_QUARK_X1000 0x0958 static DEFINE_SPINLOCK(iosf_mbi_lock); static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset) { return (op << 24) | (port << 16) | (offset << 8) | MBI_ENABLE; } static struct pci_dev *mbi_pdev; /* one mbi device */ static int iosf_mbi_pci_read_mdr(u32 mcrx, u32 mcr, u32 *mdr) { int result; if (!mbi_pdev) return -ENODEV; if (mcrx) { result = pci_write_config_dword(mbi_pdev, MBI_MCRX_OFFSET, mcrx); if (result < 0) goto fail_read; } result = pci_write_config_dword(mbi_pdev, MBI_MCR_OFFSET, mcr); if (result < 0) goto fail_read; result = pci_read_config_dword(mbi_pdev, MBI_MDR_OFFSET, mdr); if (result < 0) goto fail_read; return 0; fail_read: dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result); return result; } static int iosf_mbi_pci_write_mdr(u32 mcrx, u32 mcr, u32 mdr) { int result; if (!mbi_pdev) return -ENODEV; result = pci_write_config_dword(mbi_pdev, MBI_MDR_OFFSET, mdr); if (result < 0) goto fail_write; if (mcrx) { result = pci_write_config_dword(mbi_pdev, MBI_MCRX_OFFSET, mcrx); if (result < 0) goto fail_write; } result = pci_write_config_dword(mbi_pdev, MBI_MCR_OFFSET, mcr); if (result < 0) goto fail_write; return 0; fail_write: dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result); return result; } int iosf_mbi_read(u8 port, u8 opcode, u32 offset, u32 *mdr) { u32 mcr, mcrx; unsigned long flags; int ret; /*Access to the GFX unit is handled by GPU code */ if (port == BT_MBI_UNIT_GFX) { WARN_ON(1); return -EPERM; } mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO); mcrx = offset & MBI_MASK_HI; spin_lock_irqsave(&iosf_mbi_lock, flags); ret = iosf_mbi_pci_read_mdr(mcrx, mcr, mdr); spin_unlock_irqrestore(&iosf_mbi_lock, flags); return ret; } EXPORT_SYMBOL(iosf_mbi_read); int iosf_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr) { u32 mcr, mcrx; unsigned long flags; int ret; /*Access to the GFX unit is handled by GPU code */ if (port == BT_MBI_UNIT_GFX) { WARN_ON(1); return -EPERM; } mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO); mcrx = offset & MBI_MASK_HI; spin_lock_irqsave(&iosf_mbi_lock, flags); ret = iosf_mbi_pci_write_mdr(mcrx, mcr, mdr); spin_unlock_irqrestore(&iosf_mbi_lock, flags); return ret; } EXPORT_SYMBOL(iosf_mbi_write); int iosf_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask) { u32 mcr, mcrx; u32 value; unsigned long flags; int ret; /*Access to the GFX unit is handled by GPU code */ if (port == BT_MBI_UNIT_GFX) { WARN_ON(1); return -EPERM; } mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO); mcrx = offset & MBI_MASK_HI; spin_lock_irqsave(&iosf_mbi_lock, flags); /* Read current mdr value */ ret = iosf_mbi_pci_read_mdr(mcrx, mcr & MBI_RD_MASK, &value); if (ret < 0) { spin_unlock_irqrestore(&iosf_mbi_lock, flags); return ret; } /* Apply mask */ value &= ~mask; mdr &= mask; value |= mdr; /* Write back */ ret = iosf_mbi_pci_write_mdr(mcrx, mcr | MBI_WR_MASK, value); spin_unlock_irqrestore(&iosf_mbi_lock, flags); return ret; } EXPORT_SYMBOL(iosf_mbi_modify); bool iosf_mbi_available(void) { /* Mbi isn't hot-pluggable. No remove routine is provided */ return mbi_pdev; } EXPORT_SYMBOL(iosf_mbi_available); #ifdef CONFIG_IOSF_MBI_DEBUG static u32 dbg_mdr; static u32 dbg_mcr; static u32 dbg_mcrx; static int mcr_get(void *data, u64 *val) { *val = *(u32 *)data; return 0; } static int mcr_set(void *data, u64 val) { u8 command = ((u32)val & 0xFF000000) >> 24, port = ((u32)val & 0x00FF0000) >> 16, offset = ((u32)val & 0x0000FF00) >> 8; int err; *(u32 *)data = val; if (!capable(CAP_SYS_RAWIO)) return -EACCES; if (command & 1u) err = iosf_mbi_write(port, command, dbg_mcrx | offset, dbg_mdr); else err = iosf_mbi_read(port, command, dbg_mcrx | offset, &dbg_mdr); return err; } DEFINE_SIMPLE_ATTRIBUTE(iosf_mcr_fops, mcr_get, mcr_set , "%llx\n"); static struct dentry *iosf_dbg; static void iosf_sideband_debug_init(void) { struct dentry *d; iosf_dbg = debugfs_create_dir("iosf_sb", NULL); if (IS_ERR_OR_NULL(iosf_dbg)) return; /* mdr */ d = debugfs_create_x32("mdr", 0660, iosf_dbg, &dbg_mdr); if (!d) goto cleanup; /* mcrx */ d = debugfs_create_x32("mcrx", 0660, iosf_dbg, &dbg_mcrx); if (!d) goto cleanup; /* mcr - initiates mailbox tranaction */ d = debugfs_create_file("mcr", 0660, iosf_dbg, &dbg_mcr, &iosf_mcr_fops); if (!d) goto cleanup; return; cleanup: debugfs_remove_recursive(d); } static void iosf_debugfs_init(void) { iosf_sideband_debug_init(); } static void iosf_debugfs_remove(void) { debugfs_remove_recursive(iosf_dbg); } #else static inline void iosf_debugfs_init(void) { } static inline void iosf_debugfs_remove(void) { } #endif /* CONFIG_IOSF_MBI_DEBUG */ static int iosf_mbi_probe(struct pci_dev *pdev, const struct pci_device_id *unused) { int ret; ret = pci_enable_device(pdev); if (ret < 0) { dev_err(&pdev->dev, "error: could not enable device\n"); return ret; } mbi_pdev = pci_dev_get(pdev); return 0; } static const struct pci_device_id iosf_mbi_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_BAYTRAIL) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_BRASWELL) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_QUARK_X1000) }, { 0, }, }; MODULE_DEVICE_TABLE(pci, iosf_mbi_pci_ids); static struct pci_driver iosf_mbi_pci_driver = { .name = "iosf_mbi_pci", .probe = iosf_mbi_probe, .id_table = iosf_mbi_pci_ids, }; static int __init iosf_mbi_init(void) { iosf_debugfs_init(); return pci_register_driver(&iosf_mbi_pci_driver); } static void __exit iosf_mbi_exit(void) { iosf_debugfs_remove(); pci_unregister_driver(&iosf_mbi_pci_driver); pci_dev_put(mbi_pdev); mbi_pdev = NULL; } module_init(iosf_mbi_init); module_exit(iosf_mbi_exit); MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>"); MODULE_DESCRIPTION("IOSF Mailbox Interface accessor"); MODULE_LICENSE("GPL v2");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
You can’t perform that action at this time.