.. | .. |
---|
36 | 36 | #define MAX_IRQNAME 16 /* big enough for "QMan portal %d" */ |
---|
37 | 37 | #define QMAN_POLL_LIMIT 32 |
---|
38 | 38 | #define QMAN_PIRQ_DQRR_ITHRESH 12 |
---|
| 39 | +#define QMAN_DQRR_IT_MAX 15 |
---|
| 40 | +#define QMAN_ITP_MAX 0xFFF |
---|
39 | 41 | #define QMAN_PIRQ_MR_ITHRESH 4 |
---|
40 | 42 | #define QMAN_PIRQ_IPERIOD 100 |
---|
41 | 43 | |
---|
.. | .. |
---|
447 | 449 | return 0; |
---|
448 | 450 | } |
---|
449 | 451 | |
---|
450 | | -static inline unsigned int qm_eqcr_get_ci_stashing(struct qm_portal *portal) |
---|
451 | | -{ |
---|
452 | | - return (qm_in(portal, QM_REG_CFG) >> 28) & 0x7; |
---|
453 | | -} |
---|
454 | | - |
---|
455 | 452 | static inline void qm_eqcr_finish(struct qm_portal *portal) |
---|
456 | 453 | { |
---|
457 | 454 | struct qm_eqcr *eqcr = &portal->eqcr; |
---|
.. | .. |
---|
727 | 724 | qm_out(portal, QM_REG_DQRR_VDQCR, vdqcr); |
---|
728 | 725 | } |
---|
729 | 726 | |
---|
730 | | -static inline void qm_dqrr_set_ithresh(struct qm_portal *portal, u8 ithresh) |
---|
| 727 | +static inline int qm_dqrr_set_ithresh(struct qm_portal *portal, u8 ithresh) |
---|
731 | 728 | { |
---|
| 729 | + |
---|
| 730 | + if (ithresh > QMAN_DQRR_IT_MAX) |
---|
| 731 | + return -EINVAL; |
---|
| 732 | + |
---|
732 | 733 | qm_out(portal, QM_REG_DQRR_ITR, ithresh); |
---|
| 734 | + |
---|
| 735 | + return 0; |
---|
733 | 736 | } |
---|
734 | 737 | |
---|
735 | 738 | /* --- MR API --- */ |
---|
.. | .. |
---|
850 | 853 | |
---|
851 | 854 | static inline int qm_mc_init(struct qm_portal *portal) |
---|
852 | 855 | { |
---|
| 856 | + u8 rr0, rr1; |
---|
853 | 857 | struct qm_mc *mc = &portal->mc; |
---|
854 | 858 | |
---|
855 | 859 | mc->cr = portal->addr.ce + QM_CL_CR; |
---|
856 | 860 | mc->rr = portal->addr.ce + QM_CL_RR0; |
---|
857 | | - mc->rridx = (mc->cr->_ncw_verb & QM_MCC_VERB_VBIT) |
---|
858 | | - ? 0 : 1; |
---|
| 861 | + /* |
---|
| 862 | + * The expected valid bit polarity for the next CR command is 0 |
---|
| 863 | + * if RR1 contains a valid response, and is 1 if RR0 contains a |
---|
| 864 | + * valid response. If both RR contain all 0, this indicates either |
---|
| 865 | + * that no command has been executed since reset (in which case the |
---|
| 866 | + * expected valid bit polarity is 1) |
---|
| 867 | + */ |
---|
| 868 | + rr0 = mc->rr->verb; |
---|
| 869 | + rr1 = (mc->rr+1)->verb; |
---|
| 870 | + if ((rr0 == 0 && rr1 == 0) || rr0 != 0) |
---|
| 871 | + mc->rridx = 1; |
---|
| 872 | + else |
---|
| 873 | + mc->rridx = 0; |
---|
859 | 874 | mc->vbit = mc->rridx ? QM_MCC_VERB_VBIT : 0; |
---|
860 | 875 | #ifdef CONFIG_FSL_DPAA_CHECKING |
---|
861 | 876 | mc->state = qman_mc_idle; |
---|
.. | .. |
---|
998 | 1013 | put_cpu_var(qman_affine_portal); |
---|
999 | 1014 | } |
---|
1000 | 1015 | |
---|
| 1016 | + |
---|
| 1017 | +static inline struct qman_portal *get_portal_for_channel(u16 channel) |
---|
| 1018 | +{ |
---|
| 1019 | + int i; |
---|
| 1020 | + |
---|
| 1021 | + for (i = 0; i < num_possible_cpus(); i++) { |
---|
| 1022 | + if (affine_portals[i] && |
---|
| 1023 | + affine_portals[i]->config->channel == channel) |
---|
| 1024 | + return affine_portals[i]; |
---|
| 1025 | + } |
---|
| 1026 | + |
---|
| 1027 | + return NULL; |
---|
| 1028 | +} |
---|
| 1029 | + |
---|
1001 | 1030 | static struct workqueue_struct *qm_portal_wq; |
---|
| 1031 | + |
---|
| 1032 | +int qman_dqrr_set_ithresh(struct qman_portal *portal, u8 ithresh) |
---|
| 1033 | +{ |
---|
| 1034 | + int res; |
---|
| 1035 | + |
---|
| 1036 | + if (!portal) |
---|
| 1037 | + return -EINVAL; |
---|
| 1038 | + |
---|
| 1039 | + res = qm_dqrr_set_ithresh(&portal->p, ithresh); |
---|
| 1040 | + if (res) |
---|
| 1041 | + return res; |
---|
| 1042 | + |
---|
| 1043 | + portal->p.dqrr.ithresh = ithresh; |
---|
| 1044 | + |
---|
| 1045 | + return 0; |
---|
| 1046 | +} |
---|
| 1047 | +EXPORT_SYMBOL(qman_dqrr_set_ithresh); |
---|
| 1048 | + |
---|
| 1049 | +void qman_dqrr_get_ithresh(struct qman_portal *portal, u8 *ithresh) |
---|
| 1050 | +{ |
---|
| 1051 | + if (portal && ithresh) |
---|
| 1052 | + *ithresh = qm_in(&portal->p, QM_REG_DQRR_ITR); |
---|
| 1053 | +} |
---|
| 1054 | +EXPORT_SYMBOL(qman_dqrr_get_ithresh); |
---|
| 1055 | + |
---|
| 1056 | +void qman_portal_get_iperiod(struct qman_portal *portal, u32 *iperiod) |
---|
| 1057 | +{ |
---|
| 1058 | + if (portal && iperiod) |
---|
| 1059 | + *iperiod = qm_in(&portal->p, QM_REG_ITPR); |
---|
| 1060 | +} |
---|
| 1061 | +EXPORT_SYMBOL(qman_portal_get_iperiod); |
---|
| 1062 | + |
---|
| 1063 | +int qman_portal_set_iperiod(struct qman_portal *portal, u32 iperiod) |
---|
| 1064 | +{ |
---|
| 1065 | + if (!portal || iperiod > QMAN_ITP_MAX) |
---|
| 1066 | + return -EINVAL; |
---|
| 1067 | + |
---|
| 1068 | + qm_out(&portal->p, QM_REG_ITPR, iperiod); |
---|
| 1069 | + |
---|
| 1070 | + return 0; |
---|
| 1071 | +} |
---|
| 1072 | +EXPORT_SYMBOL(qman_portal_set_iperiod); |
---|
1002 | 1073 | |
---|
1003 | 1074 | int qman_wq_alloc(void) |
---|
1004 | 1075 | { |
---|
.. | .. |
---|
1006 | 1077 | if (!qm_portal_wq) |
---|
1007 | 1078 | return -ENOMEM; |
---|
1008 | 1079 | return 0; |
---|
| 1080 | +} |
---|
| 1081 | + |
---|
| 1082 | + |
---|
| 1083 | +void qman_enable_irqs(void) |
---|
| 1084 | +{ |
---|
| 1085 | + int i; |
---|
| 1086 | + |
---|
| 1087 | + for (i = 0; i < num_possible_cpus(); i++) { |
---|
| 1088 | + if (affine_portals[i]) { |
---|
| 1089 | + qm_out(&affine_portals[i]->p, QM_REG_ISR, 0xffffffff); |
---|
| 1090 | + qm_out(&affine_portals[i]->p, QM_REG_IIR, 0); |
---|
| 1091 | + } |
---|
| 1092 | + |
---|
| 1093 | + } |
---|
1009 | 1094 | } |
---|
1010 | 1095 | |
---|
1011 | 1096 | /* |
---|
.. | .. |
---|
1102 | 1187 | { |
---|
1103 | 1188 | const union qm_mr_entry *msg; |
---|
1104 | 1189 | loop: |
---|
| 1190 | + qm_mr_pvb_update(p); |
---|
1105 | 1191 | msg = qm_mr_current(p); |
---|
1106 | 1192 | if (!msg) { |
---|
1107 | 1193 | /* |
---|
.. | .. |
---|
1118 | 1204 | * entries well before the ring has been fully consumed, so |
---|
1119 | 1205 | * we're being *really* paranoid here. |
---|
1120 | 1206 | */ |
---|
1121 | | - msleep(1); |
---|
| 1207 | + mdelay(1); |
---|
| 1208 | + qm_mr_pvb_update(p); |
---|
1122 | 1209 | msg = qm_mr_current(p); |
---|
1123 | 1210 | if (!msg) |
---|
1124 | 1211 | return 0; |
---|
.. | .. |
---|
1205 | 1292 | qm_out(p, QM_REG_ISDR, isdr); |
---|
1206 | 1293 | portal->irq_sources = 0; |
---|
1207 | 1294 | qm_out(p, QM_REG_IER, 0); |
---|
1208 | | - qm_out(p, QM_REG_ISR, 0xffffffff); |
---|
1209 | 1295 | snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, c->cpu); |
---|
| 1296 | + qm_out(p, QM_REG_IIR, 1); |
---|
1210 | 1297 | if (request_irq(c->irq, portal_isr, 0, portal->irqname, portal)) { |
---|
1211 | 1298 | dev_err(c->dev, "request_irq() failed\n"); |
---|
1212 | 1299 | goto fail_irq; |
---|
1213 | 1300 | } |
---|
1214 | | - if (c->cpu != -1 && irq_can_set_affinity(c->irq) && |
---|
1215 | | - irq_set_affinity(c->irq, cpumask_of(c->cpu))) { |
---|
1216 | | - dev_err(c->dev, "irq_set_affinity() failed\n"); |
---|
| 1301 | + |
---|
| 1302 | + if (dpaa_set_portal_irq_affinity(c->dev, c->irq, c->cpu)) |
---|
1217 | 1303 | goto fail_affinity; |
---|
1218 | | - } |
---|
1219 | 1304 | |
---|
1220 | 1305 | /* Need EQCR to be empty before continuing */ |
---|
1221 | 1306 | isdr &= ~QM_PIRQ_EQCI; |
---|
.. | .. |
---|
1228 | 1313 | isdr &= ~(QM_PIRQ_DQRI | QM_PIRQ_MRI); |
---|
1229 | 1314 | qm_out(p, QM_REG_ISDR, isdr); |
---|
1230 | 1315 | if (qm_dqrr_current(p)) { |
---|
1231 | | - dev_err(c->dev, "DQRR unclean\n"); |
---|
| 1316 | + dev_dbg(c->dev, "DQRR unclean\n"); |
---|
1232 | 1317 | qm_dqrr_cdc_consume_n(p, 0xffff); |
---|
1233 | 1318 | } |
---|
1234 | 1319 | if (qm_mr_current(p) && drain_mr_fqrni(p)) { |
---|
.. | .. |
---|
1241 | 1326 | } |
---|
1242 | 1327 | /* Success */ |
---|
1243 | 1328 | portal->config = c; |
---|
| 1329 | + qm_out(p, QM_REG_ISR, 0xffffffff); |
---|
1244 | 1330 | qm_out(p, QM_REG_ISDR, 0); |
---|
1245 | | - qm_out(p, QM_REG_IIR, 0); |
---|
| 1331 | + if (!qman_requires_cleanup()) |
---|
| 1332 | + qm_out(p, QM_REG_IIR, 0); |
---|
1246 | 1333 | /* Write a sane SDQCR */ |
---|
1247 | 1334 | qm_dqrr_sdqcr_set(p, portal->sdqcr); |
---|
1248 | 1335 | return 0; |
---|
.. | .. |
---|
1656 | 1743 | return affine_portals[cpu]; |
---|
1657 | 1744 | } |
---|
1658 | 1745 | EXPORT_SYMBOL(qman_get_affine_portal); |
---|
| 1746 | + |
---|
| 1747 | +int qman_start_using_portal(struct qman_portal *p, struct device *dev) |
---|
| 1748 | +{ |
---|
| 1749 | + return (!device_link_add(dev, p->config->dev, |
---|
| 1750 | + DL_FLAG_AUTOREMOVE_CONSUMER)) ? -EINVAL : 0; |
---|
| 1751 | +} |
---|
| 1752 | +EXPORT_SYMBOL(qman_start_using_portal); |
---|
1659 | 1753 | |
---|
1660 | 1754 | int qman_p_poll_dqrr(struct qman_portal *p, unsigned int limit) |
---|
1661 | 1755 | { |
---|
.. | .. |
---|
2521 | 2615 | #define qm_dqrr_drain_nomatch(p) \ |
---|
2522 | 2616 | _qm_dqrr_consume_and_match(p, 0, 0, false) |
---|
2523 | 2617 | |
---|
2524 | | -static int qman_shutdown_fq(u32 fqid) |
---|
| 2618 | +int qman_shutdown_fq(u32 fqid) |
---|
2525 | 2619 | { |
---|
2526 | | - struct qman_portal *p; |
---|
| 2620 | + struct qman_portal *p, *channel_portal; |
---|
2527 | 2621 | struct device *dev; |
---|
2528 | 2622 | union qm_mc_command *mcc; |
---|
2529 | 2623 | union qm_mc_result *mcr; |
---|
.. | .. |
---|
2563 | 2657 | channel = qm_fqd_get_chan(&mcr->queryfq.fqd); |
---|
2564 | 2658 | wq = qm_fqd_get_wq(&mcr->queryfq.fqd); |
---|
2565 | 2659 | |
---|
| 2660 | + if (channel < qm_channel_pool1) { |
---|
| 2661 | + channel_portal = get_portal_for_channel(channel); |
---|
| 2662 | + if (channel_portal == NULL) { |
---|
| 2663 | + dev_err(dev, "Can't find portal for dedicated channel 0x%x\n", |
---|
| 2664 | + channel); |
---|
| 2665 | + ret = -EIO; |
---|
| 2666 | + goto out; |
---|
| 2667 | + } |
---|
| 2668 | + } else |
---|
| 2669 | + channel_portal = p; |
---|
| 2670 | + |
---|
2566 | 2671 | switch (state) { |
---|
2567 | 2672 | case QM_MCR_NP_STATE_TEN_SCHED: |
---|
2568 | 2673 | case QM_MCR_NP_STATE_TRU_SCHED: |
---|
2569 | 2674 | case QM_MCR_NP_STATE_ACTIVE: |
---|
2570 | 2675 | case QM_MCR_NP_STATE_PARKED: |
---|
2571 | 2676 | orl_empty = 0; |
---|
2572 | | - mcc = qm_mc_start(&p->p); |
---|
| 2677 | + mcc = qm_mc_start(&channel_portal->p); |
---|
2573 | 2678 | qm_fqid_set(&mcc->fq, fqid); |
---|
2574 | | - qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_RETIRE); |
---|
2575 | | - if (!qm_mc_result_timeout(&p->p, &mcr)) { |
---|
2576 | | - dev_err(dev, "QUERYFQ_NP timeout\n"); |
---|
| 2679 | + qm_mc_commit(&channel_portal->p, QM_MCC_VERB_ALTER_RETIRE); |
---|
| 2680 | + if (!qm_mc_result_timeout(&channel_portal->p, &mcr)) { |
---|
| 2681 | + dev_err(dev, "ALTER_RETIRE timeout\n"); |
---|
2577 | 2682 | ret = -ETIMEDOUT; |
---|
2578 | 2683 | goto out; |
---|
2579 | 2684 | } |
---|
2580 | 2685 | DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == |
---|
2581 | 2686 | QM_MCR_VERB_ALTER_RETIRE); |
---|
2582 | 2687 | res = mcr->result; /* Make a copy as we reuse MCR below */ |
---|
| 2688 | + |
---|
| 2689 | + if (res == QM_MCR_RESULT_OK) |
---|
| 2690 | + drain_mr_fqrni(&channel_portal->p); |
---|
2583 | 2691 | |
---|
2584 | 2692 | if (res == QM_MCR_RESULT_PENDING) { |
---|
2585 | 2693 | /* |
---|
.. | .. |
---|
2610 | 2718 | } |
---|
2611 | 2719 | /* Set the sdqcr to drain this channel */ |
---|
2612 | 2720 | if (channel < qm_channel_pool1) |
---|
2613 | | - qm_dqrr_sdqcr_set(&p->p, |
---|
| 2721 | + qm_dqrr_sdqcr_set(&channel_portal->p, |
---|
2614 | 2722 | QM_SDQCR_TYPE_ACTIVE | |
---|
2615 | 2723 | QM_SDQCR_CHANNELS_DEDICATED); |
---|
2616 | 2724 | else |
---|
2617 | | - qm_dqrr_sdqcr_set(&p->p, |
---|
| 2725 | + qm_dqrr_sdqcr_set(&channel_portal->p, |
---|
2618 | 2726 | QM_SDQCR_TYPE_ACTIVE | |
---|
2619 | 2727 | QM_SDQCR_CHANNELS_POOL_CONV |
---|
2620 | 2728 | (channel)); |
---|
2621 | 2729 | do { |
---|
2622 | 2730 | /* Keep draining DQRR while checking the MR*/ |
---|
2623 | | - qm_dqrr_drain_nomatch(&p->p); |
---|
| 2731 | + qm_dqrr_drain_nomatch(&channel_portal->p); |
---|
2624 | 2732 | /* Process message ring too */ |
---|
2625 | | - found_fqrn = qm_mr_drain(&p->p, FQRN); |
---|
| 2733 | + found_fqrn = qm_mr_drain(&channel_portal->p, |
---|
| 2734 | + FQRN); |
---|
2626 | 2735 | cpu_relax(); |
---|
2627 | 2736 | } while (!found_fqrn); |
---|
| 2737 | + /* Restore SDQCR */ |
---|
| 2738 | + qm_dqrr_sdqcr_set(&channel_portal->p, |
---|
| 2739 | + channel_portal->sdqcr); |
---|
2628 | 2740 | |
---|
2629 | 2741 | } |
---|
2630 | 2742 | if (res != QM_MCR_RESULT_OK && |
---|
.. | .. |
---|
2655 | 2767 | * Wait for a dequeue and process the dequeues, |
---|
2656 | 2768 | * making sure to empty the ring completely |
---|
2657 | 2769 | */ |
---|
2658 | | - } while (qm_dqrr_drain_wait(&p->p, fqid, FQ_EMPTY)); |
---|
| 2770 | + } while (!qm_dqrr_drain_wait(&p->p, fqid, FQ_EMPTY)); |
---|
2659 | 2771 | } |
---|
2660 | | - qm_dqrr_sdqcr_set(&p->p, 0); |
---|
2661 | 2772 | |
---|
2662 | 2773 | while (!orl_empty) { |
---|
2663 | 2774 | /* Wait for the ORL to have been completely drained */ |
---|
.. | .. |
---|
2694 | 2805 | |
---|
2695 | 2806 | DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == |
---|
2696 | 2807 | QM_MCR_VERB_ALTER_OOS); |
---|
2697 | | - if (mcr->result) { |
---|
| 2808 | + if (mcr->result != QM_MCR_RESULT_OK) { |
---|
2698 | 2809 | dev_err(dev, "OOS fail: FQ 0x%x (0x%x)\n", |
---|
2699 | 2810 | fqid, mcr->result); |
---|
2700 | 2811 | ret = -EIO; |
---|