1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Intel Speed Select Interface: Mbox via PCI Interface
4  * Copyright (c) 2019, Intel Corporation.
5  * All rights reserved.
6  *
7  * Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
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  * The average time to complete some commands is about 40us. The current
25  * count is enough to satisfy 40us. But when the firmware is very busy, this
26  * causes timeout occasionally.  So increase to deal with some worst case
27  * scenarios. Most of the command still complete in few us.
28  */
29 #define OS_MAILBOX_RETRY_COUNT		100
30 
31 struct isst_if_device {
32 	struct mutex mutex;
33 };
34 
isst_if_mbox_cmd(struct pci_dev * pdev,struct isst_if_mbox_cmd * mbox_cmd)35 static 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 	/* Poll for rb bit == 0 */
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 	/* Write DATA register */
61 	ret = pci_write_config_dword(pdev, PUNIT_MAILBOX_DATA,
62 				     mbox_cmd->req_data);
63 	if (ret)
64 		return ret;
65 
66 	/* Write command register */
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 	/* Poll for rb bit == 0 */
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 
isst_if_mbox_proc_cmd(u8 * cmd_ptr,int * write_only,int resume)104 static 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 	 * Basically we are allowing one complete mailbox transaction on
129 	 * a mapped PCI device at a time.
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 
148 static 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 };
153 MODULE_DEVICE_TABLE(pci, isst_if_mbox_ids);
154 
isst_if_mbox_probe(struct pci_dev * pdev,const struct pci_device_id * ent)155 static 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 
isst_if_mbox_remove(struct pci_dev * pdev)186 static 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 
isst_if_resume(struct device * device)195 static int __maybe_unused isst_if_resume(struct device *device)
196 {
197 	isst_resume_common();
198 	return 0;
199 }
200 
201 static SIMPLE_DEV_PM_OPS(isst_if_pm_ops, NULL, isst_if_resume);
202 
203 static 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 
211 module_pci_driver(isst_if_pci_driver);
212 
213 MODULE_LICENSE("GPL v2");
214 MODULE_DESCRIPTION("Intel speed select interface pci mailbox driver");
215