aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
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
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')
-rw-r--r--drivers/misc/mic/common/mic_device.h7
-rw-r--r--drivers/misc/mic/host/Makefile2
-rw-r--r--drivers/misc/mic/host/mic_boot.c184
-rw-r--r--drivers/misc/mic/host/mic_debugfs.c355
-rw-r--r--drivers/misc/mic/host/mic_device.h60
-rw-r--r--drivers/misc/mic/host/mic_main.c129
-rw-r--r--drivers/misc/mic/host/mic_sysfs.c369
-rw-r--r--drivers/misc/mic/host/mic_x100.c251
-rw-r--r--drivers/misc/mic/host/mic_x100.h12
9 files changed, 1365 insertions, 4 deletions
diff --git a/drivers/misc/mic/common/mic_device.h b/drivers/misc/mic/common/mic_device.h
index f02262e1c9d3..6440e9d58d3a 100644
--- a/drivers/misc/mic/common/mic_device.h
+++ b/drivers/misc/mic/common/mic_device.h
@@ -34,4 +34,11 @@ struct mic_mw {
34 resource_size_t len; 34 resource_size_t len;
35}; 35};
36 36
37/*
38 * Scratch pad register offsets used by the host to communicate
39 * device page DMA address to the card.
40 */
41#define MIC_DPLO_SPAD 14
42#define MIC_DPHI_SPAD 15
43
37#endif 44#endif
diff --git a/drivers/misc/mic/host/Makefile b/drivers/misc/mic/host/Makefile
index 6ff5550f10ac..a375dd32c3e2 100644
--- a/drivers/misc/mic/host/Makefile
+++ b/drivers/misc/mic/host/Makefile
@@ -8,3 +8,5 @@ mic_host-objs += mic_x100.o
8mic_host-objs += mic_sysfs.o 8mic_host-objs += mic_sysfs.o
9mic_host-objs += mic_smpt.o 9mic_host-objs += mic_smpt.o
10mic_host-objs += mic_intr.o 10mic_host-objs += mic_intr.o
11mic_host-objs += mic_boot.o
12mic_host-objs += mic_debugfs.o
diff --git a/drivers/misc/mic/host/mic_boot.c b/drivers/misc/mic/host/mic_boot.c
new file mode 100644
index 000000000000..936fc58084f3
--- /dev/null
+++ b/drivers/misc/mic/host/mic_boot.c
@@ -0,0 +1,184 @@
1/*
2 * Intel MIC Platform Software Stack (MPSS)
3 *
4 * Copyright(c) 2013 Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * The full GNU General Public License is included in this distribution in
16 * the file called "COPYING".
17 *
18 * Intel MIC Host driver.
19 *
20 */
21#include <linux/delay.h>
22#include <linux/firmware.h>
23#include <linux/interrupt.h>
24
25#include <linux/mic_common.h>
26#include "../common/mic_device.h"
27#include "mic_device.h"
28#include "mic_smpt.h"
29
30/**
31 * mic_reset - Reset the MIC device.
32 * @mdev: pointer to mic_device instance
33 */
34static void mic_reset(struct mic_device *mdev)
35{
36 int i;
37
38#define MIC_RESET_TO (45)
39
40 mdev->ops->reset_fw_ready(mdev);
41 mdev->ops->reset(mdev);
42
43 for (i = 0; i < MIC_RESET_TO; i++) {
44 if (mdev->ops->is_fw_ready(mdev))
45 return;
46 /*
47 * Resets typically take 10s of seconds to complete.
48 * Since an MMIO read is required to check if the
49 * firmware is ready or not, a 1 second delay works nicely.
50 */
51 msleep(1000);
52 }
53 mic_set_state(mdev, MIC_RESET_FAILED);
54}
55
56/* Initialize the MIC bootparams */
57void mic_bootparam_init(struct mic_device *mdev)
58{
59 struct mic_bootparam *bootparam = mdev->dp;
60
61 bootparam->magic = MIC_MAGIC;
62 bootparam->c2h_shutdown_db = mdev->shutdown_db;
63 bootparam->h2c_shutdown_db = -1;
64 bootparam->h2c_config_db = -1;
65 bootparam->shutdown_status = 0;
66 bootparam->shutdown_card = 0;
67}
68
69/**
70 * mic_start - Start the MIC.
71 * @mdev: pointer to mic_device instance
72 * @buf: buffer containing boot string including firmware/ramdisk path.
73 *
74 * This function prepares an MIC for boot and initiates boot.
75 * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
76 */
77int mic_start(struct mic_device *mdev, const char *buf)
78{
79 int rc;
80 mutex_lock(&mdev->mic_mutex);
81retry:
82 if (MIC_OFFLINE != mdev->state) {
83 rc = -EINVAL;
84 goto unlock_ret;
85 }
86 if (!mdev->ops->is_fw_ready(mdev)) {
87 mic_reset(mdev);
88 /*
89 * The state will either be MIC_OFFLINE if the reset succeeded
90 * or MIC_RESET_FAILED if the firmware reset failed.
91 */
92 goto retry;
93 }
94 rc = mdev->ops->load_mic_fw(mdev, buf);
95 if (rc)
96 goto unlock_ret;
97 mic_smpt_restore(mdev);
98 mic_intr_restore(mdev);
99 mdev->intr_ops->enable_interrupts(mdev);
100 mdev->ops->write_spad(mdev, MIC_DPLO_SPAD, mdev->dp_dma_addr);
101 mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32);
102 mdev->ops->send_firmware_intr(mdev);
103 mic_set_state(mdev, MIC_ONLINE);
104unlock_ret:
105 mutex_unlock(&mdev->mic_mutex);
106 return rc;
107}
108
109/**
110 * mic_stop - Prepare the MIC for reset and trigger reset.
111 * @mdev: pointer to mic_device instance
112 * @force: force a MIC to reset even if it is already offline.
113 *
114 * RETURNS: None.
115 */
116void mic_stop(struct mic_device *mdev, bool force)
117{
118 mutex_lock(&mdev->mic_mutex);
119 if (MIC_OFFLINE != mdev->state || force) {
120 mic_bootparam_init(mdev);
121 mic_reset(mdev);
122 if (MIC_RESET_FAILED == mdev->state)
123 goto unlock;
124 mic_set_shutdown_status(mdev, MIC_NOP);
125 mic_set_state(mdev, MIC_OFFLINE);
126 }
127unlock:
128 mutex_unlock(&mdev->mic_mutex);
129}
130
131/**
132 * mic_shutdown - Initiate MIC shutdown.
133 * @mdev: pointer to mic_device instance
134 *
135 * RETURNS: None.
136 */
137void mic_shutdown(struct mic_device *mdev)
138{
139 struct mic_bootparam *bootparam = mdev->dp;
140 s8 db = bootparam->h2c_shutdown_db;
141
142 mutex_lock(&mdev->mic_mutex);
143 if (MIC_ONLINE == mdev->state && db != -1) {
144 bootparam->shutdown_card = 1;
145 mdev->ops->send_intr(mdev, db);
146 mic_set_state(mdev, MIC_SHUTTING_DOWN);
147 }
148 mutex_unlock(&mdev->mic_mutex);
149}
150
151/**
152 * mic_shutdown_work - Handle shutdown interrupt from MIC.
153 * @work: The work structure.
154 *
155 * This work is scheduled whenever the host has received a shutdown
156 * interrupt from the MIC.
157 */
158void mic_shutdown_work(struct work_struct *work)
159{
160 struct mic_device *mdev = container_of(work, struct mic_device,
161 shutdown_work);
162 struct mic_bootparam *bootparam = mdev->dp;
163
164 mutex_lock(&mdev->mic_mutex);
165 mic_set_shutdown_status(mdev, bootparam->shutdown_status);
166 bootparam->shutdown_status = 0;
167 if (MIC_SHUTTING_DOWN != mdev->state)
168 mic_set_state(mdev, MIC_SHUTTING_DOWN);
169 mutex_unlock(&mdev->mic_mutex);
170}
171
172/**
173 * mic_reset_trigger_work - Trigger MIC reset.
174 * @work: The work structure.
175 *
176 * This work is scheduled whenever the host wants to reset the MIC.
177 */
178void mic_reset_trigger_work(struct work_struct *work)
179{
180 struct mic_device *mdev = container_of(work, struct mic_device,
181 reset_trigger_work);
182
183 mic_stop(mdev, false);
184}
diff --git a/drivers/misc/mic/host/mic_debugfs.c b/drivers/misc/mic/host/mic_debugfs.c
new file mode 100644
index 000000000000..78541d42aaf9
--- /dev/null
+++ b/drivers/misc/mic/host/mic_debugfs.c
@@ -0,0 +1,355 @@
1/*
2 * Intel MIC Platform Software Stack (MPSS)
3 *
4 * Copyright(c) 2013 Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * The full GNU General Public License is included in this distribution in
16 * the file called "COPYING".
17 *
18 * Intel MIC Host driver.
19 *
20 */
21#include <linux/debugfs.h>
22#include <linux/pci.h>
23#include <linux/seq_file.h>
24
25#include <linux/mic_common.h>
26#include "../common/mic_device.h"
27#include "mic_device.h"
28#include "mic_smpt.h"
29
30/* Debugfs parent dir */
31static struct dentry *mic_dbg;
32
33/**
34 * mic_log_buf_show - Display MIC kernel log buffer.
35 *
36 * log_buf addr/len is read from System.map by user space
37 * and populated in sysfs entries.
38 */
39static int mic_log_buf_show(struct seq_file *s, void *unused)
40{
41 void __iomem *log_buf_va;
42 int __iomem *log_buf_len_va;
43 struct mic_device *mdev = s->private;
44 void *kva;
45 int size;
46 unsigned long aper_offset;
47
48 if (!mdev || !mdev->log_buf_addr || !mdev->log_buf_len)
49 goto done;
50 /*
51 * Card kernel will never be relocated and any kernel text/data mapping
52 * can be translated to phys address by subtracting __START_KERNEL_map.
53 */
54 aper_offset = (unsigned long)mdev->log_buf_len - __START_KERNEL_map;
55 log_buf_len_va = mdev->aper.va + aper_offset;
56 aper_offset = (unsigned long)mdev->log_buf_addr - __START_KERNEL_map;
57 log_buf_va = mdev->aper.va + aper_offset;
58 size = ioread32(log_buf_len_va);
59
60 kva = kmalloc(size, GFP_KERNEL);
61 if (!kva)
62 goto done;
63 mutex_lock(&mdev->mic_mutex);
64 memcpy_fromio(kva, log_buf_va, size);
65 switch (mdev->state) {
66 case MIC_ONLINE:
67 /* Fall through */
68 case MIC_SHUTTING_DOWN:
69 seq_write(s, kva, size);
70 break;
71 default:
72 break;
73 }
74 mutex_unlock(&mdev->mic_mutex);
75 kfree(kva);
76done:
77 return 0;
78}
79
80static int mic_log_buf_open(struct inode *inode, struct file *file)
81{
82 return single_open(file, mic_log_buf_show, inode->i_private);
83}
84
85static int mic_log_buf_release(struct inode *inode, struct file *file)
86{
87 return single_release(inode, file);
88}
89
90static const struct file_operations log_buf_ops = {
91 .owner = THIS_MODULE,
92 .open = mic_log_buf_open,
93 .read = seq_read,
94 .llseek = seq_lseek,
95 .release = mic_log_buf_release
96};
97
98static int mic_smpt_show(struct seq_file *s, void *pos)
99{
100 int i;
101 struct mic_device *mdev = s->private;
102 unsigned long flags;
103
104 seq_printf(s, "MIC %-2d |%-10s| %-14s %-10s\n",
105 mdev->id, "SMPT entry", "SW DMA addr", "RefCount");
106 seq_puts(s, "====================================================\n");
107
108 if (mdev->smpt) {
109 struct mic_smpt_info *smpt_info = mdev->smpt;
110 spin_lock_irqsave(&smpt_info->smpt_lock, flags);
111 for (i = 0; i < smpt_info->info.num_reg; i++) {
112 seq_printf(s, "%9s|%-10d| %-#14llx %-10lld\n",
113 " ", i, smpt_info->entry[i].dma_addr,
114 smpt_info->entry[i].ref_count);
115 }
116 spin_unlock_irqrestore(&smpt_info->smpt_lock, flags);
117 }
118 seq_puts(s, "====================================================\n");
119 return 0;
120}
121
122static int mic_smpt_debug_open(struct inode *inode, struct file *file)
123{
124 return single_open(file, mic_smpt_show, inode->i_private);
125}
126
127static int mic_smpt_debug_release(struct inode *inode, struct file *file)
128{
129 return single_release(inode, file);
130}
131
132static const struct file_operations smpt_file_ops = {
133 .owner = THIS_MODULE,
134 .open = mic_smpt_debug_open,
135 .read = seq_read,
136 .llseek = seq_lseek,
137 .release = mic_smpt_debug_release
138};
139
140static int mic_soft_reset_show(struct seq_file *s, void *pos)
141{
142 struct mic_device *mdev = s->private;
143
144 mic_stop(mdev, true);
145 return 0;
146}
147
148static int mic_soft_reset_debug_open(struct inode *inode, struct file *file)
149{
150 return single_open(file, mic_soft_reset_show, inode->i_private);
151}
152
153static int mic_soft_reset_debug_release(struct inode *inode, struct file *file)
154{
155 return single_release(inode, file);
156}
157
158static const struct file_operations soft_reset_ops = {
159 .owner = THIS_MODULE,
160 .open = mic_soft_reset_debug_open,
161 .read = seq_read,
162 .llseek = seq_lseek,
163 .release = mic_soft_reset_debug_release
164};
165
166static int mic_post_code_show(struct seq_file *s, void *pos)
167{
168 struct mic_device *mdev = s->private;
169 u32 reg = mdev->ops->get_postcode(mdev);
170
171 seq_printf(s, "%c%c", reg & 0xff, (reg >> 8) & 0xff);
172 return 0;
173}
174
175static int mic_post_code_debug_open(struct inode *inode, struct file *file)
176{
177 return single_open(file, mic_post_code_show, inode->i_private);
178}
179
180static int mic_post_code_debug_release(struct inode *inode, struct file *file)
181{
182 return single_release(inode, file);
183}
184
185static const struct file_operations post_code_ops = {
186 .owner = THIS_MODULE,
187 .open = mic_post_code_debug_open,
188 .read = seq_read,
189 .llseek = seq_lseek,
190 .release = mic_post_code_debug_release
191};
192
193static int mic_dp_show(struct seq_file *s, void *pos)
194{
195 struct mic_device *mdev = s->private;
196 struct mic_bootparam *bootparam = mdev->dp;
197
198 seq_printf(s, "Bootparam: magic 0x%x\n",
199 bootparam->magic);
200 seq_printf(s, "Bootparam: h2c_shutdown_db %d\n",
201 bootparam->h2c_shutdown_db);
202 seq_printf(s, "Bootparam: h2c_config_db %d\n",
203 bootparam->h2c_config_db);
204 seq_printf(s, "Bootparam: c2h_shutdown_db %d\n",
205 bootparam->c2h_shutdown_db);
206 seq_printf(s, "Bootparam: shutdown_status %d\n",
207 bootparam->shutdown_status);
208 seq_printf(s, "Bootparam: shutdown_card %d\n",
209 bootparam->shutdown_card);
210
211 return 0;
212}
213
214static int mic_dp_debug_open(struct inode *inode, struct file *file)
215{
216 return single_open(file, mic_dp_show, inode->i_private);
217}
218
219static int mic_dp_debug_release(struct inode *inode, struct file *file)
220{
221 return single_release(inode, file);
222}
223
224static const struct file_operations dp_ops = {
225 .owner = THIS_MODULE,
226 .open = mic_dp_debug_open,
227 .read = seq_read,
228 .llseek = seq_lseek,
229 .release = mic_dp_debug_release
230};
231
232static int mic_msi_irq_info_show(struct seq_file *s, void *pos)
233{
234 struct mic_device *mdev = s->private;
235 int reg;
236 int i, j;
237 u16 entry;
238 u16 vector;
239 struct pci_dev *pdev = container_of(mdev->sdev->parent,
240 struct pci_dev, dev);
241
242 if (pci_dev_msi_enabled(pdev)) {
243 for (i = 0; i < mdev->irq_info.num_vectors; i++) {
244 if (pdev->msix_enabled) {
245 entry = mdev->irq_info.msix_entries[i].entry;
246 vector = mdev->irq_info.msix_entries[i].vector;
247 } else {
248 entry = 0;
249 vector = pdev->irq;
250 }
251
252 reg = mdev->intr_ops->read_msi_to_src_map(mdev, entry);
253
254 seq_printf(s, "%s %-10d %s %-10d MXAR[%d]: %08X\n",
255 "IRQ:", vector, "Entry:", entry, i, reg);
256
257 seq_printf(s, "%-10s", "offset:");
258 for (j = (MIC_NUM_OFFSETS - 1); j >= 0; j--)
259 seq_printf(s, "%4d ", j);
260 seq_puts(s, "\n");
261
262
263 seq_printf(s, "%-10s", "count:");
264 for (j = (MIC_NUM_OFFSETS - 1); j >= 0; j--)
265 seq_printf(s, "%4d ",
266 (mdev->irq_info.mic_msi_map[i] & BIT(j)) ?
267 1 : 0);
268 seq_puts(s, "\n\n");
269 }
270 } else {
271 seq_puts(s, "MSI/MSIx interrupts not enabled\n");
272 }
273
274 return 0;
275
276}
277
278static int mic_msi_irq_info_debug_open(struct inode *inode, struct file *file)
279{
280 return single_open(file, mic_msi_irq_info_show, inode->i_private);
281}
282
283static int
284mic_msi_irq_info_debug_release(struct inode *inode, struct file *file)
285{
286 return single_release(inode, file);
287}
288
289static const struct file_operations msi_irq_info_ops = {
290 .owner = THIS_MODULE,
291 .open = mic_msi_irq_info_debug_open,
292 .read = seq_read,
293 .llseek = seq_lseek,
294 .release = mic_msi_irq_info_debug_release
295};
296
297/**
298 * mic_create_debug_dir - Initialize MIC debugfs entries.
299 */
300void mic_create_debug_dir(struct mic_device *mdev)
301{
302 if (!mic_dbg)
303 return;
304
305 mdev->dbg_dir = debugfs_create_dir(dev_name(mdev->sdev), mic_dbg);
306 if (!mdev->dbg_dir)
307 return;
308
309 debugfs_create_file("log_buf", 0444, mdev->dbg_dir,
310 mdev, &log_buf_ops);
311
312 debugfs_create_file("smpt", 0444, mdev->dbg_dir,
313 mdev, &smpt_file_ops);
314
315 debugfs_create_file("soft_reset", 0444, mdev->dbg_dir,
316 mdev, &soft_reset_ops);
317
318 debugfs_create_file("post_code", 0444, mdev->dbg_dir,
319 mdev, &post_code_ops);
320
321 debugfs_create_file("dp", 0444, mdev->dbg_dir,
322 mdev, &dp_ops);
323
324 debugfs_create_file("msi_irq_info", 0444, mdev->dbg_dir,
325 mdev, &msi_irq_info_ops);
326}
327
328/**
329 * mic_delete_debug_dir - Uninitialize MIC debugfs entries.
330 */
331void mic_delete_debug_dir(struct mic_device *mdev)
332{
333 if (!mdev->dbg_dir)
334 return;
335
336 debugfs_remove_recursive(mdev->dbg_dir);
337}
338
339/**
340 * mic_init_debugfs - Initialize global debugfs entry.
341 */
342void __init mic_init_debugfs(void)
343{
344 mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
345 if (!mic_dbg)
346 pr_err("can't create debugfs dir\n");
347}
348
349/**
350 * mic_exit_debugfs - Uninitialize global debugfs entry
351 */
352void mic_exit_debugfs(void)
353{
354 debugfs_remove(mic_dbg);
355}
diff --git a/drivers/misc/mic/host/mic_device.h b/drivers/misc/mic/host/mic_device.h
index dd34b6532a01..50b8b88d70d3 100644
--- a/drivers/misc/mic/host/mic_device.h
+++ b/drivers/misc/mic/host/mic_device.h
@@ -63,6 +63,23 @@ enum mic_stepping {
63 * @smpt: MIC SMPT information. 63 * @smpt: MIC SMPT information.
64 * @intr_info: H/W specific interrupt information. 64 * @intr_info: H/W specific interrupt information.
65 * @irq_info: The OS specific irq information 65 * @irq_info: The OS specific irq information
66 * @dbg_dir: debugfs directory of this MIC device.
67 * @cmdline: Kernel command line.
68 * @firmware: Firmware file name.
69 * @ramdisk: Ramdisk file name.
70 * @bootmode: Boot mode i.e. "linux" or "elf" for flash updates.
71 * @bootaddr: MIC boot address.
72 * @reset_trigger_work: Work for triggering reset requests.
73 * @shutdown_work: Work for handling shutdown interrupts.
74 * @state: MIC state.
75 * @shutdown_status: MIC status reported by card for shutdown/crashes.
76 * @state_sysfs: Sysfs dirent for notifying ring 3 about MIC state changes.
77 * @log_buf_addr: Log buffer address for MIC.
78 * @log_buf_len: Log buffer length address for MIC.
79 * @dp: virtio device page
80 * @dp_dma_addr: virtio device page DMA address.
81 * @shutdown_db: shutdown doorbell.
82 * @shutdown_cookie: shutdown cookie.
66 */ 83 */
67struct mic_device { 84struct mic_device {
68 struct mic_mw mmio; 85 struct mic_mw mmio;
@@ -79,6 +96,23 @@ struct mic_device {
79 struct mic_smpt_info *smpt; 96 struct mic_smpt_info *smpt;
80 struct mic_intr_info *intr_info; 97 struct mic_intr_info *intr_info;
81 struct mic_irq_info irq_info; 98 struct mic_irq_info irq_info;
99 struct dentry *dbg_dir;
100 char *cmdline;
101 char *firmware;
102 char *ramdisk;
103 char *bootmode;
104 u32 bootaddr;
105 struct work_struct reset_trigger_work;
106 struct work_struct shutdown_work;
107 u8 state;
108 u8 shutdown_status;
109 struct sysfs_dirent *state_sysfs;
110 void *log_buf_addr;
111 int *log_buf_len;
112 void *dp;
113 dma_addr_t dp_dma_addr;
114 int shutdown_db;
115 struct mic_irq *shutdown_cookie;
82}; 116};
83 117
84/** 118/**
@@ -90,6 +124,13 @@ struct mic_device {
90 * @send_intr: Send an interrupt for a particular doorbell on the card. 124 * @send_intr: Send an interrupt for a particular doorbell on the card.
91 * @ack_interrupt: Hardware specific operations to ack the h/w on 125 * @ack_interrupt: Hardware specific operations to ack the h/w on
92 * receipt of an interrupt. 126 * receipt of an interrupt.
127 * @reset: Reset the remote processor.
128 * @reset_fw_ready: Reset firmware ready field.
129 * @is_fw_ready: Check if firmware is ready for OS download.
130 * @send_firmware_intr: Send an interrupt to the card firmware.
131 * @load_mic_fw: Load firmware segments required to boot the card
132 * into card memory. This includes the kernel, command line, ramdisk etc.
133 * @get_postcode: Get post code status from firmware.
93 */ 134 */
94struct mic_hw_ops { 135struct mic_hw_ops {
95 u8 aper_bar; 136 u8 aper_bar;
@@ -98,6 +139,12 @@ struct mic_hw_ops {
98 void (*write_spad)(struct mic_device *mdev, unsigned int idx, u32 val); 139 void (*write_spad)(struct mic_device *mdev, unsigned int idx, u32 val);
99 void (*send_intr)(struct mic_device *mdev, int doorbell); 140 void (*send_intr)(struct mic_device *mdev, int doorbell);
100 u32 (*ack_interrupt)(struct mic_device *mdev); 141 u32 (*ack_interrupt)(struct mic_device *mdev);
142 void (*reset)(struct mic_device *mdev);
143 void (*reset_fw_ready)(struct mic_device *mdev);
144 bool (*is_fw_ready)(struct mic_device *mdev);
145 void (*send_firmware_intr)(struct mic_device *mdev);
146 int (*load_mic_fw)(struct mic_device *mdev, const char *buf);
147 u32 (*get_postcode)(struct mic_device *mdev);
101}; 148};
102 149
103/** 150/**
@@ -127,4 +174,17 @@ mic_mmio_write(struct mic_mw *mw, u32 val, u32 offset)
127} 174}
128 175
129void mic_sysfs_init(struct mic_device *mdev); 176void mic_sysfs_init(struct mic_device *mdev);
177int mic_start(struct mic_device *mdev, const char *buf);
178void mic_stop(struct mic_device *mdev, bool force);
179void mic_shutdown(struct mic_device *mdev);
180void mic_reset_delayed_work(struct work_struct *work);
181void mic_reset_trigger_work(struct work_struct *work);
182void mic_shutdown_work(struct work_struct *work);
183void mic_bootparam_init(struct mic_device *mdev);
184void mic_set_state(struct mic_device *mdev, u8 state);
185void mic_set_shutdown_status(struct mic_device *mdev, u8 status);
186void mic_create_debug_dir(struct mic_device *dev);
187void mic_delete_debug_dir(struct mic_device *dev);
188void __init mic_init_debugfs(void);
189void mic_exit_debugfs(void);
130#endif 190#endif
diff --git a/drivers/misc/mic/host/mic_main.c b/drivers/misc/mic/host/mic_main.c
index 332a15e4215b..998a20ab7e96 100644
--- a/drivers/misc/mic/host/mic_main.c
+++ b/drivers/misc/mic/host/mic_main.c
@@ -26,6 +26,7 @@
26#include <linux/module.h> 26#include <linux/module.h>
27#include <linux/pci.h> 27#include <linux/pci.h>
28 28
29#include <linux/mic_common.h>
29#include "../common/mic_device.h" 30#include "../common/mic_device.h"
30#include "mic_device.h" 31#include "mic_device.h"
31#include "mic_x100.h" 32#include "mic_x100.h"
@@ -63,6 +64,60 @@ static struct class *g_mic_class;
63/* Base device node number for MIC devices */ 64/* Base device node number for MIC devices */
64static dev_t g_mic_devno; 65static dev_t g_mic_devno;
65 66
67/* Initialize the device page */
68static int mic_dp_init(struct mic_device *mdev)
69{
70 mdev->dp = kzalloc(MIC_DP_SIZE, GFP_KERNEL);
71 if (!mdev->dp) {
72 dev_err(mdev->sdev->parent, "%s %d err %d\n",
73 __func__, __LINE__, -ENOMEM);
74 return -ENOMEM;
75 }
76
77 mdev->dp_dma_addr = mic_map_single(mdev,
78 mdev->dp, MIC_DP_SIZE);
79 if (mic_map_error(mdev->dp_dma_addr)) {
80 kfree(mdev->dp);
81 dev_err(mdev->sdev->parent, "%s %d err %d\n",
82 __func__, __LINE__, -ENOMEM);
83 return -ENOMEM;
84 }
85 mdev->ops->write_spad(mdev, MIC_DPLO_SPAD, mdev->dp_dma_addr);
86 mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32);
87 return 0;
88}
89
90/* Uninitialize the device page */
91static void mic_dp_uninit(struct mic_device *mdev)
92{
93 mic_unmap_single(mdev, mdev->dp_dma_addr, MIC_DP_SIZE);
94 kfree(mdev->dp);
95}
96
97/**
98 * mic_shutdown_db - Shutdown doorbell interrupt handler.
99 */
100static irqreturn_t mic_shutdown_db(int irq, void *data)
101{
102 struct mic_device *mdev = data;
103 struct mic_bootparam *bootparam = mdev->dp;
104
105 mdev->ops->ack_interrupt(mdev);
106
107 switch (bootparam->shutdown_status) {
108 case MIC_HALTED:
109 case MIC_POWER_OFF:
110 case MIC_RESTART:
111 /* Fall through */
112 case MIC_CRASHED:
113 schedule_work(&mdev->shutdown_work);
114 break;
115 default:
116 break;
117 };
118 return IRQ_HANDLED;
119}
120
66/** 121/**
67 * mic_ops_init: Initialize HW specific operation tables. 122 * mic_ops_init: Initialize HW specific operation tables.
68 * 123 *
@@ -136,6 +191,26 @@ mic_device_init(struct mic_device *mdev, struct pci_dev *pdev)
136 mic_sysfs_init(mdev); 191 mic_sysfs_init(mdev);
137 mutex_init(&mdev->mic_mutex); 192 mutex_init(&mdev->mic_mutex);
138 mdev->irq_info.next_avail_src = 0; 193 mdev->irq_info.next_avail_src = 0;
194 INIT_WORK(&mdev->reset_trigger_work, mic_reset_trigger_work);
195 INIT_WORK(&mdev->shutdown_work, mic_shutdown_work);
196}
197
198/**
199 * mic_device_uninit - Frees resources allocated during mic_device_init(..)
200 *
201 * @mdev: pointer to mic_device instance
202 *
203 * returns none
204 */
205static void mic_device_uninit(struct mic_device *mdev)
206{
207 /* The cmdline sysfs entry might have allocated cmdline */
208 kfree(mdev->cmdline);
209 kfree(mdev->firmware);
210 kfree(mdev->ramdisk);
211 kfree(mdev->bootmode);
212 flush_work(&mdev->reset_trigger_work);
213 flush_work(&mdev->shutdown_work);
139} 214}
140 215
141/** 216/**
@@ -170,7 +245,7 @@ static int mic_probe(struct pci_dev *pdev,
170 rc = pci_enable_device(pdev); 245 rc = pci_enable_device(pdev);
171 if (rc) { 246 if (rc) {
172 dev_err(&pdev->dev, "failed to enable pci device.\n"); 247 dev_err(&pdev->dev, "failed to enable pci device.\n");
173 goto ida_remove; 248 goto uninit_device;
174 } 249 }
175 250
176 pci_set_master(pdev); 251 pci_set_master(pdev);
@@ -228,7 +303,40 @@ static int mic_probe(struct pci_dev *pdev,
228 "device_create_with_groups failed rc %d\n", rc); 303 "device_create_with_groups failed rc %d\n", rc);
229 goto smpt_uninit; 304 goto smpt_uninit;
230 } 305 }
306 mdev->state_sysfs = sysfs_get_dirent(mdev->sdev->kobj.sd,
307 NULL, "state");
308 if (!mdev->state_sysfs) {
309 rc = -ENODEV;
310 dev_err(&pdev->dev, "sysfs_get_dirent failed rc %d\n", rc);
311 goto destroy_device;
312 }
313
314 rc = mic_dp_init(mdev);
315 if (rc) {
316 dev_err(&pdev->dev, "mic_dp_init failed rc %d\n", rc);
317 goto sysfs_put;
318 }
319 mutex_lock(&mdev->mic_mutex);
320
321 mdev->shutdown_db = mic_next_db(mdev);
322 mdev->shutdown_cookie = mic_request_irq(mdev, mic_shutdown_db,
323 "shutdown-interrupt", mdev, mdev->shutdown_db, MIC_INTR_DB);
324 if (IS_ERR(mdev->shutdown_cookie)) {
325 rc = PTR_ERR(mdev->shutdown_cookie);
326 mutex_unlock(&mdev->mic_mutex);
327 goto dp_uninit;
328 }
329 mutex_unlock(&mdev->mic_mutex);
330 mic_bootparam_init(mdev);
331
332 mic_create_debug_dir(mdev);
231 return 0; 333 return 0;
334dp_uninit:
335 mic_dp_uninit(mdev);
336sysfs_put:
337 sysfs_put(mdev->state_sysfs);
338destroy_device:
339 device_destroy(g_mic_class, MKDEV(MAJOR(g_mic_devno), mdev->id));
232smpt_uninit: 340smpt_uninit:
233 mic_smpt_uninit(mdev); 341 mic_smpt_uninit(mdev);
234free_interrupts: 342free_interrupts:
@@ -241,7 +349,8 @@ release_regions:
241 pci_release_regions(pdev); 349 pci_release_regions(pdev);
242disable_device: 350disable_device:
243 pci_disable_device(pdev); 351 pci_disable_device(pdev);
244ida_remove: 352uninit_device:
353 mic_device_uninit(mdev);
245 ida_simple_remove(&g_mic_ida, mdev->id); 354 ida_simple_remove(&g_mic_ida, mdev->id);
246ida_fail: 355ida_fail:
247 kfree(mdev); 356 kfree(mdev);
@@ -265,11 +374,20 @@ static void mic_remove(struct pci_dev *pdev)
265 if (!mdev) 374 if (!mdev)
266 return; 375 return;
267 376
377 mic_stop(mdev, false);
378 mic_delete_debug_dir(mdev);
379 mutex_lock(&mdev->mic_mutex);
380 mic_free_irq(mdev, mdev->shutdown_cookie, mdev);
381 mutex_unlock(&mdev->mic_mutex);
382 flush_work(&mdev->shutdown_work);
383 mic_dp_uninit(mdev);
384 sysfs_put(mdev->state_sysfs);
268 device_destroy(g_mic_class, MKDEV(MAJOR(g_mic_devno), mdev->id)); 385 device_destroy(g_mic_class, MKDEV(MAJOR(g_mic_devno), mdev->id));
269 mic_smpt_uninit(mdev); 386 mic_smpt_uninit(mdev);
270 mic_free_interrupts(mdev, pdev); 387 mic_free_interrupts(mdev, pdev);
271 iounmap(mdev->mmio.va); 388 iounmap(mdev->mmio.va);
272 iounmap(mdev->aper.va); 389 iounmap(mdev->aper.va);
390 mic_device_uninit(mdev);
273 pci_release_regions(pdev); 391 pci_release_regions(pdev);
274 pci_disable_device(pdev); 392 pci_disable_device(pdev);
275 ida_simple_remove(&g_mic_ida, mdev->id); 393 ida_simple_remove(&g_mic_ida, mdev->id);
@@ -300,14 +418,16 @@ static int __init mic_init(void)
300 goto cleanup_chrdev; 418 goto cleanup_chrdev;
301 } 419 }
302 420
421 mic_init_debugfs();
303 ida_init(&g_mic_ida); 422 ida_init(&g_mic_ida);
304 ret = pci_register_driver(&mic_driver); 423 ret = pci_register_driver(&mic_driver);
305 if (ret) { 424 if (ret) {
306 pr_err("pci_register_driver failed ret %d\n", ret); 425 pr_err("pci_register_driver failed ret %d\n", ret);
307 goto class_destroy; 426 goto cleanup_debugfs;
308 } 427 }
309 return ret; 428 return ret;
310class_destroy: 429cleanup_debugfs:
430 mic_exit_debugfs();
311 class_destroy(g_mic_class); 431 class_destroy(g_mic_class);
312cleanup_chrdev: 432cleanup_chrdev:
313 unregister_chrdev_region(g_mic_devno, MIC_MAX_NUM_DEVS); 433 unregister_chrdev_region(g_mic_devno, MIC_MAX_NUM_DEVS);
@@ -319,6 +439,7 @@ static void __exit mic_exit(void)
319{ 439{
320 pci_unregister_driver(&mic_driver); 440 pci_unregister_driver(&mic_driver);
321 ida_destroy(&g_mic_ida); 441 ida_destroy(&g_mic_ida);
442 mic_exit_debugfs();
322 class_destroy(g_mic_class); 443 class_destroy(g_mic_class);
323 unregister_chrdev_region(g_mic_devno, MIC_MAX_NUM_DEVS); 444 unregister_chrdev_region(g_mic_devno, MIC_MAX_NUM_DEVS);
324} 445}
diff --git a/drivers/misc/mic/host/mic_sysfs.c b/drivers/misc/mic/host/mic_sysfs.c
index 972c18255263..aaf849945111 100644
--- a/drivers/misc/mic/host/mic_sysfs.c
+++ b/drivers/misc/mic/host/mic_sysfs.c
@@ -20,9 +20,50 @@
20 */ 20 */
21#include <linux/pci.h> 21#include <linux/pci.h>
22 22
23#include <linux/mic_common.h>
23#include "../common/mic_device.h" 24#include "../common/mic_device.h"
24#include "mic_device.h" 25#include "mic_device.h"
25 26
27/*
28 * A state-to-string lookup table, for exposing a human readable state
29 * via sysfs. Always keep in sync with enum mic_states
30 */
31static const char * const mic_state_string[] = {
32 [MIC_OFFLINE] = "offline",
33 [MIC_ONLINE] = "online",
34 [MIC_SHUTTING_DOWN] = "shutting_down",
35 [MIC_RESET_FAILED] = "reset_failed",
36};
37
38/*
39 * A shutdown-status-to-string lookup table, for exposing a human
40 * readable state via sysfs. Always keep in sync with enum mic_shutdown_status
41 */
42static const char * const mic_shutdown_status_string[] = {
43 [MIC_NOP] = "nop",
44 [MIC_CRASHED] = "crashed",
45 [MIC_HALTED] = "halted",
46 [MIC_POWER_OFF] = "poweroff",
47 [MIC_RESTART] = "restart",
48};
49
50void mic_set_shutdown_status(struct mic_device *mdev, u8 shutdown_status)
51{
52 dev_dbg(mdev->sdev->parent, "Shutdown Status %s -> %s\n",
53 mic_shutdown_status_string[mdev->shutdown_status],
54 mic_shutdown_status_string[shutdown_status]);
55 mdev->shutdown_status = shutdown_status;
56}
57
58void mic_set_state(struct mic_device *mdev, u8 state)
59{
60 dev_dbg(mdev->sdev->parent, "State %s -> %s\n",
61 mic_state_string[mdev->state],
62 mic_state_string[state]);
63 mdev->state = state;
64 sysfs_notify_dirent(mdev->state_sysfs);
65}
66
26static ssize_t 67static ssize_t
27mic_show_family(struct device *dev, struct device_attribute *attr, char *buf) 68mic_show_family(struct device *dev, struct device_attribute *attr, char *buf)
28{ 69{
@@ -75,9 +116,337 @@ mic_show_stepping(struct device *dev, struct device_attribute *attr, char *buf)
75} 116}
76static DEVICE_ATTR(stepping, S_IRUGO, mic_show_stepping, NULL); 117static DEVICE_ATTR(stepping, S_IRUGO, mic_show_stepping, NULL);
77 118
119static ssize_t
120mic_show_state(struct device *dev, struct device_attribute *attr, char *buf)
121{
122 struct mic_device *mdev = dev_get_drvdata(dev->parent);
123
124 if (!mdev || mdev->state >= MIC_LAST)
125 return -EINVAL;
126
127 return scnprintf(buf, PAGE_SIZE, "%s\n",
128 mic_state_string[mdev->state]);
129}
130
131static ssize_t
132mic_store_state(struct device *dev, struct device_attribute *attr,
133 const char *buf, size_t count)
134{
135 int rc = 0;
136 struct mic_device *mdev = dev_get_drvdata(dev->parent);
137 if (!mdev)
138 return -EINVAL;
139 if (sysfs_streq(buf, "boot")) {
140 rc = mic_start(mdev, buf);
141 if (rc) {
142 dev_err(mdev->sdev->parent,
143 "mic_boot failed rc %d\n", rc);
144 count = rc;
145 }
146 goto done;
147 }
148
149 if (sysfs_streq(buf, "reset")) {
150 schedule_work(&mdev->reset_trigger_work);
151 goto done;
152 }
153
154 if (sysfs_streq(buf, "shutdown")) {
155 mic_shutdown(mdev);
156 goto done;
157 }
158
159 count = -EINVAL;
160done:
161 return count;
162}
163static DEVICE_ATTR(state, S_IRUGO|S_IWUSR, mic_show_state, mic_store_state);
164
165static ssize_t mic_show_shutdown_status(struct device *dev,
166 struct device_attribute *attr, char *buf)
167{
168 struct mic_device *mdev = dev_get_drvdata(dev->parent);
169
170 if (!mdev || mdev->shutdown_status >= MIC_STATUS_LAST)
171 return -EINVAL;
172
173 return scnprintf(buf, PAGE_SIZE, "%s\n",
174 mic_shutdown_status_string[mdev->shutdown_status]);
175}
176static DEVICE_ATTR(shutdown_status, S_IRUGO|S_IWUSR,
177 mic_show_shutdown_status, NULL);
178
179static ssize_t
180mic_show_cmdline(struct device *dev, struct device_attribute *attr, char *buf)
181{
182 struct mic_device *mdev = dev_get_drvdata(dev->parent);
183 char *cmdline;
184
185 if (!mdev)
186 return -EINVAL;
187
188 cmdline = mdev->cmdline;
189
190 if (cmdline)
191 return scnprintf(buf, PAGE_SIZE, "%s\n", cmdline);
192 return 0;
193}
194
195static ssize_t
196mic_store_cmdline(struct device *dev, struct device_attribute *attr,
197 const char *buf, size_t count)
198{
199 struct mic_device *mdev = dev_get_drvdata(dev->parent);
200
201 if (!mdev)
202 return -EINVAL;
203
204 mutex_lock(&mdev->mic_mutex);
205 kfree(mdev->cmdline);
206
207 mdev->cmdline = kmalloc(count + 1, GFP_KERNEL);
208 if (!mdev->cmdline) {
209 count = -ENOMEM;
210 goto unlock;
211 }
212
213 strncpy(mdev->cmdline, buf, count);
214
215 if (mdev->cmdline[count - 1] == '\n')
216 mdev->cmdline[count - 1] = '\0';
217 else
218 mdev->cmdline[count] = '\0';
219unlock:
220 mutex_unlock(&mdev->mic_mutex);
221 return count;
222}
223static DEVICE_ATTR(cmdline, S_IRUGO | S_IWUSR,
224 mic_show_cmdline, mic_store_cmdline);
225
226static ssize_t
227mic_show_firmware(struct device *dev, struct device_attribute *attr, char *buf)
228{
229 struct mic_device *mdev = dev_get_drvdata(dev->parent);
230 char *firmware;
231
232 if (!mdev)
233 return -EINVAL;
234
235 firmware = mdev->firmware;
236
237 if (firmware)
238 return scnprintf(buf, PAGE_SIZE, "%s\n", firmware);
239 return 0;
240}
241
242static ssize_t
243mic_store_firmware(struct device *dev, struct device_attribute *attr,
244 const char *buf, size_t count)
245{
246 struct mic_device *mdev = dev_get_drvdata(dev->parent);
247
248 if (!mdev)
249 return -EINVAL;
250
251 mutex_lock(&mdev->mic_mutex);
252 kfree(mdev->firmware);
253
254 mdev->firmware = kmalloc(count + 1, GFP_KERNEL);
255 if (!mdev->firmware) {
256 count = -ENOMEM;
257 goto unlock;
258 }
259 strncpy(mdev->firmware, buf, count);
260
261 if (mdev->firmware[count - 1] == '\n')
262 mdev->firmware[count - 1] = '\0';
263 else
264 mdev->firmware[count] = '\0';
265unlock:
266 mutex_unlock(&mdev->mic_mutex);
267 return count;
268}
269static DEVICE_ATTR(firmware, S_IRUGO | S_IWUSR,
270 mic_show_firmware, mic_store_firmware);
271
272static ssize_t
273mic_show_ramdisk(struct device *dev, struct device_attribute *attr, char *buf)
274{
275 struct mic_device *mdev = dev_get_drvdata(dev->parent);
276 char *ramdisk;
277
278 if (!mdev)
279 return -EINVAL;
280
281 ramdisk = mdev->ramdisk;
282
283 if (ramdisk)
284 return scnprintf(buf, PAGE_SIZE, "%s\n", ramdisk);
285 return 0;
286}
287
288static ssize_t
289mic_store_ramdisk(struct device *dev, struct device_attribute *attr,
290 const char *buf, size_t count)
291{
292 struct mic_device *mdev = dev_get_drvdata(dev->parent);
293
294 if (!mdev)
295 return -EINVAL;
296
297 mutex_lock(&mdev->mic_mutex);
298 kfree(mdev->ramdisk);
299
300 mdev->ramdisk = kmalloc(count + 1, GFP_KERNEL);
301 if (!mdev->ramdisk) {
302 count = -ENOMEM;
303 goto unlock;
304 }
305
306 strncpy(mdev->ramdisk, buf, count);
307
308 if (mdev->ramdisk[count - 1] == '\n')
309 mdev->ramdisk[count - 1] = '\0';
310 else
311 mdev->ramdisk[count] = '\0';
312unlock:
313 mutex_unlock(&mdev->mic_mutex);
314 return count;
315}
316static DEVICE_ATTR(ramdisk, S_IRUGO | S_IWUSR,
317 mic_show_ramdisk, mic_store_ramdisk);
318
319static ssize_t
320mic_show_bootmode(struct device *dev, struct device_attribute *attr, char *buf)
321{
322 struct mic_device *mdev = dev_get_drvdata(dev->parent);
323 char *bootmode;
324
325 if (!mdev)
326 return -EINVAL;
327
328 bootmode = mdev->bootmode;
329
330 if (bootmode)
331 return scnprintf(buf, PAGE_SIZE, "%s\n", bootmode);
332 return 0;
333}
334
335static ssize_t
336mic_store_bootmode(struct device *dev, struct device_attribute *attr,
337 const char *buf, size_t count)
338{
339 struct mic_device *mdev = dev_get_drvdata(dev->parent);
340
341 if (!mdev)
342 return -EINVAL;
343
344 if (!sysfs_streq(buf, "linux") && !sysfs_streq(buf, "elf"))
345 return -EINVAL;
346
347 mutex_lock(&mdev->mic_mutex);
348 kfree(mdev->bootmode);
349
350 mdev->bootmode = kmalloc(count + 1, GFP_KERNEL);
351 if (!mdev->bootmode) {
352 count = -ENOMEM;
353 goto unlock;
354 }
355
356 strncpy(mdev->bootmode, buf, count);
357
358 if (mdev->bootmode[count - 1] == '\n')
359 mdev->bootmode[count - 1] = '\0';
360 else
361 mdev->bootmode[count] = '\0';
362unlock:
363 mutex_unlock(&mdev->mic_mutex);
364 return count;
365}
366static DEVICE_ATTR(bootmode, S_IRUGO | S_IWUSR,
367 mic_show_bootmode, mic_store_bootmode);
368
369static ssize_t
370mic_show_log_buf_addr(struct device *dev, struct device_attribute *attr,
371 char *buf)
372{
373 struct mic_device *mdev = dev_get_drvdata(dev->parent);
374
375 if (!mdev)
376 return -EINVAL;
377
378 return scnprintf(buf, PAGE_SIZE, "%p\n", mdev->log_buf_addr);
379}
380
381static ssize_t
382mic_store_log_buf_addr(struct device *dev, struct device_attribute *attr,
383 const char *buf, size_t count)
384{
385 struct mic_device *mdev = dev_get_drvdata(dev->parent);
386 int ret;
387 unsigned long addr;
388
389 if (!mdev)
390 return -EINVAL;
391
392 ret = kstrtoul(buf, 16, &addr);
393 if (ret)
394 goto exit;
395
396 mdev->log_buf_addr = (void *)addr;
397 ret = count;
398exit:
399 return ret;
400}
401static DEVICE_ATTR(log_buf_addr, S_IRUGO | S_IWUSR,
402 mic_show_log_buf_addr, mic_store_log_buf_addr);
403
404static ssize_t
405mic_show_log_buf_len(struct device *dev, struct device_attribute *attr,
406 char *buf)
407{
408 struct mic_device *mdev = dev_get_drvdata(dev->parent);
409
410 if (!mdev)
411 return -EINVAL;
412
413 return scnprintf(buf, PAGE_SIZE, "%p\n", mdev->log_buf_len);
414}
415
416static ssize_t
417mic_store_log_buf_len(struct device *dev, struct device_attribute *attr,
418 const char *buf, size_t count)
419{
420 struct mic_device *mdev = dev_get_drvdata(dev->parent);
421 int ret;
422 unsigned long addr;
423
424 if (!mdev)
425 return -EINVAL;
426
427 ret = kstrtoul(buf, 16, &addr);
428 if (ret)
429 goto exit;
430
431 mdev->log_buf_len = (int *)addr;
432 ret = count;
433exit:
434 return ret;
435}
436static DEVICE_ATTR(log_buf_len, S_IRUGO | S_IWUSR,
437 mic_show_log_buf_len, mic_store_log_buf_len);
438
78static struct attribute *mic_default_attrs[] = { 439static struct attribute *mic_default_attrs[] = {
79 &dev_attr_family.attr, 440 &dev_attr_family.attr,
80 &dev_attr_stepping.attr, 441 &dev_attr_stepping.attr,
442 &dev_attr_state.attr,
443 &dev_attr_shutdown_status.attr,
444 &dev_attr_cmdline.attr,
445 &dev_attr_firmware.attr,
446 &dev_attr_ramdisk.attr,
447 &dev_attr_bootmode.attr,
448 &dev_attr_log_buf_addr.attr,
449 &dev_attr_log_buf_len.attr,
81 450
82 NULL 451 NULL
83}; 452};
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 = {
diff --git a/drivers/misc/mic/host/mic_x100.h b/drivers/misc/mic/host/mic_x100.h
index 642cae9a0041..8b7daa182e54 100644
--- a/drivers/misc/mic/host/mic_x100.h
+++ b/drivers/misc/mic/host/mic_x100.h
@@ -69,6 +69,15 @@
69#define MIC_X100_NUM_SBOX_IRQ 8 69#define MIC_X100_NUM_SBOX_IRQ 8
70#define MIC_X100_NUM_RDMASR_IRQ 8 70#define MIC_X100_NUM_RDMASR_IRQ 8
71#define MIC_X100_RDMASR_IRQ_BASE 17 71#define MIC_X100_RDMASR_IRQ_BASE 17
72#define MIC_X100_SPAD2_DOWNLOAD_STATUS(x) ((x) & 0x1)
73#define MIC_X100_SPAD2_APIC_ID(x) (((x) >> 1) & 0x1ff)
74#define MIC_X100_SPAD2_DOWNLOAD_ADDR(x) ((x) & 0xfffff000)
75#define MIC_X100_SBOX_APICICR7 0x0000AA08
76#define MIC_X100_SBOX_RGCR 0x00004010
77#define MIC_X100_SBOX_SDBIC0 0x0000CC90
78#define MIC_X100_DOWNLOAD_INFO 2
79#define MIC_X100_FW_SIZE 5
80#define MIC_X100_POSTCODE 0x242c
72 81
73static const u16 mic_x100_intr_init[] = { 82static const u16 mic_x100_intr_init[] = {
74 MIC_X100_DOORBELL_IDX_START, 83 MIC_X100_DOORBELL_IDX_START,
@@ -79,6 +88,9 @@ static const u16 mic_x100_intr_init[] = {
79 MIC_X100_NUM_ERR, 88 MIC_X100_NUM_ERR,
80}; 89};
81 90
91/* Host->Card(bootstrap) Interrupt Vector */
92#define MIC_X100_BSP_INTERRUPT_VECTOR 229
93
82extern struct mic_hw_ops mic_x100_ops; 94extern struct mic_hw_ops mic_x100_ops;
83extern struct mic_smpt_ops mic_x100_smpt_ops; 95extern struct mic_smpt_ops mic_x100_smpt_ops;
84extern struct mic_hw_intr_ops mic_x100_intr_ops; 96extern struct mic_hw_intr_ops mic_x100_intr_ops;