aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/mic/host/mic_x100.c
diff options
context:
space:
mode:
authorSudeep Dutt <sudeep.dutt@intel.com>2013-09-05 19:41:55 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-09-26 16:50:56 -0400
commit3a6a9201897c6482573ad07ee880574147761006 (patch)
tree85b2c67221f0e003a64637d815d43585718870d3 /drivers/misc/mic/host/mic_x100.c
parenta01e28f692088e9789ebb0c374fdac83de59899b (diff)
Intel MIC Host Driver, card OS state management.
This patch enables the following features: a) Boots and shuts down the card via sysfs entries. b) Allocates and maps a device page for communication with the card driver and updates the device page address via scratchpad registers. c) Provides sysfs entries for shutdown status, kernel command line, ramdisk and log buffer information. Co-author: Dasaratharaman Chandramouli <dasaratharaman.chandramouli@intel.com> Signed-off-by: Ashutosh Dixit <ashutosh.dixit@intel.com> Signed-off-by: Caz Yokoyama <Caz.Yokoyama@intel.com> Signed-off-by: Dasaratharaman Chandramouli <dasaratharaman.chandramouli@intel.com> Signed-off-by: Harshavardhan R Kharche <harshavardhan.r.kharche@intel.com> Signed-off-by: Nikhil Rao <nikhil.rao@intel.com> Signed-off-by: Sudeep Dutt <sudeep.dutt@intel.com> Acked-by: Yaozu (Eddie) Dong <eddie.dong@intel.com> Reviewed-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc/mic/host/mic_x100.c')
-rw-r--r--drivers/misc/mic/host/mic_x100.c251
1 files changed, 251 insertions, 0 deletions
diff --git a/drivers/misc/mic/host/mic_x100.c b/drivers/misc/mic/host/mic_x100.c
index b63731691c73..a12ae5c8844d 100644
--- a/drivers/misc/mic/host/mic_x100.c
+++ b/drivers/misc/mic/host/mic_x100.c
@@ -20,6 +20,9 @@
20 */ 20 */
21#include <linux/fs.h> 21#include <linux/fs.h>
22#include <linux/pci.h> 22#include <linux/pci.h>
23#include <linux/sched.h>
24#include <linux/firmware.h>
25#include <linux/delay.h>
23 26
24#include "../common/mic_device.h" 27#include "../common/mic_device.h"
25#include "mic_device.h" 28#include "mic_device.h"
@@ -256,6 +259,248 @@ mic_x100_program_msi_to_src_map(struct mic_device *mdev,
256 mic_mmio_write(mw, reg, mxar); 259 mic_mmio_write(mw, reg, mxar);
257} 260}
258 261
262/*
263 * mic_x100_reset_fw_ready - Reset Firmware ready status field.
264 * @mdev: pointer to mic_device instance
265 */
266static void mic_x100_reset_fw_ready(struct mic_device *mdev)
267{
268 mdev->ops->write_spad(mdev, MIC_X100_DOWNLOAD_INFO, 0);
269}
270
271/*
272 * mic_x100_is_fw_ready - Check if firmware is ready.
273 * @mdev: pointer to mic_device instance
274 */
275static bool mic_x100_is_fw_ready(struct mic_device *mdev)
276{
277 u32 scratch2 = mdev->ops->read_spad(mdev, MIC_X100_DOWNLOAD_INFO);
278 return MIC_X100_SPAD2_DOWNLOAD_STATUS(scratch2) ? true : false;
279}
280
281/**
282 * mic_x100_get_apic_id - Get bootstrap APIC ID.
283 * @mdev: pointer to mic_device instance
284 */
285static u32 mic_x100_get_apic_id(struct mic_device *mdev)
286{
287 u32 scratch2 = 0;
288
289 scratch2 = mdev->ops->read_spad(mdev, MIC_X100_DOWNLOAD_INFO);
290 return MIC_X100_SPAD2_APIC_ID(scratch2);
291}
292
293/**
294 * mic_x100_send_firmware_intr - Send an interrupt to the firmware on MIC.
295 * @mdev: pointer to mic_device instance
296 */
297static void mic_x100_send_firmware_intr(struct mic_device *mdev)
298{
299 u32 apicicr_low;
300 u64 apic_icr_offset = MIC_X100_SBOX_APICICR7;
301 int vector = MIC_X100_BSP_INTERRUPT_VECTOR;
302 struct mic_mw *mw = &mdev->mmio;
303
304 /*
305 * For MIC we need to make sure we "hit"
306 * the send_icr bit (13).
307 */
308 apicicr_low = (vector | (1 << 13));
309
310 mic_mmio_write(mw, mic_x100_get_apic_id(mdev),
311 MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset + 4);
312
313 /* Ensure that the interrupt is ordered w.r.t. previous stores. */
314 wmb();
315 mic_mmio_write(mw, apicicr_low,
316 MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset);
317}
318
319/**
320 * mic_x100_hw_reset - Reset the MIC device.
321 * @mdev: pointer to mic_device instance
322 */
323static void mic_x100_hw_reset(struct mic_device *mdev)
324{
325 u32 reset_reg;
326 u32 rgcr = MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_RGCR;
327 struct mic_mw *mw = &mdev->mmio;
328
329 /* Ensure that the reset is ordered w.r.t. previous loads and stores */
330 mb();
331 /* Trigger reset */
332 reset_reg = mic_mmio_read(mw, rgcr);
333 reset_reg |= 0x1;
334 mic_mmio_write(mw, reset_reg, rgcr);
335 /*
336 * It seems we really want to delay at least 1 second
337 * after touching reset to prevent a lot of problems.
338 */
339 msleep(1000);
340}
341
342/**
343 * mic_x100_load_command_line - Load command line to MIC.
344 * @mdev: pointer to mic_device instance
345 * @fw: the firmware image
346 *
347 * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
348 */
349static int
350mic_x100_load_command_line(struct mic_device *mdev, const struct firmware *fw)
351{
352 u32 len = 0;
353 u32 boot_mem;
354 char *buf;
355 void __iomem *cmd_line_va = mdev->aper.va + mdev->bootaddr + fw->size;
356#define CMDLINE_SIZE 2048
357
358 boot_mem = mdev->aper.len >> 20;
359 buf = kzalloc(CMDLINE_SIZE, GFP_KERNEL);
360 if (!buf) {
361 dev_err(mdev->sdev->parent,
362 "%s %d allocation failed\n", __func__, __LINE__);
363 return -ENOMEM;
364 }
365 len += snprintf(buf, CMDLINE_SIZE - len,
366 " mem=%dM", boot_mem);
367 if (mdev->cmdline)
368 snprintf(buf + len, CMDLINE_SIZE - len,
369 " %s", mdev->cmdline);
370 memcpy_toio(cmd_line_va, buf, strlen(buf) + 1);
371 kfree(buf);
372 return 0;
373}
374
375/**
376 * mic_x100_load_ramdisk - Load ramdisk to MIC.
377 * @mdev: pointer to mic_device instance
378 *
379 * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
380 */
381static int
382mic_x100_load_ramdisk(struct mic_device *mdev)
383{
384 const struct firmware *fw;
385 int rc;
386 struct boot_params __iomem *bp = mdev->aper.va + mdev->bootaddr;
387
388 rc = request_firmware(&fw,
389 mdev->ramdisk, mdev->sdev->parent);
390 if (rc < 0) {
391 dev_err(mdev->sdev->parent,
392 "ramdisk request_firmware failed: %d %s\n",
393 rc, mdev->ramdisk);
394 goto error;
395 }
396 /*
397 * Typically the bootaddr for card OS is 64M
398 * so copy over the ramdisk @ 128M.
399 */
400 memcpy_toio(mdev->aper.va + (mdev->bootaddr << 1),
401 fw->data, fw->size);
402 iowrite32(cpu_to_le32(mdev->bootaddr << 1), &bp->hdr.ramdisk_image);
403 iowrite32(cpu_to_le32(fw->size), &bp->hdr.ramdisk_size);
404 release_firmware(fw);
405error:
406 return rc;
407}
408
409/**
410 * mic_x100_get_boot_addr - Get MIC boot address.
411 * @mdev: pointer to mic_device instance
412 *
413 * This function is called during firmware load to determine
414 * the address at which the OS should be downloaded in card
415 * memory i.e. GDDR.
416 * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
417 */
418static int
419mic_x100_get_boot_addr(struct mic_device *mdev)
420{
421 u32 scratch2, boot_addr;
422 int rc = 0;
423
424 scratch2 = mdev->ops->read_spad(mdev, MIC_X100_DOWNLOAD_INFO);
425 boot_addr = MIC_X100_SPAD2_DOWNLOAD_ADDR(scratch2);
426 dev_dbg(mdev->sdev->parent, "%s %d boot_addr 0x%x\n",
427 __func__, __LINE__, boot_addr);
428 if (boot_addr > (1 << 31)) {
429 dev_err(mdev->sdev->parent,
430 "incorrect bootaddr 0x%x\n",
431 boot_addr);
432 rc = -EINVAL;
433 goto error;
434 }
435 mdev->bootaddr = boot_addr;
436error:
437 return rc;
438}
439
440/**
441 * mic_x100_load_firmware - Load firmware to MIC.
442 * @mdev: pointer to mic_device instance
443 * @buf: buffer containing boot string including firmware/ramdisk path.
444 *
445 * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
446 */
447static int
448mic_x100_load_firmware(struct mic_device *mdev, const char *buf)
449{
450 int rc;
451 const struct firmware *fw;
452
453 rc = mic_x100_get_boot_addr(mdev);
454 if (rc)
455 goto error;
456 /* load OS */
457 rc = request_firmware(&fw, mdev->firmware, mdev->sdev->parent);
458 if (rc < 0) {
459 dev_err(mdev->sdev->parent,
460 "ramdisk request_firmware failed: %d %s\n",
461 rc, mdev->firmware);
462 goto error;
463 }
464 if (mdev->bootaddr > mdev->aper.len - fw->size) {
465 rc = -EINVAL;
466 dev_err(mdev->sdev->parent, "%s %d rc %d bootaddr 0x%x\n",
467 __func__, __LINE__, rc, mdev->bootaddr);
468 release_firmware(fw);
469 goto error;
470 }
471 memcpy_toio(mdev->aper.va + mdev->bootaddr, fw->data, fw->size);
472 mdev->ops->write_spad(mdev, MIC_X100_FW_SIZE, fw->size);
473 if (!strcmp(mdev->bootmode, "elf"))
474 goto done;
475 /* load command line */
476 rc = mic_x100_load_command_line(mdev, fw);
477 if (rc) {
478 dev_err(mdev->sdev->parent, "%s %d rc %d\n",
479 __func__, __LINE__, rc);
480 goto error;
481 }
482 release_firmware(fw);
483 /* load ramdisk */
484 if (mdev->ramdisk)
485 rc = mic_x100_load_ramdisk(mdev);
486error:
487 dev_dbg(mdev->sdev->parent, "%s %d rc %d\n",
488 __func__, __LINE__, rc);
489done:
490 return rc;
491}
492
493/**
494 * mic_x100_get_postcode - Get postcode status from firmware.
495 * @mdev: pointer to mic_device instance
496 *
497 * RETURNS: postcode.
498 */
499static u32 mic_x100_get_postcode(struct mic_device *mdev)
500{
501 return mic_mmio_read(&mdev->mmio, MIC_X100_POSTCODE);
502}
503
259/** 504/**
260 * mic_x100_smpt_set - Update an SMPT entry with a DMA address. 505 * mic_x100_smpt_set - Update an SMPT entry with a DMA address.
261 * @mdev: pointer to mic_device instance 506 * @mdev: pointer to mic_device instance
@@ -311,6 +556,12 @@ struct mic_hw_ops mic_x100_ops = {
311 .write_spad = mic_x100_write_spad, 556 .write_spad = mic_x100_write_spad,
312 .send_intr = mic_x100_send_intr, 557 .send_intr = mic_x100_send_intr,
313 .ack_interrupt = mic_x100_ack_interrupt, 558 .ack_interrupt = mic_x100_ack_interrupt,
559 .reset = mic_x100_hw_reset,
560 .reset_fw_ready = mic_x100_reset_fw_ready,
561 .is_fw_ready = mic_x100_is_fw_ready,
562 .send_firmware_intr = mic_x100_send_firmware_intr,
563 .load_mic_fw = mic_x100_load_firmware,
564 .get_postcode = mic_x100_get_postcode,
314}; 565};
315 566
316struct mic_hw_intr_ops mic_x100_intr_ops = { 567struct mic_hw_intr_ops mic_x100_intr_ops = {