diff options
Diffstat (limited to 'drivers/misc/mei/hw-me.c')
-rw-r--r-- | drivers/misc/mei/hw-me.c | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c new file mode 100644 index 000000000000..4e6b657cd806 --- /dev/null +++ b/drivers/misc/mei/hw-me.c | |||
@@ -0,0 +1,299 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Intel Management Engine Interface (Intel MEI) Linux driver | ||
4 | * Copyright (c) 2003-2012, Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/pci.h> | ||
18 | #include <linux/mei.h> | ||
19 | |||
20 | #include "mei_dev.h" | ||
21 | #include "hw-me.h" | ||
22 | |||
23 | /** | ||
24 | * mei_reg_read - Reads 32bit data from the mei device | ||
25 | * | ||
26 | * @dev: the device structure | ||
27 | * @offset: offset from which to read the data | ||
28 | * | ||
29 | * returns register value (u32) | ||
30 | */ | ||
31 | static inline u32 mei_reg_read(const struct mei_device *dev, | ||
32 | unsigned long offset) | ||
33 | { | ||
34 | return ioread32(dev->mem_addr + offset); | ||
35 | } | ||
36 | |||
37 | |||
38 | /** | ||
39 | * mei_reg_write - Writes 32bit data to the mei device | ||
40 | * | ||
41 | * @dev: the device structure | ||
42 | * @offset: offset from which to write the data | ||
43 | * @value: register value to write (u32) | ||
44 | */ | ||
45 | static inline void mei_reg_write(const struct mei_device *dev, | ||
46 | unsigned long offset, u32 value) | ||
47 | { | ||
48 | iowrite32(value, dev->mem_addr + offset); | ||
49 | } | ||
50 | |||
51 | /** | ||
52 | * mei_hcsr_read - Reads 32bit data from the host CSR | ||
53 | * | ||
54 | * @dev: the device structure | ||
55 | * | ||
56 | * returns the byte read. | ||
57 | */ | ||
58 | u32 mei_hcsr_read(const struct mei_device *dev) | ||
59 | { | ||
60 | return mei_reg_read(dev, H_CSR); | ||
61 | } | ||
62 | |||
63 | u32 mei_mecbrw_read(const struct mei_device *dev) | ||
64 | { | ||
65 | return mei_reg_read(dev, ME_CB_RW); | ||
66 | } | ||
67 | /** | ||
68 | * mei_mecsr_read - Reads 32bit data from the ME CSR | ||
69 | * | ||
70 | * @dev: the device structure | ||
71 | * | ||
72 | * returns ME_CSR_HA register value (u32) | ||
73 | */ | ||
74 | u32 mei_mecsr_read(const struct mei_device *dev) | ||
75 | { | ||
76 | return mei_reg_read(dev, ME_CSR_HA); | ||
77 | } | ||
78 | |||
79 | /** | ||
80 | * mei_set_csr_register - writes H_CSR register to the mei device, | ||
81 | * and ignores the H_IS bit for it is write-one-to-zero. | ||
82 | * | ||
83 | * @dev: the device structure | ||
84 | */ | ||
85 | void mei_hcsr_set(struct mei_device *dev) | ||
86 | { | ||
87 | if ((dev->host_hw_state & H_IS) == H_IS) | ||
88 | dev->host_hw_state &= ~H_IS; | ||
89 | mei_reg_write(dev, H_CSR, dev->host_hw_state); | ||
90 | dev->host_hw_state = mei_hcsr_read(dev); | ||
91 | } | ||
92 | |||
93 | /** | ||
94 | * mei_enable_interrupts - clear and stop interrupts | ||
95 | * | ||
96 | * @dev: the device structure | ||
97 | */ | ||
98 | void mei_clear_interrupts(struct mei_device *dev) | ||
99 | { | ||
100 | if ((dev->host_hw_state & H_IS) == H_IS) | ||
101 | mei_reg_write(dev, H_CSR, dev->host_hw_state); | ||
102 | } | ||
103 | |||
104 | /** | ||
105 | * mei_enable_interrupts - enables mei device interrupts | ||
106 | * | ||
107 | * @dev: the device structure | ||
108 | */ | ||
109 | void mei_enable_interrupts(struct mei_device *dev) | ||
110 | { | ||
111 | dev->host_hw_state |= H_IE; | ||
112 | mei_hcsr_set(dev); | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * mei_disable_interrupts - disables mei device interrupts | ||
117 | * | ||
118 | * @dev: the device structure | ||
119 | */ | ||
120 | void mei_disable_interrupts(struct mei_device *dev) | ||
121 | { | ||
122 | dev->host_hw_state &= ~H_IE; | ||
123 | mei_hcsr_set(dev); | ||
124 | } | ||
125 | |||
126 | |||
127 | /** | ||
128 | * mei_interrupt_quick_handler - The ISR of the MEI device | ||
129 | * | ||
130 | * @irq: The irq number | ||
131 | * @dev_id: pointer to the device structure | ||
132 | * | ||
133 | * returns irqreturn_t | ||
134 | */ | ||
135 | irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id) | ||
136 | { | ||
137 | struct mei_device *dev = (struct mei_device *) dev_id; | ||
138 | u32 csr_reg = mei_hcsr_read(dev); | ||
139 | |||
140 | if ((csr_reg & H_IS) != H_IS) | ||
141 | return IRQ_NONE; | ||
142 | |||
143 | /* clear H_IS bit in H_CSR */ | ||
144 | mei_reg_write(dev, H_CSR, csr_reg); | ||
145 | |||
146 | return IRQ_WAKE_THREAD; | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * mei_hbuf_filled_slots - gets number of device filled buffer slots | ||
151 | * | ||
152 | * @device: the device structure | ||
153 | * | ||
154 | * returns number of filled slots | ||
155 | */ | ||
156 | static unsigned char mei_hbuf_filled_slots(struct mei_device *dev) | ||
157 | { | ||
158 | char read_ptr, write_ptr; | ||
159 | |||
160 | dev->host_hw_state = mei_hcsr_read(dev); | ||
161 | |||
162 | read_ptr = (char) ((dev->host_hw_state & H_CBRP) >> 8); | ||
163 | write_ptr = (char) ((dev->host_hw_state & H_CBWP) >> 16); | ||
164 | |||
165 | return (unsigned char) (write_ptr - read_ptr); | ||
166 | } | ||
167 | |||
168 | /** | ||
169 | * mei_hbuf_is_empty - checks if host buffer is empty. | ||
170 | * | ||
171 | * @dev: the device structure | ||
172 | * | ||
173 | * returns true if empty, false - otherwise. | ||
174 | */ | ||
175 | bool mei_hbuf_is_empty(struct mei_device *dev) | ||
176 | { | ||
177 | return mei_hbuf_filled_slots(dev) == 0; | ||
178 | } | ||
179 | |||
180 | /** | ||
181 | * mei_hbuf_empty_slots - counts write empty slots. | ||
182 | * | ||
183 | * @dev: the device structure | ||
184 | * | ||
185 | * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count | ||
186 | */ | ||
187 | int mei_hbuf_empty_slots(struct mei_device *dev) | ||
188 | { | ||
189 | unsigned char filled_slots, empty_slots; | ||
190 | |||
191 | filled_slots = mei_hbuf_filled_slots(dev); | ||
192 | empty_slots = dev->hbuf_depth - filled_slots; | ||
193 | |||
194 | /* check for overflow */ | ||
195 | if (filled_slots > dev->hbuf_depth) | ||
196 | return -EOVERFLOW; | ||
197 | |||
198 | return empty_slots; | ||
199 | } | ||
200 | |||
201 | /** | ||
202 | * mei_write_message - writes a message to mei device. | ||
203 | * | ||
204 | * @dev: the device structure | ||
205 | * @hader: mei HECI header of message | ||
206 | * @buf: message payload will be written | ||
207 | * | ||
208 | * This function returns -EIO if write has failed | ||
209 | */ | ||
210 | int mei_write_message(struct mei_device *dev, struct mei_msg_hdr *header, | ||
211 | unsigned char *buf) | ||
212 | { | ||
213 | unsigned long rem, dw_cnt; | ||
214 | unsigned long length = header->length; | ||
215 | u32 *reg_buf = (u32 *)buf; | ||
216 | int i; | ||
217 | int empty_slots; | ||
218 | |||
219 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header)); | ||
220 | |||
221 | empty_slots = mei_hbuf_empty_slots(dev); | ||
222 | dev_dbg(&dev->pdev->dev, "empty slots = %hu.\n", empty_slots); | ||
223 | |||
224 | dw_cnt = mei_data2slots(length); | ||
225 | if (empty_slots < 0 || dw_cnt > empty_slots) | ||
226 | return -EIO; | ||
227 | |||
228 | mei_reg_write(dev, H_CB_WW, *((u32 *) header)); | ||
229 | |||
230 | for (i = 0; i < length / 4; i++) | ||
231 | mei_reg_write(dev, H_CB_WW, reg_buf[i]); | ||
232 | |||
233 | rem = length & 0x3; | ||
234 | if (rem > 0) { | ||
235 | u32 reg = 0; | ||
236 | memcpy(®, &buf[length - rem], rem); | ||
237 | mei_reg_write(dev, H_CB_WW, reg); | ||
238 | } | ||
239 | |||
240 | dev->host_hw_state = mei_hcsr_read(dev); | ||
241 | dev->host_hw_state |= H_IG; | ||
242 | mei_hcsr_set(dev); | ||
243 | dev->me_hw_state = mei_mecsr_read(dev); | ||
244 | if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA) | ||
245 | return -EIO; | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | /** | ||
251 | * mei_count_full_read_slots - counts read full slots. | ||
252 | * | ||
253 | * @dev: the device structure | ||
254 | * | ||
255 | * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count | ||
256 | */ | ||
257 | int mei_count_full_read_slots(struct mei_device *dev) | ||
258 | { | ||
259 | char read_ptr, write_ptr; | ||
260 | unsigned char buffer_depth, filled_slots; | ||
261 | |||
262 | dev->me_hw_state = mei_mecsr_read(dev); | ||
263 | buffer_depth = (unsigned char)((dev->me_hw_state & ME_CBD_HRA) >> 24); | ||
264 | read_ptr = (char) ((dev->me_hw_state & ME_CBRP_HRA) >> 8); | ||
265 | write_ptr = (char) ((dev->me_hw_state & ME_CBWP_HRA) >> 16); | ||
266 | filled_slots = (unsigned char) (write_ptr - read_ptr); | ||
267 | |||
268 | /* check for overflow */ | ||
269 | if (filled_slots > buffer_depth) | ||
270 | return -EOVERFLOW; | ||
271 | |||
272 | dev_dbg(&dev->pdev->dev, "filled_slots =%08x\n", filled_slots); | ||
273 | return (int)filled_slots; | ||
274 | } | ||
275 | |||
276 | /** | ||
277 | * mei_read_slots - reads a message from mei device. | ||
278 | * | ||
279 | * @dev: the device structure | ||
280 | * @buffer: message buffer will be written | ||
281 | * @buffer_length: message size will be read | ||
282 | */ | ||
283 | void mei_read_slots(struct mei_device *dev, unsigned char *buffer, | ||
284 | unsigned long buffer_length) | ||
285 | { | ||
286 | u32 *reg_buf = (u32 *)buffer; | ||
287 | |||
288 | for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32)) | ||
289 | *reg_buf++ = mei_mecbrw_read(dev); | ||
290 | |||
291 | if (buffer_length > 0) { | ||
292 | u32 reg = mei_mecbrw_read(dev); | ||
293 | memcpy(reg_buf, ®, buffer_length); | ||
294 | } | ||
295 | |||
296 | dev->host_hw_state |= H_IG; | ||
297 | mei_hcsr_set(dev); | ||
298 | } | ||
299 | |||