diff options
| -rw-r--r-- | drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 213 |
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"); | |||
| 25 | MODULE_LICENSE("GPL"); | 25 | MODULE_LICENSE("GPL"); |
| 26 | MODULE_AUTHOR("Microsemi Corporation"); | 26 | MODULE_AUTHOR("Microsemi Corporation"); |
| 27 | 27 | ||
| 28 | static ulong max_mw_size = SZ_2M; | ||
| 29 | module_param(max_mw_size, ulong, 0644); | ||
| 30 | MODULE_PARM_DESC(max_mw_size, | ||
| 31 | "Max memory window size reported to the upper layer"); | ||
| 32 | |||
| 28 | static bool use_lut_mws; | 33 | static bool use_lut_mws; |
| 29 | module_param(use_lut_mws, bool, 0644); | 34 | module_param(use_lut_mws, bool, 0644); |
| 30 | MODULE_PARM_DESC(use_lut_mws, | 35 | MODULE_PARM_DESC(use_lut_mws, |
| @@ -190,7 +195,27 @@ static int switchtec_ntb_send_msg(struct switchtec_ntb *sndev, int idx, | |||
| 190 | 195 | ||
| 191 | static int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx) | 196 | static 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 | |||
| 211 | static int lut_index(struct switchtec_ntb *sndev, int mw_idx) | ||
| 212 | { | ||
| 213 | return mw_idx - sndev->nr_direct_mw + 1; | ||
| 214 | } | ||
| 215 | |||
| 216 | static 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 | ||
| 196 | static int switchtec_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, | 221 | static 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 | ||
| 251 | static 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 | |||
| 264 | static 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 | |||
| 271 | static 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 | |||
| 288 | static 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 | |||
| 204 | static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx, | 297 | static 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 | ||
| 210 | static int switchtec_ntb_peer_mw_count(struct ntb_dev *ntb) | 355 | static 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 | |||
| 362 | static 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 | |||
| 397 | static 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 | ||
| 222 | static void switchtec_ntb_part_link_speed(struct switchtec_ntb *sndev, | 429 | static void switchtec_ntb_part_link_speed(struct switchtec_ntb *sndev, |
