1
2
3
4
5
6
7
8
9
10#include <linux/cpufeature.h>
11#include <linux/module.h>
12#include <linux/pci.h>
13#include <linux/sched/signal.h>
14#include <linux/uaccess.h>
15#include <uapi/linux/isst_if.h>
16
17#include "isst_if_common.h"
18
19#define PUNIT_MAILBOX_DATA 0xA0
20#define PUNIT_MAILBOX_INTERFACE 0xA4
21#define PUNIT_MAILBOX_BUSY_BIT 31
22
23
24
25
26
27
28
29#define OS_MAILBOX_RETRY_COUNT 100
30
31struct isst_if_device {
32 struct mutex mutex;
33};
34
35static int isst_if_mbox_cmd(struct pci_dev *pdev,
36 struct isst_if_mbox_cmd *mbox_cmd)
37{
38 u32 retries, data;
39 int ret;
40
41
42 retries = OS_MAILBOX_RETRY_COUNT;
43 do {
44 ret = pci_read_config_dword(pdev, PUNIT_MAILBOX_INTERFACE,
45 &data);
46 if (ret)
47 return ret;
48
49 if (data & BIT_ULL(PUNIT_MAILBOX_BUSY_BIT)) {
50 ret = -EBUSY;
51 continue;
52 }
53 ret = 0;
54 break;
55 } while (--retries);
56
57 if (ret)
58 return ret;
59
60
61 ret = pci_write_config_dword(pdev, PUNIT_MAILBOX_DATA,
62 mbox_cmd->req_data);
63 if (ret)
64 return ret;
65
66
67 data = BIT_ULL(PUNIT_MAILBOX_BUSY_BIT) |
68 (mbox_cmd->parameter & GENMASK_ULL(13, 0)) << 16 |
69 (mbox_cmd->sub_command << 8) |
70 mbox_cmd->command;
71
72 ret = pci_write_config_dword(pdev, PUNIT_MAILBOX_INTERFACE, data);
73 if (ret)
74 return ret;
75
76
77 retries = OS_MAILBOX_RETRY_COUNT;
78 do {
79 ret = pci_read_config_dword(pdev, PUNIT_MAILBOX_INTERFACE,
80 &data);
81 if (ret)
82 return ret;
83
84 if (data & BIT_ULL(PUNIT_MAILBOX_BUSY_BIT)) {
85 ret = -EBUSY;
86 continue;
87 }
88
89 if (data & 0xff)
90 return -ENXIO;
91
92 ret = pci_read_config_dword(pdev, PUNIT_MAILBOX_DATA, &data);
93 if (ret)
94 return ret;
95
96 mbox_cmd->resp_data = data;
97 ret = 0;
98 break;
99 } while (--retries);
100
101 return ret;
102}
103
104static long isst_if_mbox_proc_cmd(u8 *cmd_ptr, int *write_only, int resume)
105{
106 struct isst_if_mbox_cmd *mbox_cmd;
107 struct isst_if_device *punit_dev;
108 struct pci_dev *pdev;
109 int ret;
110
111 mbox_cmd = (struct isst_if_mbox_cmd *)cmd_ptr;
112
113 if (isst_if_mbox_cmd_invalid(mbox_cmd))
114 return -EINVAL;
115
116 if (isst_if_mbox_cmd_set_req(mbox_cmd) && !capable(CAP_SYS_ADMIN))
117 return -EPERM;
118
119 pdev = isst_if_get_pci_dev(mbox_cmd->logical_cpu, 1, 30, 1);
120 if (!pdev)
121 return -EINVAL;
122
123 punit_dev = pci_get_drvdata(pdev);
124 if (!punit_dev)
125 return -EINVAL;
126
127
128
129
130
131 mutex_lock(&punit_dev->mutex);
132 ret = isst_if_mbox_cmd(pdev, mbox_cmd);
133 if (!ret && !resume && isst_if_mbox_cmd_set_req(mbox_cmd))
134 ret = isst_store_cmd(mbox_cmd->command,
135 mbox_cmd->sub_command,
136 mbox_cmd->logical_cpu, 1,
137 mbox_cmd->parameter,
138 mbox_cmd->req_data);
139 mutex_unlock(&punit_dev->mutex);
140 if (ret)
141 return ret;
142
143 *write_only = 0;
144
145 return 0;
146}
147
148static const struct pci_device_id isst_if_mbox_ids[] = {
149 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, INTEL_CFG_MBOX_DEVID_0)},
150 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, INTEL_CFG_MBOX_DEVID_1)},
151 { 0 },
152};
153MODULE_DEVICE_TABLE(pci, isst_if_mbox_ids);
154
155static int isst_if_mbox_probe(struct pci_dev *pdev,
156 const struct pci_device_id *ent)
157{
158 struct isst_if_device *punit_dev;
159 struct isst_if_cmd_cb cb;
160 int ret;
161
162 punit_dev = devm_kzalloc(&pdev->dev, sizeof(*punit_dev), GFP_KERNEL);
163 if (!punit_dev)
164 return -ENOMEM;
165
166 ret = pcim_enable_device(pdev);
167 if (ret)
168 return ret;
169
170 mutex_init(&punit_dev->mutex);
171 pci_set_drvdata(pdev, punit_dev);
172
173 memset(&cb, 0, sizeof(cb));
174 cb.cmd_size = sizeof(struct isst_if_mbox_cmd);
175 cb.offset = offsetof(struct isst_if_mbox_cmds, mbox_cmd);
176 cb.cmd_callback = isst_if_mbox_proc_cmd;
177 cb.owner = THIS_MODULE;
178 ret = isst_if_cdev_register(ISST_IF_DEV_MBOX, &cb);
179
180 if (ret)
181 mutex_destroy(&punit_dev->mutex);
182
183 return ret;
184}
185
186static void isst_if_mbox_remove(struct pci_dev *pdev)
187{
188 struct isst_if_device *punit_dev;
189
190 punit_dev = pci_get_drvdata(pdev);
191 isst_if_cdev_unregister(ISST_IF_DEV_MBOX);
192 mutex_destroy(&punit_dev->mutex);
193}
194
195static int __maybe_unused isst_if_resume(struct device *device)
196{
197 isst_resume_common();
198 return 0;
199}
200
201static SIMPLE_DEV_PM_OPS(isst_if_pm_ops, NULL, isst_if_resume);
202
203static struct pci_driver isst_if_pci_driver = {
204 .name = "isst_if_mbox_pci",
205 .id_table = isst_if_mbox_ids,
206 .probe = isst_if_mbox_probe,
207 .remove = isst_if_mbox_remove,
208 .driver.pm = &isst_if_pm_ops,
209};
210
211module_pci_driver(isst_if_pci_driver);
212
213MODULE_LICENSE("GPL v2");
214MODULE_DESCRIPTION("Intel speed select interface pci mailbox driver");
215