aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLogan Gunthorpe <logang@deltatee.com>2017-08-03 14:19:53 -0400
committerJon Mason <jdmason@kudzu.us>2017-11-18 20:37:12 -0500
commit87d11e645e31d66be751211946e8d1e3eb624066 (patch)
treecf063272ce3e833906835b8196400ef5675f2184
parentb9a4acac282eff60cba800bdbc5a3b57c33c10be (diff)
NTB: switchtec_ntb: Add memory window support
The Switchtec hardware has two types of memory windows: LUTs and Direct. The first area in each BAR is for LUT windows and the remaining area is for the direct region. The total number of LUT entries is set by a configuration setting in hardware and they all must be the same size. (This is fixed by switchtec_ntb to be 64K.) switchtec_ntb enables the LUTs only for the first BAR and enables the highest power of two possible. Seeing the LUTs are at the beginning of the BAR, the direct memory window's alignment is affected. Therefore, the maximum direct memory window size can not be greater than the number of LUTs times 64K. The direct window in other BARs will not have this restriction as the LUTs will not be enabled there. LUTs will only be exposed through the NTB API if the use_lut_mw parameter is set. Seeing the Switchtec hardware, by default, configures BARs to be 4G a module parameter is given to limit the size of the advertised memory windows. Higher layers tend to allocate the maximum BAR size and this has a tendency to fail when they try to allocate 4GB of contiguous memory. 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.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,