Commit 1da2b3ee authored by Ashutosh Dixit's avatar Ashutosh Dixit Committed by Greg Kroah-Hartman

misc: mic: Remove COSM functionality from the MIC host driver

Since COSM functionality is now moved into a separate COSM driver
drivers, this patch removes this functionality from the base MIC host
driver. The MIC host driver now implements cosm_hw_ops and registers a
COSM device which allows the COSM driver to trigger
boot/shutdown/reset of the MIC devices via the cosm_hw_ops.
Reviewed-by: default avatarNikhil Rao <nikhil.rao@intel.com>
Reviewed-by: default avatarSudeep Dutt <sudeep.dutt@intel.com>
Signed-off-by: default avatarDasaratharaman Chandramouli <dasaratharaman.chandramouli@intel.com>
Signed-off-by: default avatarAshutosh Dixit <ashutosh.dixit@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 7cb46d9b
...@@ -2,7 +2,5 @@ ...@@ -2,7 +2,5 @@
# Makefile - Intel MIC Linux driver. # Makefile - Intel MIC Linux driver.
# Copyright(c) 2013, Intel Corporation. # Copyright(c) 2013, Intel Corporation.
# #
obj-$(CONFIG_INTEL_MIC_HOST) += host/
obj-$(CONFIG_INTEL_MIC_CARD) += card/
obj-y += bus/ obj-y += bus/
obj-$(CONFIG_SCIF) += scif/ obj-$(CONFIG_SCIF) += scif/
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
obj-$(CONFIG_INTEL_MIC_HOST) += mic_host.o obj-$(CONFIG_INTEL_MIC_HOST) += mic_host.o
mic_host-objs := mic_main.o mic_host-objs := mic_main.o
mic_host-objs += mic_x100.o mic_host-objs += mic_x100.o
mic_host-objs += mic_sysfs.o
mic_host-objs += mic_smpt.o mic_host-objs += mic_smpt.o
mic_host-objs += mic_intr.o mic_host-objs += mic_intr.o
mic_host-objs += mic_boot.o mic_host-objs += mic_boot.o
......
...@@ -22,9 +22,9 @@ ...@@ -22,9 +22,9 @@
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/mic_common.h> #include <linux/mic_common.h>
#include <linux/mic_bus.h> #include <linux/mic_bus.h>
#include "../bus/scif_bus.h"
#include "../common/mic_dev.h" #include "../common/mic_dev.h"
#include "mic_device.h" #include "mic_device.h"
#include "mic_smpt.h" #include "mic_smpt.h"
...@@ -99,7 +99,7 @@ static int __mic_dma_map_sg(struct device *dev, struct scatterlist *sg, ...@@ -99,7 +99,7 @@ static int __mic_dma_map_sg(struct device *dev, struct scatterlist *sg,
int i, j, ret; int i, j, ret;
dma_addr_t da; dma_addr_t da;
ret = dma_map_sg(mdev->sdev->parent, sg, nents, dir); ret = dma_map_sg(&mdev->pdev->dev, sg, nents, dir);
if (ret <= 0) if (ret <= 0)
return 0; return 0;
...@@ -115,7 +115,7 @@ static int __mic_dma_map_sg(struct device *dev, struct scatterlist *sg, ...@@ -115,7 +115,7 @@ static int __mic_dma_map_sg(struct device *dev, struct scatterlist *sg,
mic_unmap(mdev, sg_dma_address(s), s->length); mic_unmap(mdev, sg_dma_address(s), s->length);
sg_dma_address(s) = mic_to_dma_addr(mdev, sg_dma_address(s)); sg_dma_address(s) = mic_to_dma_addr(mdev, sg_dma_address(s));
} }
dma_unmap_sg(mdev->sdev->parent, sg, nents, dir); dma_unmap_sg(&mdev->pdev->dev, sg, nents, dir);
return 0; return 0;
} }
...@@ -135,7 +135,7 @@ static void __mic_dma_unmap_sg(struct device *dev, ...@@ -135,7 +135,7 @@ static void __mic_dma_unmap_sg(struct device *dev,
mic_unmap(mdev, sg_dma_address(s), s->length); mic_unmap(mdev, sg_dma_address(s), s->length);
sg_dma_address(s) = da; sg_dma_address(s) = da;
} }
dma_unmap_sg(mdev->sdev->parent, sg, nents, dir); dma_unmap_sg(&mdev->pdev->dev, sg, nents, dir);
} }
static struct dma_map_ops __mic_dma_ops = { static struct dma_map_ops __mic_dma_ops = {
...@@ -270,48 +270,13 @@ static struct mbus_hw_ops mbus_hw_ops = { ...@@ -270,48 +270,13 @@ static struct mbus_hw_ops mbus_hw_ops = {
.ack_interrupt = _mic_ack_interrupt, .ack_interrupt = _mic_ack_interrupt,
}; };
/**
* mic_reset - Reset the MIC device.
* @mdev: pointer to mic_device instance
*/
static void mic_reset(struct mic_device *mdev)
{
int i;
#define MIC_RESET_TO (45)
reinit_completion(&mdev->reset_wait);
mdev->ops->reset_fw_ready(mdev);
mdev->ops->reset(mdev);
for (i = 0; i < MIC_RESET_TO; i++) {
if (mdev->ops->is_fw_ready(mdev))
goto done;
/*
* Resets typically take 10s of seconds to complete.
* Since an MMIO read is required to check if the
* firmware is ready or not, a 1 second delay works nicely.
*/
msleep(1000);
}
mic_set_state(mdev, MIC_RESET_FAILED);
done:
complete_all(&mdev->reset_wait);
}
/* Initialize the MIC bootparams */ /* Initialize the MIC bootparams */
void mic_bootparam_init(struct mic_device *mdev) void mic_bootparam_init(struct mic_device *mdev)
{ {
struct mic_bootparam *bootparam = mdev->dp; struct mic_bootparam *bootparam = mdev->dp;
bootparam->magic = cpu_to_le32(MIC_MAGIC); bootparam->magic = cpu_to_le32(MIC_MAGIC);
bootparam->c2h_shutdown_db = mdev->shutdown_db;
bootparam->h2c_shutdown_db = -1;
bootparam->h2c_config_db = -1; bootparam->h2c_config_db = -1;
bootparam->shutdown_status = 0;
bootparam->shutdown_card = 0;
/* Total nodes = number of MICs + 1 for self node */
bootparam->tot_nodes = atomic_read(&g_num_mics) + 1;
bootparam->node_id = mdev->id + 1; bootparam->node_id = mdev->id + 1;
bootparam->scif_host_dma_addr = 0x0; bootparam->scif_host_dma_addr = 0x0;
bootparam->scif_card_dma_addr = 0x0; bootparam->scif_card_dma_addr = 0x0;
...@@ -319,6 +284,26 @@ void mic_bootparam_init(struct mic_device *mdev) ...@@ -319,6 +284,26 @@ void mic_bootparam_init(struct mic_device *mdev)
bootparam->h2c_scif_db = -1; bootparam->h2c_scif_db = -1;
} }
static inline struct mic_device *cosmdev_to_mdev(struct cosm_device *cdev)
{
return dev_get_drvdata(cdev->dev.parent);
}
static void _mic_reset(struct cosm_device *cdev)
{
struct mic_device *mdev = cosmdev_to_mdev(cdev);
mdev->ops->reset_fw_ready(mdev);
mdev->ops->reset(mdev);
}
static bool _mic_ready(struct cosm_device *cdev)
{
struct mic_device *mdev = cosmdev_to_mdev(cdev);
return mdev->ops->is_fw_ready(mdev);
}
/** /**
* mic_request_dma_chans - Request DMA channels * mic_request_dma_chans - Request DMA channels
* @mdev: pointer to mic_device instance * @mdev: pointer to mic_device instance
...@@ -336,14 +321,14 @@ static int mic_request_dma_chans(struct mic_device *mdev) ...@@ -336,14 +321,14 @@ static int mic_request_dma_chans(struct mic_device *mdev)
do { do {
chan = dma_request_channel(mask, mdev->ops->dma_filter, chan = dma_request_channel(mask, mdev->ops->dma_filter,
mdev->sdev->parent); &mdev->pdev->dev);
if (chan) { if (chan) {
mdev->dma_ch[mdev->num_dma_ch++] = chan; mdev->dma_ch[mdev->num_dma_ch++] = chan;
if (mdev->num_dma_ch >= MIC_MAX_DMA_CHAN) if (mdev->num_dma_ch >= MIC_MAX_DMA_CHAN)
break; break;
} }
} while (chan); } while (chan);
dev_info(mdev->sdev->parent, "DMA channels # %d\n", mdev->num_dma_ch); dev_info(&mdev->pdev->dev, "DMA channels # %d\n", mdev->num_dma_ch);
return mdev->num_dma_ch; return mdev->num_dma_ch;
} }
...@@ -365,34 +350,24 @@ static void mic_free_dma_chans(struct mic_device *mdev) ...@@ -365,34 +350,24 @@ static void mic_free_dma_chans(struct mic_device *mdev)
} }
/** /**
* mic_start - Start the MIC. * _mic_start - Start the MIC.
* @mdev: pointer to mic_device instance * @cdev: pointer to cosm_device instance
* @buf: buffer containing boot string including firmware/ramdisk path. * @id: MIC device id/index provided by COSM used in other drivers like SCIF
* *
* This function prepares an MIC for boot and initiates boot. * This function prepares an MIC for boot and initiates boot.
* RETURNS: An appropriate -ERRNO error value on error, or zero for success. * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
*
* For all cosm_hw_ops the caller holds a mutex to ensure serialization.
*/ */
int mic_start(struct mic_device *mdev, const char *buf) static int _mic_start(struct cosm_device *cdev, int id)
{ {
struct mic_device *mdev = cosmdev_to_mdev(cdev);
int rc; int rc;
mutex_lock(&mdev->mic_mutex);
mic_bootparam_init(mdev); mic_bootparam_init(mdev);
retry: mdev->dma_mbdev = mbus_register_device(&mdev->pdev->dev,
if (MIC_OFFLINE != mdev->state) {
rc = -EINVAL;
goto unlock_ret;
}
if (!mdev->ops->is_fw_ready(mdev)) {
mic_reset(mdev);
/*
* The state will either be MIC_OFFLINE if the reset succeeded
* or MIC_RESET_FAILED if the firmware reset failed.
*/
goto retry;
}
mdev->dma_mbdev = mbus_register_device(mdev->sdev->parent,
MBUS_DEV_DMA_HOST, &mic_dma_ops, MBUS_DEV_DMA_HOST, &mic_dma_ops,
&mbus_hw_ops, mdev->mmio.va); &mbus_hw_ops, id, mdev->mmio.va);
if (IS_ERR(mdev->dma_mbdev)) { if (IS_ERR(mdev->dma_mbdev)) {
rc = PTR_ERR(mdev->dma_mbdev); rc = PTR_ERR(mdev->dma_mbdev);
goto unlock_ret; goto unlock_ret;
...@@ -401,16 +376,18 @@ int mic_start(struct mic_device *mdev, const char *buf) ...@@ -401,16 +376,18 @@ int mic_start(struct mic_device *mdev, const char *buf)
rc = -ENODEV; rc = -ENODEV;
goto dma_remove; goto dma_remove;
} }
mdev->scdev = scif_register_device(mdev->sdev->parent, MIC_SCIF_DEV, mdev->scdev = scif_register_device(&mdev->pdev->dev, MIC_SCIF_DEV,
&__mic_dma_ops, &scif_hw_ops, &__mic_dma_ops, &scif_hw_ops,
mdev->id + 1, 0, &mdev->mmio, id + 1, 0, &mdev->mmio,
&mdev->aper, mdev->dp, NULL, &mdev->aper, mdev->dp, NULL,
mdev->dma_ch, mdev->num_dma_ch); mdev->dma_ch, mdev->num_dma_ch,
true);
if (IS_ERR(mdev->scdev)) { if (IS_ERR(mdev->scdev)) {
rc = PTR_ERR(mdev->scdev); rc = PTR_ERR(mdev->scdev);
goto dma_free; goto dma_free;
} }
rc = mdev->ops->load_mic_fw(mdev, buf);
rc = mdev->ops->load_mic_fw(mdev, NULL);
if (rc) if (rc)
goto scif_remove; goto scif_remove;
mic_smpt_restore(mdev); mic_smpt_restore(mdev);
...@@ -419,7 +396,6 @@ int mic_start(struct mic_device *mdev, const char *buf) ...@@ -419,7 +396,6 @@ int mic_start(struct mic_device *mdev, const char *buf)
mdev->ops->write_spad(mdev, MIC_DPLO_SPAD, mdev->dp_dma_addr); mdev->ops->write_spad(mdev, MIC_DPLO_SPAD, mdev->dp_dma_addr);
mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32); mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32);
mdev->ops->send_firmware_intr(mdev); mdev->ops->send_firmware_intr(mdev);
mic_set_state(mdev, MIC_ONLINE);
goto unlock_ret; goto unlock_ret;
scif_remove: scif_remove:
scif_unregister_device(mdev->scdev); scif_unregister_device(mdev->scdev);
...@@ -428,198 +404,79 @@ int mic_start(struct mic_device *mdev, const char *buf) ...@@ -428,198 +404,79 @@ int mic_start(struct mic_device *mdev, const char *buf)
dma_remove: dma_remove:
mbus_unregister_device(mdev->dma_mbdev); mbus_unregister_device(mdev->dma_mbdev);
unlock_ret: unlock_ret:
mutex_unlock(&mdev->mic_mutex);
return rc; return rc;
} }
/** /**
* mic_stop - Prepare the MIC for reset and trigger reset. * _mic_stop - Prepare the MIC for reset and trigger reset.
* @mdev: pointer to mic_device instance * @cdev: pointer to cosm_device instance
* @force: force a MIC to reset even if it is already offline. * @force: force a MIC to reset even if it is already offline.
* *
* RETURNS: None. * RETURNS: None.
*/ */
void mic_stop(struct mic_device *mdev, bool force) static void _mic_stop(struct cosm_device *cdev, bool force)
{ {
mutex_lock(&mdev->mic_mutex); struct mic_device *mdev = cosmdev_to_mdev(cdev);
if (MIC_OFFLINE != mdev->state || force) {
scif_unregister_device(mdev->scdev); /*
* Since SCIF handles card shutdown and reset (using COSM), it will
* will be the first to be registered and the last to be
* unregistered.
*/
mic_virtio_reset_devices(mdev); mic_virtio_reset_devices(mdev);
scif_unregister_device(mdev->scdev);
mic_free_dma_chans(mdev); mic_free_dma_chans(mdev);
mbus_unregister_device(mdev->dma_mbdev); mbus_unregister_device(mdev->dma_mbdev);
mic_bootparam_init(mdev); mic_bootparam_init(mdev);
mic_reset(mdev);
if (MIC_RESET_FAILED == mdev->state)
goto unlock;
mic_set_shutdown_status(mdev, MIC_NOP);
if (MIC_SUSPENDED != mdev->state)
mic_set_state(mdev, MIC_OFFLINE);
}
unlock:
mutex_unlock(&mdev->mic_mutex);
}
/**
* mic_shutdown - Initiate MIC shutdown.
* @mdev: pointer to mic_device instance
*
* RETURNS: None.
*/
void mic_shutdown(struct mic_device *mdev)
{
struct mic_bootparam *bootparam = mdev->dp;
s8 db = bootparam->h2c_shutdown_db;
mutex_lock(&mdev->mic_mutex);
if (MIC_ONLINE == mdev->state && db != -1) {
bootparam->shutdown_card = 1;
mdev->ops->send_intr(mdev, db);
mic_set_state(mdev, MIC_SHUTTING_DOWN);
}
mutex_unlock(&mdev->mic_mutex);
} }
/** static ssize_t _mic_family(struct cosm_device *cdev, char *buf)
* mic_shutdown_work - Handle shutdown interrupt from MIC.
* @work: The work structure.
*
* This work is scheduled whenever the host has received a shutdown
* interrupt from the MIC.
*/
void mic_shutdown_work(struct work_struct *work)
{ {
struct mic_device *mdev = container_of(work, struct mic_device, struct mic_device *mdev = cosmdev_to_mdev(cdev);
shutdown_work); static const char *family[MIC_FAMILY_LAST] = { "x100", "Unknown" };
struct mic_bootparam *bootparam = mdev->dp;
mutex_lock(&mdev->mic_mutex);
mic_set_shutdown_status(mdev, bootparam->shutdown_status);
bootparam->shutdown_status = 0;
/* return scnprintf(buf, PAGE_SIZE, "%s\n", family[mdev->family]);
* if state is MIC_SUSPENDED, OSPM suspend is in progress. We do not
* change the state here so as to prevent users from booting the card
* during and after the suspend operation.
*/
if (MIC_SHUTTING_DOWN != mdev->state &&
MIC_SUSPENDED != mdev->state)
mic_set_state(mdev, MIC_SHUTTING_DOWN);
mutex_unlock(&mdev->mic_mutex);
} }
/** static ssize_t _mic_stepping(struct cosm_device *cdev, char *buf)
* mic_reset_trigger_work - Trigger MIC reset.
* @work: The work structure.
*
* This work is scheduled whenever the host wants to reset the MIC.
*/
void mic_reset_trigger_work(struct work_struct *work)
{ {
struct mic_device *mdev = container_of(work, struct mic_device, struct mic_device *mdev = cosmdev_to_mdev(cdev);
reset_trigger_work); const char *string = "??";
mic_stop(mdev, false);
}
/**
* mic_complete_resume - Complete MIC Resume after an OSPM suspend/hibernate
* event.
* @mdev: pointer to mic_device instance
*
* RETURNS: None.
*/
void mic_complete_resume(struct mic_device *mdev)
{
if (mdev->state != MIC_SUSPENDED) {
dev_warn(mdev->sdev->parent, "state %d should be %d\n",
mdev->state, MIC_SUSPENDED);
return;
}
/* Make sure firmware is ready */
if (!mdev->ops->is_fw_ready(mdev))
mic_stop(mdev, true);
mutex_lock(&mdev->mic_mutex);
mic_set_state(mdev, MIC_OFFLINE);
mutex_unlock(&mdev->mic_mutex);
}
/** switch (mdev->stepping) {
* mic_prepare_suspend - Handle suspend notification for the MIC device. case MIC_A0_STEP:
* @mdev: pointer to mic_device instance string = "A0";
*
* RETURNS: None.
*/
void mic_prepare_suspend(struct mic_device *mdev)
{
unsigned long timeout;
#define MIC_SUSPEND_TIMEOUT (60 * HZ)
mutex_lock(&mdev->mic_mutex);
switch (mdev->state) {
case MIC_OFFLINE:
/*
* Card is already offline. Set state to MIC_SUSPENDED
* to prevent users from booting the card.
*/
mic_set_state(mdev, MIC_SUSPENDED);
mutex_unlock(&mdev->mic_mutex);
break; break;
case MIC_ONLINE: case MIC_B0_STEP:
/* string = "B0";
* Card is online. Set state to MIC_SUSPENDING and notify
* MIC user space daemon which will issue card
* shutdown and reset.
*/
mic_set_state(mdev, MIC_SUSPENDING);
mutex_unlock(&mdev->mic_mutex);
timeout = wait_for_completion_timeout(&mdev->reset_wait,
MIC_SUSPEND_TIMEOUT);
/* Force reset the card if the shutdown completion timed out */
if (!timeout) {
mutex_lock(&mdev->mic_mutex);
mic_set_state(mdev, MIC_SUSPENDED);
mutex_unlock(&mdev->mic_mutex);
mic_stop(mdev, true);
}
break; break;
case MIC_SHUTTING_DOWN: case MIC_B1_STEP:
/* string = "B1";
* Card is shutting down. Set state to MIC_SUSPENDED break;
* to prevent further boot of the card. case MIC_C0_STEP:
*/ string = "C0";
mic_set_state(mdev, MIC_SUSPENDED);
mutex_unlock(&mdev->mic_mutex);
timeout = wait_for_completion_timeout(&mdev->reset_wait,
MIC_SUSPEND_TIMEOUT);
/* Force reset the card if the shutdown completion timed out */
if (!timeout)
mic_stop(mdev, true);
break; break;
default: default:
mutex_unlock(&mdev->mic_mutex);
break; break;
} }
return scnprintf(buf, PAGE_SIZE, "%s\n", string);
} }
/** static struct mic_mw *_mic_aper(struct cosm_device *cdev)
* mic_suspend - Initiate MIC suspend. Suspend merely issues card shutdown.
* @mdev: pointer to mic_device instance
*
* RETURNS: None.
*/
void mic_suspend(struct mic_device *mdev)
{ {
struct mic_bootparam *bootparam = mdev->dp; struct mic_device *mdev = cosmdev_to_mdev(cdev);
s8 db = bootparam->h2c_shutdown_db;
mutex_lock(&mdev->mic_mutex); return &mdev->aper;
if (MIC_SUSPENDING == mdev->state && db != -1) {
bootparam->shutdown_card = 1;
mdev->ops->send_intr(mdev, db);
mic_set_state(mdev, MIC_SUSPENDED);
}
mutex_unlock(&mdev->mic_mutex);
} }
struct cosm_hw_ops cosm_hw_ops = {
.reset = _mic_reset,
.force_reset = _mic_reset,
.post_reset = NULL,
.ready = _mic_ready,
.start = _mic_start,
.stop = _mic_stop,
.family = _mic_family,
.stepping = _mic_stepping,
.aper = _mic_aper,
};
...@@ -31,71 +31,6 @@ ...@@ -31,71 +31,6 @@
/* Debugfs parent dir */ /* Debugfs parent dir */
static struct dentry *mic_dbg; static struct dentry *mic_dbg;
/**
* mic_log_buf_show - Display MIC kernel log buffer.
*
* log_buf addr/len is read from System.map by user space
* and populated in sysfs entries.
*/
static int mic_log_buf_show(struct seq_file *s, void *unused)
{
void __iomem *log_buf_va;
int __iomem *log_buf_len_va;
struct mic_device *mdev = s->private;
void *kva;
int size;
unsigned long aper_offset;
if (!mdev || !mdev->log_buf_addr || !mdev->log_buf_len)
goto done;
/*
* Card kernel will never be relocated and any kernel text/data mapping
* can be translated to phys address by subtracting __START_KERNEL_map.
*/
aper_offset = (unsigned long)mdev->log_buf_len - __START_KERNEL_map;
log_buf_len_va = mdev->aper.va + aper_offset;
aper_offset = (unsigned long)mdev->log_buf_addr - __START_KERNEL_map;
log_buf_va = mdev->aper.va + aper_offset;
size = ioread32(log_buf_len_va);
kva = kmalloc(size, GFP_KERNEL);
if (!kva)
goto done;
mutex_lock(&mdev->mic_mutex);
memcpy_fromio(kva, log_buf_va, size);
switch (mdev->state) {
case MIC_ONLINE:
/* Fall through */
case MIC_SHUTTING_DOWN:
seq_write(s, kva, size);
break;
default:
break;
}
mutex_unlock(&mdev->mic_mutex);
kfree(kva);
done:
return 0;
}
static int mic_log_buf_open(struct inode *inode, struct file *file)
{
return single_open(file, mic_log_buf_show, inode->i_private);
}
static int mic_log_buf_release(struct inode *inode, struct file *file)
{
return single_release(inode, file);
}
static const struct file_operations log_buf_ops = {
.owner = THIS_MODULE,
.open = mic_log_buf_open,
.read = seq_read,
.llseek = seq_lseek,
.release = mic_log_buf_release
};
static int mic_smpt_show(struct seq_file *s, void *pos) static int mic_smpt_show(struct seq_file *s, void *pos)
{ {
int i; int i;
...@@ -138,32 +73,6 @@ static const struct file_operations smpt_file_ops = { ...@@ -138,32 +73,6 @@ static const struct file_operations smpt_file_ops = {
.release = mic_smpt_debug_release .release = mic_smpt_debug_release
}; };
static int mic_soft_reset_show(struct seq_file *s, void *pos)
{
struct mic_device *mdev = s->private;
mic_stop(mdev, true);
return 0;
}
static int mic_soft_reset_debug_open(struct inode *inode, struct file *file)
{
return single_open(file, mic_soft_reset_show, inode->i_private);
}
static int mic_soft_reset_debug_release(struct inode *inode, struct file *file)
{
return single_release(inode, file);
}
static const struct file_operations soft_reset_ops = {
.owner = THIS_MODULE,
.open = mic_soft_reset_debug_open,
.read = seq_read,
.llseek = seq_lseek,
.release = mic_soft_reset_debug_release
};
static int mic_post_code_show(struct seq_file *s, void *pos) static int mic_post_code_show(struct seq_file *s, void *pos)
{ {
struct mic_device *mdev = s->private; struct mic_device *mdev = s->private;
...@@ -204,18 +113,8 @@ static int mic_dp_show(struct seq_file *s, void *pos) ...@@ -204,18 +113,8 @@ static int mic_dp_show(struct seq_file *s, void *pos)
seq_printf(s, "Bootparam: magic 0x%x\n", seq_printf(s, "Bootparam: magic 0x%x\n",
bootparam->magic); bootparam->magic);
seq_printf(s, "Bootparam: h2c_shutdown_db %d\n",
bootparam->h2c_shutdown_db);
seq_printf(s, "Bootparam: h2c_config_db %d\n", seq_printf(s, "Bootparam: h2c_config_db %d\n",
bootparam->h2c_config_db); bootparam->h2c_config_db);
seq_printf(s, "Bootparam: c2h_shutdown_db %d\n",
bootparam->c2h_shutdown_db);
seq_printf(s, "Bootparam: shutdown_status %d\n",
bootparam->shutdown_status);
seq_printf(s, "Bootparam: shutdown_card %d\n",
bootparam->shutdown_card);
seq_printf(s, "Bootparam: tot_nodes %d\n",
bootparam->tot_nodes);
seq_printf(s, "Bootparam: node_id %d\n", seq_printf(s, "Bootparam: node_id %d\n",
bootparam->node_id); bootparam->node_id);
seq_printf(s, "Bootparam: c2h_scif_db %d\n", seq_printf(s, "Bootparam: c2h_scif_db %d\n",
...@@ -392,8 +291,7 @@ static int mic_msi_irq_info_show(struct seq_file *s, void *pos) ...@@ -392,8 +291,7 @@ static int mic_msi_irq_info_show(struct seq_file *s, void *pos)
int i, j; int i, j;
u16 entry; u16 entry;
u16 vector; u16 vector;
struct pci_dev *pdev = container_of(mdev->sdev->parent, struct pci_dev *pdev = mdev->pdev;
struct pci_dev, dev);
if (pci_dev_msi_enabled(pdev)) { if (pci_dev_msi_enabled(pdev)) {
for (i = 0; i < mdev->irq_info.num_vectors; i++) { for (i = 0; i < mdev->irq_info.num_vectors; i++) {
...@@ -454,20 +352,18 @@ static const struct file_operations msi_irq_info_ops = { ...@@ -454,20 +352,18 @@ static const struct file_operations msi_irq_info_ops = {
*/ */
void mic_create_debug_dir(struct mic_device *mdev) void mic_create_debug_dir(struct mic_device *mdev)
{ {
char name[16];
if (!mic_dbg) if (!mic_dbg)
return; return;
mdev->dbg_dir = debugfs_create_dir(dev_name(mdev->sdev), mic_dbg); scnprintf(name, sizeof(name), "mic%d", mdev->id);
mdev->dbg_dir = debugfs_create_dir(name, mic_dbg);
if (!mdev->dbg_dir) if (!mdev->dbg_dir)
return; return;
debugfs_create_file("log_buf", 0444, mdev->dbg_dir, mdev, &log_buf_ops);
debugfs_create_file("smpt", 0444, mdev->dbg_dir, mdev, &smpt_file_ops); debugfs_create_file("smpt", 0444, mdev->dbg_dir, mdev, &smpt_file_ops);
debugfs_create_file("soft_reset", 0444, mdev->dbg_dir, mdev,
&soft_reset_ops);
debugfs_create_file("post_code", 0444, mdev->dbg_dir, mdev, debugfs_create_file("post_code", 0444, mdev->dbg_dir, mdev,
&post_code_ops); &post_code_ops);
......
...@@ -26,21 +26,12 @@ ...@@ -26,21 +26,12 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/irqreturn.h> #include <linux/irqreturn.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/miscdevice.h>
#include <linux/mic_bus.h> #include <linux/mic_bus.h>
#include "../bus/scif_bus.h" #include "../bus/scif_bus.h"
#include "../bus/cosm_bus.h"
#include "mic_intr.h" #include "mic_intr.h"
/* The maximum number of MIC devices supported in a single host system. */
#define MIC_MAX_NUM_DEVS 256
/**
* enum mic_hw_family - The hardware family to which a device belongs.
*/
enum mic_hw_family {
MIC_FAMILY_X100 = 0,
MIC_FAMILY_UNKNOWN
};
/** /**
* enum mic_stepping - MIC stepping ids. * enum mic_stepping - MIC stepping ids.
*/ */
...@@ -51,6 +42,8 @@ enum mic_stepping { ...@@ -51,6 +42,8 @@ enum mic_stepping {
MIC_C0_STEP = 0x20, MIC_C0_STEP = 0x20,
}; };
extern struct cosm_hw_ops cosm_hw_ops;
/** /**
* struct mic_device - MIC device information for each card. * struct mic_device - MIC device information for each card.
* *
...@@ -60,8 +53,7 @@ enum mic_stepping { ...@@ -60,8 +53,7 @@ enum mic_stepping {
* @ops: MIC HW specific operations. * @ops: MIC HW specific operations.
* @id: The unique device id for this MIC device. * @id: The unique device id for this MIC device.
* @stepping: Stepping ID. * @stepping: Stepping ID.
* @attr_group: Pointer to list of sysfs attribute groups. * @pdev: Underlying PCI device.
* @sdev: Device for sysfs entries.
* @mic_mutex: Mutex for synchronizing access to mic_device. * @mic_mutex: Mutex for synchronizing access to mic_device.
* @intr_ops: HW specific interrupt operations. * @intr_ops: HW specific interrupt operations.
* @smpt_ops: Hardware specific SMPT operations. * @smpt_ops: Hardware specific SMPT operations.
...@@ -69,30 +61,17 @@ enum mic_stepping { ...@@ -69,30 +61,17 @@ enum mic_stepping {
* @intr_info: H/W specific interrupt information. * @intr_info: H/W specific interrupt information.
* @irq_info: The OS specific irq information * @irq_info: The OS specific irq information
* @dbg_dir: debugfs directory of this MIC device. * @dbg_dir: debugfs directory of this MIC device.
* @cmdline: Kernel command line.
* @firmware: Firmware file name.
* @ramdisk: Ramdisk file name.
* @bootmode: Boot mode i.e. "linux" or "elf" for flash updates.
* @bootaddr: MIC boot address. * @bootaddr: MIC boot address.
* @reset_trigger_work: Work for triggering reset requests.
* @shutdown_work: Work for handling shutdown interrupts.
* @state: MIC state.
* @shutdown_status: MIC status reported by card for shutdown/crashes.
* @state_sysfs: Sysfs dirent for notifying ring 3 about MIC state changes.
* @reset_wait: Waitqueue for sleeping while reset completes.
* @log_buf_addr: Log buffer address for MIC.
* @log_buf_len: Log buffer length address for MIC.
* @dp: virtio device page * @dp: virtio device page
* @dp_dma_addr: virtio device page DMA address. * @dp_dma_addr: virtio device page DMA address.
* @shutdown_db: shutdown doorbell. * @name: name for the misc char device
* @shutdown_cookie: shutdown cookie. * @miscdev: registered misc char device
* @cdev: Character device for MIC.
* @vdev_list: list of virtio devices. * @vdev_list: list of virtio devices.
* @pm_notifier: Handles PM notifications from the OS.
* @dma_mbdev: MIC BUS DMA device. * @dma_mbdev: MIC BUS DMA device.
* @dma_ch - Array of DMA channels * @dma_ch - Array of DMA channels
* @num_dma_ch - Number of DMA channels available * @num_dma_ch - Number of DMA channels available
* @scdev: SCIF device on the SCIF virtual bus. * @scdev: SCIF device on the SCIF virtual bus.
* @cosm_dev: COSM device
*/ */
struct mic_device { struct mic_device {
struct mic_mw mmio; struct mic_mw mmio;
...@@ -101,8 +80,7 @@ struct mic_device { ...@@ -101,8 +80,7 @@ struct mic_device {
struct mic_hw_ops *ops; struct mic_hw_ops *ops;
int id; int id;
enum mic_stepping stepping; enum mic_stepping stepping;
const struct attribute_group **attr_group; struct pci_dev *pdev;
struct device *sdev;
struct mutex mic_mutex; struct mutex mic_mutex;
struct mic_hw_intr_ops *intr_ops; struct mic_hw_intr_ops *intr_ops;
struct mic_smpt_ops *smpt_ops; struct mic_smpt_ops *smpt_ops;
...@@ -110,30 +88,17 @@ struct mic_device { ...@@ -110,30 +88,17 @@ struct mic_device {
struct mic_intr_info *intr_info; struct mic_intr_info *intr_info;
struct mic_irq_info irq_info; struct mic_irq_info irq_info;
struct dentry *dbg_dir; struct dentry *dbg_dir;
char *cmdline;
char *firmware;
char *ramdisk;
char *bootmode;
u32 bootaddr; u32 bootaddr;
struct work_struct reset_trigger_work;
struct work_struct shutdown_work;
u8 state;
u8 shutdown_status;
struct kernfs_node *state_sysfs;
struct completion reset_wait;
void *log_buf_addr;
int *log_buf_len;
void *dp; void *dp;
dma_addr_t dp_dma_addr; dma_addr_t dp_dma_addr;
int shutdown_db; char name[16];
struct mic_irq *shutdown_cookie; struct miscdevice miscdev;
struct cdev cdev;
struct list_head vdev_list; struct list_head vdev_list;
struct notifier_block pm_notifier;
struct mbus_device *dma_mbdev; struct mbus_device *dma_mbdev;
struct dma_chan *dma_ch[MIC_MAX_DMA_CHAN]; struct dma_chan *dma_ch[MIC_MAX_DMA_CHAN];
int num_dma_ch; int num_dma_ch;
struct scif_hw_dev *scdev; struct scif_hw_dev *scdev;
struct cosm_device *cosm_dev;
}; };
/** /**
...@@ -199,38 +164,9 @@ mic_mmio_write(struct mic_mw *mw, u32 val, u32 offset) ...@@ -199,38 +164,9 @@ mic_mmio_write(struct mic_mw *mw, u32 val, u32 offset)
iowrite32(val, mw->va + offset); iowrite32(val, mw->va + offset);
} }
static inline struct dma_chan *mic_request_dma_chan(struct mic_device *mdev)
{
dma_cap_mask_t mask;
struct dma_chan *chan;
dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);
chan = dma_request_channel(mask, mdev->ops->dma_filter,
mdev->sdev->parent);
if (chan)
return chan;
dev_err(mdev->sdev->parent, "%s %d unable to acquire channel\n",
__func__, __LINE__);
return NULL;
}
void mic_sysfs_init(struct mic_device *mdev);
int mic_start(struct mic_device *mdev, const char *buf);
void mic_stop(struct mic_device *mdev, bool force);
void mic_shutdown(struct mic_device *mdev);
void mic_reset_delayed_work(struct work_struct *work);
void mic_reset_trigger_work(struct work_struct *work);
void mic_shutdown_work(struct work_struct *work);
void mic_bootparam_init(struct mic_device *mdev); void mic_bootparam_init(struct mic_device *mdev);
void mic_set_state(struct mic_device *mdev, u8 state);
void mic_set_shutdown_status(struct mic_device *mdev, u8 status);
void mic_create_debug_dir(struct mic_device *dev); void mic_create_debug_dir(struct mic_device *dev);
void mic_delete_debug_dir(struct mic_device *dev); void mic_delete_debug_dir(struct mic_device *dev);
void __init mic_init_debugfs(void); void __init mic_init_debugfs(void);
void mic_exit_debugfs(void); void mic_exit_debugfs(void);
void mic_prepare_suspend(struct mic_device *mdev);
void mic_complete_resume(struct mic_device *mdev);
void mic_suspend(struct mic_device *mdev);
extern atomic_t g_num_mics;
#endif #endif
...@@ -30,8 +30,8 @@ ...@@ -30,8 +30,8 @@
int mic_open(struct inode *inode, struct file *f) int mic_open(struct inode *inode, struct file *f)
{ {
struct mic_vdev *mvdev; struct mic_vdev *mvdev;
struct mic_device *mdev = container_of(inode->i_cdev, struct mic_device *mdev = container_of(f->private_data,
struct mic_device, cdev); struct mic_device, miscdev);
mvdev = kzalloc(sizeof(*mvdev), GFP_KERNEL); mvdev = kzalloc(sizeof(*mvdev), GFP_KERNEL);
if (!mvdev) if (!mvdev)
......
...@@ -30,8 +30,7 @@ static irqreturn_t mic_thread_fn(int irq, void *dev) ...@@ -30,8 +30,7 @@ static irqreturn_t mic_thread_fn(int irq, void *dev)
struct mic_intr_info *intr_info = mdev->intr_info; struct mic_intr_info *intr_info = mdev->intr_info;
struct mic_irq_info *irq_info = &mdev->irq_info; struct mic_irq_info *irq_info = &mdev->irq_info;
struct mic_intr_cb *intr_cb; struct mic_intr_cb *intr_cb;
struct pci_dev *pdev = container_of(mdev->sdev->parent, struct pci_dev *pdev = mdev->pdev;
struct pci_dev, dev);
int i; int i;
spin_lock(&irq_info->mic_thread_lock); spin_lock(&irq_info->mic_thread_lock);
...@@ -57,8 +56,7 @@ static irqreturn_t mic_interrupt(int irq, void *dev) ...@@ -57,8 +56,7 @@ static irqreturn_t mic_interrupt(int irq, void *dev)
struct mic_intr_info *intr_info = mdev->intr_info; struct mic_intr_info *intr_info = mdev->intr_info;
struct mic_irq_info *irq_info = &mdev->irq_info; struct mic_irq_info *irq_info = &mdev->irq_info;
struct mic_intr_cb *intr_cb; struct mic_intr_cb *intr_cb;
struct pci_dev *pdev = container_of(mdev->sdev->parent, struct pci_dev *pdev = mdev->pdev;
struct pci_dev, dev);
u32 mask; u32 mask;
int i; int i;
...@@ -229,7 +227,7 @@ static int mic_setup_msix(struct mic_device *mdev, struct pci_dev *pdev) ...@@ -229,7 +227,7 @@ static int mic_setup_msix(struct mic_device *mdev, struct pci_dev *pdev)
goto err_nomem2; goto err_nomem2;
} }
dev_dbg(mdev->sdev->parent, dev_dbg(&mdev->pdev->dev,
"%d MSIx irqs setup\n", mdev->irq_info.num_vectors); "%d MSIx irqs setup\n", mdev->irq_info.num_vectors);
return 0; return 0;
err_nomem2: err_nomem2:
...@@ -281,7 +279,6 @@ static void mic_release_callbacks(struct mic_device *mdev) ...@@ -281,7 +279,6 @@ static void mic_release_callbacks(struct mic_device *mdev)
spin_lock(&mdev->irq_info.mic_thread_lock); spin_lock(&mdev->irq_info.mic_thread_lock);
spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags);
for (i = 0; i < MIC_NUM_OFFSETS; i++) { for (i = 0; i < MIC_NUM_OFFSETS; i++) {
if (list_empty(&mdev->irq_info.cb_list[i])) if (list_empty(&mdev->irq_info.cb_list[i]))
break; break;
...@@ -443,12 +440,11 @@ mic_request_threaded_irq(struct mic_device *mdev, ...@@ -443,12 +440,11 @@ mic_request_threaded_irq(struct mic_device *mdev,
unsigned long cookie = 0; unsigned long cookie = 0;
u16 entry; u16 entry;
struct mic_intr_cb *intr_cb; struct mic_intr_cb *intr_cb;
struct pci_dev *pdev = container_of(mdev->sdev->parent, struct pci_dev *pdev = mdev->pdev;
struct pci_dev, dev);
offset = mic_map_src_to_offset(mdev, intr_src, type); offset = mic_map_src_to_offset(mdev, intr_src, type);
if (offset >= MIC_NUM_OFFSETS) { if (offset >= MIC_NUM_OFFSETS) {
dev_err(mdev->sdev->parent, dev_err(&mdev->pdev->dev,
"Error mapping index %d to a valid source id.\n", "Error mapping index %d to a valid source id.\n",
intr_src); intr_src);
rc = -EINVAL; rc = -EINVAL;
...@@ -458,7 +454,7 @@ mic_request_threaded_irq(struct mic_device *mdev, ...@@ -458,7 +454,7 @@ mic_request_threaded_irq(struct mic_device *mdev,
if (mdev->irq_info.num_vectors > 1) { if (mdev->irq_info.num_vectors > 1) {
msix = mic_get_available_vector(mdev); msix = mic_get_available_vector(mdev);
if (!msix) { if (!msix) {
dev_err(mdev->sdev->parent, dev_err(&mdev->pdev->dev,
"No MSIx vectors available for use.\n"); "No MSIx vectors available for use.\n");
rc = -ENOSPC; rc = -ENOSPC;
goto err; goto err;
...@@ -467,7 +463,7 @@ mic_request_threaded_irq(struct mic_device *mdev, ...@@ -467,7 +463,7 @@ mic_request_threaded_irq(struct mic_device *mdev,
rc = request_threaded_irq(msix->vector, handler, thread_fn, rc = request_threaded_irq(msix->vector, handler, thread_fn,
0, name, data); 0, name, data);
if (rc) { if (rc) {
dev_dbg(mdev->sdev->parent, dev_dbg(&mdev->pdev->dev,
"request irq failed rc = %d\n", rc); "request irq failed rc = %d\n", rc);
goto err; goto err;
} }
...@@ -476,13 +472,13 @@ mic_request_threaded_irq(struct mic_device *mdev, ...@@ -476,13 +472,13 @@ mic_request_threaded_irq(struct mic_device *mdev,
mdev->intr_ops->program_msi_to_src_map(mdev, mdev->intr_ops->program_msi_to_src_map(mdev,
entry, offset, true); entry, offset, true);
cookie = MK_COOKIE(entry, offset); cookie = MK_COOKIE(entry, offset);
dev_dbg(mdev->sdev->parent, "irq: %d assigned for src: %d\n", dev_dbg(&mdev->pdev->dev, "irq: %d assigned for src: %d\n",
msix->vector, intr_src); msix->vector, intr_src);
} else { } else {
intr_cb = mic_register_intr_callback(mdev, offset, handler, intr_cb = mic_register_intr_callback(mdev, offset, handler,
thread_fn, data); thread_fn, data);
if (IS_ERR(intr_cb)) { if (IS_ERR(intr_cb)) {
dev_err(mdev->sdev->parent, dev_err(&mdev->pdev->dev,
"No available callback entries for use\n"); "No available callback entries for use\n");
rc = PTR_ERR(intr_cb); rc = PTR_ERR(intr_cb);
goto err; goto err;
...@@ -495,7 +491,7 @@ mic_request_threaded_irq(struct mic_device *mdev, ...@@ -495,7 +491,7 @@ mic_request_threaded_irq(struct mic_device *mdev,
entry, offset, true); entry, offset, true);
} }
cookie = MK_COOKIE(entry, intr_cb->cb_id); cookie = MK_COOKIE(entry, intr_cb->cb_id);
dev_dbg(mdev->sdev->parent, "callback %d registered for src: %d\n", dev_dbg(&mdev->pdev->dev, "callback %d registered for src: %d\n",
intr_cb->cb_id, intr_src); intr_cb->cb_id, intr_src);
} }
return (struct mic_irq *)cookie; return (struct mic_irq *)cookie;
...@@ -521,14 +517,13 @@ void mic_free_irq(struct mic_device *mdev, ...@@ -521,14 +517,13 @@ void mic_free_irq(struct mic_device *mdev,
u32 entry; u32 entry;
u8 src_id; u8 src_id;
unsigned int irq; unsigned int irq;
struct pci_dev *pdev = container_of(mdev->sdev->parent, struct pci_dev *pdev = mdev->pdev;
struct pci_dev, dev);
entry = GET_ENTRY((unsigned long)cookie); entry = GET_ENTRY((unsigned long)cookie);
offset = GET_OFFSET((unsigned long)cookie); offset = GET_OFFSET((unsigned long)cookie);
if (mdev->irq_info.num_vectors > 1) { if (mdev->irq_info.num_vectors > 1) {
if (entry >= mdev->irq_info.num_vectors) { if (entry >= mdev->irq_info.num_vectors) {
dev_warn(mdev->sdev->parent, dev_warn(&mdev->pdev->dev,
"entry %d should be < num_irq %d\n", "entry %d should be < num_irq %d\n",
entry, mdev->irq_info.num_vectors); entry, mdev->irq_info.num_vectors);
return; return;
...@@ -539,12 +534,12 @@ void mic_free_irq(struct mic_device *mdev, ...@@ -539,12 +534,12 @@ void mic_free_irq(struct mic_device *mdev,
mdev->intr_ops->program_msi_to_src_map(mdev, mdev->intr_ops->program_msi_to_src_map(mdev,
entry, offset, false); entry, offset, false);
dev_dbg(mdev->sdev->parent, "irq: %d freed\n", irq); dev_dbg(&mdev->pdev->dev, "irq: %d freed\n", irq);
} else { } else {
irq = pdev->irq; irq = pdev->irq;
src_id = mic_unregister_intr_callback(mdev, offset); src_id = mic_unregister_intr_callback(mdev, offset);
if (src_id >= MIC_NUM_OFFSETS) { if (src_id >= MIC_NUM_OFFSETS) {
dev_warn(mdev->sdev->parent, "Error unregistering callback\n"); dev_warn(&mdev->pdev->dev, "Error unregistering callback\n");
return; return;
} }
if (pci_dev_msi_enabled(pdev)) { if (pci_dev_msi_enabled(pdev)) {
...@@ -552,7 +547,7 @@ void mic_free_irq(struct mic_device *mdev, ...@@ -552,7 +547,7 @@ void mic_free_irq(struct mic_device *mdev,
mdev->intr_ops->program_msi_to_src_map(mdev, mdev->intr_ops->program_msi_to_src_map(mdev,
entry, src_id, false); entry, src_id, false);
} }
dev_dbg(mdev->sdev->parent, "callback %d unregistered for src: %d\n", dev_dbg(&mdev->pdev->dev, "callback %d unregistered for src: %d\n",
offset, src_id); offset, src_id);
} }
} }
...@@ -579,7 +574,7 @@ int mic_setup_interrupts(struct mic_device *mdev, struct pci_dev *pdev) ...@@ -579,7 +574,7 @@ int mic_setup_interrupts(struct mic_device *mdev, struct pci_dev *pdev)
rc = mic_setup_intx(mdev, pdev); rc = mic_setup_intx(mdev, pdev);
if (rc) { if (rc) {
dev_err(mdev->sdev->parent, "no usable interrupts\n"); dev_err(&mdev->pdev->dev, "no usable interrupts\n");
return rc; return rc;
} }
done: done:
...@@ -635,8 +630,7 @@ void mic_free_interrupts(struct mic_device *mdev, struct pci_dev *pdev) ...@@ -635,8 +630,7 @@ void mic_free_interrupts(struct mic_device *mdev, struct pci_dev *pdev)
void mic_intr_restore(struct mic_device *mdev) void mic_intr_restore(struct mic_device *mdev)
{ {
int entry, offset; int entry, offset;
struct pci_dev *pdev = container_of(mdev->sdev->parent, struct pci_dev *pdev = mdev->pdev;
struct pci_dev, dev);
if (!pci_dev_msi_enabled(pdev)) if (!pci_dev_msi_enabled(pdev))
return; return;
......
...@@ -16,17 +16,11 @@ ...@@ -16,17 +16,11 @@
* the file called "COPYING". * the file called "COPYING".
* *
* Intel MIC Host driver. * Intel MIC Host driver.
*
* Global TODO's across the driver to be added after initial base
* patches are accepted upstream:
* 1) Enable DMA support.
* 2) Enable per vring interrupt support.
*/ */
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/suspend.h>
#include <linux/mic_common.h> #include <linux/mic_common.h>
#include "../common/mic_dev.h" #include "../common/mic_dev.h"
...@@ -63,12 +57,8 @@ MODULE_DEVICE_TABLE(pci, mic_pci_tbl); ...@@ -63,12 +57,8 @@ MODULE_DEVICE_TABLE(pci, mic_pci_tbl);
/* ID allocator for MIC devices */ /* ID allocator for MIC devices */
static struct ida g_mic_ida; static struct ida g_mic_ida;
/* Class of MIC devices for sysfs accessibility. */
static struct class *g_mic_class;
/* Base device node number for MIC devices */ /* Base device node number for MIC devices */
static dev_t g_mic_devno; static dev_t g_mic_devno;
/* Track the total number of MIC devices */
atomic_t g_num_mics;
static const struct file_operations mic_fops = { static const struct file_operations mic_fops = {
.open = mic_open, .open = mic_open,
...@@ -83,17 +73,14 @@ static const struct file_operations mic_fops = { ...@@ -83,17 +73,14 @@ static const struct file_operations mic_fops = {
static int mic_dp_init(struct mic_device *mdev) static int mic_dp_init(struct mic_device *mdev)
{ {
mdev->dp = kzalloc(MIC_DP_SIZE, GFP_KERNEL); mdev->dp = kzalloc(MIC_DP_SIZE, GFP_KERNEL);
if (!mdev->dp) { if (!mdev->dp)
dev_err(mdev->sdev->parent, "%s %d err %d\n",
__func__, __LINE__, -ENOMEM);
return -ENOMEM; return -ENOMEM;
}
mdev->dp_dma_addr = mic_map_single(mdev, mdev->dp_dma_addr = mic_map_single(mdev,
mdev->dp, MIC_DP_SIZE); mdev->dp, MIC_DP_SIZE);
if (mic_map_error(mdev->dp_dma_addr)) { if (mic_map_error(mdev->dp_dma_addr)) {
kfree(mdev->dp); kfree(mdev->dp);
dev_err(mdev->sdev->parent, "%s %d err %d\n", dev_err(&mdev->pdev->dev, "%s %d err %d\n",
__func__, __LINE__, -ENOMEM); __func__, __LINE__, -ENOMEM);
return -ENOMEM; return -ENOMEM;
} }
...@@ -109,30 +96,6 @@ static void mic_dp_uninit(struct mic_device *mdev) ...@@ -109,30 +96,6 @@ static void mic_dp_uninit(struct mic_device *mdev)
kfree(mdev->dp); kfree(mdev->dp);
} }
/**
* mic_shutdown_db - Shutdown doorbell interrupt handler.
*/
static irqreturn_t mic_shutdown_db(int irq, void *data)
{
struct mic_device *mdev = data;
struct mic_bootparam *bootparam = mdev->dp;
mdev->ops->intr_workarounds(mdev);
switch (bootparam->shutdown_status) {
case MIC_HALTED:
case MIC_POWER_OFF:
case MIC_RESTART:
/* Fall through */
case MIC_CRASHED:
schedule_work(&mdev->shutdown_work);
break;
default:
break;
};
return IRQ_HANDLED;
}
/** /**
* mic_ops_init: Initialize HW specific operation tables. * mic_ops_init: Initialize HW specific operation tables.
* *
...@@ -189,43 +152,6 @@ static enum mic_hw_family mic_get_family(struct pci_dev *pdev) ...@@ -189,43 +152,6 @@ static enum mic_hw_family mic_get_family(struct pci_dev *pdev)
return family; return family;
} }
/**
* mic_pm_notifier: Notifier callback function that handles
* PM notifications.
*
* @notifier_block: The notifier structure.
* @pm_event: The event for which the driver was notified.
* @unused: Meaningless. Always NULL.
*
* returns NOTIFY_DONE
*/
static int mic_pm_notifier(struct notifier_block *notifier,
unsigned long pm_event, void *unused)
{
struct mic_device *mdev = container_of(notifier,
struct mic_device, pm_notifier);
switch (pm_event) {
case PM_HIBERNATION_PREPARE:
/* Fall through */
case PM_SUSPEND_PREPARE:
mic_prepare_suspend(mdev);
break;
case PM_POST_HIBERNATION:
/* Fall through */
case PM_POST_SUSPEND:
/* Fall through */
case PM_POST_RESTORE:
mic_complete_resume(mdev);
break;
case PM_RESTORE_PREPARE:
break;
default:
break;
}
return NOTIFY_DONE;
}
/** /**
* mic_device_init - Allocates and initializes the MIC device structure * mic_device_init - Allocates and initializes the MIC device structure
* *
...@@ -234,52 +160,16 @@ static int mic_pm_notifier(struct notifier_block *notifier, ...@@ -234,52 +160,16 @@ static int mic_pm_notifier(struct notifier_block *notifier,
* *
* returns none. * returns none.
*/ */
static int static void
mic_device_init(struct mic_device *mdev, struct pci_dev *pdev) mic_device_init(struct mic_device *mdev, struct pci_dev *pdev)
{ {
int rc; mdev->pdev = pdev;
mdev->family = mic_get_family(pdev); mdev->family = mic_get_family(pdev);
mdev->stepping = pdev->revision; mdev->stepping = pdev->revision;
mic_ops_init(mdev); mic_ops_init(mdev);
mic_sysfs_init(mdev);
mutex_init(&mdev->mic_mutex); mutex_init(&mdev->mic_mutex);
mdev->irq_info.next_avail_src = 0; mdev->irq_info.next_avail_src = 0;
INIT_WORK(&mdev->reset_trigger_work, mic_reset_trigger_work);
INIT_WORK(&mdev->shutdown_work, mic_shutdown_work);
init_completion(&mdev->reset_wait);
INIT_LIST_HEAD(&mdev->vdev_list); INIT_LIST_HEAD(&mdev->vdev_list);
mdev->pm_notifier.notifier_call = mic_pm_notifier;
rc = register_pm_notifier(&mdev->pm_notifier);
if (rc) {
dev_err(&pdev->dev, "register_pm_notifier failed rc %d\n",
rc);
goto register_pm_notifier_fail;
}
return 0;
register_pm_notifier_fail:
flush_work(&mdev->shutdown_work);
flush_work(&mdev->reset_trigger_work);
return rc;
}
/**
* mic_device_uninit - Frees resources allocated during mic_device_init(..)
*
* @mdev: pointer to mic_device instance
*
* returns none
*/
static void mic_device_uninit(struct mic_device *mdev)
{
/* The cmdline sysfs entry might have allocated cmdline */
kfree(mdev->cmdline);
kfree(mdev->firmware);
kfree(mdev->ramdisk);
kfree(mdev->bootmode);
flush_work(&mdev->reset_trigger_work);
flush_work(&mdev->shutdown_work);
unregister_pm_notifier(&mdev->pm_notifier);
} }
/** /**
...@@ -309,16 +199,12 @@ static int mic_probe(struct pci_dev *pdev, ...@@ -309,16 +199,12 @@ static int mic_probe(struct pci_dev *pdev,
goto ida_fail; goto ida_fail;
} }
rc = mic_device_init(mdev, pdev); mic_device_init(mdev, pdev);
if (rc) {
dev_err(&pdev->dev, "mic_device_init failed rc %d\n", rc);
goto device_init_fail;
}
rc = pci_enable_device(pdev); rc = pci_enable_device(pdev);
if (rc) { if (rc) {
dev_err(&pdev->dev, "failed to enable pci device.\n"); dev_err(&pdev->dev, "failed to enable pci device.\n");
goto uninit_device; goto ida_remove;
} }
pci_set_master(pdev); pci_set_master(pdev);
...@@ -367,62 +253,39 @@ static int mic_probe(struct pci_dev *pdev, ...@@ -367,62 +253,39 @@ static int mic_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, mdev); pci_set_drvdata(pdev, mdev);
mdev->sdev = device_create_with_groups(g_mic_class, &pdev->dev,
MKDEV(MAJOR(g_mic_devno), mdev->id), NULL,
mdev->attr_group, "mic%d", mdev->id);
if (IS_ERR(mdev->sdev)) {
rc = PTR_ERR(mdev->sdev);
dev_err(&pdev->dev,
"device_create_with_groups failed rc %d\n", rc);
goto smpt_uninit;
}
mdev->state_sysfs = sysfs_get_dirent(mdev->sdev->kobj.sd, "state");
if (!mdev->state_sysfs) {
rc = -ENODEV;
dev_err(&pdev->dev, "sysfs_get_dirent failed rc %d\n", rc);
goto destroy_device;
}
rc = mic_dp_init(mdev); rc = mic_dp_init(mdev);
if (rc) { if (rc) {
dev_err(&pdev->dev, "mic_dp_init failed rc %d\n", rc); dev_err(&pdev->dev, "mic_dp_init failed rc %d\n", rc);
goto sysfs_put; goto smpt_uninit;
}
mutex_lock(&mdev->mic_mutex);
mdev->shutdown_db = mic_next_db(mdev);
mdev->shutdown_cookie = mic_request_threaded_irq(mdev, mic_shutdown_db,
NULL, "shutdown-interrupt", mdev,
mdev->shutdown_db, MIC_INTR_DB);
if (IS_ERR(mdev->shutdown_cookie)) {
rc = PTR_ERR(mdev->shutdown_cookie);
mutex_unlock(&mdev->mic_mutex);
goto dp_uninit;
} }
mutex_unlock(&mdev->mic_mutex);
mic_bootparam_init(mdev); mic_bootparam_init(mdev);
mic_create_debug_dir(mdev); mic_create_debug_dir(mdev);
cdev_init(&mdev->cdev, &mic_fops);
mdev->cdev.owner = THIS_MODULE; mdev->miscdev.minor = MISC_DYNAMIC_MINOR;
rc = cdev_add(&mdev->cdev, MKDEV(MAJOR(g_mic_devno), mdev->id), 1); snprintf(mdev->name, sizeof(mdev->name), "mic%d", mdev->id);
mdev->miscdev.name = mdev->name;
mdev->miscdev.fops = &mic_fops;
mdev->miscdev.parent = &mdev->pdev->dev;
rc = misc_register(&mdev->miscdev);
if (rc) { if (rc) {
dev_err(&pdev->dev, "cdev_add err id %d rc %d\n", mdev->id, rc); dev_err(&pdev->dev, "misc_register err id %d rc %d\n",
mdev->id, rc);
goto cleanup_debug_dir; goto cleanup_debug_dir;
} }
atomic_inc(&g_num_mics);
mdev->cosm_dev = cosm_register_device(&mdev->pdev->dev, &cosm_hw_ops);
if (IS_ERR(mdev->cosm_dev)) {
rc = PTR_ERR(mdev->cosm_dev);
dev_err(&pdev->dev, "cosm_add_device failed rc %d\n", rc);
goto misc_dereg;
}
return 0; return 0;
misc_dereg:
misc_deregister(&mdev->miscdev);
cleanup_debug_dir: cleanup_debug_dir:
mic_delete_debug_dir(mdev); mic_delete_debug_dir(mdev);
mutex_lock(&mdev->mic_mutex);
mic_free_irq(mdev, mdev->shutdown_cookie, mdev);
mutex_unlock(&mdev->mic_mutex);
dp_uninit:
mic_dp_uninit(mdev); mic_dp_uninit(mdev);
sysfs_put:
sysfs_put(mdev->state_sysfs);
destroy_device:
device_destroy(g_mic_class, MKDEV(MAJOR(g_mic_devno), mdev->id));
smpt_uninit: smpt_uninit:
mic_smpt_uninit(mdev); mic_smpt_uninit(mdev);
free_interrupts: free_interrupts:
...@@ -435,9 +298,7 @@ static int mic_probe(struct pci_dev *pdev, ...@@ -435,9 +298,7 @@ static int mic_probe(struct pci_dev *pdev,
pci_release_regions(pdev); pci_release_regions(pdev);
disable_device: disable_device:
pci_disable_device(pdev); pci_disable_device(pdev);
uninit_device: ida_remove:
mic_device_uninit(mdev);
device_init_fail:
ida_simple_remove(&g_mic_ida, mdev->id); ida_simple_remove(&g_mic_ida, mdev->id);
ida_fail: ida_fail:
kfree(mdev); kfree(mdev);
...@@ -461,22 +322,14 @@ static void mic_remove(struct pci_dev *pdev) ...@@ -461,22 +322,14 @@ static void mic_remove(struct pci_dev *pdev)
if (!mdev) if (!mdev)
return; return;
mic_stop(mdev, false); cosm_unregister_device(mdev->cosm_dev);
atomic_dec(&g_num_mics); misc_deregister(&mdev->miscdev);
cdev_del(&mdev->cdev);
mic_delete_debug_dir(mdev); mic_delete_debug_dir(mdev);
mutex_lock(&mdev->mic_mutex);
mic_free_irq(mdev, mdev->shutdown_cookie, mdev);
mutex_unlock(&mdev->mic_mutex);
flush_work(&mdev->shutdown_work);
mic_dp_uninit(mdev); mic_dp_uninit(mdev);
sysfs_put(mdev->state_sysfs);
device_destroy(g_mic_class, MKDEV(MAJOR(g_mic_devno), mdev->id));
mic_smpt_uninit(mdev); mic_smpt_uninit(mdev);
mic_free_interrupts(mdev, pdev); mic_free_interrupts(mdev, pdev);
iounmap(mdev->mmio.va);
iounmap(mdev->aper.va); iounmap(mdev->aper.va);
mic_device_uninit(mdev); iounmap(mdev->mmio.va);
pci_release_regions(pdev); pci_release_regions(pdev);
pci_disable_device(pdev); pci_disable_device(pdev);
ida_simple_remove(&g_mic_ida, mdev->id); ida_simple_remove(&g_mic_ida, mdev->id);
...@@ -501,26 +354,17 @@ static int __init mic_init(void) ...@@ -501,26 +354,17 @@ static int __init mic_init(void)
goto error; goto error;
} }
g_mic_class = class_create(THIS_MODULE, mic_driver_name);
if (IS_ERR(g_mic_class)) {
ret = PTR_ERR(g_mic_class);
pr_err("class_create failed ret %d\n", ret);
goto cleanup_chrdev;
}
mic_init_debugfs(); mic_init_debugfs();
ida_init(&g_mic_ida); ida_init(&g_mic_ida);
ret = pci_register_driver(&mic_driver); ret = pci_register_driver(&mic_driver);
if (ret) { if (ret) {
pr_err("pci_register_driver failed ret %d\n", ret); pr_err("pci_register_driver failed ret %d\n", ret);
goto cleanup_debugfs; goto cleanup_chrdev;
} }
return ret; return ret;
cleanup_debugfs: cleanup_chrdev:
ida_destroy(&g_mic_ida); ida_destroy(&g_mic_ida);
mic_exit_debugfs(); mic_exit_debugfs();
class_destroy(g_mic_class);
cleanup_chrdev:
unregister_chrdev_region(g_mic_devno, MIC_MAX_NUM_DEVS); unregister_chrdev_region(g_mic_devno, MIC_MAX_NUM_DEVS);
error: error:
return ret; return ret;
...@@ -531,7 +375,6 @@ static void __exit mic_exit(void) ...@@ -531,7 +375,6 @@ static void __exit mic_exit(void)
pci_unregister_driver(&mic_driver); pci_unregister_driver(&mic_driver);
ida_destroy(&g_mic_ida); ida_destroy(&g_mic_ida);
mic_exit_debugfs(); mic_exit_debugfs();
class_destroy(g_mic_class);
unregister_chrdev_region(g_mic_devno, MIC_MAX_NUM_DEVS); unregister_chrdev_region(g_mic_devno, MIC_MAX_NUM_DEVS);
} }
......
...@@ -181,7 +181,7 @@ dma_addr_t mic_to_dma_addr(struct mic_device *mdev, dma_addr_t mic_addr) ...@@ -181,7 +181,7 @@ dma_addr_t mic_to_dma_addr(struct mic_device *mdev, dma_addr_t mic_addr)
dma_addr_t dma_addr; dma_addr_t dma_addr;
if (!mic_is_system_addr(mdev, mic_addr)) { if (!mic_is_system_addr(mdev, mic_addr)) {
dev_err(mdev->sdev->parent, dev_err(&mdev->pdev->dev,
"mic_addr is invalid. mic_addr = 0x%llx\n", mic_addr); "mic_addr is invalid. mic_addr = 0x%llx\n", mic_addr);
return -EINVAL; return -EINVAL;
} }
...@@ -231,7 +231,7 @@ dma_addr_t mic_map(struct mic_device *mdev, dma_addr_t dma_addr, size_t size) ...@@ -231,7 +231,7 @@ dma_addr_t mic_map(struct mic_device *mdev, dma_addr_t dma_addr, size_t size)
* else generate mic_addr by adding the 16G offset in dma_addr * else generate mic_addr by adding the 16G offset in dma_addr
*/ */
if (!mic_addr && MIC_FAMILY_X100 == mdev->family) { if (!mic_addr && MIC_FAMILY_X100 == mdev->family) {
dev_err(mdev->sdev->parent, dev_err(&mdev->pdev->dev,
"mic_map failed dma_addr 0x%llx size 0x%lx\n", "mic_map failed dma_addr 0x%llx size 0x%lx\n",
dma_addr, size); dma_addr, size);
return mic_addr; return mic_addr;
...@@ -264,7 +264,7 @@ void mic_unmap(struct mic_device *mdev, dma_addr_t mic_addr, size_t size) ...@@ -264,7 +264,7 @@ void mic_unmap(struct mic_device *mdev, dma_addr_t mic_addr, size_t size)
return; return;
if (!mic_is_system_addr(mdev, mic_addr)) { if (!mic_is_system_addr(mdev, mic_addr)) {
dev_err(mdev->sdev->parent, dev_err(&mdev->pdev->dev,
"invalid address: 0x%llx\n", mic_addr); "invalid address: 0x%llx\n", mic_addr);
return; return;
} }
...@@ -284,7 +284,7 @@ void mic_unmap(struct mic_device *mdev, dma_addr_t mic_addr, size_t size) ...@@ -284,7 +284,7 @@ void mic_unmap(struct mic_device *mdev, dma_addr_t mic_addr, size_t size)
for (i = spt; i < spt + num_smpt; i++) { for (i = spt; i < spt + num_smpt; i++) {
smpt_info->entry[i].ref_count -= ref[i - spt]; smpt_info->entry[i].ref_count -= ref[i - spt];
if (smpt_info->entry[i].ref_count < 0) if (smpt_info->entry[i].ref_count < 0)
dev_warn(mdev->sdev->parent, dev_warn(&mdev->pdev->dev,
"ref count for entry %d is negative\n", i); "ref count for entry %d is negative\n", i);
} }
spin_unlock_irqrestore(&smpt_info->smpt_lock, flags); spin_unlock_irqrestore(&smpt_info->smpt_lock, flags);
...@@ -307,15 +307,14 @@ void mic_unmap(struct mic_device *mdev, dma_addr_t mic_addr, size_t size) ...@@ -307,15 +307,14 @@ void mic_unmap(struct mic_device *mdev, dma_addr_t mic_addr, size_t size)
dma_addr_t mic_map_single(struct mic_device *mdev, void *va, size_t size) dma_addr_t mic_map_single(struct mic_device *mdev, void *va, size_t size)
{ {
dma_addr_t mic_addr = 0; dma_addr_t mic_addr = 0;
struct pci_dev *pdev = container_of(mdev->sdev->parent, struct pci_dev *pdev = mdev->pdev;
struct pci_dev, dev);
dma_addr_t dma_addr = dma_addr_t dma_addr =
pci_map_single(pdev, va, size, PCI_DMA_BIDIRECTIONAL); pci_map_single(pdev, va, size, PCI_DMA_BIDIRECTIONAL);
if (!pci_dma_mapping_error(pdev, dma_addr)) { if (!pci_dma_mapping_error(pdev, dma_addr)) {
mic_addr = mic_map(mdev, dma_addr, size); mic_addr = mic_map(mdev, dma_addr, size);
if (!mic_addr) { if (!mic_addr) {
dev_err(mdev->sdev->parent, dev_err(&mdev->pdev->dev,
"mic_map failed dma_addr 0x%llx size 0x%lx\n", "mic_map failed dma_addr 0x%llx size 0x%lx\n",
dma_addr, size); dma_addr, size);
pci_unmap_single(pdev, dma_addr, pci_unmap_single(pdev, dma_addr,
...@@ -339,8 +338,7 @@ dma_addr_t mic_map_single(struct mic_device *mdev, void *va, size_t size) ...@@ -339,8 +338,7 @@ dma_addr_t mic_map_single(struct mic_device *mdev, void *va, size_t size)
void void
mic_unmap_single(struct mic_device *mdev, dma_addr_t mic_addr, size_t size) mic_unmap_single(struct mic_device *mdev, dma_addr_t mic_addr, size_t size)
{ {
struct pci_dev *pdev = container_of(mdev->sdev->parent, struct pci_dev *pdev = mdev->pdev;
struct pci_dev, dev);
dma_addr_t dma_addr = mic_to_dma_addr(mdev, mic_addr); dma_addr_t dma_addr = mic_to_dma_addr(mdev, mic_addr);
mic_unmap(mdev, mic_addr, size); mic_unmap(mdev, mic_addr, size);
pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL); pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL);
...@@ -399,18 +397,18 @@ void mic_smpt_uninit(struct mic_device *mdev) ...@@ -399,18 +397,18 @@ void mic_smpt_uninit(struct mic_device *mdev)
struct mic_smpt_info *smpt_info = mdev->smpt; struct mic_smpt_info *smpt_info = mdev->smpt;
int i; int i;
dev_dbg(mdev->sdev->parent, dev_dbg(&mdev->pdev->dev,
"nodeid %d SMPT ref count %lld map %lld unmap %lld\n", "nodeid %d SMPT ref count %lld map %lld unmap %lld\n",
mdev->id, smpt_info->ref_count, mdev->id, smpt_info->ref_count,
smpt_info->map_count, smpt_info->unmap_count); smpt_info->map_count, smpt_info->unmap_count);
for (i = 0; i < smpt_info->info.num_reg; i++) { for (i = 0; i < smpt_info->info.num_reg; i++) {
dev_dbg(mdev->sdev->parent, dev_dbg(&mdev->pdev->dev,
"SMPT entry[%d] dma_addr = 0x%llx ref_count = %lld\n", "SMPT entry[%d] dma_addr = 0x%llx ref_count = %lld\n",
i, smpt_info->entry[i].dma_addr, i, smpt_info->entry[i].dma_addr,
smpt_info->entry[i].ref_count); smpt_info->entry[i].ref_count);
if (smpt_info->entry[i].ref_count) if (smpt_info->entry[i].ref_count)
dev_warn(mdev->sdev->parent, dev_warn(&mdev->pdev->dev,
"ref count for entry %d is not zero\n", i); "ref count for entry %d is not zero\n", i);
} }
kfree(smpt_info->entry); kfree(smpt_info->entry);
......
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2013 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Intel MIC Host driver.
*
*/
#include <linux/pci.h>
#include <linux/mic_common.h>
#include "../common/mic_dev.h"
#include "mic_device.h"
/*
* A state-to-string lookup table, for exposing a human readable state
* via sysfs. Always keep in sync with enum mic_states
*/
static const char * const mic_state_string[] = {
[MIC_OFFLINE] = "offline",
[MIC_ONLINE] = "online",
[MIC_SHUTTING_DOWN] = "shutting_down",
[MIC_RESET_FAILED] = "reset_failed",
[MIC_SUSPENDING] = "suspending",
[MIC_SUSPENDED] = "suspended",
};
/*
* A shutdown-status-to-string lookup table, for exposing a human
* readable state via sysfs. Always keep in sync with enum mic_shutdown_status
*/
static const char * const mic_shutdown_status_string[] = {
[MIC_NOP] = "nop",
[MIC_CRASHED] = "crashed",
[MIC_HALTED] = "halted",
[MIC_POWER_OFF] = "poweroff",
[MIC_RESTART] = "restart",
};
void mic_set_shutdown_status(struct mic_device *mdev, u8 shutdown_status)
{
dev_dbg(mdev->sdev->parent, "Shutdown Status %s -> %s\n",
mic_shutdown_status_string[mdev->shutdown_status],
mic_shutdown_status_string[shutdown_status]);
mdev->shutdown_status = shutdown_status;
}
void mic_set_state(struct mic_device *mdev, u8 state)
{
dev_dbg(mdev->sdev->parent, "State %s -> %s\n",
mic_state_string[mdev->state],
mic_state_string[state]);
mdev->state = state;
sysfs_notify_dirent(mdev->state_sysfs);
}
static ssize_t
family_show(struct device *dev, struct device_attribute *attr, char *buf)
{
static const char x100[] = "x100";
static const char unknown[] = "Unknown";
const char *card = NULL;
struct mic_device *mdev = dev_get_drvdata(dev->parent);
if (!mdev)
return -EINVAL;
switch (mdev->family) {
case MIC_FAMILY_X100:
card = x100;
break;
default:
card = unknown;
break;
}
return scnprintf(buf, PAGE_SIZE, "%s\n", card);
}
static DEVICE_ATTR_RO(family);
static ssize_t
stepping_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct mic_device *mdev = dev_get_drvdata(dev->parent);
char *string = "??";
if (!mdev)
return -EINVAL;
switch (mdev->stepping) {
case MIC_A0_STEP:
string = "A0";
break;
case MIC_B0_STEP:
string = "B0";
break;
case MIC_B1_STEP:
string = "B1";
break;
case MIC_C0_STEP:
string = "C0";
break;
default:
break;
}
return scnprintf(buf, PAGE_SIZE, "%s\n", string);
}
static DEVICE_ATTR_RO(stepping);
static ssize_t
state_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct mic_device *mdev = dev_get_drvdata(dev->parent);
if (!mdev || mdev->state >= MIC_LAST)
return -EINVAL;
return scnprintf(buf, PAGE_SIZE, "%s\n",
mic_state_string[mdev->state]);
}
static ssize_t
state_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int rc = 0;
struct mic_device *mdev = dev_get_drvdata(dev->parent);
if (!mdev)
return -EINVAL;
if (sysfs_streq(buf, "boot")) {
rc = mic_start(mdev, buf);
if (rc) {
dev_err(mdev->sdev->parent,
"mic_boot failed rc %d\n", rc);
count = rc;
}
goto done;
}
if (sysfs_streq(buf, "reset")) {
schedule_work(&mdev->reset_trigger_work);
goto done;
}
if (sysfs_streq(buf, "shutdown")) {
mic_shutdown(mdev);
goto done;
}
if (sysfs_streq(buf, "suspend")) {
mic_suspend(mdev);
goto done;
}
count = -EINVAL;
done:
return count;
}
static DEVICE_ATTR_RW(state);
static ssize_t shutdown_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mic_device *mdev = dev_get_drvdata(dev->parent);
if (!mdev || mdev->shutdown_status >= MIC_STATUS_LAST)
return -EINVAL;
return scnprintf(buf, PAGE_SIZE, "%s\n",
mic_shutdown_status_string[mdev->shutdown_status]);
}
static DEVICE_ATTR_RO(shutdown_status);
static ssize_t
cmdline_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct mic_device *mdev = dev_get_drvdata(dev->parent);
char *cmdline;
if (!mdev)
return -EINVAL;
cmdline = mdev->cmdline;
if (cmdline)
return scnprintf(buf, PAGE_SIZE, "%s\n", cmdline);
return 0;
}
static ssize_t
cmdline_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mic_device *mdev = dev_get_drvdata(dev->parent);
if (!mdev)
return -EINVAL;
mutex_lock(&mdev->mic_mutex);
kfree(mdev->cmdline);
mdev->cmdline = kmalloc(count + 1, GFP_KERNEL);
if (!mdev->cmdline) {
count = -ENOMEM;
goto unlock;
}
strncpy(mdev->cmdline, buf, count);
if (mdev->cmdline[count - 1] == '\n')
mdev->cmdline[count - 1] = '\0';
else
mdev->cmdline[count] = '\0';
unlock:
mutex_unlock(&mdev->mic_mutex);
return count;
}
static DEVICE_ATTR_RW(cmdline);
static ssize_t
firmware_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct mic_device *mdev = dev_get_drvdata(dev->parent);
char *firmware;
if (!mdev)
return -EINVAL;
firmware = mdev->firmware;
if (firmware)
return scnprintf(buf, PAGE_SIZE, "%s\n", firmware);
return 0;
}
static ssize_t
firmware_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mic_device *mdev = dev_get_drvdata(dev->parent);
if (!mdev)
return -EINVAL;
mutex_lock(&mdev->mic_mutex);
kfree(mdev->firmware);
mdev->firmware = kmalloc(count + 1, GFP_KERNEL);
if (!mdev->firmware) {
count = -ENOMEM;
goto unlock;
}
strncpy(mdev->firmware, buf, count);
if (mdev->firmware[count - 1] == '\n')
mdev->firmware[count - 1] = '\0';
else
mdev->firmware[count] = '\0';
unlock:
mutex_unlock(&mdev->mic_mutex);
return count;
}
static DEVICE_ATTR_RW(firmware);
static ssize_t
ramdisk_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct mic_device *mdev = dev_get_drvdata(dev->parent);
char *ramdisk;
if (!mdev)
return -EINVAL;
ramdisk = mdev->ramdisk;
if (ramdisk)
return scnprintf(buf, PAGE_SIZE, "%s\n", ramdisk);
return 0;
}
static ssize_t
ramdisk_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mic_device *mdev = dev_get_drvdata(dev->parent);
if (!mdev)
return -EINVAL;
mutex_lock(&mdev->mic_mutex);
kfree(mdev->ramdisk);
mdev->ramdisk = kmalloc(count + 1, GFP_KERNEL);
if (!mdev->ramdisk) {
count = -ENOMEM;
goto unlock;
}
strncpy(mdev->ramdisk, buf, count);
if (mdev->ramdisk[count - 1] == '\n')
mdev->ramdisk[count - 1] = '\0';
else
mdev->ramdisk[count] = '\0';
unlock:
mutex_unlock(&mdev->mic_mutex);
return count;
}
static DEVICE_ATTR_RW(ramdisk);
static ssize_t
bootmode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct mic_device *mdev = dev_get_drvdata(dev->parent);
char *bootmode;
if (!mdev)
return -EINVAL;
bootmode = mdev->bootmode;
if (bootmode)
return scnprintf(buf, PAGE_SIZE, "%s\n", bootmode);
return 0;
}
static ssize_t
bootmode_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mic_device *mdev = dev_get_drvdata(dev->parent);
if (!mdev)
return -EINVAL;
if (!sysfs_streq(buf, "linux") && !sysfs_streq(buf, "elf"))
return -EINVAL;
mutex_lock(&mdev->mic_mutex);
kfree(mdev->bootmode);
mdev->bootmode = kmalloc(count + 1, GFP_KERNEL);
if (!mdev->bootmode) {
count = -ENOMEM;
goto unlock;
}
strncpy(mdev->bootmode, buf, count);
if (mdev->bootmode[count - 1] == '\n')
mdev->bootmode[count - 1] = '\0';
else
mdev->bootmode[count] = '\0';
unlock:
mutex_unlock(&mdev->mic_mutex);
return count;
}
static DEVICE_ATTR_RW(bootmode);
static ssize_t
log_buf_addr_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct mic_device *mdev = dev_get_drvdata(dev->parent);
if (!mdev)
return -EINVAL;
return scnprintf(buf, PAGE_SIZE, "%p\n", mdev->log_buf_addr);
}
static ssize_t
log_buf_addr_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mic_device *mdev = dev_get_drvdata(dev->parent);
int ret;
unsigned long addr;
if (!mdev)
return -EINVAL;
ret = kstrtoul(buf, 16, &addr);
if (ret)
goto exit;
mdev->log_buf_addr = (void *)addr;
ret = count;
exit:
return ret;
}
static DEVICE_ATTR_RW(log_buf_addr);
static ssize_t
log_buf_len_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct mic_device *mdev = dev_get_drvdata(dev->parent);
if (!mdev)
return -EINVAL;
return scnprintf(buf, PAGE_SIZE, "%p\n", mdev->log_buf_len);
}
static ssize_t
log_buf_len_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mic_device *mdev = dev_get_drvdata(dev->parent);
int ret;
unsigned long addr;
if (!mdev)
return -EINVAL;
ret = kstrtoul(buf, 16, &addr);
if (ret)
goto exit;
mdev->log_buf_len = (int *)addr;
ret = count;
exit:
return ret;
}
static DEVICE_ATTR_RW(log_buf_len);
static struct attribute *mic_default_attrs[] = {
&dev_attr_family.attr,
&dev_attr_stepping.attr,
&dev_attr_state.attr,
&dev_attr_shutdown_status.attr,
&dev_attr_cmdline.attr,
&dev_attr_firmware.attr,
&dev_attr_ramdisk.attr,
&dev_attr_bootmode.attr,
&dev_attr_log_buf_addr.attr,
&dev_attr_log_buf_len.attr,
NULL
};
ATTRIBUTE_GROUPS(mic_default);
void mic_sysfs_init(struct mic_device *mdev)
{
mdev->attr_group = mic_default_groups;
}
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/mic_common.h> #include <linux/mic_common.h>
#include "../common/mic_dev.h" #include "../common/mic_dev.h"
#include "mic_device.h" #include "mic_device.h"
#include "mic_smpt.h" #include "mic_smpt.h"
...@@ -62,7 +61,7 @@ static int mic_sync_dma(struct mic_device *mdev, dma_addr_t dst, ...@@ -62,7 +61,7 @@ static int mic_sync_dma(struct mic_device *mdev, dma_addr_t dst,
} }
error: error:
if (err) if (err)
dev_err(mdev->sdev->parent, "%s %d err %d\n", dev_err(&mdev->pdev->dev, "%s %d err %d\n",
__func__, __LINE__, err); __func__, __LINE__, err);
return err; return err;
} }
...@@ -440,7 +439,7 @@ void mic_virtio_reset_devices(struct mic_device *mdev) ...@@ -440,7 +439,7 @@ void mic_virtio_reset_devices(struct mic_device *mdev)
struct list_head *pos, *tmp; struct list_head *pos, *tmp;
struct mic_vdev *mvdev; struct mic_vdev *mvdev;
dev_dbg(mdev->sdev->parent, "%s\n", __func__); dev_dbg(&mdev->pdev->dev, "%s\n", __func__);
list_for_each_safe(pos, tmp, &mdev->vdev_list) { list_for_each_safe(pos, tmp, &mdev->vdev_list) {
mvdev = list_entry(pos, struct mic_vdev, list); mvdev = list_entry(pos, struct mic_vdev, list);
...@@ -686,7 +685,7 @@ int mic_virtio_add_device(struct mic_vdev *mvdev, ...@@ -686,7 +685,7 @@ int mic_virtio_add_device(struct mic_vdev *mvdev,
mvr->head = USHRT_MAX; mvr->head = USHRT_MAX;
mvr->mvdev = mvdev; mvr->mvdev = mvdev;
mvr->vrh.notify = mic_notify; mvr->vrh.notify = mic_notify;
dev_dbg(mdev->sdev->parent, dev_dbg(&mdev->pdev->dev,
"%s %d index %d va %p info %p vr_size 0x%x\n", "%s %d index %d va %p info %p vr_size 0x%x\n",
__func__, __LINE__, i, vr->va, vr->info, vr_size); __func__, __LINE__, i, vr->va, vr->info, vr_size);
mvr->buf = (void *)__get_free_pages(GFP_KERNEL, mvr->buf = (void *)__get_free_pages(GFP_KERNEL,
...@@ -704,7 +703,7 @@ int mic_virtio_add_device(struct mic_vdev *mvdev, ...@@ -704,7 +703,7 @@ int mic_virtio_add_device(struct mic_vdev *mvdev,
mvdev->virtio_db, MIC_INTR_DB); mvdev->virtio_db, MIC_INTR_DB);
if (IS_ERR(mvdev->virtio_cookie)) { if (IS_ERR(mvdev->virtio_cookie)) {
ret = PTR_ERR(mvdev->virtio_cookie); ret = PTR_ERR(mvdev->virtio_cookie);
dev_dbg(mdev->sdev->parent, "request irq failed\n"); dev_dbg(&mdev->pdev->dev, "request irq failed\n");
goto err; goto err;
} }
...@@ -720,7 +719,7 @@ int mic_virtio_add_device(struct mic_vdev *mvdev, ...@@ -720,7 +719,7 @@ int mic_virtio_add_device(struct mic_vdev *mvdev,
smp_wmb(); smp_wmb();
dd->type = type; dd->type = type;
dev_dbg(mdev->sdev->parent, "Added virtio device id %d\n", dd->type); dev_dbg(&mdev->pdev->dev, "Added virtio device id %d\n", dd->type);
db = bootparam->h2c_config_db; db = bootparam->h2c_config_db;
if (db != -1) if (db != -1)
...@@ -755,7 +754,7 @@ void mic_virtio_del_device(struct mic_vdev *mvdev) ...@@ -755,7 +754,7 @@ void mic_virtio_del_device(struct mic_vdev *mvdev)
db = bootparam->h2c_config_db; db = bootparam->h2c_config_db;
if (db == -1) if (db == -1)
goto skip_hot_remove; goto skip_hot_remove;
dev_dbg(mdev->sdev->parent, dev_dbg(&mdev->pdev->dev,
"Requesting hot remove id %d\n", mvdev->virtio_id); "Requesting hot remove id %d\n", mvdev->virtio_id);
mvdev->dc->config_change = MIC_VIRTIO_PARAM_DEV_REMOVE; mvdev->dc->config_change = MIC_VIRTIO_PARAM_DEV_REMOVE;
mdev->ops->send_intr(mdev, db); mdev->ops->send_intr(mdev, db);
...@@ -765,7 +764,7 @@ void mic_virtio_del_device(struct mic_vdev *mvdev) ...@@ -765,7 +764,7 @@ void mic_virtio_del_device(struct mic_vdev *mvdev)
if (ret) if (ret)
break; break;
} }
dev_dbg(mdev->sdev->parent, dev_dbg(&mdev->pdev->dev,
"Device id %d config_change %d guest_ack %d retry %d\n", "Device id %d config_change %d guest_ack %d retry %d\n",
mvdev->virtio_id, mvdev->dc->config_change, mvdev->virtio_id, mvdev->dc->config_change,
mvdev->dc->guest_ack, retry); mvdev->dc->guest_ack, retry);
...@@ -794,7 +793,7 @@ void mic_virtio_del_device(struct mic_vdev *mvdev) ...@@ -794,7 +793,7 @@ void mic_virtio_del_device(struct mic_vdev *mvdev)
tmp_mvdev = list_entry(pos, struct mic_vdev, list); tmp_mvdev = list_entry(pos, struct mic_vdev, list);
if (tmp_mvdev == mvdev) { if (tmp_mvdev == mvdev) {
list_del(pos); list_del(pos);
dev_dbg(mdev->sdev->parent, dev_dbg(&mdev->pdev->dev,
"Removing virtio device id %d\n", "Removing virtio device id %d\n",
mvdev->virtio_id); mvdev->virtio_id);
break; break;
......
...@@ -124,7 +124,7 @@ void mic_bh_handler(struct work_struct *work); ...@@ -124,7 +124,7 @@ void mic_bh_handler(struct work_struct *work);
/* Helper API to obtain the MIC PCIe device */ /* Helper API to obtain the MIC PCIe device */
static inline struct device *mic_dev(struct mic_vdev *mvdev) static inline struct device *mic_dev(struct mic_vdev *mvdev)
{ {
return mvdev->mdev->sdev->parent; return &mvdev->mdev->pdev->dev;
} }
/* Helper API to check if a virtio device is initialized */ /* Helper API to check if a virtio device is initialized */
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
static void static void
mic_x100_write_spad(struct mic_device *mdev, unsigned int idx, u32 val) mic_x100_write_spad(struct mic_device *mdev, unsigned int idx, u32 val)
{ {
dev_dbg(mdev->sdev->parent, "Writing 0x%x to scratch pad index %d\n", dev_dbg(&mdev->pdev->dev, "Writing 0x%x to scratch pad index %d\n",
val, idx); val, idx);
mic_mmio_write(&mdev->mmio, val, mic_mmio_write(&mdev->mmio, val,
MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_BASE_ADDRESS +
...@@ -66,7 +66,7 @@ mic_x100_read_spad(struct mic_device *mdev, unsigned int idx) ...@@ -66,7 +66,7 @@ mic_x100_read_spad(struct mic_device *mdev, unsigned int idx)
MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_BASE_ADDRESS +
MIC_X100_SBOX_SPAD0 + idx * 4); MIC_X100_SBOX_SPAD0 + idx * 4);
dev_dbg(mdev->sdev->parent, dev_dbg(&mdev->pdev->dev,
"Reading 0x%x from scratch pad index %d\n", val, idx); "Reading 0x%x from scratch pad index %d\n", val, idx);
return val; return val;
} }
...@@ -359,15 +359,14 @@ mic_x100_load_command_line(struct mic_device *mdev, const struct firmware *fw) ...@@ -359,15 +359,14 @@ mic_x100_load_command_line(struct mic_device *mdev, const struct firmware *fw)
boot_mem = mdev->aper.len >> 20; boot_mem = mdev->aper.len >> 20;
buf = kzalloc(CMDLINE_SIZE, GFP_KERNEL); buf = kzalloc(CMDLINE_SIZE, GFP_KERNEL);
if (!buf) { if (!buf)
dev_err(mdev->sdev->parent,
"%s %d allocation failed\n", __func__, __LINE__);
return -ENOMEM; return -ENOMEM;
}
len += snprintf(buf, CMDLINE_SIZE - len, len += snprintf(buf, CMDLINE_SIZE - len,
" mem=%dM", boot_mem); " mem=%dM", boot_mem);
if (mdev->cmdline) if (mdev->cosm_dev->cmdline)
snprintf(buf + len, CMDLINE_SIZE - len, " %s", mdev->cmdline); snprintf(buf + len, CMDLINE_SIZE - len, " %s",
mdev->cosm_dev->cmdline);
memcpy_toio(cmd_line_va, buf, strlen(buf) + 1); memcpy_toio(cmd_line_va, buf, strlen(buf) + 1);
kfree(buf); kfree(buf);
return 0; return 0;
...@@ -386,12 +385,11 @@ mic_x100_load_ramdisk(struct mic_device *mdev) ...@@ -386,12 +385,11 @@ mic_x100_load_ramdisk(struct mic_device *mdev)
int rc; int rc;
struct boot_params __iomem *bp = mdev->aper.va + mdev->bootaddr; struct boot_params __iomem *bp = mdev->aper.va + mdev->bootaddr;
rc = request_firmware(&fw, rc = request_firmware(&fw, mdev->cosm_dev->ramdisk, &mdev->pdev->dev);
mdev->ramdisk, mdev->sdev->parent);
if (rc < 0) { if (rc < 0) {
dev_err(mdev->sdev->parent, dev_err(&mdev->pdev->dev,
"ramdisk request_firmware failed: %d %s\n", "ramdisk request_firmware failed: %d %s\n",
rc, mdev->ramdisk); rc, mdev->cosm_dev->ramdisk);
goto error; goto error;
} }
/* /*
...@@ -423,10 +421,10 @@ mic_x100_get_boot_addr(struct mic_device *mdev) ...@@ -423,10 +421,10 @@ mic_x100_get_boot_addr(struct mic_device *mdev)
scratch2 = mdev->ops->read_spad(mdev, MIC_X100_DOWNLOAD_INFO); scratch2 = mdev->ops->read_spad(mdev, MIC_X100_DOWNLOAD_INFO);
boot_addr = MIC_X100_SPAD2_DOWNLOAD_ADDR(scratch2); boot_addr = MIC_X100_SPAD2_DOWNLOAD_ADDR(scratch2);
dev_dbg(mdev->sdev->parent, "%s %d boot_addr 0x%x\n", dev_dbg(&mdev->pdev->dev, "%s %d boot_addr 0x%x\n",
__func__, __LINE__, boot_addr); __func__, __LINE__, boot_addr);
if (boot_addr > (1 << 31)) { if (boot_addr > (1 << 31)) {
dev_err(mdev->sdev->parent, dev_err(&mdev->pdev->dev,
"incorrect bootaddr 0x%x\n", "incorrect bootaddr 0x%x\n",
boot_addr); boot_addr);
rc = -EINVAL; rc = -EINVAL;
...@@ -454,37 +452,37 @@ mic_x100_load_firmware(struct mic_device *mdev, const char *buf) ...@@ -454,37 +452,37 @@ mic_x100_load_firmware(struct mic_device *mdev, const char *buf)
if (rc) if (rc)
goto error; goto error;
/* load OS */ /* load OS */
rc = request_firmware(&fw, mdev->firmware, mdev->sdev->parent); rc = request_firmware(&fw, mdev->cosm_dev->firmware, &mdev->pdev->dev);
if (rc < 0) { if (rc < 0) {
dev_err(mdev->sdev->parent, dev_err(&mdev->pdev->dev,
"ramdisk request_firmware failed: %d %s\n", "ramdisk request_firmware failed: %d %s\n",
rc, mdev->firmware); rc, mdev->cosm_dev->firmware);
goto error; goto error;
} }
if (mdev->bootaddr > mdev->aper.len - fw->size) { if (mdev->bootaddr > mdev->aper.len - fw->size) {
rc = -EINVAL; rc = -EINVAL;
dev_err(mdev->sdev->parent, "%s %d rc %d bootaddr 0x%x\n", dev_err(&mdev->pdev->dev, "%s %d rc %d bootaddr 0x%x\n",
__func__, __LINE__, rc, mdev->bootaddr); __func__, __LINE__, rc, mdev->bootaddr);
release_firmware(fw); release_firmware(fw);
goto error; goto error;
} }
memcpy_toio(mdev->aper.va + mdev->bootaddr, fw->data, fw->size); memcpy_toio(mdev->aper.va + mdev->bootaddr, fw->data, fw->size);
mdev->ops->write_spad(mdev, MIC_X100_FW_SIZE, fw->size); mdev->ops->write_spad(mdev, MIC_X100_FW_SIZE, fw->size);
if (!strcmp(mdev->bootmode, "elf")) if (!strcmp(mdev->cosm_dev->bootmode, "flash"))
goto done; goto done;
/* load command line */ /* load command line */
rc = mic_x100_load_command_line(mdev, fw); rc = mic_x100_load_command_line(mdev, fw);
if (rc) { if (rc) {
dev_err(mdev->sdev->parent, "%s %d rc %d\n", dev_err(&mdev->pdev->dev, "%s %d rc %d\n",
__func__, __LINE__, rc); __func__, __LINE__, rc);
goto error; goto error;
} }
release_firmware(fw); release_firmware(fw);
/* load ramdisk */ /* load ramdisk */
if (mdev->ramdisk) if (mdev->cosm_dev->ramdisk)
rc = mic_x100_load_ramdisk(mdev); rc = mic_x100_load_ramdisk(mdev);
error: error:
dev_dbg(mdev->sdev->parent, "%s %d rc %d\n", __func__, __LINE__, rc); dev_dbg(&mdev->pdev->dev, "%s %d rc %d\n", __func__, __LINE__, rc);
done: done:
return rc; return rc;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment