Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
0002 // Copyright (c) 2017 Synopsys, Inc. and/or its affiliates.
0003 // stmmac Support for 5.xx Ethernet QoS cores
0004 
0005 #include <linux/bitops.h>
0006 #include <linux/iopoll.h>
0007 #include "common.h"
0008 #include "dwmac4.h"
0009 #include "dwmac5.h"
0010 #include "stmmac.h"
0011 #include "stmmac_ptp.h"
0012 
0013 struct dwmac5_error_desc {
0014     bool valid;
0015     const char *desc;
0016     const char *detailed_desc;
0017 };
0018 
0019 #define STAT_OFF(field)     offsetof(struct stmmac_safety_stats, field)
0020 
0021 static void dwmac5_log_error(struct net_device *ndev, u32 value, bool corr,
0022         const char *module_name, const struct dwmac5_error_desc *desc,
0023         unsigned long field_offset, struct stmmac_safety_stats *stats)
0024 {
0025     unsigned long loc, mask;
0026     u8 *bptr = (u8 *)stats;
0027     unsigned long *ptr;
0028 
0029     ptr = (unsigned long *)(bptr + field_offset);
0030 
0031     mask = value;
0032     for_each_set_bit(loc, &mask, 32) {
0033         netdev_err(ndev, "Found %s error in %s: '%s: %s'\n", corr ?
0034                 "correctable" : "uncorrectable", module_name,
0035                 desc[loc].desc, desc[loc].detailed_desc);
0036 
0037         /* Update counters */
0038         ptr[loc]++;
0039     }
0040 }
0041 
0042 static const struct dwmac5_error_desc dwmac5_mac_errors[32]= {
0043     { true, "ATPES", "Application Transmit Interface Parity Check Error" },
0044     { true, "TPES", "TSO Data Path Parity Check Error" },
0045     { true, "RDPES", "Read Descriptor Parity Check Error" },
0046     { true, "MPES", "MTL Data Path Parity Check Error" },
0047     { true, "MTSPES", "MTL TX Status Data Path Parity Check Error" },
0048     { true, "ARPES", "Application Receive Interface Data Path Parity Check Error" },
0049     { true, "CWPES", "CSR Write Data Path Parity Check Error" },
0050     { true, "ASRPES", "AXI Slave Read Data Path Parity Check Error" },
0051     { true, "TTES", "TX FSM Timeout Error" },
0052     { true, "RTES", "RX FSM Timeout Error" },
0053     { true, "CTES", "CSR FSM Timeout Error" },
0054     { true, "ATES", "APP FSM Timeout Error" },
0055     { true, "PTES", "PTP FSM Timeout Error" },
0056     { true, "T125ES", "TX125 FSM Timeout Error" },
0057     { true, "R125ES", "RX125 FSM Timeout Error" },
0058     { true, "RVCTES", "REV MDC FSM Timeout Error" },
0059     { true, "MSTTES", "Master Read/Write Timeout Error" },
0060     { true, "SLVTES", "Slave Read/Write Timeout Error" },
0061     { true, "ATITES", "Application Timeout on ATI Interface Error" },
0062     { true, "ARITES", "Application Timeout on ARI Interface Error" },
0063     { false, "UNKNOWN", "Unknown Error" }, /* 20 */
0064     { false, "UNKNOWN", "Unknown Error" }, /* 21 */
0065     { false, "UNKNOWN", "Unknown Error" }, /* 22 */
0066     { false, "UNKNOWN", "Unknown Error" }, /* 23 */
0067     { true, "FSMPES", "FSM State Parity Error" },
0068     { false, "UNKNOWN", "Unknown Error" }, /* 25 */
0069     { false, "UNKNOWN", "Unknown Error" }, /* 26 */
0070     { false, "UNKNOWN", "Unknown Error" }, /* 27 */
0071     { false, "UNKNOWN", "Unknown Error" }, /* 28 */
0072     { false, "UNKNOWN", "Unknown Error" }, /* 29 */
0073     { false, "UNKNOWN", "Unknown Error" }, /* 30 */
0074     { false, "UNKNOWN", "Unknown Error" }, /* 31 */
0075 };
0076 
0077 static void dwmac5_handle_mac_err(struct net_device *ndev,
0078         void __iomem *ioaddr, bool correctable,
0079         struct stmmac_safety_stats *stats)
0080 {
0081     u32 value;
0082 
0083     value = readl(ioaddr + MAC_DPP_FSM_INT_STATUS);
0084     writel(value, ioaddr + MAC_DPP_FSM_INT_STATUS);
0085 
0086     dwmac5_log_error(ndev, value, correctable, "MAC", dwmac5_mac_errors,
0087             STAT_OFF(mac_errors), stats);
0088 }
0089 
0090 static const struct dwmac5_error_desc dwmac5_mtl_errors[32]= {
0091     { true, "TXCES", "MTL TX Memory Error" },
0092     { true, "TXAMS", "MTL TX Memory Address Mismatch Error" },
0093     { true, "TXUES", "MTL TX Memory Error" },
0094     { false, "UNKNOWN", "Unknown Error" }, /* 3 */
0095     { true, "RXCES", "MTL RX Memory Error" },
0096     { true, "RXAMS", "MTL RX Memory Address Mismatch Error" },
0097     { true, "RXUES", "MTL RX Memory Error" },
0098     { false, "UNKNOWN", "Unknown Error" }, /* 7 */
0099     { true, "ECES", "MTL EST Memory Error" },
0100     { true, "EAMS", "MTL EST Memory Address Mismatch Error" },
0101     { true, "EUES", "MTL EST Memory Error" },
0102     { false, "UNKNOWN", "Unknown Error" }, /* 11 */
0103     { true, "RPCES", "MTL RX Parser Memory Error" },
0104     { true, "RPAMS", "MTL RX Parser Memory Address Mismatch Error" },
0105     { true, "RPUES", "MTL RX Parser Memory Error" },
0106     { false, "UNKNOWN", "Unknown Error" }, /* 15 */
0107     { false, "UNKNOWN", "Unknown Error" }, /* 16 */
0108     { false, "UNKNOWN", "Unknown Error" }, /* 17 */
0109     { false, "UNKNOWN", "Unknown Error" }, /* 18 */
0110     { false, "UNKNOWN", "Unknown Error" }, /* 19 */
0111     { false, "UNKNOWN", "Unknown Error" }, /* 20 */
0112     { false, "UNKNOWN", "Unknown Error" }, /* 21 */
0113     { false, "UNKNOWN", "Unknown Error" }, /* 22 */
0114     { false, "UNKNOWN", "Unknown Error" }, /* 23 */
0115     { false, "UNKNOWN", "Unknown Error" }, /* 24 */
0116     { false, "UNKNOWN", "Unknown Error" }, /* 25 */
0117     { false, "UNKNOWN", "Unknown Error" }, /* 26 */
0118     { false, "UNKNOWN", "Unknown Error" }, /* 27 */
0119     { false, "UNKNOWN", "Unknown Error" }, /* 28 */
0120     { false, "UNKNOWN", "Unknown Error" }, /* 29 */
0121     { false, "UNKNOWN", "Unknown Error" }, /* 30 */
0122     { false, "UNKNOWN", "Unknown Error" }, /* 31 */
0123 };
0124 
0125 static void dwmac5_handle_mtl_err(struct net_device *ndev,
0126         void __iomem *ioaddr, bool correctable,
0127         struct stmmac_safety_stats *stats)
0128 {
0129     u32 value;
0130 
0131     value = readl(ioaddr + MTL_ECC_INT_STATUS);
0132     writel(value, ioaddr + MTL_ECC_INT_STATUS);
0133 
0134     dwmac5_log_error(ndev, value, correctable, "MTL", dwmac5_mtl_errors,
0135             STAT_OFF(mtl_errors), stats);
0136 }
0137 
0138 static const struct dwmac5_error_desc dwmac5_dma_errors[32]= {
0139     { true, "TCES", "DMA TSO Memory Error" },
0140     { true, "TAMS", "DMA TSO Memory Address Mismatch Error" },
0141     { true, "TUES", "DMA TSO Memory Error" },
0142     { false, "UNKNOWN", "Unknown Error" }, /* 3 */
0143     { false, "UNKNOWN", "Unknown Error" }, /* 4 */
0144     { false, "UNKNOWN", "Unknown Error" }, /* 5 */
0145     { false, "UNKNOWN", "Unknown Error" }, /* 6 */
0146     { false, "UNKNOWN", "Unknown Error" }, /* 7 */
0147     { false, "UNKNOWN", "Unknown Error" }, /* 8 */
0148     { false, "UNKNOWN", "Unknown Error" }, /* 9 */
0149     { false, "UNKNOWN", "Unknown Error" }, /* 10 */
0150     { false, "UNKNOWN", "Unknown Error" }, /* 11 */
0151     { false, "UNKNOWN", "Unknown Error" }, /* 12 */
0152     { false, "UNKNOWN", "Unknown Error" }, /* 13 */
0153     { false, "UNKNOWN", "Unknown Error" }, /* 14 */
0154     { false, "UNKNOWN", "Unknown Error" }, /* 15 */
0155     { false, "UNKNOWN", "Unknown Error" }, /* 16 */
0156     { false, "UNKNOWN", "Unknown Error" }, /* 17 */
0157     { false, "UNKNOWN", "Unknown Error" }, /* 18 */
0158     { false, "UNKNOWN", "Unknown Error" }, /* 19 */
0159     { false, "UNKNOWN", "Unknown Error" }, /* 20 */
0160     { false, "UNKNOWN", "Unknown Error" }, /* 21 */
0161     { false, "UNKNOWN", "Unknown Error" }, /* 22 */
0162     { false, "UNKNOWN", "Unknown Error" }, /* 23 */
0163     { false, "UNKNOWN", "Unknown Error" }, /* 24 */
0164     { false, "UNKNOWN", "Unknown Error" }, /* 25 */
0165     { false, "UNKNOWN", "Unknown Error" }, /* 26 */
0166     { false, "UNKNOWN", "Unknown Error" }, /* 27 */
0167     { false, "UNKNOWN", "Unknown Error" }, /* 28 */
0168     { false, "UNKNOWN", "Unknown Error" }, /* 29 */
0169     { false, "UNKNOWN", "Unknown Error" }, /* 30 */
0170     { false, "UNKNOWN", "Unknown Error" }, /* 31 */
0171 };
0172 
0173 static void dwmac5_handle_dma_err(struct net_device *ndev,
0174         void __iomem *ioaddr, bool correctable,
0175         struct stmmac_safety_stats *stats)
0176 {
0177     u32 value;
0178 
0179     value = readl(ioaddr + DMA_ECC_INT_STATUS);
0180     writel(value, ioaddr + DMA_ECC_INT_STATUS);
0181 
0182     dwmac5_log_error(ndev, value, correctable, "DMA", dwmac5_dma_errors,
0183             STAT_OFF(dma_errors), stats);
0184 }
0185 
0186 int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp,
0187                   struct stmmac_safety_feature_cfg *safety_feat_cfg)
0188 {
0189     u32 value;
0190 
0191     if (!asp)
0192         return -EINVAL;
0193 
0194     /* 1. Enable Safety Features */
0195     value = readl(ioaddr + MTL_ECC_CONTROL);
0196     value |= MEEAO; /* MTL ECC Error Addr Status Override */
0197     if (safety_feat_cfg->tsoee)
0198         value |= TSOEE; /* TSO ECC */
0199     if (safety_feat_cfg->mrxpee)
0200         value |= MRXPEE; /* MTL RX Parser ECC */
0201     if (safety_feat_cfg->mestee)
0202         value |= MESTEE; /* MTL EST ECC */
0203     if (safety_feat_cfg->mrxee)
0204         value |= MRXEE; /* MTL RX FIFO ECC */
0205     if (safety_feat_cfg->mtxee)
0206         value |= MTXEE; /* MTL TX FIFO ECC */
0207     writel(value, ioaddr + MTL_ECC_CONTROL);
0208 
0209     /* 2. Enable MTL Safety Interrupts */
0210     value = readl(ioaddr + MTL_ECC_INT_ENABLE);
0211     value |= RPCEIE; /* RX Parser Memory Correctable Error */
0212     value |= ECEIE; /* EST Memory Correctable Error */
0213     value |= RXCEIE; /* RX Memory Correctable Error */
0214     value |= TXCEIE; /* TX Memory Correctable Error */
0215     writel(value, ioaddr + MTL_ECC_INT_ENABLE);
0216 
0217     /* 3. Enable DMA Safety Interrupts */
0218     value = readl(ioaddr + DMA_ECC_INT_ENABLE);
0219     value |= TCEIE; /* TSO Memory Correctable Error */
0220     writel(value, ioaddr + DMA_ECC_INT_ENABLE);
0221 
0222     /* Only ECC Protection for External Memory feature is selected */
0223     if (asp <= 0x1)
0224         return 0;
0225 
0226     /* 5. Enable Parity and Timeout for FSM */
0227     value = readl(ioaddr + MAC_FSM_CONTROL);
0228     if (safety_feat_cfg->prtyen)
0229         value |= PRTYEN; /* FSM Parity Feature */
0230     if (safety_feat_cfg->tmouten)
0231         value |= TMOUTEN; /* FSM Timeout Feature */
0232     writel(value, ioaddr + MAC_FSM_CONTROL);
0233 
0234     /* 4. Enable Data Parity Protection */
0235     value = readl(ioaddr + MTL_DPP_CONTROL);
0236     if (safety_feat_cfg->edpp)
0237         value |= EDPP;
0238     writel(value, ioaddr + MTL_DPP_CONTROL);
0239 
0240     /*
0241      * All the Automotive Safety features are selected without the "Parity
0242      * Port Enable for external interface" feature.
0243      */
0244     if (asp <= 0x2)
0245         return 0;
0246 
0247     if (safety_feat_cfg->epsi)
0248         value |= EPSI;
0249     writel(value, ioaddr + MTL_DPP_CONTROL);
0250     return 0;
0251 }
0252 
0253 int dwmac5_safety_feat_irq_status(struct net_device *ndev,
0254         void __iomem *ioaddr, unsigned int asp,
0255         struct stmmac_safety_stats *stats)
0256 {
0257     bool err, corr;
0258     u32 mtl, dma;
0259     int ret = 0;
0260 
0261     if (!asp)
0262         return -EINVAL;
0263 
0264     mtl = readl(ioaddr + MTL_SAFETY_INT_STATUS);
0265     dma = readl(ioaddr + DMA_SAFETY_INT_STATUS);
0266 
0267     err = (mtl & MCSIS) || (dma & MCSIS);
0268     corr = false;
0269     if (err) {
0270         dwmac5_handle_mac_err(ndev, ioaddr, corr, stats);
0271         ret |= !corr;
0272     }
0273 
0274     err = (mtl & (MEUIS | MECIS)) || (dma & (MSUIS | MSCIS));
0275     corr = (mtl & MECIS) || (dma & MSCIS);
0276     if (err) {
0277         dwmac5_handle_mtl_err(ndev, ioaddr, corr, stats);
0278         ret |= !corr;
0279     }
0280 
0281     err = dma & (DEUIS | DECIS);
0282     corr = dma & DECIS;
0283     if (err) {
0284         dwmac5_handle_dma_err(ndev, ioaddr, corr, stats);
0285         ret |= !corr;
0286     }
0287 
0288     return ret;
0289 }
0290 
0291 static const struct dwmac5_error {
0292     const struct dwmac5_error_desc *desc;
0293 } dwmac5_all_errors[] = {
0294     { dwmac5_mac_errors },
0295     { dwmac5_mtl_errors },
0296     { dwmac5_dma_errors },
0297 };
0298 
0299 int dwmac5_safety_feat_dump(struct stmmac_safety_stats *stats,
0300             int index, unsigned long *count, const char **desc)
0301 {
0302     int module = index / 32, offset = index % 32;
0303     unsigned long *ptr = (unsigned long *)stats;
0304 
0305     if (module >= ARRAY_SIZE(dwmac5_all_errors))
0306         return -EINVAL;
0307     if (!dwmac5_all_errors[module].desc[offset].valid)
0308         return -EINVAL;
0309     if (count)
0310         *count = *(ptr + index);
0311     if (desc)
0312         *desc = dwmac5_all_errors[module].desc[offset].desc;
0313     return 0;
0314 }
0315 
0316 static int dwmac5_rxp_disable(void __iomem *ioaddr)
0317 {
0318     u32 val;
0319 
0320     val = readl(ioaddr + MTL_OPERATION_MODE);
0321     val &= ~MTL_FRPE;
0322     writel(val, ioaddr + MTL_OPERATION_MODE);
0323 
0324     return readl_poll_timeout(ioaddr + MTL_RXP_CONTROL_STATUS, val,
0325             val & RXPI, 1, 10000);
0326 }
0327 
0328 static void dwmac5_rxp_enable(void __iomem *ioaddr)
0329 {
0330     u32 val;
0331 
0332     val = readl(ioaddr + MTL_OPERATION_MODE);
0333     val |= MTL_FRPE;
0334     writel(val, ioaddr + MTL_OPERATION_MODE);
0335 }
0336 
0337 static int dwmac5_rxp_update_single_entry(void __iomem *ioaddr,
0338                       struct stmmac_tc_entry *entry,
0339                       int pos)
0340 {
0341     int ret, i;
0342 
0343     for (i = 0; i < (sizeof(entry->val) / sizeof(u32)); i++) {
0344         int real_pos = pos * (sizeof(entry->val) / sizeof(u32)) + i;
0345         u32 val;
0346 
0347         /* Wait for ready */
0348         ret = readl_poll_timeout(ioaddr + MTL_RXP_IACC_CTRL_STATUS,
0349                 val, !(val & STARTBUSY), 1, 10000);
0350         if (ret)
0351             return ret;
0352 
0353         /* Write data */
0354         val = *((u32 *)&entry->val + i);
0355         writel(val, ioaddr + MTL_RXP_IACC_DATA);
0356 
0357         /* Write pos */
0358         val = real_pos & ADDR;
0359         writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
0360 
0361         /* Write OP */
0362         val |= WRRDN;
0363         writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
0364 
0365         /* Start Write */
0366         val |= STARTBUSY;
0367         writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
0368 
0369         /* Wait for done */
0370         ret = readl_poll_timeout(ioaddr + MTL_RXP_IACC_CTRL_STATUS,
0371                 val, !(val & STARTBUSY), 1, 10000);
0372         if (ret)
0373             return ret;
0374     }
0375 
0376     return 0;
0377 }
0378 
0379 static struct stmmac_tc_entry *
0380 dwmac5_rxp_get_next_entry(struct stmmac_tc_entry *entries, unsigned int count,
0381               u32 curr_prio)
0382 {
0383     struct stmmac_tc_entry *entry;
0384     u32 min_prio = ~0x0;
0385     int i, min_prio_idx;
0386     bool found = false;
0387 
0388     for (i = count - 1; i >= 0; i--) {
0389         entry = &entries[i];
0390 
0391         /* Do not update unused entries */
0392         if (!entry->in_use)
0393             continue;
0394         /* Do not update already updated entries (i.e. fragments) */
0395         if (entry->in_hw)
0396             continue;
0397         /* Let last entry be updated last */
0398         if (entry->is_last)
0399             continue;
0400         /* Do not return fragments */
0401         if (entry->is_frag)
0402             continue;
0403         /* Check if we already checked this prio */
0404         if (entry->prio < curr_prio)
0405             continue;
0406         /* Check if this is the minimum prio */
0407         if (entry->prio < min_prio) {
0408             min_prio = entry->prio;
0409             min_prio_idx = i;
0410             found = true;
0411         }
0412     }
0413 
0414     if (found)
0415         return &entries[min_prio_idx];
0416     return NULL;
0417 }
0418 
0419 int dwmac5_rxp_config(void __iomem *ioaddr, struct stmmac_tc_entry *entries,
0420               unsigned int count)
0421 {
0422     struct stmmac_tc_entry *entry, *frag;
0423     int i, ret, nve = 0;
0424     u32 curr_prio = 0;
0425     u32 old_val, val;
0426 
0427     /* Force disable RX */
0428     old_val = readl(ioaddr + GMAC_CONFIG);
0429     val = old_val & ~GMAC_CONFIG_RE;
0430     writel(val, ioaddr + GMAC_CONFIG);
0431 
0432     /* Disable RX Parser */
0433     ret = dwmac5_rxp_disable(ioaddr);
0434     if (ret)
0435         goto re_enable;
0436 
0437     /* Set all entries as NOT in HW */
0438     for (i = 0; i < count; i++) {
0439         entry = &entries[i];
0440         entry->in_hw = false;
0441     }
0442 
0443     /* Update entries by reverse order */
0444     while (1) {
0445         entry = dwmac5_rxp_get_next_entry(entries, count, curr_prio);
0446         if (!entry)
0447             break;
0448 
0449         curr_prio = entry->prio;
0450         frag = entry->frag_ptr;
0451 
0452         /* Set special fragment requirements */
0453         if (frag) {
0454             entry->val.af = 0;
0455             entry->val.rf = 0;
0456             entry->val.nc = 1;
0457             entry->val.ok_index = nve + 2;
0458         }
0459 
0460         ret = dwmac5_rxp_update_single_entry(ioaddr, entry, nve);
0461         if (ret)
0462             goto re_enable;
0463 
0464         entry->table_pos = nve++;
0465         entry->in_hw = true;
0466 
0467         if (frag && !frag->in_hw) {
0468             ret = dwmac5_rxp_update_single_entry(ioaddr, frag, nve);
0469             if (ret)
0470                 goto re_enable;
0471             frag->table_pos = nve++;
0472             frag->in_hw = true;
0473         }
0474     }
0475 
0476     if (!nve)
0477         goto re_enable;
0478 
0479     /* Update all pass entry */
0480     for (i = 0; i < count; i++) {
0481         entry = &entries[i];
0482         if (!entry->is_last)
0483             continue;
0484 
0485         ret = dwmac5_rxp_update_single_entry(ioaddr, entry, nve);
0486         if (ret)
0487             goto re_enable;
0488 
0489         entry->table_pos = nve++;
0490     }
0491 
0492     /* Assume n. of parsable entries == n. of valid entries */
0493     val = (nve << 16) & NPE;
0494     val |= nve & NVE;
0495     writel(val, ioaddr + MTL_RXP_CONTROL_STATUS);
0496 
0497     /* Enable RX Parser */
0498     dwmac5_rxp_enable(ioaddr);
0499 
0500 re_enable:
0501     /* Re-enable RX */
0502     writel(old_val, ioaddr + GMAC_CONFIG);
0503     return ret;
0504 }
0505 
0506 int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
0507                struct stmmac_pps_cfg *cfg, bool enable,
0508                u32 sub_second_inc, u32 systime_flags)
0509 {
0510     u32 tnsec = readl(ioaddr + MAC_PPSx_TARGET_TIME_NSEC(index));
0511     u32 val = readl(ioaddr + MAC_PPS_CONTROL);
0512     u64 period;
0513 
0514     if (!cfg->available)
0515         return -EINVAL;
0516     if (tnsec & TRGTBUSY0)
0517         return -EBUSY;
0518     if (!sub_second_inc || !systime_flags)
0519         return -EINVAL;
0520 
0521     val &= ~PPSx_MASK(index);
0522 
0523     if (!enable) {
0524         val |= PPSCMDx(index, 0x5);
0525         val |= PPSEN0;
0526         writel(val, ioaddr + MAC_PPS_CONTROL);
0527         return 0;
0528     }
0529 
0530     val |= PPSCMDx(index, 0x2);
0531     val |= TRGTMODSELx(index, 0x2);
0532     val |= PPSEN0;
0533 
0534     writel(cfg->start.tv_sec, ioaddr + MAC_PPSx_TARGET_TIME_SEC(index));
0535 
0536     if (!(systime_flags & PTP_TCR_TSCTRLSSR))
0537         cfg->start.tv_nsec = (cfg->start.tv_nsec * 1000) / 465;
0538     writel(cfg->start.tv_nsec, ioaddr + MAC_PPSx_TARGET_TIME_NSEC(index));
0539 
0540     period = cfg->period.tv_sec * 1000000000;
0541     period += cfg->period.tv_nsec;
0542 
0543     do_div(period, sub_second_inc);
0544 
0545     if (period <= 1)
0546         return -EINVAL;
0547 
0548     writel(period - 1, ioaddr + MAC_PPSx_INTERVAL(index));
0549 
0550     period >>= 1;
0551     if (period <= 1)
0552         return -EINVAL;
0553 
0554     writel(period - 1, ioaddr + MAC_PPSx_WIDTH(index));
0555 
0556     /* Finally, activate it */
0557     writel(val, ioaddr + MAC_PPS_CONTROL);
0558     return 0;
0559 }
0560 
0561 static int dwmac5_est_write(void __iomem *ioaddr, u32 reg, u32 val, bool gcl)
0562 {
0563     u32 ctrl;
0564 
0565     writel(val, ioaddr + MTL_EST_GCL_DATA);
0566 
0567     ctrl = (reg << ADDR_SHIFT);
0568     ctrl |= gcl ? 0 : GCRR;
0569 
0570     writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
0571 
0572     ctrl |= SRWO;
0573     writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
0574 
0575     return readl_poll_timeout(ioaddr + MTL_EST_GCL_CONTROL,
0576                   ctrl, !(ctrl & SRWO), 100, 5000);
0577 }
0578 
0579 int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
0580              unsigned int ptp_rate)
0581 {
0582     int i, ret = 0x0;
0583     u32 ctrl;
0584 
0585     ret |= dwmac5_est_write(ioaddr, BTR_LOW, cfg->btr[0], false);
0586     ret |= dwmac5_est_write(ioaddr, BTR_HIGH, cfg->btr[1], false);
0587     ret |= dwmac5_est_write(ioaddr, TER, cfg->ter, false);
0588     ret |= dwmac5_est_write(ioaddr, LLR, cfg->gcl_size, false);
0589     ret |= dwmac5_est_write(ioaddr, CTR_LOW, cfg->ctr[0], false);
0590     ret |= dwmac5_est_write(ioaddr, CTR_HIGH, cfg->ctr[1], false);
0591     if (ret)
0592         return ret;
0593 
0594     for (i = 0; i < cfg->gcl_size; i++) {
0595         ret = dwmac5_est_write(ioaddr, i, cfg->gcl[i], true);
0596         if (ret)
0597             return ret;
0598     }
0599 
0600     ctrl = readl(ioaddr + MTL_EST_CONTROL);
0601     ctrl &= ~PTOV;
0602     ctrl |= ((1000000000 / ptp_rate) * 6) << PTOV_SHIFT;
0603     if (cfg->enable)
0604         ctrl |= EEST | SSWL;
0605     else
0606         ctrl &= ~EEST;
0607 
0608     writel(ctrl, ioaddr + MTL_EST_CONTROL);
0609 
0610     /* Configure EST interrupt */
0611     if (cfg->enable)
0612         ctrl = (IECGCE | IEHS | IEHF | IEBE | IECC);
0613     else
0614         ctrl = 0;
0615 
0616     writel(ctrl, ioaddr + MTL_EST_INT_EN);
0617 
0618     return 0;
0619 }
0620 
0621 void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev,
0622               struct stmmac_extra_stats *x, u32 txqcnt)
0623 {
0624     u32 status, value, feqn, hbfq, hbfs, btrl;
0625     u32 txqcnt_mask = (1 << txqcnt) - 1;
0626 
0627     status = readl(ioaddr + MTL_EST_STATUS);
0628 
0629     value = (CGCE | HLBS | HLBF | BTRE | SWLC);
0630 
0631     /* Return if there is no error */
0632     if (!(status & value))
0633         return;
0634 
0635     if (status & CGCE) {
0636         /* Clear Interrupt */
0637         writel(CGCE, ioaddr + MTL_EST_STATUS);
0638 
0639         x->mtl_est_cgce++;
0640     }
0641 
0642     if (status & HLBS) {
0643         value = readl(ioaddr + MTL_EST_SCH_ERR);
0644         value &= txqcnt_mask;
0645 
0646         x->mtl_est_hlbs++;
0647 
0648         /* Clear Interrupt */
0649         writel(value, ioaddr + MTL_EST_SCH_ERR);
0650 
0651         /* Collecting info to shows all the queues that has HLBS
0652          * issue. The only way to clear this is to clear the
0653          * statistic
0654          */
0655         if (net_ratelimit())
0656             netdev_err(dev, "EST: HLB(sched) Queue 0x%x\n", value);
0657     }
0658 
0659     if (status & HLBF) {
0660         value = readl(ioaddr + MTL_EST_FRM_SZ_ERR);
0661         feqn = value & txqcnt_mask;
0662 
0663         value = readl(ioaddr + MTL_EST_FRM_SZ_CAP);
0664         hbfq = (value & SZ_CAP_HBFQ_MASK(txqcnt)) >> SZ_CAP_HBFQ_SHIFT;
0665         hbfs = value & SZ_CAP_HBFS_MASK;
0666 
0667         x->mtl_est_hlbf++;
0668 
0669         /* Clear Interrupt */
0670         writel(feqn, ioaddr + MTL_EST_FRM_SZ_ERR);
0671 
0672         if (net_ratelimit())
0673             netdev_err(dev, "EST: HLB(size) Queue %u Size %u\n",
0674                    hbfq, hbfs);
0675     }
0676 
0677     if (status & BTRE) {
0678         if ((status & BTRL) == BTRL_MAX)
0679             x->mtl_est_btrlm++;
0680         else
0681             x->mtl_est_btre++;
0682 
0683         btrl = (status & BTRL) >> BTRL_SHIFT;
0684 
0685         if (net_ratelimit())
0686             netdev_info(dev, "EST: BTR Error Loop Count %u\n",
0687                     btrl);
0688 
0689         writel(BTRE, ioaddr + MTL_EST_STATUS);
0690     }
0691 
0692     if (status & SWLC) {
0693         writel(SWLC, ioaddr + MTL_EST_STATUS);
0694         netdev_info(dev, "EST: SWOL has been switched\n");
0695     }
0696 }
0697 
0698 void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
0699               bool enable)
0700 {
0701     u32 value;
0702 
0703     if (!enable) {
0704         value = readl(ioaddr + MAC_FPE_CTRL_STS);
0705 
0706         value &= ~EFPE;
0707 
0708         writel(value, ioaddr + MAC_FPE_CTRL_STS);
0709         return;
0710     }
0711 
0712     value = readl(ioaddr + GMAC_RXQ_CTRL1);
0713     value &= ~GMAC_RXQCTRL_FPRQ;
0714     value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT;
0715     writel(value, ioaddr + GMAC_RXQ_CTRL1);
0716 
0717     value = readl(ioaddr + MAC_FPE_CTRL_STS);
0718     value |= EFPE;
0719     writel(value, ioaddr + MAC_FPE_CTRL_STS);
0720 }
0721 
0722 int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev)
0723 {
0724     u32 value;
0725     int status;
0726 
0727     status = FPE_EVENT_UNKNOWN;
0728 
0729     value = readl(ioaddr + MAC_FPE_CTRL_STS);
0730 
0731     if (value & TRSP) {
0732         status |= FPE_EVENT_TRSP;
0733         netdev_info(dev, "FPE: Respond mPacket is transmitted\n");
0734     }
0735 
0736     if (value & TVER) {
0737         status |= FPE_EVENT_TVER;
0738         netdev_info(dev, "FPE: Verify mPacket is transmitted\n");
0739     }
0740 
0741     if (value & RRSP) {
0742         status |= FPE_EVENT_RRSP;
0743         netdev_info(dev, "FPE: Respond mPacket is received\n");
0744     }
0745 
0746     if (value & RVER) {
0747         status |= FPE_EVENT_RVER;
0748         netdev_info(dev, "FPE: Verify mPacket is received\n");
0749     }
0750 
0751     return status;
0752 }
0753 
0754 void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, enum stmmac_mpacket_type type)
0755 {
0756     u32 value;
0757 
0758     value = readl(ioaddr + MAC_FPE_CTRL_STS);
0759 
0760     if (type == MPACKET_VERIFY) {
0761         value &= ~SRSP;
0762         value |= SVER;
0763     } else {
0764         value &= ~SVER;
0765         value |= SRSP;
0766     }
0767 
0768     writel(value, ioaddr + MAC_FPE_CTRL_STS);
0769 }