aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLogan Gunthorpe <logang@deltatee.com>2017-08-03 14:19:47 -0400
committerJon Mason <jdmason@kudzu.us>2017-11-18 20:37:12 -0500
commitec0467ccbdeb69a86c8729073057bda7bce00eec (patch)
tree1ecef00f35997951e9f3380c8057fd9e0e4567d3
parent33dea5aae0320345af26ae9aba0894a930e0d4ec (diff)
NTB: switchtec_ntb: Initialize hardware for memory windows
Add the code to initialize the memory windows in the hardware. This includes setting up the requester ID table, and figuring out which BAR corresponds to which memory window. (Seeing the switch can be configured with any number of BARs.) Also, seeing the device doesn't have hardware for scratchpads or determining the link status, we create a shared memory window that has these features. A magic number with a version component will be used to determine if the other side's driver is actually up. The shared memory window also informs the other side of the size and count of the local memory windows. Signed-off-by: Logan Gunthorpe <logang@deltatee.com> Reviewed-by: Stephen Bates <sbates@raithlin.com> Reviewed-by: Kurt Schwemmer <kurt.schwemmer@microsemi.com> Acked-by: Allen Hubbe <Allen.Hubbe@dell.com> Signed-off-by: Jon Mason <jdmason@kudzu.us>
-rw-r--r--drivers/ntb/hw/mscc/ntb_hw_switchtec.c360
1 files changed, 360 insertions, 0 deletions
diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c
index 253efba72275..831bfdf40068 100644
--- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c
+++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c
@@ -15,37 +15,396 @@
15 15
16#include <linux/switchtec.h> 16#include <linux/switchtec.h>
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/delay.h>
19#include <linux/kthread.h>
18 20
19MODULE_DESCRIPTION("Microsemi Switchtec(tm) NTB Driver"); 21MODULE_DESCRIPTION("Microsemi Switchtec(tm) NTB Driver");
20MODULE_VERSION("0.1"); 22MODULE_VERSION("0.1");
21MODULE_LICENSE("GPL"); 23MODULE_LICENSE("GPL");
22MODULE_AUTHOR("Microsemi Corporation"); 24MODULE_AUTHOR("Microsemi Corporation");
23 25
26static bool use_lut_mws;
27module_param(use_lut_mws, bool, 0644);
28MODULE_PARM_DESC(use_lut_mws,
29 "Enable the use of the LUT based memory windows");
30
31#ifndef ioread64
32#ifdef readq
33#define ioread64 readq
34#else
35#define ioread64 _ioread64
36static inline u64 _ioread64(void __iomem *mmio)
37{
38 u64 low, high;
39
40 low = ioread32(mmio);
41 high = ioread32(mmio + sizeof(u32));
42 return low | (high << 32);
43}
44#endif
45#endif
46
47#ifndef iowrite64
48#ifdef writeq
49#define iowrite64 writeq
50#else
51#define iowrite64 _iowrite64
52static inline void _iowrite64(u64 val, void __iomem *mmio)
53{
54 iowrite32(val, mmio);
55 iowrite32(val >> 32, mmio + sizeof(u32));
56}
57#endif
58#endif
59
60#define SWITCHTEC_NTB_MAGIC 0x45CC0001
61#define MAX_MWS 128
62
63struct shared_mw {
64 u32 magic;
65 u32 partition_id;
66 u64 mw_sizes[MAX_MWS];
67};
68
69#define MAX_DIRECT_MW ARRAY_SIZE(((struct ntb_ctrl_regs *)(0))->bar_entry)
70#define LUT_SIZE SZ_64K
71
24struct switchtec_ntb { 72struct switchtec_ntb {
25 struct switchtec_dev *stdev; 73 struct switchtec_dev *stdev;
74
75 int self_partition;
76 int peer_partition;
77
78 struct ntb_info_regs __iomem *mmio_ntb;
79 struct ntb_ctrl_regs __iomem *mmio_ctrl;
80 struct ntb_dbmsg_regs __iomem *mmio_dbmsg;
81 struct ntb_ctrl_regs __iomem *mmio_self_ctrl;
82 struct ntb_ctrl_regs __iomem *mmio_peer_ctrl;
83 struct ntb_dbmsg_regs __iomem *mmio_self_dbmsg;
84
85 struct shared_mw *self_shared;
86 struct shared_mw __iomem *peer_shared;
87 dma_addr_t self_shared_dma;
88
89 int nr_direct_mw;
90 int nr_lut_mw;
91 int direct_mw_to_bar[MAX_DIRECT_MW];
92
93 int peer_nr_direct_mw;
94 int peer_nr_lut_mw;
95 int peer_direct_mw_to_bar[MAX_DIRECT_MW];
26}; 96};
27 97
98static int switchtec_ntb_part_op(struct switchtec_ntb *sndev,
99 struct ntb_ctrl_regs __iomem *ctl,
100 u32 op, int wait_status)
101{
102 static const char * const op_text[] = {
103 [NTB_CTRL_PART_OP_LOCK] = "lock",
104 [NTB_CTRL_PART_OP_CFG] = "configure",
105 [NTB_CTRL_PART_OP_RESET] = "reset",
106 };
107
108 int i;
109 u32 ps;
110 int status;
111
112 switch (op) {
113 case NTB_CTRL_PART_OP_LOCK:
114 status = NTB_CTRL_PART_STATUS_LOCKING;
115 break;
116 case NTB_CTRL_PART_OP_CFG:
117 status = NTB_CTRL_PART_STATUS_CONFIGURING;
118 break;
119 case NTB_CTRL_PART_OP_RESET:
120 status = NTB_CTRL_PART_STATUS_RESETTING;
121 break;
122 default:
123 return -EINVAL;
124 }
125
126 iowrite32(op, &ctl->partition_op);
127
128 for (i = 0; i < 1000; i++) {
129 if (msleep_interruptible(50) != 0) {
130 iowrite32(NTB_CTRL_PART_OP_RESET, &ctl->partition_op);
131 return -EINTR;
132 }
133
134 ps = ioread32(&ctl->partition_status) & 0xFFFF;
135
136 if (ps != status)
137 break;
138 }
139
140 if (ps == wait_status)
141 return 0;
142
143 if (ps == status) {
144 dev_err(&sndev->stdev->dev,
145 "Timed out while peforming %s (%d). (%08x)",
146 op_text[op], op,
147 ioread32(&ctl->partition_status));
148
149 return -ETIMEDOUT;
150 }
151
152 return -EIO;
153}
154
155static void switchtec_ntb_init_sndev(struct switchtec_ntb *sndev)
156{
157 u64 part_map;
158
159 sndev->self_partition = sndev->stdev->partition;
160
161 sndev->mmio_ntb = sndev->stdev->mmio_ntb;
162 part_map = ioread64(&sndev->mmio_ntb->ep_map);
163 part_map &= ~(1 << sndev->self_partition);
164 sndev->peer_partition = ffs(part_map) - 1;
165
166 dev_dbg(&sndev->stdev->dev, "Partition ID %d of %d (%llx)",
167 sndev->self_partition, sndev->stdev->partition_count,
168 part_map);
169
170 sndev->mmio_ctrl = (void * __iomem)sndev->mmio_ntb +
171 SWITCHTEC_NTB_REG_CTRL_OFFSET;
172 sndev->mmio_dbmsg = (void * __iomem)sndev->mmio_ntb +
173 SWITCHTEC_NTB_REG_DBMSG_OFFSET;
174
175 sndev->mmio_self_ctrl = &sndev->mmio_ctrl[sndev->self_partition];
176 sndev->mmio_peer_ctrl = &sndev->mmio_ctrl[sndev->peer_partition];
177 sndev->mmio_self_dbmsg = &sndev->mmio_dbmsg[sndev->self_partition];
178}
179
180static int map_bars(int *map, struct ntb_ctrl_regs __iomem *ctrl)
181{
182 int i;
183 int cnt = 0;
184
185 for (i = 0; i < ARRAY_SIZE(ctrl->bar_entry); i++) {
186 u32 r = ioread32(&ctrl->bar_entry[i].ctl);
187
188 if (r & NTB_CTRL_BAR_VALID)
189 map[cnt++] = i;
190 }
191
192 return cnt;
193}
194
195static void switchtec_ntb_init_mw(struct switchtec_ntb *sndev)
196{
197 sndev->nr_direct_mw = map_bars(sndev->direct_mw_to_bar,
198 sndev->mmio_self_ctrl);
199
200 sndev->nr_lut_mw = ioread16(&sndev->mmio_self_ctrl->lut_table_entries);
201 sndev->nr_lut_mw = rounddown_pow_of_two(sndev->nr_lut_mw);
202
203 dev_dbg(&sndev->stdev->dev, "MWs: %d direct, %d lut",
204 sndev->nr_direct_mw, sndev->nr_lut_mw);
205
206 sndev->peer_nr_direct_mw = map_bars(sndev->peer_direct_mw_to_bar,
207 sndev->mmio_peer_ctrl);
208
209 sndev->peer_nr_lut_mw =
210 ioread16(&sndev->mmio_peer_ctrl->lut_table_entries);
211 sndev->peer_nr_lut_mw = rounddown_pow_of_two(sndev->peer_nr_lut_mw);
212
213 dev_dbg(&sndev->stdev->dev, "Peer MWs: %d direct, %d lut",
214 sndev->peer_nr_direct_mw, sndev->peer_nr_lut_mw);
215
216}
217
218static int switchtec_ntb_init_req_id_table(struct switchtec_ntb *sndev)
219{
220 int rc = 0;
221 u16 req_id;
222 u32 error;
223
224 req_id = ioread16(&sndev->mmio_ntb->requester_id);
225
226 if (ioread32(&sndev->mmio_self_ctrl->req_id_table_size) < 2) {
227 dev_err(&sndev->stdev->dev,
228 "Not enough requester IDs available.");
229 return -EFAULT;
230 }
231
232 rc = switchtec_ntb_part_op(sndev, sndev->mmio_self_ctrl,
233 NTB_CTRL_PART_OP_LOCK,
234 NTB_CTRL_PART_STATUS_LOCKED);
235 if (rc)
236 return rc;
237
238 iowrite32(NTB_PART_CTRL_ID_PROT_DIS,
239 &sndev->mmio_self_ctrl->partition_ctrl);
240
241 /*
242 * Root Complex Requester ID (which is 0:00.0)
243 */
244 iowrite32(0 << 16 | NTB_CTRL_REQ_ID_EN,
245 &sndev->mmio_self_ctrl->req_id_table[0]);
246
247 /*
248 * Host Bridge Requester ID (as read from the mmap address)
249 */
250 iowrite32(req_id << 16 | NTB_CTRL_REQ_ID_EN,
251 &sndev->mmio_self_ctrl->req_id_table[1]);
252
253 rc = switchtec_ntb_part_op(sndev, sndev->mmio_self_ctrl,
254 NTB_CTRL_PART_OP_CFG,
255 NTB_CTRL_PART_STATUS_NORMAL);
256 if (rc == -EIO) {
257 error = ioread32(&sndev->mmio_self_ctrl->req_id_error);
258 dev_err(&sndev->stdev->dev,
259 "Error setting up the requester ID table: %08x",
260 error);
261 }
262
263 return rc;
264}
265
266static void switchtec_ntb_init_shared(struct switchtec_ntb *sndev)
267{
268 int i;
269
270 memset(sndev->self_shared, 0, LUT_SIZE);
271 sndev->self_shared->magic = SWITCHTEC_NTB_MAGIC;
272 sndev->self_shared->partition_id = sndev->stdev->partition;
273
274 for (i = 0; i < sndev->nr_direct_mw; i++) {
275 int bar = sndev->direct_mw_to_bar[i];
276 resource_size_t sz = pci_resource_len(sndev->stdev->pdev, bar);
277
278 if (i == 0)
279 sz = min_t(resource_size_t, sz,
280 LUT_SIZE * sndev->nr_lut_mw);
281
282 sndev->self_shared->mw_sizes[i] = sz;
283 }
284
285 for (i = 0; i < sndev->nr_lut_mw; i++) {
286 int idx = sndev->nr_direct_mw + i;
287
288 sndev->self_shared->mw_sizes[idx] = LUT_SIZE;
289 }
290}
291
292static int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev)
293{
294 struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
295 int bar = sndev->direct_mw_to_bar[0];
296 u32 ctl_val;
297 int rc;
298
299 sndev->self_shared = dma_zalloc_coherent(&sndev->stdev->pdev->dev,
300 LUT_SIZE,
301 &sndev->self_shared_dma,
302 GFP_KERNEL);
303 if (!sndev->self_shared) {
304 dev_err(&sndev->stdev->dev,
305 "unable to allocate memory for shared mw");
306 return -ENOMEM;
307 }
308
309 switchtec_ntb_init_shared(sndev);
310
311 rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK,
312 NTB_CTRL_PART_STATUS_LOCKED);
313 if (rc)
314 goto unalloc_and_exit;
315
316 ctl_val = ioread32(&ctl->bar_entry[bar].ctl);
317 ctl_val &= 0xFF;
318 ctl_val |= NTB_CTRL_BAR_LUT_WIN_EN;
319 ctl_val |= ilog2(LUT_SIZE) << 8;
320 ctl_val |= (sndev->nr_lut_mw - 1) << 14;
321 iowrite32(ctl_val, &ctl->bar_entry[bar].ctl);
322
323 iowrite64((NTB_CTRL_LUT_EN | (sndev->self_partition << 1) |
324 sndev->self_shared_dma),
325 &ctl->lut_entry[0]);
326
327 rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG,
328 NTB_CTRL_PART_STATUS_NORMAL);
329 if (rc) {
330 u32 bar_error, lut_error;
331
332 bar_error = ioread32(&ctl->bar_error);
333 lut_error = ioread32(&ctl->lut_error);
334 dev_err(&sndev->stdev->dev,
335 "Error setting up shared MW: %08x / %08x",
336 bar_error, lut_error);
337 goto unalloc_and_exit;
338 }
339
340 sndev->peer_shared = pci_iomap(sndev->stdev->pdev, bar, LUT_SIZE);
341 if (!sndev->peer_shared) {
342 rc = -ENOMEM;
343 goto unalloc_and_exit;
344 }
345
346 dev_dbg(&sndev->stdev->dev, "Shared MW Ready");
347 return 0;
348
349unalloc_and_exit:
350 dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE,
351 sndev->self_shared, sndev->self_shared_dma);
352
353 return rc;
354}
355
356static void switchtec_ntb_deinit_shared_mw(struct switchtec_ntb *sndev)
357{
358 if (sndev->peer_shared)
359 pci_iounmap(sndev->stdev->pdev, sndev->peer_shared);
360
361 if (sndev->self_shared)
362 dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE,
363 sndev->self_shared,
364 sndev->self_shared_dma);
365}
366
28static int switchtec_ntb_add(struct device *dev, 367static int switchtec_ntb_add(struct device *dev,
29 struct class_interface *class_intf) 368 struct class_interface *class_intf)
30{ 369{
31 struct switchtec_dev *stdev = to_stdev(dev); 370 struct switchtec_dev *stdev = to_stdev(dev);
32 struct switchtec_ntb *sndev; 371 struct switchtec_ntb *sndev;
372 int rc;
33 373
34 stdev->sndev = NULL; 374 stdev->sndev = NULL;
35 375
36 if (stdev->pdev->class != MICROSEMI_NTB_CLASSCODE) 376 if (stdev->pdev->class != MICROSEMI_NTB_CLASSCODE)
37 return -ENODEV; 377 return -ENODEV;
38 378
379 if (stdev->partition_count != 2)
380 dev_warn(dev, "ntb driver only supports 2 partitions");
381
39 sndev = kzalloc_node(sizeof(*sndev), GFP_KERNEL, dev_to_node(dev)); 382 sndev = kzalloc_node(sizeof(*sndev), GFP_KERNEL, dev_to_node(dev));
40 if (!sndev) 383 if (!sndev)
41 return -ENOMEM; 384 return -ENOMEM;
42 385
43 sndev->stdev = stdev; 386 sndev->stdev = stdev;
44 387
388 switchtec_ntb_init_sndev(sndev);
389 switchtec_ntb_init_mw(sndev);
390
391 rc = switchtec_ntb_init_req_id_table(sndev);
392 if (rc)
393 goto free_and_exit;
394
395 rc = switchtec_ntb_init_shared_mw(sndev);
396 if (rc)
397 goto free_and_exit;
398
45 stdev->sndev = sndev; 399 stdev->sndev = sndev;
46 dev_info(dev, "NTB device registered"); 400 dev_info(dev, "NTB device registered");
47 401
48 return 0; 402 return 0;
403
404free_and_exit:
405 kfree(sndev);
406 dev_err(dev, "failed to register ntb device: %d", rc);
407 return rc;
49} 408}
50 409
51void switchtec_ntb_remove(struct device *dev, 410void switchtec_ntb_remove(struct device *dev,
@@ -58,6 +417,7 @@ void switchtec_ntb_remove(struct device *dev,
58 return; 417 return;
59 418
60 stdev->sndev = NULL; 419 stdev->sndev = NULL;
420 switchtec_ntb_deinit_shared_mw(sndev);
61 kfree(sndev); 421 kfree(sndev);
62 dev_info(dev, "ntb device unregistered"); 422 dev_info(dev, "ntb device unregistered");
63} 423}