hw-me.c 7.7 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 109 110 111 112 113 114
 *
 * @dev: the device structure
 */
void mei_clear_interrupts(struct mei_device *dev)
{
	if ((dev->host_hw_state & H_IS) == H_IS)
		mei_reg_write(dev, H_CSR, dev->host_hw_state);
}

/**
 * mei_enable_interrupts - enables mei device interrupts
O
Oren Weil 已提交
115 116 117 118 119 120 121 122 123 124
 *
 * @dev: the device structure
 */
void mei_enable_interrupts(struct mei_device *dev)
{
	dev->host_hw_state |= H_IE;
	mei_hcsr_set(dev);
}

/**
125
 * mei_disable_interrupts - disables mei device interrupts
O
Oren Weil 已提交
126 127 128 129 130 131 132 133 134
 *
 * @dev: the device structure
 */
void mei_disable_interrupts(struct mei_device *dev)
{
	dev->host_hw_state &= ~H_IE;
	mei_hcsr_set(dev);
}

135 136 137 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
/**
 * 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);
}

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192

/**
 * 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 已提交
193
/**
194
 * mei_hbuf_filled_slots - gets number of device filled buffer slots
O
Oren Weil 已提交
195 196 197 198 199
 *
 * @device: the device structure
 *
 * returns number of filled slots
 */
200
static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
O
Oren Weil 已提交
201 202 203
{
	char read_ptr, write_ptr;

204 205
	dev->host_hw_state = mei_hcsr_read(dev);

O
Oren Weil 已提交
206 207 208 209 210 211 212
	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);
}

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

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

235
	filled_slots = mei_hbuf_filled_slots(dev);
236
	empty_slots = dev->hbuf_depth - filled_slots;
O
Oren Weil 已提交
237 238

	/* check for overflow */
239
	if (filled_slots > dev->hbuf_depth)
O
Oren Weil 已提交
240 241 242 243 244 245 246 247 248
		return -EOVERFLOW;

	return empty_slots;
}

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

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

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

268
	dw_cnt = mei_data2slots(length);
269
	if (empty_slots < 0 || dw_cnt > empty_slots)
270
		return -EIO;
O
Oren Weil 已提交
271 272 273

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

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

277 278 279 280 281
	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 已提交
282 283
	}

284
	dev->host_hw_state = mei_hcsr_read(dev);
O
Oren Weil 已提交
285 286 287 288
	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)
289
		return -EIO;
O
Oren Weil 已提交
290

291
	return 0;
O
Oren Weil 已提交
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
}

/**
 * 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
 */
327 328
void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
		    unsigned long buffer_length)
O
Oren Weil 已提交
329
{
330
	u32 *reg_buf = (u32 *)buffer;
O
Oren Weil 已提交
331

332 333
	for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32))
		*reg_buf++ = mei_mecbrw_read(dev);
O
Oren Weil 已提交
334 335

	if (buffer_length > 0) {
336 337
		u32 reg = mei_mecbrw_read(dev);
		memcpy(reg_buf, &reg, buffer_length);
O
Oren Weil 已提交
338 339 340 341 342 343
	}

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