hw-me.c 7.1 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

/**
 * 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 已提交
158
/**
159
 * mei_hbuf_filled_slots - gets number of device filled buffer slots
O
Oren Weil 已提交
160 161 162 163 164
 *
 * @device: the device structure
 *
 * returns number of filled slots
 */
165
static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
O
Oren Weil 已提交
166 167 168
{
	char read_ptr, write_ptr;

169 170
	dev->host_hw_state = mei_hcsr_read(dev);

O
Oren Weil 已提交
171 172 173 174 175 176 177
	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);
}

/**
178
 * mei_hbuf_is_empty - checks if host buffer is empty.
O
Oren Weil 已提交
179 180 181
 *
 * @dev: the device structure
 *
182
 * returns true if empty, false - otherwise.
O
Oren Weil 已提交
183
 */
184
bool mei_hbuf_is_empty(struct mei_device *dev)
O
Oren Weil 已提交
185
{
186
	return mei_hbuf_filled_slots(dev) == 0;
O
Oren Weil 已提交
187 188 189
}

/**
190
 * mei_hbuf_empty_slots - counts write empty slots.
O
Oren Weil 已提交
191 192 193 194 195
 *
 * @dev: the device structure
 *
 * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count
 */
196
int mei_hbuf_empty_slots(struct mei_device *dev)
O
Oren Weil 已提交
197
{
198
	unsigned char filled_slots, empty_slots;
O
Oren Weil 已提交
199

200
	filled_slots = mei_hbuf_filled_slots(dev);
201
	empty_slots = dev->hbuf_depth - filled_slots;
O
Oren Weil 已提交
202 203

	/* check for overflow */
204
	if (filled_slots > dev->hbuf_depth)
O
Oren Weil 已提交
205 206 207 208 209 210 211 212 213
		return -EOVERFLOW;

	return empty_slots;
}

/**
 * mei_write_message - writes a message to mei device.
 *
 * @dev: the device structure
214 215
 * @hader: mei HECI header of message
 * @buf: message payload will be written
O
Oren Weil 已提交
216
 *
217
 * This function returns -EIO if write has failed
O
Oren Weil 已提交
218
 */
219
int mei_write_message(struct mei_device *dev, struct mei_msg_hdr *header,
220
		      unsigned char *buf)
O
Oren Weil 已提交
221
{
222
	unsigned long rem, dw_cnt;
223
	unsigned long length = header->length;
224 225 226
	u32 *reg_buf = (u32 *)buf;
	int i;
	int empty_slots;
O
Oren Weil 已提交
227

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

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

233
	dw_cnt = mei_data2slots(length);
234
	if (empty_slots < 0 || dw_cnt > empty_slots)
235
		return -EIO;
O
Oren Weil 已提交
236 237 238

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

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

242 243 244 245 246
	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 已提交
247 248
	}

249
	dev->host_hw_state = mei_hcsr_read(dev);
O
Oren Weil 已提交
250 251 252 253
	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)
254
		return -EIO;
O
Oren Weil 已提交
255

256
	return 0;
O
Oren Weil 已提交
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
}

/**
 * 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
 */
292 293
void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
		    unsigned long buffer_length)
O
Oren Weil 已提交
294
{
295
	u32 *reg_buf = (u32 *)buffer;
O
Oren Weil 已提交
296

297 298
	for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32))
		*reg_buf++ = mei_mecbrw_read(dev);
O
Oren Weil 已提交
299 300

	if (buffer_length > 0) {
301 302
		u32 reg = mei_mecbrw_read(dev);
		memcpy(reg_buf, &reg, buffer_length);
O
Oren Weil 已提交
303 304 305 306 307 308
	}

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