aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/ntb/hw/mscc/ntb_hw_switchtec.c213
1 files changed, 210 insertions, 3 deletions
diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c
index 205bd9481122..afe8ed6f3b23 100644
--- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c
+++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c
@@ -25,6 +25,11 @@ MODULE_VERSION("0.1");
25MODULE_LICENSE("GPL"); 25MODULE_LICENSE("GPL");
26MODULE_AUTHOR("Microsemi Corporation"); 26MODULE_AUTHOR("Microsemi Corporation");
27 27
28static ulong max_mw_size = SZ_2M;
29module_param(max_mw_size, ulong, 0644);
30MODULE_PARM_DESC(max_mw_size,
31 "Max memory window size reported to the upper layer");
32
28static bool use_lut_mws; 33static bool use_lut_mws;
29module_param(use_lut_mws, bool, 0644); 34module_param(use_lut_mws, bool, 0644);
30MODULE_PARM_DESC(use_lut_mws, 35MODULE_PARM_DESC(use_lut_mws,
@@ -190,7 +195,27 @@ static int switchtec_ntb_send_msg(struct switchtec_ntb *sndev, int idx,
190 195
191static int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx) 196static int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx)
192{ 197{
193 return 0; 198 struct switchtec_ntb *sndev = ntb_sndev(ntb);
199 int nr_direct_mw = sndev->peer_nr_direct_mw;
200 int nr_lut_mw = sndev->peer_nr_lut_mw - 1;
201
202 if (pidx != NTB_DEF_PEER_IDX)
203 return -EINVAL;
204
205 if (!use_lut_mws)
206 nr_lut_mw = 0;
207
208 return nr_direct_mw + nr_lut_mw;
209}
210
211static int lut_index(struct switchtec_ntb *sndev, int mw_idx)
212{
213 return mw_idx - sndev->nr_direct_mw + 1;
214}
215
216static int peer_lut_index(struct switchtec_ntb *sndev, int mw_idx)
217{
218 return mw_idx - sndev->peer_nr_direct_mw + 1;
194} 219}
195 220
196static int switchtec_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, 221static int switchtec_ntb_mw_get_align(struct ntb_dev *ntb, int pidx,
@@ -198,17 +223,192 @@ static int switchtec_ntb_mw_get_align(struct ntb_dev *ntb, int pidx,
198 resource_size_t *size_align, 223 resource_size_t *size_align,
199 resource_size_t *size_max) 224 resource_size_t *size_max)
200{ 225{
226 struct switchtec_ntb *sndev = ntb_sndev(ntb);
227 int lut;
228 resource_size_t size;
229
230 if (pidx != NTB_DEF_PEER_IDX)
231 return -EINVAL;
232
233 lut = widx >= sndev->peer_nr_direct_mw;
234 size = ioread64(&sndev->peer_shared->mw_sizes[widx]);
235
236 if (size == 0)
237 return -EINVAL;
238
239 if (addr_align)
240 *addr_align = lut ? size : SZ_4K;
241
242 if (size_align)
243 *size_align = lut ? size : SZ_4K;
244
245 if (size_max)
246 *size_max = size;
247
201 return 0; 248 return 0;
202} 249}
203 250
251static void switchtec_ntb_mw_clr_direct(struct switchtec_ntb *sndev, int idx)
252{
253 struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
254 int bar = sndev->peer_direct_mw_to_bar[idx];
255 u32 ctl_val;
256
257 ctl_val = ioread32(&ctl->bar_entry[bar].ctl);
258 ctl_val &= ~NTB_CTRL_BAR_DIR_WIN_EN;
259 iowrite32(ctl_val, &ctl->bar_entry[bar].ctl);
260 iowrite32(0, &ctl->bar_entry[bar].win_size);
261 iowrite64(sndev->self_partition, &ctl->bar_entry[bar].xlate_addr);
262}
263
264static void switchtec_ntb_mw_clr_lut(struct switchtec_ntb *sndev, int idx)
265{
266 struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
267
268 iowrite64(0, &ctl->lut_entry[peer_lut_index(sndev, idx)]);
269}
270
271static void switchtec_ntb_mw_set_direct(struct switchtec_ntb *sndev, int idx,
272 dma_addr_t addr, resource_size_t size)
273{
274 int xlate_pos = ilog2(size);
275 int bar = sndev->peer_direct_mw_to_bar[idx];
276 struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
277 u32 ctl_val;
278
279 ctl_val = ioread32(&ctl->bar_entry[bar].ctl);
280 ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN;
281
282 iowrite32(ctl_val, &ctl->bar_entry[bar].ctl);
283 iowrite32(xlate_pos | size, &ctl->bar_entry[bar].win_size);
284 iowrite64(sndev->self_partition | addr,
285 &ctl->bar_entry[bar].xlate_addr);
286}
287
288static void switchtec_ntb_mw_set_lut(struct switchtec_ntb *sndev, int idx,
289 dma_addr_t addr, resource_size_t size)
290{
291 struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
292
293 iowrite64((NTB_CTRL_LUT_EN | (sndev->self_partition << 1) | addr),
294 &ctl->lut_entry[peer_lut_index(sndev, idx)]);
295}
296
204static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx, 297static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
205 dma_addr_t addr, resource_size_t size) 298 dma_addr_t addr, resource_size_t size)
206{ 299{
207 return 0; 300 struct switchtec_ntb *sndev = ntb_sndev(ntb);
301 struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
302 int xlate_pos = ilog2(size);
303 int nr_direct_mw = sndev->peer_nr_direct_mw;
304 int rc;
305
306 if (pidx != NTB_DEF_PEER_IDX)
307 return -EINVAL;
308
309 dev_dbg(&sndev->stdev->dev, "MW %d: part %d addr %pad size %pap",
310 widx, pidx, &addr, &size);
311
312 if (widx >= switchtec_ntb_mw_count(ntb, pidx))
313 return -EINVAL;
314
315 if (xlate_pos < 12)
316 return -EINVAL;
317
318 rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK,
319 NTB_CTRL_PART_STATUS_LOCKED);
320 if (rc)
321 return rc;
322
323 if (addr == 0 || size == 0) {
324 if (widx < nr_direct_mw)
325 switchtec_ntb_mw_clr_direct(sndev, widx);
326 else
327 switchtec_ntb_mw_clr_lut(sndev, widx);
328 } else {
329 if (widx < nr_direct_mw)
330 switchtec_ntb_mw_set_direct(sndev, widx, addr, size);
331 else
332 switchtec_ntb_mw_set_lut(sndev, widx, addr, size);
333 }
334
335 rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG,
336 NTB_CTRL_PART_STATUS_NORMAL);
337
338 if (rc == -EIO) {
339 dev_err(&sndev->stdev->dev,
340 "Hardware reported an error configuring mw %d: %08x",
341 widx, ioread32(&ctl->bar_error));
342
343 if (widx < nr_direct_mw)
344 switchtec_ntb_mw_clr_direct(sndev, widx);
345 else
346 switchtec_ntb_mw_clr_lut(sndev, widx);
347
348 switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG,
349 NTB_CTRL_PART_STATUS_NORMAL);
350 }
351
352 return rc;
208} 353}
209 354
210static int switchtec_ntb_peer_mw_count(struct ntb_dev *ntb) 355static int switchtec_ntb_peer_mw_count(struct ntb_dev *ntb)
211{ 356{
357 struct switchtec_ntb *sndev = ntb_sndev(ntb);
358
359 return sndev->nr_direct_mw + (use_lut_mws ? sndev->nr_lut_mw - 1 : 0);
360}
361
362static int switchtec_ntb_direct_get_addr(struct switchtec_ntb *sndev,
363 int idx, phys_addr_t *base,
364 resource_size_t *size)
365{
366 int bar = sndev->direct_mw_to_bar[idx];
367 size_t offset = 0;
368
369 if (bar < 0)
370 return -EINVAL;
371
372 if (idx == 0) {
373 /*
374 * This is the direct BAR shared with the LUTs
375 * which means the actual window will be offset
376 * by the size of all the LUT entries.
377 */
378
379 offset = LUT_SIZE * sndev->nr_lut_mw;
380 }
381
382 if (base)
383 *base = pci_resource_start(sndev->ntb.pdev, bar) + offset;
384
385 if (size) {
386 *size = pci_resource_len(sndev->ntb.pdev, bar) - offset;
387 if (offset && *size > offset)
388 *size = offset;
389
390 if (*size > max_mw_size)
391 *size = max_mw_size;
392 }
393
394 return 0;
395}
396
397static int switchtec_ntb_lut_get_addr(struct switchtec_ntb *sndev,
398 int idx, phys_addr_t *base,
399 resource_size_t *size)
400{
401 int bar = sndev->direct_mw_to_bar[0];
402 int offset;
403
404 offset = LUT_SIZE * lut_index(sndev, idx);
405
406 if (base)
407 *base = pci_resource_start(sndev->ntb.pdev, bar) + offset;
408
409 if (size)
410 *size = LUT_SIZE;
411
212 return 0; 412 return 0;
213} 413}
214 414
@@ -216,7 +416,14 @@ static int switchtec_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
216 phys_addr_t *base, 416 phys_addr_t *base,
217 resource_size_t *size) 417 resource_size_t *size)
218{ 418{
219 return 0; 419 struct switchtec_ntb *sndev = ntb_sndev(ntb);
420
421 if (idx < sndev->nr_direct_mw)
422 return switchtec_ntb_direct_get_addr(sndev, idx, base, size);
423 else if (idx < switchtec_ntb_peer_mw_count(ntb))
424 return switchtec_ntb_lut_get_addr(sndev, idx, base, size);
425 else
426 return -EINVAL;
220} 427}
221 428
222static void switchtec_ntb_part_link_speed(struct switchtec_ntb *sndev, 429static void switchtec_ntb_part_link_speed(struct switchtec_ntb *sndev,