|
@@ -22,9 +22,9 @@
|
|
|
#include <linux/firmware.h>
|
|
|
#include <linux/pci.h>
|
|
|
#include <linux/kmod.h>
|
|
|
-
|
|
|
#include <linux/mic_common.h>
|
|
|
#include <linux/mic_bus.h>
|
|
|
+#include "../bus/scif_bus.h"
|
|
|
#include "../common/mic_dev.h"
|
|
|
#include "mic_device.h"
|
|
|
#include "mic_smpt.h"
|
|
@@ -99,7 +99,7 @@ static int __mic_dma_map_sg(struct device *dev, struct scatterlist *sg,
|
|
|
int i, j, ret;
|
|
|
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)
|
|
|
return 0;
|
|
|
|
|
@@ -115,7 +115,7 @@ err:
|
|
|
mic_unmap(mdev, sg_dma_address(s), s->length);
|
|
|
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;
|
|
|
}
|
|
|
|
|
@@ -135,7 +135,7 @@ static void __mic_dma_unmap_sg(struct device *dev,
|
|
|
mic_unmap(mdev, sg_dma_address(s), s->length);
|
|
|
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 = {
|
|
@@ -270,48 +270,13 @@ static struct mbus_hw_ops mbus_hw_ops = {
|
|
|
.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 */
|
|
|
void mic_bootparam_init(struct mic_device *mdev)
|
|
|
{
|
|
|
struct mic_bootparam *bootparam = mdev->dp;
|
|
|
|
|
|
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->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->scif_host_dma_addr = 0x0;
|
|
|
bootparam->scif_card_dma_addr = 0x0;
|
|
@@ -319,6 +284,26 @@ void mic_bootparam_init(struct mic_device *mdev)
|
|
|
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
|
|
|
* @mdev: pointer to mic_device instance
|
|
@@ -336,14 +321,14 @@ static int mic_request_dma_chans(struct mic_device *mdev)
|
|
|
|
|
|
do {
|
|
|
chan = dma_request_channel(mask, mdev->ops->dma_filter,
|
|
|
- mdev->sdev->parent);
|
|
|
+ &mdev->pdev->dev);
|
|
|
if (chan) {
|
|
|
mdev->dma_ch[mdev->num_dma_ch++] = chan;
|
|
|
if (mdev->num_dma_ch >= MIC_MAX_DMA_CHAN)
|
|
|
break;
|
|
|
}
|
|
|
} 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;
|
|
|
}
|
|
|
|
|
@@ -365,34 +350,24 @@ static void mic_free_dma_chans(struct mic_device *mdev)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * mic_start - Start the MIC.
|
|
|
- * @mdev: pointer to mic_device instance
|
|
|
- * @buf: buffer containing boot string including firmware/ramdisk path.
|
|
|
+ * _mic_start - Start the MIC.
|
|
|
+ * @cdev: pointer to cosm_device instance
|
|
|
+ * @id: MIC device id/index provided by COSM used in other drivers like SCIF
|
|
|
*
|
|
|
* This function prepares an MIC for boot and initiates boot.
|
|
|
* 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;
|
|
|
- mutex_lock(&mdev->mic_mutex);
|
|
|
+
|
|
|
mic_bootparam_init(mdev);
|
|
|
-retry:
|
|
|
- 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,
|
|
|
+ mdev->dma_mbdev = mbus_register_device(&mdev->pdev->dev,
|
|
|
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)) {
|
|
|
rc = PTR_ERR(mdev->dma_mbdev);
|
|
|
goto unlock_ret;
|
|
@@ -401,16 +376,18 @@ retry:
|
|
|
rc = -ENODEV;
|
|
|
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,
|
|
|
- mdev->id + 1, 0, &mdev->mmio,
|
|
|
+ id + 1, 0, &mdev->mmio,
|
|
|
&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)) {
|
|
|
rc = PTR_ERR(mdev->scdev);
|
|
|
goto dma_free;
|
|
|
}
|
|
|
- rc = mdev->ops->load_mic_fw(mdev, buf);
|
|
|
+
|
|
|
+ rc = mdev->ops->load_mic_fw(mdev, NULL);
|
|
|
if (rc)
|
|
|
goto scif_remove;
|
|
|
mic_smpt_restore(mdev);
|
|
@@ -419,7 +396,6 @@ retry:
|
|
|
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->send_firmware_intr(mdev);
|
|
|
- mic_set_state(mdev, MIC_ONLINE);
|
|
|
goto unlock_ret;
|
|
|
scif_remove:
|
|
|
scif_unregister_device(mdev->scdev);
|
|
@@ -428,198 +404,79 @@ dma_free:
|
|
|
dma_remove:
|
|
|
mbus_unregister_device(mdev->dma_mbdev);
|
|
|
unlock_ret:
|
|
|
- mutex_unlock(&mdev->mic_mutex);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * mic_stop - Prepare the MIC for reset and trigger reset.
|
|
|
- * @mdev: pointer to mic_device instance
|
|
|
+ * _mic_stop - Prepare the MIC for reset and trigger reset.
|
|
|
+ * @cdev: pointer to cosm_device instance
|
|
|
* @force: force a MIC to reset even if it is already offline.
|
|
|
*
|
|
|
* RETURNS: None.
|
|
|
*/
|
|
|
-void mic_stop(struct mic_device *mdev, bool force)
|
|
|
-{
|
|
|
- mutex_lock(&mdev->mic_mutex);
|
|
|
- if (MIC_OFFLINE != mdev->state || force) {
|
|
|
- scif_unregister_device(mdev->scdev);
|
|
|
- mic_virtio_reset_devices(mdev);
|
|
|
- mic_free_dma_chans(mdev);
|
|
|
- mbus_unregister_device(mdev->dma_mbdev);
|
|
|
- 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)
|
|
|
+static void _mic_stop(struct cosm_device *cdev, bool force)
|
|
|
{
|
|
|
- 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);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 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,
|
|
|
- shutdown_work);
|
|
|
- struct mic_bootparam *bootparam = mdev->dp;
|
|
|
-
|
|
|
- mutex_lock(&mdev->mic_mutex);
|
|
|
- mic_set_shutdown_status(mdev, bootparam->shutdown_status);
|
|
|
- bootparam->shutdown_status = 0;
|
|
|
+ struct mic_device *mdev = cosmdev_to_mdev(cdev);
|
|
|
|
|
|
/*
|
|
|
- * 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.
|
|
|
+ * Since SCIF handles card shutdown and reset (using COSM), it will
|
|
|
+ * will be the first to be registered and the last to be
|
|
|
+ * unregistered.
|
|
|
*/
|
|
|
- if (MIC_SHUTTING_DOWN != mdev->state &&
|
|
|
- MIC_SUSPENDED != mdev->state)
|
|
|
- mic_set_state(mdev, MIC_SHUTTING_DOWN);
|
|
|
- mutex_unlock(&mdev->mic_mutex);
|
|
|
+ mic_virtio_reset_devices(mdev);
|
|
|
+ scif_unregister_device(mdev->scdev);
|
|
|
+ mic_free_dma_chans(mdev);
|
|
|
+ mbus_unregister_device(mdev->dma_mbdev);
|
|
|
+ mic_bootparam_init(mdev);
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * 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)
|
|
|
+static ssize_t _mic_family(struct cosm_device *cdev, char *buf)
|
|
|
{
|
|
|
- struct mic_device *mdev = container_of(work, struct mic_device,
|
|
|
- reset_trigger_work);
|
|
|
+ struct mic_device *mdev = cosmdev_to_mdev(cdev);
|
|
|
+ static const char *family[MIC_FAMILY_LAST] = { "x100", "Unknown" };
|
|
|
|
|
|
- mic_stop(mdev, false);
|
|
|
+ return scnprintf(buf, PAGE_SIZE, "%s\n", family[mdev->family]);
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * 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)
|
|
|
+static ssize_t _mic_stepping(struct cosm_device *cdev, char *buf)
|
|
|
{
|
|
|
- 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);
|
|
|
+ struct mic_device *mdev = cosmdev_to_mdev(cdev);
|
|
|
+ const char *string = "??";
|
|
|
|
|
|
- mutex_lock(&mdev->mic_mutex);
|
|
|
- mic_set_state(mdev, MIC_OFFLINE);
|
|
|
- mutex_unlock(&mdev->mic_mutex);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * mic_prepare_suspend - Handle suspend notification for the MIC device.
|
|
|
- * @mdev: pointer to mic_device instance
|
|
|
- *
|
|
|
- * 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);
|
|
|
+ switch (mdev->stepping) {
|
|
|
+ case MIC_A0_STEP:
|
|
|
+ string = "A0";
|
|
|
break;
|
|
|
- case MIC_ONLINE:
|
|
|
- /*
|
|
|
- * 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);
|
|
|
- }
|
|
|
+ case MIC_B0_STEP:
|
|
|
+ string = "B0";
|
|
|
+ break;
|
|
|
+ case MIC_B1_STEP:
|
|
|
+ string = "B1";
|
|
|
break;
|
|
|
- case MIC_SHUTTING_DOWN:
|
|
|
- /*
|
|
|
- * Card is shutting down. Set state to MIC_SUSPENDED
|
|
|
- * to prevent further boot of the card.
|
|
|
- */
|
|
|
- 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);
|
|
|
+ case MIC_C0_STEP:
|
|
|
+ string = "C0";
|
|
|
break;
|
|
|
default:
|
|
|
- mutex_unlock(&mdev->mic_mutex);
|
|
|
break;
|
|
|
}
|
|
|
+ return scnprintf(buf, PAGE_SIZE, "%s\n", string);
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * 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)
|
|
|
+static struct mic_mw *_mic_aper(struct cosm_device *cdev)
|
|
|
{
|
|
|
- struct mic_bootparam *bootparam = mdev->dp;
|
|
|
- s8 db = bootparam->h2c_shutdown_db;
|
|
|
+ struct mic_device *mdev = cosmdev_to_mdev(cdev);
|
|
|
|
|
|
- mutex_lock(&mdev->mic_mutex);
|
|
|
- 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);
|
|
|
+ return &mdev->aper;
|
|
|
}
|
|
|
+
|
|
|
+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,
|
|
|
+};
|