hw-me.c 7.8 KB
Newer Older
O
Oren Weil 已提交
1 2 3
/*
 *
 * Intel Management Engine Interface (Intel MEI) Linux driver
4
 * Copyright (c) 2003-2012, Intel Corporation.
O
Oren Weil 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * 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.
 *
 */

#include <linux/pci.h>
18
#include <linux/mei.h>
19 20

#include "mei_dev.h"
T
Tomas Winkler 已提交
21
#include "hw-me.h"
O
Oren Weil 已提交
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
/**
 * mei_reg_read - Reads 32bit data from the mei device
 *
 * @dev: the device structure
 * @offset: offset from which to read the data
 *
 * returns register value (u32)
 */
static inline u32 mei_reg_read(const struct mei_device *dev,
			       unsigned long offset)
{
	return ioread32(dev->mem_addr + offset);
}


/**
 * mei_reg_write - Writes 32bit data to the mei device
 *
 * @dev: the device structure
 * @offset: offset from which to write the data
 * @value: register value to write (u32)
 */
static inline void mei_reg_write(const struct mei_device *dev,
				 unsigned long offset, u32 value)
{
	iowrite32(value, dev->mem_addr + offset);
}
O
Oren Weil 已提交
50

51
/**
T
Tomas Winkler 已提交
52 53
 * mei_mecbrw_read - Reads 32bit data from ME circular buffer
 *  read window register
54 55 56
 *
 * @dev: the device structure
 *
T
Tomas Winkler 已提交
57
 * returns ME_CB_RW register value (u32)
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
 */
u32 mei_mecbrw_read(const struct mei_device *dev)
{
	return mei_reg_read(dev, ME_CB_RW);
}
/**
 * mei_mecsr_read - Reads 32bit data from the ME CSR
 *
 * @dev: the device structure
 *
 * returns ME_CSR_HA register value (u32)
 */
u32 mei_mecsr_read(const struct mei_device *dev)
{
	return mei_reg_read(dev, ME_CSR_HA);
}
O
Oren Weil 已提交
74 75

/**
T
Tomas Winkler 已提交
76 77 78 79 80 81 82 83 84 85 86 87 88
 * mei_hcsr_read - Reads 32bit data from the host CSR
 *
 * @dev: the device structure
 *
 * returns H_CSR register value (u32)
 */
u32 mei_hcsr_read(const struct mei_device *dev)
{
	return mei_reg_read(dev, H_CSR);
}

/**
 * mei_hcsr_set - writes H_CSR register to the mei device,
O
Oren Weil 已提交
89 90 91 92 93 94
 * and ignores the H_IS bit for it is write-one-to-zero.
 *
 * @dev: the device structure
 */
void mei_hcsr_set(struct mei_device *dev)
{
T
Tomas Winkler 已提交
95

O
Oren Weil 已提交
96 97 98 99 100 101 102
	if ((dev->host_hw_state & H_IS) == H_IS)
		dev->host_hw_state &= ~H_IS;
	mei_reg_write(dev, H_CSR, dev->host_hw_state);
	dev->host_hw_state = mei_hcsr_read(dev);
}

/**
T
Tomas Winkler 已提交
103
 * mei_clear_interrupts - clear and stop interrupts
104 105 106 107 108
 *
 * @dev: the device structure
 */
void mei_clear_interrupts(struct mei_device *dev)
{
109 110 111
	u32 hcsr = mei_hcsr_read(dev);
	if ((hcsr & H_IS) == H_IS)
		mei_reg_write(dev, H_CSR, hcsr);
112 113 114 115
}

/**
 * mei_enable_interrupts - enables mei device interrupts
O
Oren Weil 已提交
116 117 118 119 120
 *
 * @dev: the device structure
 */
void mei_enable_interrupts(struct mei_device *dev)
{
121 122 123 124
	u32 hcsr = mei_hcsr_read(dev);
	hcsr |= H_IE;
	hcsr &= ~H_IS;
	mei_reg_write(dev, H_CSR, hcsr);
O
Oren Weil 已提交
125 126 127
}

/**
128
 * mei_disable_interrupts - disables mei device interrupts
O
Oren Weil 已提交
129 130 131 132 133
 *
 * @dev: the device structure
 */
void mei_disable_interrupts(struct mei_device *dev)
{
134 135 136 137
	u32 hcsr = mei_hcsr_read(dev);
	hcsr  &= ~H_IE;
	hcsr &= ~H_IS;
	mei_reg_write(dev, H_CSR, hcsr);
O
Oren Weil 已提交
138 139
}

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
/**
 * mei_hw_reset - resets fw via mei csr register.
 *
 * @dev: the device structure
 * @interrupts_enabled: if interrupt should be enabled after reset.
 */
void mei_hw_reset(struct mei_device *dev, bool intr_enable)
{
	u32 hcsr = mei_hcsr_read(dev);

	dev_dbg(&dev->pdev->dev, "before reset HCSR = 0x%08x.\n", hcsr);

	hcsr |= (H_RST | H_IG);

	if (intr_enable)
		hcsr |= H_IE;
	else
		hcsr &= ~H_IE;

	hcsr &= ~H_IS;

	mei_reg_write(dev, H_CSR, hcsr);
	hcsr = mei_hcsr_read(dev);

	hcsr &= ~H_RST;
	hcsr |= H_IG;
	hcsr &= ~H_IS;

	mei_reg_write(dev, H_CSR, hcsr);

	hcsr = mei_hcsr_read(dev);

	dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", hcsr);
}

175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197

/**
 * mei_interrupt_quick_handler - The ISR of the MEI device
 *
 * @irq: The irq number
 * @dev_id: pointer to the device structure
 *
 * returns irqreturn_t
 */
irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id)
{
	struct mei_device *dev = (struct mei_device *) dev_id;
	u32 csr_reg = mei_hcsr_read(dev);

	if ((csr_reg & H_IS) != H_IS)
		return IRQ_NONE;

	/* clear H_IS bit in H_CSR */
	mei_reg_write(dev, H_CSR, csr_reg);

	return IRQ_WAKE_THREAD;
}

O
Oren Weil 已提交
198
/**
199
 * mei_hbuf_filled_slots - gets number of device filled buffer slots
O
Oren Weil 已提交
200 201 202 203 204
 *
 * @device: the device structure
 *
 * returns number of filled slots
 */
205
static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
O
Oren Weil 已提交
206 207 208
{
	char read_ptr, write_ptr;

209 210
	dev->host_hw_state = mei_hcsr_read(dev);

O
Oren Weil 已提交
211 212 213 214 215 216 217
	read_ptr = (char) ((dev->host_hw_state & H_CBRP) >> 8);
	write_ptr = (char) ((dev->host_hw_state & H_CBWP) >> 16);

	return (unsigned char) (write_ptr - read_ptr);
}

/**
218
 * mei_hbuf_is_empty - checks if host buffer is empty.
O
Oren Weil 已提交
219 220 221
 *
 * @dev: the device structure
 *
222
 * returns true if empty, false - otherwise.
O
Oren Weil 已提交
223
 */
224
bool mei_hbuf_is_empty(struct mei_device *dev)
O
Oren Weil 已提交
225
{
226
	return mei_hbuf_filled_slots(dev) == 0;
O
Oren Weil 已提交
227 228 229
}

/**
230
 * mei_hbuf_empty_slots - counts write empty slots.
O
Oren Weil 已提交
231 232 233 234 235
 *
 * @dev: the device structure
 *
 * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count
 */
236
int mei_hbuf_empty_slots(struct mei_device *dev)
O
Oren Weil 已提交
237
{
238
	unsigned char filled_slots, empty_slots;
O
Oren Weil 已提交
239

240
	filled_slots = mei_hbuf_filled_slots(dev);
241
	empty_slots = dev->hbuf_depth - filled_slots;
O
Oren Weil 已提交
242 243

	/* check for overflow */
244
	if (filled_slots > dev->hbuf_depth)
O
Oren Weil 已提交
245 246 247 248 249 250 251 252 253
		return -EOVERFLOW;

	return empty_slots;
}

