| .. | .. |
|---|
| 102 | 102 | struct mlxsw_pci { |
|---|
| 103 | 103 | struct pci_dev *pdev; |
|---|
| 104 | 104 | u8 __iomem *hw_addr; |
|---|
| 105 | + u64 free_running_clock_offset; |
|---|
| 105 | 106 | struct mlxsw_pci_queue_type_group queues[MLXSW_PCI_QUEUE_TYPE_COUNT]; |
|---|
| 106 | 107 | u32 doorbell_offset; |
|---|
| 107 | 108 | struct mlxsw_core *core; |
|---|
| .. | .. |
|---|
| 283 | 284 | static int mlxsw_pci_sdq_init(struct mlxsw_pci *mlxsw_pci, char *mbox, |
|---|
| 284 | 285 | struct mlxsw_pci_queue *q) |
|---|
| 285 | 286 | { |
|---|
| 287 | + int tclass; |
|---|
| 288 | + int lp; |
|---|
| 286 | 289 | int i; |
|---|
| 287 | 290 | int err; |
|---|
| 288 | 291 | |
|---|
| 289 | 292 | q->producer_counter = 0; |
|---|
| 290 | 293 | q->consumer_counter = 0; |
|---|
| 294 | + tclass = q->num == MLXSW_PCI_SDQ_EMAD_INDEX ? MLXSW_PCI_SDQ_EMAD_TC : |
|---|
| 295 | + MLXSW_PCI_SDQ_CTL_TC; |
|---|
| 296 | + lp = q->num == MLXSW_PCI_SDQ_EMAD_INDEX ? MLXSW_CMD_MBOX_SW2HW_DQ_SDQ_LP_IGNORE_WQE : |
|---|
| 297 | + MLXSW_CMD_MBOX_SW2HW_DQ_SDQ_LP_WQE; |
|---|
| 291 | 298 | |
|---|
| 292 | 299 | /* Set CQ of same number of this SDQ. */ |
|---|
| 293 | 300 | mlxsw_cmd_mbox_sw2hw_dq_cq_set(mbox, q->num); |
|---|
| 294 | | - mlxsw_cmd_mbox_sw2hw_dq_sdq_tclass_set(mbox, 3); |
|---|
| 301 | + mlxsw_cmd_mbox_sw2hw_dq_sdq_lp_set(mbox, lp); |
|---|
| 302 | + mlxsw_cmd_mbox_sw2hw_dq_sdq_tclass_set(mbox, tclass); |
|---|
| 295 | 303 | mlxsw_cmd_mbox_sw2hw_dq_log2_dq_sz_set(mbox, 3); /* 8 pages */ |
|---|
| 296 | 304 | for (i = 0; i < MLXSW_PCI_AQ_PAGES; i++) { |
|---|
| 297 | 305 | dma_addr_t mapaddr = __mlxsw_pci_queue_page_get(q, i); |
|---|
| .. | .. |
|---|
| 349 | 357 | struct sk_buff *skb; |
|---|
| 350 | 358 | int err; |
|---|
| 351 | 359 | |
|---|
| 352 | | - elem_info->u.rdq.skb = NULL; |
|---|
| 353 | 360 | skb = netdev_alloc_skb_ip_align(NULL, buf_len); |
|---|
| 354 | 361 | if (!skb) |
|---|
| 355 | 362 | return -ENOMEM; |
|---|
| 356 | | - |
|---|
| 357 | | - /* Assume that wqe was previously zeroed. */ |
|---|
| 358 | 363 | |
|---|
| 359 | 364 | err = mlxsw_pci_wqe_frag_map(mlxsw_pci, wqe, 0, skb->data, |
|---|
| 360 | 365 | buf_len, DMA_FROM_DEVICE); |
|---|
| .. | .. |
|---|
| 507 | 512 | { |
|---|
| 508 | 513 | struct pci_dev *pdev = mlxsw_pci->pdev; |
|---|
| 509 | 514 | struct mlxsw_pci_queue_elem_info *elem_info; |
|---|
| 515 | + struct mlxsw_tx_info tx_info; |
|---|
| 510 | 516 | char *wqe; |
|---|
| 511 | 517 | struct sk_buff *skb; |
|---|
| 512 | 518 | int i; |
|---|
| 513 | 519 | |
|---|
| 514 | 520 | spin_lock(&q->lock); |
|---|
| 515 | 521 | elem_info = mlxsw_pci_queue_elem_info_consumer_get(q); |
|---|
| 522 | + tx_info = mlxsw_skb_cb(elem_info->u.sdq.skb)->tx_info; |
|---|
| 516 | 523 | skb = elem_info->u.sdq.skb; |
|---|
| 517 | 524 | wqe = elem_info->elem; |
|---|
| 518 | 525 | for (i = 0; i < MLXSW_PCI_WQE_SG_ENTRIES; i++) |
|---|
| 519 | 526 | mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, i, DMA_TO_DEVICE); |
|---|
| 520 | | - dev_kfree_skb_any(skb); |
|---|
| 527 | + |
|---|
| 528 | + if (unlikely(!tx_info.is_emad && |
|---|
| 529 | + skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { |
|---|
| 530 | + mlxsw_core_ptp_transmitted(mlxsw_pci->core, skb, |
|---|
| 531 | + tx_info.local_port); |
|---|
| 532 | + skb = NULL; |
|---|
| 533 | + } |
|---|
| 534 | + |
|---|
| 535 | + if (skb) |
|---|
| 536 | + dev_kfree_skb_any(skb); |
|---|
| 521 | 537 | elem_info->u.sdq.skb = NULL; |
|---|
| 522 | 538 | |
|---|
| 523 | 539 | if (q->consumer_counter++ != consumer_counter_limit) |
|---|
| .. | .. |
|---|
| 532 | 548 | { |
|---|
| 533 | 549 | struct pci_dev *pdev = mlxsw_pci->pdev; |
|---|
| 534 | 550 | struct mlxsw_pci_queue_elem_info *elem_info; |
|---|
| 535 | | - char *wqe; |
|---|
| 551 | + struct mlxsw_rx_info rx_info = {}; |
|---|
| 552 | + char wqe[MLXSW_PCI_WQE_SIZE]; |
|---|
| 536 | 553 | struct sk_buff *skb; |
|---|
| 537 | | - struct mlxsw_rx_info rx_info; |
|---|
| 538 | 554 | u16 byte_count; |
|---|
| 539 | 555 | int err; |
|---|
| 540 | 556 | |
|---|
| 541 | 557 | elem_info = mlxsw_pci_queue_elem_info_consumer_get(q); |
|---|
| 542 | | - skb = elem_info->u.sdq.skb; |
|---|
| 543 | | - if (!skb) |
|---|
| 544 | | - return; |
|---|
| 545 | | - wqe = elem_info->elem; |
|---|
| 546 | | - mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, 0, DMA_FROM_DEVICE); |
|---|
| 558 | + skb = elem_info->u.rdq.skb; |
|---|
| 559 | + memcpy(wqe, elem_info->elem, MLXSW_PCI_WQE_SIZE); |
|---|
| 547 | 560 | |
|---|
| 548 | 561 | if (q->consumer_counter++ != consumer_counter_limit) |
|---|
| 549 | 562 | dev_dbg_ratelimited(&pdev->dev, "Consumer counter does not match limit in RDQ\n"); |
|---|
| 563 | + |
|---|
| 564 | + err = mlxsw_pci_rdq_skb_alloc(mlxsw_pci, elem_info); |
|---|
| 565 | + if (err) { |
|---|
| 566 | + dev_err_ratelimited(&pdev->dev, "Failed to alloc skb for RDQ\n"); |
|---|
| 567 | + goto out; |
|---|
| 568 | + } |
|---|
| 569 | + |
|---|
| 570 | + mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, 0, DMA_FROM_DEVICE); |
|---|
| 550 | 571 | |
|---|
| 551 | 572 | if (mlxsw_pci_cqe_lag_get(cqe_v, cqe)) { |
|---|
| 552 | 573 | rx_info.is_lag = true; |
|---|
| .. | .. |
|---|
| 560 | 581 | |
|---|
| 561 | 582 | rx_info.trap_id = mlxsw_pci_cqe_trap_id_get(cqe); |
|---|
| 562 | 583 | |
|---|
| 584 | + if (rx_info.trap_id == MLXSW_TRAP_ID_DISCARD_INGRESS_ACL || |
|---|
| 585 | + rx_info.trap_id == MLXSW_TRAP_ID_DISCARD_EGRESS_ACL) { |
|---|
| 586 | + u32 cookie_index = 0; |
|---|
| 587 | + |
|---|
| 588 | + if (mlxsw_pci->max_cqe_ver >= MLXSW_PCI_CQE_V2) |
|---|
| 589 | + cookie_index = mlxsw_pci_cqe2_user_def_val_orig_pkt_len_get(cqe); |
|---|
| 590 | + mlxsw_skb_cb(skb)->cookie_index = cookie_index; |
|---|
| 591 | + } else if (rx_info.trap_id >= MLXSW_TRAP_ID_MIRROR_SESSION0 && |
|---|
| 592 | + rx_info.trap_id <= MLXSW_TRAP_ID_MIRROR_SESSION7 && |
|---|
| 593 | + mlxsw_pci->max_cqe_ver >= MLXSW_PCI_CQE_V2) { |
|---|
| 594 | + rx_info.mirror_reason = mlxsw_pci_cqe2_mirror_reason_get(cqe); |
|---|
| 595 | + } |
|---|
| 596 | + |
|---|
| 563 | 597 | byte_count = mlxsw_pci_cqe_byte_count_get(cqe); |
|---|
| 564 | 598 | if (mlxsw_pci_cqe_crc_get(cqe_v, cqe)) |
|---|
| 565 | 599 | byte_count -= ETH_FCS_LEN; |
|---|
| 566 | 600 | skb_put(skb, byte_count); |
|---|
| 567 | 601 | mlxsw_core_skb_receive(mlxsw_pci->core, skb, &rx_info); |
|---|
| 568 | 602 | |
|---|
| 569 | | - memset(wqe, 0, q->elem_size); |
|---|
| 570 | | - err = mlxsw_pci_rdq_skb_alloc(mlxsw_pci, elem_info); |
|---|
| 571 | | - if (err) |
|---|
| 572 | | - dev_dbg_ratelimited(&pdev->dev, "Failed to alloc skb for RDQ\n"); |
|---|
| 603 | +out: |
|---|
| 573 | 604 | /* Everything is set up, ring doorbell to pass elem to HW */ |
|---|
| 574 | 605 | q->producer_counter++; |
|---|
| 575 | 606 | mlxsw_pci_queue_doorbell_producer_ring(mlxsw_pci, q); |
|---|
| .. | .. |
|---|
| 592 | 623 | return elem; |
|---|
| 593 | 624 | } |
|---|
| 594 | 625 | |
|---|
| 595 | | -static void mlxsw_pci_cq_tasklet(unsigned long data) |
|---|
| 626 | +static void mlxsw_pci_cq_tasklet(struct tasklet_struct *t) |
|---|
| 596 | 627 | { |
|---|
| 597 | | - struct mlxsw_pci_queue *q = (struct mlxsw_pci_queue *) data; |
|---|
| 628 | + struct mlxsw_pci_queue *q = from_tasklet(q, t, tasklet); |
|---|
| 598 | 629 | struct mlxsw_pci *mlxsw_pci = q->pci; |
|---|
| 599 | 630 | char *cqe; |
|---|
| 600 | 631 | int items = 0; |
|---|
| .. | .. |
|---|
| 705 | 736 | return elem; |
|---|
| 706 | 737 | } |
|---|
| 707 | 738 | |
|---|
| 708 | | -static void mlxsw_pci_eq_tasklet(unsigned long data) |
|---|
| 739 | +static void mlxsw_pci_eq_tasklet(struct tasklet_struct *t) |
|---|
| 709 | 740 | { |
|---|
| 710 | | - struct mlxsw_pci_queue *q = (struct mlxsw_pci_queue *) data; |
|---|
| 741 | + struct mlxsw_pci_queue *q = from_tasklet(q, t, tasklet); |
|---|
| 711 | 742 | struct mlxsw_pci *mlxsw_pci = q->pci; |
|---|
| 712 | 743 | u8 cq_count = mlxsw_pci_cq_count(mlxsw_pci); |
|---|
| 713 | 744 | unsigned long active_cqns[BITS_TO_LONGS(MLXSW_PCI_CQS_MAX)]; |
|---|
| .. | .. |
|---|
| 764 | 795 | struct mlxsw_pci_queue *q); |
|---|
| 765 | 796 | void (*fini)(struct mlxsw_pci *mlxsw_pci, |
|---|
| 766 | 797 | struct mlxsw_pci_queue *q); |
|---|
| 767 | | - void (*tasklet)(unsigned long data); |
|---|
| 798 | + void (*tasklet)(struct tasklet_struct *t); |
|---|
| 768 | 799 | u16 (*elem_count_f)(const struct mlxsw_pci_queue *q); |
|---|
| 769 | 800 | u8 (*elem_size_f)(const struct mlxsw_pci_queue *q); |
|---|
| 770 | 801 | u16 elem_count; |
|---|
| .. | .. |
|---|
| 827 | 858 | q->pci = mlxsw_pci; |
|---|
| 828 | 859 | |
|---|
| 829 | 860 | if (q_ops->tasklet) |
|---|
| 830 | | - tasklet_init(&q->tasklet, q_ops->tasklet, (unsigned long) q); |
|---|
| 861 | + tasklet_setup(&q->tasklet, q_ops->tasklet); |
|---|
| 831 | 862 | |
|---|
| 832 | 863 | mem_item->size = MLXSW_PCI_AQ_SIZE; |
|---|
| 833 | 864 | mem_item->buf = pci_alloc_consistent(mlxsw_pci->pdev, |
|---|
| .. | .. |
|---|
| 835 | 866 | &mem_item->mapaddr); |
|---|
| 836 | 867 | if (!mem_item->buf) |
|---|
| 837 | 868 | return -ENOMEM; |
|---|
| 838 | | - memset(mem_item->buf, 0, mem_item->size); |
|---|
| 839 | 869 | |
|---|
| 840 | 870 | q->elem_info = kcalloc(q->count, sizeof(*q->elem_info), GFP_KERNEL); |
|---|
| 841 | 871 | if (!q->elem_info) { |
|---|
| .. | .. |
|---|
| 952 | 982 | eq_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_eq_sz_get(mbox); |
|---|
| 953 | 983 | |
|---|
| 954 | 984 | if (num_sdqs + num_rdqs > num_cqs || |
|---|
| 985 | + num_sdqs < MLXSW_PCI_SDQS_MIN || |
|---|
| 955 | 986 | num_cqs > MLXSW_PCI_CQS_MAX || num_eqs != MLXSW_PCI_EQS_COUNT) { |
|---|
| 956 | 987 | dev_err(&pdev->dev, "Unsupported number of queues\n"); |
|---|
| 957 | 988 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 1037 | 1068 | mask |= 2; |
|---|
| 1038 | 1069 | } |
|---|
| 1039 | 1070 | mlxsw_cmd_mbox_config_profile_swid_config_mask_set(mbox, index, mask); |
|---|
| 1040 | | -} |
|---|
| 1041 | | - |
|---|
| 1042 | | -static int mlxsw_pci_resources_query(struct mlxsw_pci *mlxsw_pci, char *mbox, |
|---|
| 1043 | | - struct mlxsw_res *res) |
|---|
| 1044 | | -{ |
|---|
| 1045 | | - int index, i; |
|---|
| 1046 | | - u64 data; |
|---|
| 1047 | | - u16 id; |
|---|
| 1048 | | - int err; |
|---|
| 1049 | | - |
|---|
| 1050 | | - if (!res) |
|---|
| 1051 | | - return 0; |
|---|
| 1052 | | - |
|---|
| 1053 | | - mlxsw_cmd_mbox_zero(mbox); |
|---|
| 1054 | | - |
|---|
| 1055 | | - for (index = 0; index < MLXSW_CMD_QUERY_RESOURCES_MAX_QUERIES; |
|---|
| 1056 | | - index++) { |
|---|
| 1057 | | - err = mlxsw_cmd_query_resources(mlxsw_pci->core, mbox, index); |
|---|
| 1058 | | - if (err) |
|---|
| 1059 | | - return err; |
|---|
| 1060 | | - |
|---|
| 1061 | | - for (i = 0; i < MLXSW_CMD_QUERY_RESOURCES_PER_QUERY; i++) { |
|---|
| 1062 | | - id = mlxsw_cmd_mbox_query_resource_id_get(mbox, i); |
|---|
| 1063 | | - data = mlxsw_cmd_mbox_query_resource_data_get(mbox, i); |
|---|
| 1064 | | - |
|---|
| 1065 | | - if (id == MLXSW_CMD_QUERY_RESOURCES_TABLE_END_ID) |
|---|
| 1066 | | - return 0; |
|---|
| 1067 | | - |
|---|
| 1068 | | - mlxsw_res_parse(res, id, data); |
|---|
| 1069 | | - } |
|---|
| 1070 | | - } |
|---|
| 1071 | | - |
|---|
| 1072 | | - /* If after MLXSW_RESOURCES_QUERY_MAX_QUERIES we still didn't get |
|---|
| 1073 | | - * MLXSW_RESOURCES_TABLE_END_ID, something went bad in the FW. |
|---|
| 1074 | | - */ |
|---|
| 1075 | | - return -EIO; |
|---|
| 1076 | 1071 | } |
|---|
| 1077 | 1072 | |
|---|
| 1078 | 1073 | static int |
|---|
| .. | .. |
|---|
| 1343 | 1338 | mbox->mapaddr); |
|---|
| 1344 | 1339 | } |
|---|
| 1345 | 1340 | |
|---|
| 1346 | | -static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci, |
|---|
| 1347 | | - const struct pci_device_id *id) |
|---|
| 1341 | +static int mlxsw_pci_sys_ready_wait(struct mlxsw_pci *mlxsw_pci, |
|---|
| 1342 | + const struct pci_device_id *id, |
|---|
| 1343 | + u32 *p_sys_status) |
|---|
| 1348 | 1344 | { |
|---|
| 1349 | 1345 | unsigned long end; |
|---|
| 1350 | | - char mrsr_pl[MLXSW_REG_MRSR_LEN]; |
|---|
| 1351 | | - int err; |
|---|
| 1346 | + u32 val; |
|---|
| 1352 | 1347 | |
|---|
| 1353 | | - mlxsw_reg_mrsr_pack(mrsr_pl); |
|---|
| 1354 | | - err = mlxsw_reg_write(mlxsw_pci->core, MLXSW_REG(mrsr), mrsr_pl); |
|---|
| 1355 | | - if (err) |
|---|
| 1356 | | - return err; |
|---|
| 1357 | 1348 | if (id->device == PCI_DEVICE_ID_MELLANOX_SWITCHX2) { |
|---|
| 1358 | 1349 | msleep(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS); |
|---|
| 1359 | 1350 | return 0; |
|---|
| 1360 | 1351 | } |
|---|
| 1361 | 1352 | |
|---|
| 1362 | | - /* We must wait for the HW to become responsive once again. */ |
|---|
| 1353 | + /* We must wait for the HW to become responsive. */ |
|---|
| 1363 | 1354 | msleep(MLXSW_PCI_SW_RESET_WAIT_MSECS); |
|---|
| 1364 | 1355 | |
|---|
| 1365 | 1356 | end = jiffies + msecs_to_jiffies(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS); |
|---|
| 1366 | 1357 | do { |
|---|
| 1367 | | - u32 val = mlxsw_pci_read32(mlxsw_pci, FW_READY); |
|---|
| 1368 | | - |
|---|
| 1358 | + val = mlxsw_pci_read32(mlxsw_pci, FW_READY); |
|---|
| 1369 | 1359 | if ((val & MLXSW_PCI_FW_READY_MASK) == MLXSW_PCI_FW_READY_MAGIC) |
|---|
| 1370 | 1360 | return 0; |
|---|
| 1371 | 1361 | cond_resched(); |
|---|
| 1372 | 1362 | } while (time_before(jiffies, end)); |
|---|
| 1363 | + |
|---|
| 1364 | + *p_sys_status = val & MLXSW_PCI_FW_READY_MASK; |
|---|
| 1365 | + |
|---|
| 1373 | 1366 | return -EBUSY; |
|---|
| 1367 | +} |
|---|
| 1368 | + |
|---|
| 1369 | +static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci, |
|---|
| 1370 | + const struct pci_device_id *id) |
|---|
| 1371 | +{ |
|---|
| 1372 | + struct pci_dev *pdev = mlxsw_pci->pdev; |
|---|
| 1373 | + char mrsr_pl[MLXSW_REG_MRSR_LEN]; |
|---|
| 1374 | + u32 sys_status; |
|---|
| 1375 | + int err; |
|---|
| 1376 | + |
|---|
| 1377 | + err = mlxsw_pci_sys_ready_wait(mlxsw_pci, id, &sys_status); |
|---|
| 1378 | + if (err) { |
|---|
| 1379 | + dev_err(&pdev->dev, "Failed to reach system ready status before reset. Status is 0x%x\n", |
|---|
| 1380 | + sys_status); |
|---|
| 1381 | + return err; |
|---|
| 1382 | + } |
|---|
| 1383 | + |
|---|
| 1384 | + mlxsw_reg_mrsr_pack(mrsr_pl); |
|---|
| 1385 | + err = mlxsw_reg_write(mlxsw_pci->core, MLXSW_REG(mrsr), mrsr_pl); |
|---|
| 1386 | + if (err) |
|---|
| 1387 | + return err; |
|---|
| 1388 | + |
|---|
| 1389 | + err = mlxsw_pci_sys_ready_wait(mlxsw_pci, id, &sys_status); |
|---|
| 1390 | + if (err) { |
|---|
| 1391 | + dev_err(&pdev->dev, "Failed to reach system ready status after reset. Status is 0x%x\n", |
|---|
| 1392 | + sys_status); |
|---|
| 1393 | + return err; |
|---|
| 1394 | + } |
|---|
| 1395 | + |
|---|
| 1396 | + return 0; |
|---|
| 1374 | 1397 | } |
|---|
| 1375 | 1398 | |
|---|
| 1376 | 1399 | static int mlxsw_pci_alloc_irq_vectors(struct mlxsw_pci *mlxsw_pci) |
|---|
| .. | .. |
|---|
| 1398 | 1421 | u16 num_pages; |
|---|
| 1399 | 1422 | int err; |
|---|
| 1400 | 1423 | |
|---|
| 1401 | | - mutex_init(&mlxsw_pci->cmd.lock); |
|---|
| 1402 | | - init_waitqueue_head(&mlxsw_pci->cmd.wait); |
|---|
| 1403 | | - |
|---|
| 1404 | 1424 | mlxsw_pci->core = mlxsw_core; |
|---|
| 1405 | 1425 | |
|---|
| 1406 | 1426 | mbox = mlxsw_cmd_mbox_alloc(); |
|---|
| 1407 | 1427 | if (!mbox) |
|---|
| 1408 | 1428 | return -ENOMEM; |
|---|
| 1409 | | - |
|---|
| 1410 | | - err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); |
|---|
| 1411 | | - if (err) |
|---|
| 1412 | | - goto mbox_put; |
|---|
| 1413 | | - |
|---|
| 1414 | | - err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); |
|---|
| 1415 | | - if (err) |
|---|
| 1416 | | - goto err_out_mbox_alloc; |
|---|
| 1417 | 1429 | |
|---|
| 1418 | 1430 | err = mlxsw_pci_sw_reset(mlxsw_pci, mlxsw_pci->id); |
|---|
| 1419 | 1431 | if (err) |
|---|
| .. | .. |
|---|
| 1450 | 1462 | mlxsw_pci->doorbell_offset = |
|---|
| 1451 | 1463 | mlxsw_cmd_mbox_query_fw_doorbell_page_offset_get(mbox); |
|---|
| 1452 | 1464 | |
|---|
| 1465 | + if (mlxsw_cmd_mbox_query_fw_fr_rn_clk_bar_get(mbox) != 0) { |
|---|
| 1466 | + dev_err(&pdev->dev, "Unsupported free running clock BAR queried from hw\n"); |
|---|
| 1467 | + err = -EINVAL; |
|---|
| 1468 | + goto err_fr_rn_clk_bar; |
|---|
| 1469 | + } |
|---|
| 1470 | + |
|---|
| 1471 | + mlxsw_pci->free_running_clock_offset = |
|---|
| 1472 | + mlxsw_cmd_mbox_query_fw_free_running_clock_offset_get(mbox); |
|---|
| 1473 | + |
|---|
| 1453 | 1474 | num_pages = mlxsw_cmd_mbox_query_fw_fw_pages_get(mbox); |
|---|
| 1454 | 1475 | err = mlxsw_pci_fw_area_init(mlxsw_pci, mbox, num_pages); |
|---|
| 1455 | 1476 | if (err) |
|---|
| .. | .. |
|---|
| 1459 | 1480 | if (err) |
|---|
| 1460 | 1481 | goto err_boardinfo; |
|---|
| 1461 | 1482 | |
|---|
| 1462 | | - err = mlxsw_pci_resources_query(mlxsw_pci, mbox, res); |
|---|
| 1483 | + err = mlxsw_core_resources_query(mlxsw_core, mbox, res); |
|---|
| 1463 | 1484 | if (err) |
|---|
| 1464 | 1485 | goto err_query_resources; |
|---|
| 1465 | 1486 | |
|---|
| .. | .. |
|---|
| 1505 | 1526 | err_boardinfo: |
|---|
| 1506 | 1527 | mlxsw_pci_fw_area_fini(mlxsw_pci); |
|---|
| 1507 | 1528 | err_fw_area_init: |
|---|
| 1529 | +err_fr_rn_clk_bar: |
|---|
| 1508 | 1530 | err_doorbell_page_bar: |
|---|
| 1509 | 1531 | err_iface_rev: |
|---|
| 1510 | 1532 | err_query_fw: |
|---|
| 1511 | 1533 | mlxsw_pci_free_irq_vectors(mlxsw_pci); |
|---|
| 1512 | 1534 | err_alloc_irq: |
|---|
| 1513 | 1535 | err_sw_reset: |
|---|
| 1514 | | - mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); |
|---|
| 1515 | | -err_out_mbox_alloc: |
|---|
| 1516 | | - mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); |
|---|
| 1517 | 1536 | mbox_put: |
|---|
| 1518 | 1537 | mlxsw_cmd_mbox_free(mbox); |
|---|
| 1519 | 1538 | return err; |
|---|
| .. | .. |
|---|
| 1527 | 1546 | mlxsw_pci_aqs_fini(mlxsw_pci); |
|---|
| 1528 | 1547 | mlxsw_pci_fw_area_fini(mlxsw_pci); |
|---|
| 1529 | 1548 | mlxsw_pci_free_irq_vectors(mlxsw_pci); |
|---|
| 1530 | | - mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); |
|---|
| 1531 | | - mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); |
|---|
| 1532 | 1549 | } |
|---|
| 1533 | 1550 | |
|---|
| 1534 | 1551 | static struct mlxsw_pci_queue * |
|---|
| 1535 | 1552 | mlxsw_pci_sdq_pick(struct mlxsw_pci *mlxsw_pci, |
|---|
| 1536 | 1553 | const struct mlxsw_tx_info *tx_info) |
|---|
| 1537 | 1554 | { |
|---|
| 1538 | | - u8 sdqn = tx_info->local_port % mlxsw_pci_sdq_count(mlxsw_pci); |
|---|
| 1555 | + u8 ctl_sdq_count = mlxsw_pci_sdq_count(mlxsw_pci) - 1; |
|---|
| 1556 | + u8 sdqn; |
|---|
| 1557 | + |
|---|
| 1558 | + if (tx_info->is_emad) { |
|---|
| 1559 | + sdqn = MLXSW_PCI_SDQ_EMAD_INDEX; |
|---|
| 1560 | + } else { |
|---|
| 1561 | + BUILD_BUG_ON(MLXSW_PCI_SDQ_EMAD_INDEX != 0); |
|---|
| 1562 | + sdqn = 1 + (tx_info->local_port % ctl_sdq_count); |
|---|
| 1563 | + } |
|---|
| 1539 | 1564 | |
|---|
| 1540 | 1565 | return mlxsw_pci_sdq_get(mlxsw_pci, sdqn); |
|---|
| 1541 | 1566 | } |
|---|
| .. | .. |
|---|
| 1573 | 1598 | err = -EAGAIN; |
|---|
| 1574 | 1599 | goto unlock; |
|---|
| 1575 | 1600 | } |
|---|
| 1601 | + mlxsw_skb_cb(skb)->tx_info = *tx_info; |
|---|
| 1576 | 1602 | elem_info->u.sdq.skb = skb; |
|---|
| 1577 | 1603 | |
|---|
| 1578 | 1604 | wqe = elem_info->elem; |
|---|
| 1579 | 1605 | mlxsw_pci_wqe_c_set(wqe, 1); /* always report completion */ |
|---|
| 1580 | | - mlxsw_pci_wqe_lp_set(wqe, !!tx_info->is_emad); |
|---|
| 1606 | + mlxsw_pci_wqe_lp_set(wqe, 0); |
|---|
| 1581 | 1607 | mlxsw_pci_wqe_type_set(wqe, MLXSW_PCI_WQE_TYPE_ETHERNET); |
|---|
| 1582 | 1608 | |
|---|
| 1583 | 1609 | err = mlxsw_pci_wqe_frag_map(mlxsw_pci, wqe, 0, skb->data, |
|---|
| .. | .. |
|---|
| 1595 | 1621 | if (err) |
|---|
| 1596 | 1622 | goto unmap_frags; |
|---|
| 1597 | 1623 | } |
|---|
| 1624 | + |
|---|
| 1625 | + if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) |
|---|
| 1626 | + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; |
|---|
| 1598 | 1627 | |
|---|
| 1599 | 1628 | /* Set unused sq entries byte count to zero. */ |
|---|
| 1600 | 1629 | for (i++; i < MLXSW_PCI_WQE_SG_ENTRIES; i++) |
|---|
| .. | .. |
|---|
| 1708 | 1737 | return err; |
|---|
| 1709 | 1738 | } |
|---|
| 1710 | 1739 | |
|---|
| 1740 | +static u32 mlxsw_pci_read_frc_h(void *bus_priv) |
|---|
| 1741 | +{ |
|---|
| 1742 | + struct mlxsw_pci *mlxsw_pci = bus_priv; |
|---|
| 1743 | + u64 frc_offset; |
|---|
| 1744 | + |
|---|
| 1745 | + frc_offset = mlxsw_pci->free_running_clock_offset; |
|---|
| 1746 | + return mlxsw_pci_read32(mlxsw_pci, FREE_RUNNING_CLOCK_H(frc_offset)); |
|---|
| 1747 | +} |
|---|
| 1748 | + |
|---|
| 1749 | +static u32 mlxsw_pci_read_frc_l(void *bus_priv) |
|---|
| 1750 | +{ |
|---|
| 1751 | + struct mlxsw_pci *mlxsw_pci = bus_priv; |
|---|
| 1752 | + u64 frc_offset; |
|---|
| 1753 | + |
|---|
| 1754 | + frc_offset = mlxsw_pci->free_running_clock_offset; |
|---|
| 1755 | + return mlxsw_pci_read32(mlxsw_pci, FREE_RUNNING_CLOCK_L(frc_offset)); |
|---|
| 1756 | +} |
|---|
| 1757 | + |
|---|
| 1711 | 1758 | static const struct mlxsw_bus mlxsw_pci_bus = { |
|---|
| 1712 | 1759 | .kind = "pci", |
|---|
| 1713 | 1760 | .init = mlxsw_pci_init, |
|---|
| .. | .. |
|---|
| 1715 | 1762 | .skb_transmit_busy = mlxsw_pci_skb_transmit_busy, |
|---|
| 1716 | 1763 | .skb_transmit = mlxsw_pci_skb_transmit, |
|---|
| 1717 | 1764 | .cmd_exec = mlxsw_pci_cmd_exec, |
|---|
| 1765 | + .read_frc_h = mlxsw_pci_read_frc_h, |
|---|
| 1766 | + .read_frc_l = mlxsw_pci_read_frc_l, |
|---|
| 1718 | 1767 | .features = MLXSW_BUS_F_TXRX | MLXSW_BUS_F_RESET, |
|---|
| 1719 | 1768 | }; |
|---|
| 1769 | + |
|---|
| 1770 | +static int mlxsw_pci_cmd_init(struct mlxsw_pci *mlxsw_pci) |
|---|
| 1771 | +{ |
|---|
| 1772 | + int err; |
|---|
| 1773 | + |
|---|
| 1774 | + mutex_init(&mlxsw_pci->cmd.lock); |
|---|
| 1775 | + init_waitqueue_head(&mlxsw_pci->cmd.wait); |
|---|
| 1776 | + |
|---|
| 1777 | + err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); |
|---|
| 1778 | + if (err) |
|---|
| 1779 | + goto err_in_mbox_alloc; |
|---|
| 1780 | + |
|---|
| 1781 | + err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); |
|---|
| 1782 | + if (err) |
|---|
| 1783 | + goto err_out_mbox_alloc; |
|---|
| 1784 | + |
|---|
| 1785 | + return 0; |
|---|
| 1786 | + |
|---|
| 1787 | +err_out_mbox_alloc: |
|---|
| 1788 | + mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); |
|---|
| 1789 | +err_in_mbox_alloc: |
|---|
| 1790 | + mutex_destroy(&mlxsw_pci->cmd.lock); |
|---|
| 1791 | + return err; |
|---|
| 1792 | +} |
|---|
| 1793 | + |
|---|
| 1794 | +static void mlxsw_pci_cmd_fini(struct mlxsw_pci *mlxsw_pci) |
|---|
| 1795 | +{ |
|---|
| 1796 | + mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); |
|---|
| 1797 | + mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); |
|---|
| 1798 | + mutex_destroy(&mlxsw_pci->cmd.lock); |
|---|
| 1799 | +} |
|---|
| 1720 | 1800 | |
|---|
| 1721 | 1801 | static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
|---|
| 1722 | 1802 | { |
|---|
| 1723 | 1803 | const char *driver_name = pdev->driver->name; |
|---|
| 1724 | 1804 | struct mlxsw_pci *mlxsw_pci; |
|---|
| 1725 | | - bool called_again = false; |
|---|
| 1726 | 1805 | int err; |
|---|
| 1727 | 1806 | |
|---|
| 1728 | 1807 | mlxsw_pci = kzalloc(sizeof(*mlxsw_pci), GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 1774 | 1853 | mlxsw_pci->pdev = pdev; |
|---|
| 1775 | 1854 | pci_set_drvdata(pdev, mlxsw_pci); |
|---|
| 1776 | 1855 | |
|---|
| 1856 | + err = mlxsw_pci_cmd_init(mlxsw_pci); |
|---|
| 1857 | + if (err) |
|---|
| 1858 | + goto err_pci_cmd_init; |
|---|
| 1859 | + |
|---|
| 1777 | 1860 | mlxsw_pci->bus_info.device_kind = driver_name; |
|---|
| 1778 | 1861 | mlxsw_pci->bus_info.device_name = pci_name(mlxsw_pci->pdev); |
|---|
| 1779 | 1862 | mlxsw_pci->bus_info.dev = &pdev->dev; |
|---|
| 1863 | + mlxsw_pci->bus_info.read_frc_capable = true; |
|---|
| 1780 | 1864 | mlxsw_pci->id = id; |
|---|
| 1781 | 1865 | |
|---|
| 1782 | | -again: |
|---|
| 1783 | 1866 | err = mlxsw_core_bus_device_register(&mlxsw_pci->bus_info, |
|---|
| 1784 | 1867 | &mlxsw_pci_bus, mlxsw_pci, false, |
|---|
| 1785 | | - NULL); |
|---|
| 1786 | | - /* -EAGAIN is returned in case the FW was updated. FW needs |
|---|
| 1787 | | - * a reset, so lets try to call mlxsw_core_bus_device_register() |
|---|
| 1788 | | - * again. |
|---|
| 1789 | | - */ |
|---|
| 1790 | | - if (err == -EAGAIN && !called_again) { |
|---|
| 1791 | | - called_again = true; |
|---|
| 1792 | | - goto again; |
|---|
| 1793 | | - } else if (err) { |
|---|
| 1868 | + NULL, NULL); |
|---|
| 1869 | + if (err) { |
|---|
| 1794 | 1870 | dev_err(&pdev->dev, "cannot register bus device\n"); |
|---|
| 1795 | 1871 | goto err_bus_device_register; |
|---|
| 1796 | 1872 | } |
|---|
| .. | .. |
|---|
| 1798 | 1874 | return 0; |
|---|
| 1799 | 1875 | |
|---|
| 1800 | 1876 | err_bus_device_register: |
|---|
| 1877 | + mlxsw_pci_cmd_fini(mlxsw_pci); |
|---|
| 1878 | +err_pci_cmd_init: |
|---|
| 1801 | 1879 | iounmap(mlxsw_pci->hw_addr); |
|---|
| 1802 | 1880 | err_ioremap: |
|---|
| 1803 | 1881 | err_pci_resource_len_check: |
|---|
| .. | .. |
|---|
| 1815 | 1893 | struct mlxsw_pci *mlxsw_pci = pci_get_drvdata(pdev); |
|---|
| 1816 | 1894 | |
|---|
| 1817 | 1895 | mlxsw_core_bus_device_unregister(mlxsw_pci->core, false); |
|---|
| 1896 | + mlxsw_pci_cmd_fini(mlxsw_pci); |
|---|
| 1818 | 1897 | iounmap(mlxsw_pci->hw_addr); |
|---|
| 1819 | 1898 | pci_release_regions(mlxsw_pci->pdev); |
|---|
| 1820 | 1899 | pci_disable_device(mlxsw_pci->pdev); |
|---|