/* * Copyright 2015-2016 Freescale Semiconductor, Inc. * Copyright 2017 NXP * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "pfe_mod.h" #define PE_EXCEPTION_DUMP_ADDRESS 0x1fa8 #define NUM_QUEUES 16 static char register_name[20][5] = { "EPC", "ECAS", "EID", "ED", "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", }; static char exception_name[14][20] = { "Reset", "HardwareFailure", "NMI", "InstBreakpoint", "DataBreakpoint", "Unsupported", "PrivilegeViolation", "InstBusError", "DataBusError", "AlignmentError", "ArithmeticError", "SystemCall", "MemoryManagement", "Interrupt", }; static unsigned long class_do_clear; static unsigned long tmu_do_clear; #if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED) static unsigned long util_do_clear; #endif static ssize_t display_pe_status(char *buf, int id, u32 dmem_addr, unsigned long do_clear) { ssize_t len = 0; u32 val; char statebuf[5]; struct pfe_cpumon *cpumon = &pfe->cpumon; u32 debug_indicator; u32 debug[20]; *(u32 *)statebuf = pe_dmem_read(id, dmem_addr, 4); dmem_addr += 4; statebuf[4] = '\0'; len += sprintf(buf + len, "state=%4s ", statebuf); val = pe_dmem_read(id, dmem_addr, 4); dmem_addr += 4; len += sprintf(buf + len, "ctr=%08x ", cpu_to_be32(val)); val = pe_dmem_read(id, dmem_addr, 4); if (do_clear && val) pe_dmem_write(id, 0, dmem_addr, 4); dmem_addr += 4; len += sprintf(buf + len, "rx=%u ", cpu_to_be32(val)); val = pe_dmem_read(id, dmem_addr, 4); if (do_clear && val) pe_dmem_write(id, 0, dmem_addr, 4); dmem_addr += 4; if (id >= TMU0_ID && id <= TMU_MAX_ID) len += sprintf(buf + len, "qstatus=%x", cpu_to_be32(val)); else len += sprintf(buf + len, "tx=%u", cpu_to_be32(val)); val = pe_dmem_read(id, dmem_addr, 4); if (do_clear && val) pe_dmem_write(id, 0, dmem_addr, 4); dmem_addr += 4; if (val) len += sprintf(buf + len, " drop=%u", cpu_to_be32(val)); len += sprintf(buf + len, " load=%d%%", cpumon->cpu_usage_pct[id]); len += sprintf(buf + len, "\n"); debug_indicator = pe_dmem_read(id, dmem_addr, 4); dmem_addr += 4; if (!strncmp((char *)&debug_indicator, "DBUG", 4)) { int j, last = 0; for (j = 0; j < 16; j++) { debug[j] = pe_dmem_read(id, dmem_addr, 4); if (debug[j]) { if (do_clear) pe_dmem_write(id, 0, dmem_addr, 4); last = j + 1; } dmem_addr += 4; } for (j = 0; j < last; j++) { len += sprintf(buf + len, "%08x%s", cpu_to_be32(debug[j]), (j & 0x7) == 0x7 || j == last - 1 ? "\n" : " "); } } if (!strncmp(statebuf, "DEAD", 4)) { u32 i, dump = PE_EXCEPTION_DUMP_ADDRESS; len += sprintf(buf + len, "Exception details:\n"); for (i = 0; i < 20; i++) { debug[i] = pe_dmem_read(id, dump, 4); dump += 4; if (i == 2) len += sprintf(buf + len, "%4s = %08x (=%s) ", register_name[i], cpu_to_be32(debug[i]), exception_name[min((u32) cpu_to_be32(debug[i]), (u32)13)]); else len += sprintf(buf + len, "%4s = %08x%s", register_name[i], cpu_to_be32(debug[i]), (i & 0x3) == 0x3 || i == 19 ? "\n" : " "); } } return len; } static ssize_t class_phy_stats(char *buf, int phy) { ssize_t len = 0; int off1 = phy * 0x28; int off2 = phy * 0x10; if (phy == 3) off1 = CLASS_PHY4_RX_PKTS - CLASS_PHY1_RX_PKTS; len += sprintf(buf + len, "phy: %d\n", phy); len += sprintf(buf + len, " rx: %10u, tx: %10u, intf: %10u, ipv4: %10u, ipv6: %10u\n", readl(CLASS_PHY1_RX_PKTS + off1), readl(CLASS_PHY1_TX_PKTS + off1), readl(CLASS_PHY1_INTF_MATCH_PKTS + off1), readl(CLASS_PHY1_V4_PKTS + off1), readl(CLASS_PHY1_V6_PKTS + off1)); len += sprintf(buf + len, " icmp: %10u, igmp: %10u, tcp: %10u, udp: %10u\n", readl(CLASS_PHY1_ICMP_PKTS + off2), readl(CLASS_PHY1_IGMP_PKTS + off2), readl(CLASS_PHY1_TCP_PKTS + off2), readl(CLASS_PHY1_UDP_PKTS + off2)); len += sprintf(buf + len, " err\n"); len += sprintf(buf + len, " lp: %10u, intf: %10u, l3: %10u, chcksum: %10u, ttl: %10u\n", readl(CLASS_PHY1_LP_FAIL_PKTS + off1), readl(CLASS_PHY1_INTF_FAIL_PKTS + off1), readl(CLASS_PHY1_L3_FAIL_PKTS + off1), readl(CLASS_PHY1_CHKSUM_ERR_PKTS + off1), readl(CLASS_PHY1_TTL_ERR_PKTS + off1)); return len; } /* qm_read_drop_stat * This function is used to read the drop statistics from the TMU * hw drop counter. Since the hw counter is always cleared afer * reading, this function maintains the previous drop count, and * adds the new value to it. That value can be retrieved by * passing a pointer to it with the total_drops arg. * * @param tmu TMU number (0 - 3) * @param queue queue number (0 - 15) * @param total_drops pointer to location to store total drops (or NULL) * @param do_reset if TRUE, clear total drops after updating */ u32 qm_read_drop_stat(u32 tmu, u32 queue, u32 *total_drops, int do_reset) { static u32 qtotal[TMU_MAX_ID + 1][NUM_QUEUES]; u32 val; writel((tmu << 8) | queue, TMU_TEQ_CTRL); writel((tmu << 8) | queue, TMU_LLM_CTRL); val = readl(TMU_TEQ_DROP_STAT); qtotal[tmu][queue] += val; if (total_drops) *total_drops = qtotal[tmu][queue]; if (do_reset) qtotal[tmu][queue] = 0; return val; } static ssize_t tmu_queue_stats(char *buf, int tmu, int queue) { ssize_t len = 0; u32 drops; len += sprintf(buf + len, "%d-%02d, ", tmu, queue); drops = qm_read_drop_stat(tmu, queue, NULL, 0); /* Select queue */ writel((tmu << 8) | queue, TMU_TEQ_CTRL); writel((tmu << 8) | queue, TMU_LLM_CTRL); len += sprintf(buf + len, "(teq) drop: %10u, tx: %10u (llm) head: %08x, tail: %08x, drop: %10u\n", drops, readl(TMU_TEQ_TRANS_STAT), readl(TMU_LLM_QUE_HEADPTR), readl(TMU_LLM_QUE_TAILPTR), readl(TMU_LLM_QUE_DROPCNT)); return len; } static ssize_t tmu_queues(char *buf, int tmu) { ssize_t len = 0; int queue; for (queue = 0; queue < 16; queue++) len += tmu_queue_stats(buf + len, tmu, queue); return len; } static ssize_t block_version(char *buf, void *addr) { ssize_t len = 0; u32 val; val = readl(addr); len += sprintf(buf + len, "revision: %x, version: %x, id: %x\n", (val >> 24) & 0xff, (val >> 16) & 0xff, val & 0xffff); return len; } static ssize_t bmu(char *buf, int id, void *base) { ssize_t len = 0; len += sprintf(buf + len, "%s: %d\n ", __func__, id); len += block_version(buf + len, base + BMU_VERSION); len += sprintf(buf + len, " buf size: %x\n", (1 << readl(base + BMU_BUF_SIZE))); len += sprintf(buf + len, " buf count: %x\n", readl(base + BMU_BUF_CNT)); len += sprintf(buf + len, " buf rem: %x\n", readl(base + BMU_REM_BUF_CNT)); len += sprintf(buf + len, " buf curr: %x\n", readl(base + BMU_CURR_BUF_CNT)); len += sprintf(buf + len, " free err: %x\n", readl(base + BMU_FREE_ERR_ADDR)); return len; } static ssize_t gpi(char *buf, int id, void *base) { ssize_t len = 0; u32 val; len += sprintf(buf + len, "%s%d:\n ", __func__, id); len += block_version(buf + len, base + GPI_VERSION); len += sprintf(buf + len, " tx under stick: %x\n", readl(base + GPI_FIFO_STATUS)); val = readl(base + GPI_FIFO_DEBUG); len += sprintf(buf + len, " tx pkts: %x\n", (val >> 23) & 0x3f); len += sprintf(buf + len, " rx pkts: %x\n", (val >> 18) & 0x3f); len += sprintf(buf + len, " tx bytes: %x\n", (val >> 9) & 0x1ff); len += sprintf(buf + len, " rx bytes: %x\n", (val >> 0) & 0x1ff); len += sprintf(buf + len, " overrun: %x\n", readl(base + GPI_OVERRUN_DROPCNT)); return len; } static ssize_t pfe_set_class(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { class_do_clear = kstrtoul(buf, 0, 0); return count; } static ssize_t pfe_show_class(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; int id; u32 val; struct pfe_cpumon *cpumon = &pfe->cpumon; len += block_version(buf + len, CLASS_VERSION); for (id = CLASS0_ID; id <= CLASS_MAX_ID; id++) { len += sprintf(buf + len, "%d: ", id - CLASS0_ID); val = readl(CLASS_PE0_DEBUG + id * 4); len += sprintf(buf + len, "pc=1%04x ", val & 0xffff); len += display_pe_status(buf + len, id, CLASS_DM_PESTATUS, class_do_clear); } len += sprintf(buf + len, "aggregate load=%d%%\n\n", cpumon->class_usage_pct); len += sprintf(buf + len, "pe status: 0x%x\n", readl(CLASS_PE_STATUS)); len += sprintf(buf + len, "max buf cnt: 0x%x afull thres: 0x%x\n", readl(CLASS_MAX_BUF_CNT), readl(CLASS_AFULL_THRES)); len += sprintf(buf + len, "tsq max cnt: 0x%x tsq fifo thres: 0x%x\n", readl(CLASS_TSQ_MAX_CNT), readl(CLASS_TSQ_FIFO_THRES)); len += sprintf(buf + len, "state: 0x%x\n", readl(CLASS_STATE)); len += class_phy_stats(buf + len, 0); len += class_phy_stats(buf + len, 1); len += class_phy_stats(buf + len, 2); len += class_phy_stats(buf + len, 3); return len; } static ssize_t pfe_set_tmu(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { tmu_do_clear = kstrtoul(buf, 0, 0); return count; } static ssize_t pfe_show_tmu(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; int id; u32 val; len += block_version(buf + len, TMU_VERSION); for (id = TMU0_ID; id <= TMU_MAX_ID; id++) { if (id == TMU2_ID) continue; len += sprintf(buf + len, "%d: ", id - TMU0_ID); len += display_pe_status(buf + len, id, TMU_DM_PESTATUS, tmu_do_clear); } len += sprintf(buf + len, "pe status: %x\n", readl(TMU_PE_STATUS)); len += sprintf(buf + len, "inq fifo cnt: %x\n", readl(TMU_PHY_INQ_FIFO_CNT)); val = readl(TMU_INQ_STAT); len += sprintf(buf + len, "inq wr ptr: %x\n", val & 0x3ff); len += sprintf(buf + len, "inq rd ptr: %x\n", val >> 10); return len; } static unsigned long drops_do_clear; static u32 class_drop_counter[CLASS_NUM_DROP_COUNTERS]; #if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED) static u32 util_drop_counter[UTIL_NUM_DROP_COUNTERS]; #endif char *class_drop_description[CLASS_NUM_DROP_COUNTERS] = { "ICC", "Host Pkt Error", "Rx Error", "IPsec Outbound", "IPsec Inbound", "EXPT IPsec Error", "Reassembly", "Fragmenter", "NAT-T", "Socket", "Multicast", "NAT-PT", "Tx Disabled", }; #if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED) char *util_drop_description[UTIL_NUM_DROP_COUNTERS] = { "IPsec Outbound", "IPsec Inbound", "IPsec Rate Limiter", "Fragmenter", "Socket", "Tx Disabled", "Rx Error", }; #endif static ssize_t pfe_set_drops(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { drops_do_clear = kstrtoul(buf, 0, 0); return count; } static u32 tmu_drops[4][16]; static ssize_t pfe_show_drops(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; int id, dropnum; int tmu, queue; u32 val; u32 dmem_addr; int num_class_drops = 0, num_tmu_drops = 0, num_util_drops = 0; struct pfe_ctrl *ctrl = &pfe->ctrl; memset(class_drop_counter, 0, sizeof(class_drop_counter)); for (id = CLASS0_ID; id <= CLASS_MAX_ID; id++) { if (drops_do_clear) pe_sync_stop(ctrl, (1 << id)); for (dropnum = 0; dropnum < CLASS_NUM_DROP_COUNTERS; dropnum++) { dmem_addr = CLASS_DM_DROP_CNTR; val = be32_to_cpu(pe_dmem_read(id, dmem_addr, 4)); class_drop_counter[dropnum] += val; num_class_drops += val; if (drops_do_clear) pe_dmem_write(id, 0, dmem_addr, 4); } if (drops_do_clear) pe_start(ctrl, (1 << id)); } #if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED) if (drops_do_clear) pe_sync_stop(ctrl, (1 << UTIL_ID)); for (dropnum = 0; dropnum < UTIL_NUM_DROP_COUNTERS; dropnum++) { dmem_addr = UTIL_DM_DROP_CNTR; val = be32_to_cpu(pe_dmem_read(UTIL_ID, dmem_addr, 4)); util_drop_counter[dropnum] = val; num_util_drops += val; if (drops_do_clear) pe_dmem_write(UTIL_ID, 0, dmem_addr, 4); } if (drops_do_clear) pe_start(ctrl, (1 << UTIL_ID)); #endif for (tmu = 0; tmu < 4; tmu++) { for (queue = 0; queue < 16; queue++) { qm_read_drop_stat(tmu, queue, &tmu_drops[tmu][queue], drops_do_clear); num_tmu_drops += tmu_drops[tmu][queue]; } } if (num_class_drops == 0 && num_util_drops == 0 && num_tmu_drops == 0) len += sprintf(buf + len, "No PE drops\n\n"); if (num_class_drops > 0) { len += sprintf(buf + len, "Class PE drops --\n"); for (dropnum = 0; dropnum < CLASS_NUM_DROP_COUNTERS; dropnum++) { if (class_drop_counter[dropnum] > 0) len += sprintf(buf + len, " %s: %d\n", class_drop_description[dropnum], class_drop_counter[dropnum]); } len += sprintf(buf + len, "\n"); } #if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED) if (num_util_drops > 0) { len += sprintf(buf + len, "Util PE drops --\n"); for (dropnum = 0; dropnum < UTIL_NUM_DROP_COUNTERS; dropnum++) { if (util_drop_counter[dropnum] > 0) len += sprintf(buf + len, " %s: %d\n", util_drop_description[dropnum], util_drop_counter[dropnum]); } len += sprintf(buf + len, "\n"); } #endif if (num_tmu_drops > 0) { len += sprintf(buf + len, "TMU drops --\n"); for (tmu = 0; tmu < 4; tmu++) { for (queue = 0; queue < 16; queue++) { if (tmu_drops[tmu][queue] > 0) len += sprintf(buf + len, " TMU%d-Q%d: %d\n" , tmu, queue, tmu_drops[tmu][queue]); } } len += sprintf(buf + len, "\n"); } return len; } static ssize_t pfe_show_tmu0_queues(struct device *dev, struct device_attribute *attr, char *buf) { return tmu_queues(buf, 0); } static ssize_t pfe_show_tmu1_queues(struct device *dev, struct device_attribute *attr, char *buf) { return tmu_queues(buf, 1); } static ssize_t pfe_show_tmu2_queues(struct device *dev, struct device_attribute *attr, char *buf) { return tmu_queues(buf, 2); } static ssize_t pfe_show_tmu3_queues(struct device *dev, struct device_attribute *attr, char *buf) { return tmu_queues(buf, 3); } #if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED) static ssize_t pfe_set_util(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { util_do_clear = kstrtoul(buf, NULL, 0); return count; } static ssize_t pfe_show_util(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; struct pfe_ctrl *ctrl = &pfe->ctrl; len += block_version(buf + len, UTIL_VERSION); pe_sync_stop(ctrl, (1 << UTIL_ID)); len += display_pe_status(buf + len, UTIL_ID, UTIL_DM_PESTATUS, util_do_clear); pe_start(ctrl, (1 << UTIL_ID)); len += sprintf(buf + len, "pe status: %x\n", readl(UTIL_PE_STATUS)); len += sprintf(buf + len, "max buf cnt: %x\n", readl(UTIL_MAX_BUF_CNT)); len += sprintf(buf + len, "tsq max cnt: %x\n", readl(UTIL_TSQ_MAX_CNT)); return len; } #endif static ssize_t pfe_show_bmu(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; len += bmu(buf + len, 1, BMU1_BASE_ADDR); len += bmu(buf + len, 2, BMU2_BASE_ADDR); return len; } static ssize_t pfe_show_hif(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; len += sprintf(buf + len, "hif:\n "); len += block_version(buf + len, HIF_VERSION); len += sprintf(buf + len, " tx curr bd: %x\n", readl(HIF_TX_CURR_BD_ADDR)); len += sprintf(buf + len, " tx status: %x\n", readl(HIF_TX_STATUS)); len += sprintf(buf + len, " tx dma status: %x\n", readl(HIF_TX_DMA_STATUS)); len += sprintf(buf + len, " rx curr bd: %x\n", readl(HIF_RX_CURR_BD_ADDR)); len += sprintf(buf + len, " rx status: %x\n", readl(HIF_RX_STATUS)); len += sprintf(buf + len, " rx dma status: %x\n", readl(HIF_RX_DMA_STATUS)); len += sprintf(buf + len, "hif nocopy:\n "); len += block_version(buf + len, HIF_NOCPY_VERSION); len += sprintf(buf + len, " tx curr bd: %x\n", readl(HIF_NOCPY_TX_CURR_BD_ADDR)); len += sprintf(buf + len, " tx status: %x\n", readl(HIF_NOCPY_TX_STATUS)); len += sprintf(buf + len, " tx dma status: %x\n", readl(HIF_NOCPY_TX_DMA_STATUS)); len += sprintf(buf + len, " rx curr bd: %x\n", readl(HIF_NOCPY_RX_CURR_BD_ADDR)); len += sprintf(buf + len, " rx status: %x\n", readl(HIF_NOCPY_RX_STATUS)); len += sprintf(buf + len, " rx dma status: %x\n", readl(HIF_NOCPY_RX_DMA_STATUS)); return len; } static ssize_t pfe_show_gpi(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; len += gpi(buf + len, 0, EGPI1_BASE_ADDR); len += gpi(buf + len, 1, EGPI2_BASE_ADDR); len += gpi(buf + len, 3, HGPI_BASE_ADDR); return len; } static ssize_t pfe_show_pfemem(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; struct pfe_memmon *memmon = &pfe->memmon; len += sprintf(buf + len, "Kernel Memory: %d Bytes (%d KB)\n", memmon->kernel_memory_allocated, (memmon->kernel_memory_allocated + 1023) / 1024); return len; } #ifdef HIF_NAPI_STATS static ssize_t pfe_show_hif_napi_stats(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct pfe *pfe = platform_get_drvdata(pdev); ssize_t len = 0; len += sprintf(buf + len, "sched: %u\n", pfe->hif.napi_counters[NAPI_SCHED_COUNT]); len += sprintf(buf + len, "poll: %u\n", pfe->hif.napi_counters[NAPI_POLL_COUNT]); len += sprintf(buf + len, "packet: %u\n", pfe->hif.napi_counters[NAPI_PACKET_COUNT]); len += sprintf(buf + len, "budget: %u\n", pfe->hif.napi_counters[NAPI_FULL_BUDGET_COUNT]); len += sprintf(buf + len, "desc: %u\n", pfe->hif.napi_counters[NAPI_DESC_COUNT]); len += sprintf(buf + len, "full: %u\n", pfe->hif.napi_counters[NAPI_CLIENT_FULL_COUNT]); return len; } static ssize_t pfe_set_hif_napi_stats(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct pfe *pfe = platform_get_drvdata(pdev); memset(pfe->hif.napi_counters, 0, sizeof(pfe->hif.napi_counters)); return count; } static DEVICE_ATTR(hif_napi_stats, 0644, pfe_show_hif_napi_stats, pfe_set_hif_napi_stats); #endif static DEVICE_ATTR(class, 0644, pfe_show_class, pfe_set_class); static DEVICE_ATTR(tmu, 0644, pfe_show_tmu, pfe_set_tmu); #if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED) static DEVICE_ATTR(util, 0644, pfe_show_util, pfe_set_util); #endif static DEVICE_ATTR(bmu, 0444, pfe_show_bmu, NULL); static DEVICE_ATTR(hif, 0444, pfe_show_hif, NULL); static DEVICE_ATTR(gpi, 0444, pfe_show_gpi, NULL); static DEVICE_ATTR(drops, 0644, pfe_show_drops, pfe_set_drops); static DEVICE_ATTR(tmu0_queues, 0444, pfe_show_tmu0_queues, NULL); static DEVICE_ATTR(tmu1_queues, 0444, pfe_show_tmu1_queues, NULL); static DEVICE_ATTR(tmu2_queues, 0444, pfe_show_tmu2_queues, NULL); static DEVICE_ATTR(tmu3_queues, 0444, pfe_show_tmu3_queues, NULL); static DEVICE_ATTR(pfemem, 0444, pfe_show_pfemem, NULL); int pfe_sysfs_init(struct pfe *pfe) { if (device_create_file(pfe->dev, &dev_attr_class)) goto err_class; if (device_create_file(pfe->dev, &dev_attr_tmu)) goto err_tmu; #if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED) if (device_create_file(pfe->dev, &dev_attr_util)) goto err_util; #endif if (device_create_file(pfe->dev, &dev_attr_bmu)) goto err_bmu; if (device_create_file(pfe->dev, &dev_attr_hif)) goto err_hif; if (device_create_file(pfe->dev, &dev_attr_gpi)) goto err_gpi; if (device_create_file(pfe->dev, &dev_attr_drops)) goto err_drops; if (device_create_file(pfe->dev, &dev_attr_tmu0_queues)) goto err_tmu0_queues; if (device_create_file(pfe->dev, &dev_attr_tmu1_queues)) goto err_tmu1_queues; if (device_create_file(pfe->dev, &dev_attr_tmu2_queues)) goto err_tmu2_queues; if (device_create_file(pfe->dev, &dev_attr_tmu3_queues)) goto err_tmu3_queues; if (device_create_file(pfe->dev, &dev_attr_pfemem)) goto err_pfemem; #ifdef HIF_NAPI_STATS if (device_create_file(pfe->dev, &dev_attr_hif_napi_stats)) goto err_hif_napi_stats; #endif return 0; #ifdef HIF_NAPI_STATS err_hif_napi_stats: device_remove_file(pfe->dev, &dev_attr_pfemem); #endif err_pfemem: device_remove_file(pfe->dev, &dev_attr_tmu3_queues); err_tmu3_queues: device_remove_file(pfe->dev, &dev_attr_tmu2_queues); err_tmu2_queues: device_remove_file(pfe->dev, &dev_attr_tmu1_queues); err_tmu1_queues: device_remove_file(pfe->dev, &dev_attr_tmu0_queues); err_tmu0_queues: device_remove_file(pfe->dev, &dev_attr_drops); err_drops: device_remove_file(pfe->dev, &dev_attr_gpi); err_gpi: device_remove_file(pfe->dev, &dev_attr_hif); err_hif: device_remove_file(pfe->dev, &dev_attr_bmu); err_bmu: #if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED) device_remove_file(pfe->dev, &dev_attr_util); err_util: #endif device_remove_file(pfe->dev, &dev_attr_tmu); err_tmu: device_remove_file(pfe->dev, &dev_attr_class); err_class: return -1; } void pfe_sysfs_exit(struct pfe *pfe) { #ifdef HIF_NAPI_STATS device_remove_file(pfe->dev, &dev_attr_hif_napi_stats); #endif device_remove_file(pfe->dev, &dev_attr_pfemem); device_remove_file(pfe->dev, &dev_attr_tmu3_queues); device_remove_file(pfe->dev, &dev_attr_tmu2_queues); device_remove_file(pfe->dev, &dev_attr_tmu1_queues); device_remove_file(pfe->dev, &dev_attr_tmu0_queues); device_remove_file(pfe->dev, &dev_attr_drops); device_remove_file(pfe->dev, &dev_attr_gpi); device_remove_file(pfe->dev, &dev_attr_hif); device_remove_file(pfe->dev, &dev_attr_bmu); #if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED) device_remove_file(pfe->dev, &dev_attr_util); #endif device_remove_file(pfe->dev, &dev_attr_tmu); device_remove_file(pfe->dev, &dev_attr_class); }