/**
 * mei_write_message - writes a message to mei device.
 *
 * @dev: the device structure
254 255
 * @hader: mei HECI header of message
 * @buf: message payload will be written
O
Oren Weil 已提交
256
 *
257
 * This function returns -EIO if write has failed
O
Oren Weil 已提交
258
 */
259
int mei_write_message(struct mei_device *dev, struct mei_msg_hdr *header,
260
		      unsigned char *buf)
O
Oren Weil 已提交
261
{
262
	unsigned long rem, dw_cnt;
263
	unsigned long length = header->length;
264 265 266
	u32 *reg_buf = (u32 *)buf;
	int i;
	int empty_slots;
O
Oren Weil 已提交
267

268
	dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
O
Oren Weil 已提交
269

270
	empty_slots = mei_hbuf_empty_slots(dev);
271
	dev_dbg(&dev->pdev->dev, "empty slots = %hu.\n", empty_slots);
O
Oren Weil 已提交
272

273
	dw_cnt = mei_data2slots(length);
274
	if (empty_slots < 0 || dw_cnt > empty_slots)
275
		return -EIO;
O
Oren Weil 已提交
276 277 278

	mei_reg_write(dev, H_CB_WW, *((u32 *) header));

279 280
	for (i = 0; i < length / 4; i++)
		mei_reg_write(dev, H_CB_WW, reg_buf[i]);
O
Oren Weil 已提交
281

282 283 284 285 286
	rem = length & 0x3;
	if (rem > 0) {
		u32 reg = 0;
		memcpy(&reg, &buf[length - rem], rem);
		mei_reg_write(dev, H_CB_WW, reg);
O
Oren Weil 已提交
287 288
	}

289
	dev->host_hw_state = mei_hcsr_read(dev);
O
Oren Weil 已提交
290 291 292 293
	dev->host_hw_state |= H_IG;
	mei_hcsr_set(dev);
	dev->me_hw_state = mei_mecsr_read(dev);
	if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
294
		return -EIO;
O
Oren Weil 已提交
295

296
	return 0;
O
Oren Weil 已提交
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 327 328 329 330 331
}

/**
 * mei_count_full_read_slots - counts read full slots.
 *
 * @dev: the device structure
 *
 * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count
 */
int mei_count_full_read_slots(struct mei_device *dev)
{
	char read_ptr, write_ptr;
	unsigned char buffer_depth, filled_slots;

	dev->me_hw_state = mei_mecsr_read(dev);
	buffer_depth = (unsigned char)((dev->me_hw_state & ME_CBD_HRA) >> 24);
	read_ptr = (char) ((dev->me_hw_state & ME_CBRP_HRA) >> 8);
	write_ptr = (char) ((dev->me_hw_state & ME_CBWP_HRA) >> 16);
	filled_slots = (unsigned char) (write_ptr - read_ptr);

	/* check for overflow */
	if (filled_slots > buffer_depth)
		return -EOVERFLOW;

	dev_dbg(&dev->pdev->dev, "filled_slots =%08x\n", filled_slots);
	return (int)filled_slots;
}

/**
 * mei_read_slots - reads a message from mei device.
 *
 * @dev: the device structure
 * @buffer: message buffer will be written
 * @buffer_length: message size will be read
 */
332 333
void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
		    unsigned long buffer_length)
O
Oren Weil 已提交
334
{
335
	u32 *reg_buf = (u32 *)buffer;
O
Oren Weil 已提交
336

337 338
	for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32))
		*reg_buf++ = mei_mecbrw_read(dev);
O
Oren Weil 已提交
339 340

	if (buffer_length > 0) {
341 342
		u32 reg = mei_mecbrw_read(dev);
		memcpy(reg_buf, &reg, buffer_length);
O
Oren Weil 已提交
343 344 345 346 347 348
	}

	dev->host_hw_state |= H_IG;
	mei_hcsr_set(dev);
}