diff --git a/root/package/utils/sysupgrade-helper/src/MAKEALL b/root/package/utils/sysupgrade-helper/src/MAKEALL new file mode 100644 index 00000000..2e8b9973 --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/MAKEALL @@ -0,0 +1,790 @@ +#!/bin/bash +# Tool mainly for U-Boot Quality Assurance: build one or more board +# configurations with minimal verbosity, showing only warnings and +# errors. + +usage() +{ + # if exiting with 0, write to stdout, else write to stderr + local ret=${1:-0} + [ "${ret}" -eq 1 ] && exec 1>&2 + cat <<-EOF + Usage: MAKEALL [options] [--] [boards-to-build] + + Options: + -a ARCH, --arch ARCH Build all boards with arch ARCH + -c CPU, --cpu CPU Build all boards with cpu CPU + -v VENDOR, --vendor VENDOR Build all boards with vendor VENDOR + -s SOC, --soc SOC Build all boards with soc SOC + -l, --list List all targets to be built + -m, --maintainers List all targets and maintainer email + -M, --mails List all targets and all affilated emails + -h, --help This help output + + Selections by these options are logically ANDed; if the same option + is used repeatedly, such selections are ORed. So "-v FOO -v BAR" + will select all configurations where the vendor is either FOO or + BAR. Any additional arguments specified on the command line are + always build additionally. See the boards.cfg file for more info. + + If no boards are specified, then the default is "powerpc". + + Environment variables: + BUILD_NCPUS number of parallel make jobs (default: auto) + CROSS_COMPILE cross-compiler toolchain prefix (default: "") + MAKEALL_LOGDIR output all logs to here (default: ./LOG/) + BUILD_DIR output build directory (default: ./) + BUILD_NBUILDS number of parallel targets (default: 1) + + Examples: + - build all Power Architecture boards: + MAKEALL -a powerpc + MAKEALL --arch powerpc + MAKEALL powerpc + - build all PowerPC boards manufactured by vendor "esd": + MAKEALL -a powerpc -v esd + - build all PowerPC boards manufactured either by "keymile" or "siemens": + MAKEALL -a powerpc -v keymile -v siemens + - build all Freescale boards with MPC83xx CPUs, plus all 4xx boards: + MAKEALL -c mpc83xx -v freescale 4xx + EOF + exit ${ret} +} + +SHORT_OPTS="ha:c:v:s:lmM" +LONG_OPTS="help,arch:,cpu:,vendor:,soc:,list,maintainers,mails" + +# Option processing based on util-linux-2.13/getopt-parse.bash + +# Note that we use `"$@"' to let each command-line parameter expand to a +# separate word. The quotes around `$@' are essential! +# We need TEMP as the `eval set --' would nuke the return value of +# getopt. +TEMP=`getopt -o ${SHORT_OPTS} --long ${LONG_OPTS} \ + -n 'MAKEALL' -- "$@"` + +[ $? != 0 ] && usage 1 + +# Note the quotes around `$TEMP': they are essential! +eval set -- "$TEMP" + +SELECTED='' +ONLY_LIST='' +PRINT_MAINTS='' +MAINTAINERS_ONLY='' + +while true ; do + case "$1" in + -a|--arch) + # echo "Option ARCH: argument \`$2'" + if [ "$opt_a" ] ; then + opt_a="${opt_a%)} || \$2 == \"$2\")" + else + opt_a="(\$2 == \"$2\")" + fi + SELECTED='y' + shift 2 ;; + -c|--cpu) + # echo "Option CPU: argument \`$2'" + if [ "$opt_c" ] ; then + opt_c="${opt_c%)} || \$3 == \"$2\")" + else + opt_c="(\$3 == \"$2\")" + fi + SELECTED='y' + shift 2 ;; + -s|--soc) + # echo "Option SoC: argument \`$2'" + if [ "$opt_s" ] ; then + opt_s="${opt_s%)} || \$6 == \"$2\")" + else + opt_s="(\$6 == \"$2\")" + fi + SELECTED='y' + shift 2 ;; + -v|--vendor) + # echo "Option VENDOR: argument \`$2'" + if [ "$opt_v" ] ; then + opt_v="${opt_v%)} || \$5 == \"$2\")" + else + opt_v="(\$5 == \"$2\")" + fi + SELECTED='y' + shift 2 ;; + -l|--list) + ONLY_LIST='y' + shift ;; + -m|--maintainers) + ONLY_LIST='y' + PRINT_MAINTS='y' + MAINTAINERS_ONLY='y' + shift ;; + -M|--mails) + ONLY_LIST='y' + PRINT_MAINTS='y' + shift ;; + -h|--help) + usage ;; + --) + shift ; break ;; + *) + echo "Internal error!" >&2 ; exit 1 ;; + esac +done +# echo "Remaining arguments:" +# for arg do echo '--> '"\`$arg'" ; done + +FILTER="\$1 !~ /^#/" +[ "$opt_a" ] && FILTER="${FILTER} && $opt_a" +[ "$opt_c" ] && FILTER="${FILTER} && $opt_c" +[ "$opt_s" ] && FILTER="${FILTER} && $opt_s" +[ "$opt_v" ] && FILTER="${FILTER} && $opt_v" + +if [ "$SELECTED" ] ; then + SELECTED=$(awk '('"$FILTER"') { print $1 }' boards.cfg) + + # Make sure some boards from boards.cfg are actually found + if [ -z "$SELECTED" ] ; then + echo "Error: No boards selected, invalid arguments" + exit 1 + fi +fi + +######################################################################### + +# Print statistics when we exit +trap exit 1 2 3 15 +trap print_stats 0 + +# Determine number of CPU cores if no default was set +: ${BUILD_NCPUS:="`getconf _NPROCESSORS_ONLN`"} + +if [ "$BUILD_NCPUS" -gt 1 ] +then + JOBS="-j $((BUILD_NCPUS + 1))" +else + JOBS="" +fi + + +if [ "${CROSS_COMPILE}" ] ; then + MAKE="make CROSS_COMPILE=${CROSS_COMPILE}" +else + MAKE=make +fi + +if [ "${MAKEALL_LOGDIR}" ] ; then + LOG_DIR=${MAKEALL_LOGDIR} +else + LOG_DIR="LOG" +fi + +: ${BUILD_NBUILDS:=1} +BUILD_MANY=0 + +if [ "${BUILD_NBUILDS}" -gt 1 ] ; then + BUILD_MANY=1 + : ${BUILD_DIR:=./build} + mkdir -p "${BUILD_DIR}/ERR" + find "${BUILD_DIR}/ERR/" -type f -exec rm -f {} + +fi + +: ${BUILD_DIR:=.} + +OUTPUT_PREFIX="${BUILD_DIR}" + +[ -d ${LOG_DIR} ] || mkdir "${LOG_DIR}" || exit 1 +find "${LOG_DIR}/" -type f -exec rm -f {} + + +LIST="" + +# Keep track of the number of builds and errors +ERR_CNT=0 +ERR_LIST="" +WRN_CNT=0 +WRN_LIST="" +TOTAL_CNT=0 +CURRENT_CNT=0 +OLDEST_IDX=1 +RC=0 + +# Helper funcs for parsing boards.cfg +boards_by_field() +{ + awk \ + -v field="$1" \ + -v select="$2" \ + '($1 !~ /^#/ && $field == select) { print $1 }' \ + boards.cfg +} +boards_by_arch() { boards_by_field 2 "$@" ; } +boards_by_cpu() { boards_by_field 3 "$@" ; } +boards_by_soc() { boards_by_field 6 "$@" ; } + +######################################################################### +## MPC5xx Systems +######################################################################### + +LIST_5xx="$(boards_by_cpu mpc5xx)" + +######################################################################### +## MPC5xxx Systems +######################################################################### + +LIST_5xxx="$(boards_by_cpu mpc5xxx)" + +######################################################################### +## MPC512x Systems +######################################################################### + +LIST_512x="$(boards_by_cpu mpc512x)" + +######################################################################### +## MPC8xx Systems +######################################################################### + +LIST_8xx="$(boards_by_cpu mpc8xx)" + +######################################################################### +## PPC4xx Systems +######################################################################### + +LIST_4xx="$(boards_by_cpu ppc4xx)" + +######################################################################### +## MPC8220 Systems +######################################################################### + +LIST_8220="$(boards_by_cpu mpc8220)" + +######################################################################### +## MPC824x Systems +######################################################################### + +LIST_824x="$(boards_by_cpu mpc824x)" + +######################################################################### +## MPC8260 Systems (includes 8250, 8255 etc.) +######################################################################### + +LIST_8260="$(boards_by_cpu mpc8260)" + +######################################################################### +## MPC83xx Systems (includes 8349, etc.) +######################################################################### + +LIST_83xx="$(boards_by_cpu mpc83xx)" + +######################################################################### +## MPC85xx Systems (includes 8540, 8560 etc.) +######################################################################### + +LIST_85xx="$(boards_by_cpu mpc85xx)" + +######################################################################### +## MPC86xx Systems +######################################################################### + +LIST_86xx="$(boards_by_cpu mpc86xx)" + +######################################################################### +## 74xx/7xx Systems +######################################################################### + +LIST_74xx_7xx="$(boards_by_cpu 74xx_7xx)" + +######################################################################### +## PowerPC groups +######################################################################### + +LIST_TSEC=" \ + ${LIST_83xx} \ + ${LIST_85xx} \ + ${LIST_86xx} \ +" + +LIST_powerpc=" \ + ${LIST_5xx} \ + ${LIST_512x} \ + ${LIST_5xxx} \ + ${LIST_8xx} \ + ${LIST_8220} \ + ${LIST_824x} \ + ${LIST_8260} \ + ${LIST_83xx} \ + ${LIST_85xx} \ + ${LIST_86xx} \ + ${LIST_4xx} \ + ${LIST_74xx_7xx}\ +" + +# Alias "ppc" -> "powerpc" to not break compatibility with older scripts +# still using "ppc" instead of "powerpc" +LIST_ppc=" \ + ${LIST_powerpc} \ +" + +######################################################################### +## StrongARM Systems +######################################################################### + +LIST_SA="$(boards_by_cpu sa1100)" + +######################################################################### +## ARM9 Systems +######################################################################### + +LIST_ARM9="$(boards_by_cpu arm920t) \ + $(boards_by_cpu arm926ejs) \ + $(boards_by_cpu arm925t) \ +" + +######################################################################### +## ARM11 Systems +######################################################################### +LIST_ARM11="$(boards_by_cpu arm1136)" + +######################################################################### +## ARMV7 Systems +######################################################################### + +LIST_ARMV7="$(boards_by_cpu armv7)" + +######################################################################### +## AT91 Systems +######################################################################### + +LIST_at91="$(boards_by_soc at91)" + +######################################################################### +## Xscale Systems +######################################################################### + +LIST_pxa="$(boards_by_cpu pxa)" + +LIST_ixp="$(boards_by_cpu ixp)" + +######################################################################### +## ARM groups +######################################################################### + +LIST_arm=" \ + ${LIST_SA} \ + ${LIST_ARM9} \ + ${LIST_ARM10} \ + ${LIST_ARM11} \ + ${LIST_ARMV7} \ + ${LIST_at91} \ + ${LIST_pxa} \ + ${LIST_ixp} \ +" + +######################################################################### +## MIPS Systems (default = big endian) +######################################################################### + +LIST_mips4kc=" \ + incaip \ + qemu_mips \ + vct_platinum \ + vct_platinum_small \ + vct_platinum_onenand \ + vct_platinum_onenand_small \ + vct_platinumavc \ + vct_platinumavc_small \ + vct_platinumavc_onenand \ + vct_platinumavc_onenand_small \ + vct_premium \ + vct_premium_small \ + vct_premium_onenand \ + vct_premium_onenand_small \ +" + +LIST_au1xx0=" \ + dbau1000 \ + dbau1100 \ + dbau1500 \ + dbau1550 \ + gth2 \ +" + +LIST_mips=" \ + ${LIST_mips4kc} \ + ${LIST_mips5kc} \ + ${LIST_au1xx0} \ +" + +######################################################################### +## MIPS Systems (little endian) +######################################################################### + +LIST_xburst_el=" \ + qi_lb60 \ +" + +LIST_au1xx0_el=" \ + dbau1550_el \ + pb1000 \ +" +LIST_mips_el=" \ + ${LIST_xburst_el} \ + ${LIST_au1xx0_el} \ +" +######################################################################### +## OpenRISC Systems +######################################################################### + +LIST_openrisc="$(boards_by_arch openrisc)" + +######################################################################### +## x86 Systems +######################################################################### + +LIST_x86="$(boards_by_arch x86)" + +######################################################################### +## Nios-II Systems +######################################################################### + +LIST_nios2="$(boards_by_arch nios2)" + +######################################################################### +## MicroBlaze Systems +######################################################################### + +LIST_microblaze="$(boards_by_arch microblaze)" + +######################################################################### +## ColdFire Systems +######################################################################### + +LIST_m68k="$(boards_by_arch m68k) + EB+MCF-EV123 \ + EB+MCF-EV123_internal \ + M52277EVB \ + M5235EVB \ + M54451EVB \ + M54455EVB \ +" +LIST_coldfire=${LIST_m68k} + +######################################################################### +## AVR32 Systems +######################################################################### + +LIST_avr32="$(boards_by_arch avr32)" + +######################################################################### +## Blackfin Systems +######################################################################### + +LIST_blackfin="$(boards_by_arch blackfin)" + +######################################################################### +## SH Systems +######################################################################### + +LIST_sh2="$(boards_by_cpu sh2)" +LIST_sh3="$(boards_by_cpu sh3)" +LIST_sh4="$(boards_by_cpu sh4)" + +LIST_sh="$(boards_by_arch sh)" + +######################################################################### +## SPARC Systems +######################################################################### + +LIST_sparc="$(boards_by_arch sparc)" + +######################################################################### +## NDS32 Systems +######################################################################### + +LIST_nds32="$(boards_by_arch nds32)" + +#----------------------------------------------------------------------- + +get_target_location() { + local target=$1 + local BOARD_NAME="" + local CONFIG_NAME="" + local board="" + local vendor="" + + # Automatic mode + local line=`egrep -i "^[[:space:]]*${target}[[:space:]]" boards.cfg` + + if [ -z "${line}" ] ; then echo "" ; return ; fi + + set ${line} + + # add default board name if needed + [ $# = 3 ] && set ${line} ${1} + + CONFIG_NAME="${1%_config}" + + [ "${BOARD_NAME}" ] || BOARD_NAME="${1%_config}" + + if [ "$4" = "-" ] ; then + board=${BOARD_NAME} + else + board="$4" + fi + + [ $# -gt 4 ] && [ "$5" != "-" ] && vendor="$5" + [ $# -gt 6 ] && [ "$7" != "-" ] && { + tmp="${7%:*}" + if [ "$tmp" ] ; then + CONFIG_NAME="$tmp" + fi + } + + # Assign board directory to BOARDIR variable + if [ -z "${vendor}" ] ; then + BOARDDIR=${board} + else + BOARDDIR=${vendor}/${board} + fi + + echo "${CONFIG_NAME}:${BOARDDIR}" +} + +get_target_maintainers() { + local name=`echo $1 | cut -d : -f 1` + + if ! grep -qsi "[[:blank:]]${name}[[:blank:]]" MAINTAINERS ; then + echo "" + return ; + fi + + local line=`tac MAINTAINERS | grep -ni "[[:blank:]]${name}[[:blank:]]" | cut -d : -f 1` + local mail=`tac MAINTAINERS | tail -n +${line} | \ + sed -n ":start /.*@.*/ { b mail } ; n ; b start ; :mail /.*@.*/ { p ; n ; b mail } ; q" | \ + sed "s/^.*.*$//"` + echo "$mail" +} + +list_target() { + if [ "$PRINT_MAINTS" != 'y' ] ; then + echo "$1" + return + fi + + echo -n "$1:" + + local loc=`get_target_location $1` + + if [ -z "${loc}" ] ; then echo "ERROR" ; return ; fi + + local maintainers_result=`get_target_maintainers ${loc} | tr " " "\n"` + + if [ "$MAINTAINERS_ONLY" != 'y' ] ; then + + local dir=`echo ${loc} | cut -d ":" -f 2` + local cfg=`echo ${loc} | cut -d ":" -f 1` + local git_result=`git log --format=%aE board/${dir} \ + include/configs/${cfg}.h | grep "@"` + local git_result_recent=`echo ${git_result} | tr " " "\n" | \ + head -n 3` + local git_result_top=`echo ${git_result} | tr " " "\n" | \ + sort | uniq -c | sort -nr | head -n 3 | \ + sed "s/^ \+[0-9]\+ \+//"` + + echo -e "$git_result_recent\n$git_result_top\n$maintainers_result" | \ + sort -u | tr "\n" " " | sed "s/ $//" ; + else + echo -e "$maintainers_result" | sort -u | tr "\n" " " | \ + sed "s/ $//" ; + fi + + echo "" +} + +# Each finished build will have a file called ${donep}${n}, +# where n is the index of the build. Each build +# we've already noted as finished will have ${skipp}${n}. +# The code managing the build process will use this information +# to ensure that only BUILD_NBUILDS builds are in flight at once +donep="${LOG_DIR}/._done_" +skipp="${LOG_DIR}/._skip_" + +build_target() { + target=$1 + build_idx=$2 + + if [ "$ONLY_LIST" == 'y' ] ; then + list_target ${target} + return + fi + + if [ $BUILD_MANY == 1 ] ; then + output_dir="${OUTPUT_PREFIX}/${target}" + mkdir -p "${output_dir}" + else + output_dir="${OUTPUT_PREFIX}" + fi + + export BUILD_DIR="${output_dir}" + + ${MAKE} distclean >/dev/null + ${MAKE} -s ${target}_config + + ${MAKE} ${JOBS} all \ + >${LOG_DIR}/$target.MAKELOG 2> ${LOG_DIR}/$target.ERR + + # Check for 'make' errors + if [ ${PIPESTATUS[0]} -ne 0 ] ; then + RC=1 + fi + + if [ $BUILD_MANY == 1 ] ; then + ${MAKE} tidy + + if [ -s ${LOG_DIR}/${target}.ERR ] ; then + cp ${LOG_DIR}/${target}.ERR ${OUTPUT_PREFIX}/ERR/${target} + else + rm ${LOG_DIR}/${target}.ERR + fi + else + if [ -s ${LOG_DIR}/${target}.ERR ] ; then + if grep -iw error ${LOG_DIR}/${target}.ERR ; then + : $(( ERR_CNT += 1 )) + ERR_LIST="${ERR_LIST} $target" + else + : $(( WRN_CNT += 1 )) + WRN_LIST="${WRN_LIST} $target" + fi + else + rm ${LOG_DIR}/${target}.ERR + fi + fi + + OBJS=${output_dir}/u-boot + if [ -e ${output_dir}/spl/u-boot-spl ]; then + OBJS="${OBJS} ${output_dir}/spl/u-boot-spl" + fi + + ${CROSS_COMPILE}size ${OBJS} | tee -a ${LOG_DIR}/$target.MAKELOG + + [ -e "${LOG_DIR}/${target}.ERR" ] && cat "${LOG_DIR}/${target}.ERR" + + touch "${donep}${build_idx}" +} + +manage_builds() { + search_idx=${OLDEST_IDX} + if [ "$ONLY_LIST" == 'y' ] ; then return ; fi + + while true; do + if [ -e "${donep}${search_idx}" ] ; then + : $(( CURRENT_CNT-- )) + [ ${OLDEST_IDX} -eq ${search_idx} ] && + : $(( OLDEST_IDX++ )) + + # Only want to count it once + rm -f "${donep}${search_idx}" + touch "${skipp}${search_idx}" + elif [ -e "${skipp}${search_idx}" ] ; then + [ ${OLDEST_IDX} -eq ${search_idx} ] && + : $(( OLDEST_IDX++ )) + fi + : $(( search_idx++ )) + if [ ${search_idx} -gt ${TOTAL_CNT} ] ; then + if [ ${CURRENT_CNT} -ge ${BUILD_NBUILDS} ] ; then + search_idx=${OLDEST_IDX} + sleep 1 + else + break + fi + fi + done +} + +build_targets() { + for t in "$@" ; do + # If a LIST_xxx var exists, use it. But avoid variable + # expansion in the eval when a board name contains certain + # characters that the shell interprets. + case ${t} in + *[-+=]*) list= ;; + *) list=$(eval echo '${LIST_'$t'}') ;; + esac + if [ -n "${list}" ] ; then + build_targets ${list} + else + : $((TOTAL_CNT += 1)) + : $((CURRENT_CNT += 1)) + rm -f "${donep}${TOTAL_CNT}" + rm -f "${skipp}${TOTAL_CNT}" + if [ $BUILD_MANY == 1 ] ; then + build_target ${t} ${TOTAL_CNT} & + else + build_target ${t} ${TOTAL_CNT} + fi + fi + + # We maintain a running count of all the builds we have done. + # Each finished build will have a file called ${donep}${n}, + # where n is the index of the build. Each build + # we've already noted as finished will have ${skipp}${n}. + # We track the current index via TOTAL_CNT, and the oldest + # index. When we exceed the maximum number of parallel builds, + # We look from oldest to current for builds that have completed, + # and update the current count and oldest index as appropriate. + # If we've gone through the entire list, wait a second, and + # reprocess the entire list until we find a build that has + # completed + if [ ${CURRENT_CNT} -ge ${BUILD_NBUILDS} ] ; then + manage_builds + fi + done +} + +#----------------------------------------------------------------------- + +kill_children() { + kill -- "-$1" + + exit +} + +print_stats() { + if [ "$ONLY_LIST" == 'y' ] ; then return ; fi + + rm -f ${donep}* ${skipp}* + + if [ $BUILD_MANY == 1 ] && [ -e "${OUTPUT_PREFIX}/ERR" ] ; then + ERR_LIST=`grep -iwl error ${OUTPUT_PREFIX}/ERR/*` + ERR_LIST=`for f in $ERR_LIST ; do echo -n " $(basename $f)" ; done` + ERR_CNT=`echo $ERR_LIST | wc -w | awk '{print $1}'` + WRN_LIST=`grep -iwL error ${OUTPUT_PREFIX}/ERR/*` + WRN_LIST=`for f in $WRN_LIST ; do echo -n " $(basename $f)" ; done` + WRN_CNT=`echo $WRN_LIST | wc -w | awk '{print $1}'` + fi + + echo "" + echo "--------------------- SUMMARY ----------------------------" + echo "Boards compiled: ${TOTAL_CNT}" + if [ ${ERR_CNT} -gt 0 ] ; then + echo "Boards with errors: ${ERR_CNT} (${ERR_LIST} )" + fi + if [ ${WRN_CNT} -gt 0 ] ; then + echo "Boards with warnings but no errors: ${WRN_CNT} (${WRN_LIST} )" + fi + echo "----------------------------------------------------------" + + if [ $BUILD_MANY == 1 ] ; then + kill_children $$ & + fi + + exit $RC +} + +#----------------------------------------------------------------------- + +# Build target groups selected by options, plus any command line args +set -- ${SELECTED} "$@" +# run PowerPC by default +[ $# = 0 ] && set -- powerpc +build_targets "$@" +wait diff --git a/root/package/utils/sysupgrade-helper/src/arch/blackfin/cpu/bootrom-asm-offsets.awk b/root/package/utils/sysupgrade-helper/src/arch/blackfin/cpu/bootrom-asm-offsets.awk new file mode 100644 index 00000000..1d618242 --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/arch/blackfin/cpu/bootrom-asm-offsets.awk @@ -0,0 +1,41 @@ +#!/usr/bin/gawk -f +BEGIN { + print "/* DO NOT EDIT: AUTOMATICALLY GENERATED" + print " * Input files: bootrom-asm-offsets.awk bootrom-asm-offsets.c.in" + print " * DO NOT EDIT: AUTOMATICALLY GENERATED" + print " */" + print "" + system("cat bootrom-asm-offsets.c.in") + print "{" +} + +{ + /* find a structure definition */ + if ($0 ~ /typedef struct .* {/) { + delete members; + i = 0; + + /* extract each member of the structure */ + while (1) { + getline + if ($1 == "}") + break; + gsub(/[*;]/, ""); + members[i++] = $NF; + } + + /* grab the structure's name */ + struct = $NF; + sub(/;$/, "", struct); + + /* output the DEFINE() macros */ + while (i-- > 0) + print "\tDEFINE(" struct ", " members[i] ");" + print "" + } +} + +END { + print "\treturn 0;" + print "}" +} diff --git a/root/package/utils/sysupgrade-helper/src/drivers/net/nss/synopGMAC_Dev.c b/root/package/utils/sysupgrade-helper/src/drivers/net/nss/synopGMAC_Dev.c new file mode 100644 index 00000000..121717f9 --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/drivers/net/nss/synopGMAC_Dev.c @@ -0,0 +1,1692 @@ + +/* * Copyright (c) 2012 - 2013 The Linux Foundation. All rights reserved.* */ + +/* \file + * This file defines the synopsys GMAC device dependent functions. + * Most of the operations on the GMAC device are available in this file. + * Functions for initiliasing and accessing MAC/DMA/PHY registers and the DMA descriptors + * are encapsulated in this file. The functions are platform/host/OS independent. + * These functions in turn use the low level device dependent (HAL) functions to + * access the register space. + * \internal + * ------------------------REVISION HISTORY--------------------------------- + * Synopsys 01/Aug/2007 Created + */ +#include "synopGMAC_Dev.h" +#include +#include + +extern uint16_t mii_read_reg(synopGMACdevice *gmacdev, uint32_t phy, uint32_t reg); +/* + * Function to read the Phy register. The access to phy register + * is a slow process as the data is moved accross MDI/MDO interface + * @param[in] pointer to Register Base (It is the mac base in our case) . + * @param[in] PhyBase register is the index of one of supported 32 PHY devices. + * @param[in] Register offset is the index of one of the 32 phy register. + * @param[out] u16 data read from the respective phy register (only valid iff return value is 0). + * \return Returns 0 on success else return the error status. + */ +s32 synopGMAC_read_phy_reg(u32 *RegBase,u32 PhyBase, u32 RegOffset, u16 * data) +{ + u32 addr; + u32 loop_variable; + + addr = ((PhyBase << GmiiDevShift) & GmiiDevMask) | ((RegOffset << GmiiRegShift) & GmiiRegMask); + addr = addr | GmiiBusy ; //Gmii busy bit + synopGMACWriteReg(RegBase,GmacGmiiAddr,addr); //write the address from where the data to be read in GmiiGmiiAddr register of synopGMAC ip + + //Wait till the busy bit gets cleared with in a certain amount of time + for (loop_variable = 0; loop_variable < DEFAULT_LOOP_VARIABLE; loop_variable++) { + if (!(synopGMACReadReg(RegBase,GmacGmiiAddr) & GmiiBusy)){ + break; + } + __udelay(0xFFFFF); + } + if(loop_variable < DEFAULT_LOOP_VARIABLE) + *data = (u16)(synopGMACReadReg(RegBase, GmacGmiiData) & 0xFFFF); + else{ + TR("Error::: PHY not responding Busy bit didnot get cleared !!!!!!\n"); + BUG(); + return -ESYNOPGMACPHYERR; + } + return -ESYNOPGMACNOERR; +} + +/* + * Function to write to the Phy register. The access to phy register + * is a slow process as the data is moved accross MDI/MDO interface + * @param[in] pointer to Register Base (It is the mac base in our case) . + * @param[in] PhyBase register is the index of one of supported 32 PHY devices. + * @param[in] Register offset is the index of one of the 32 phy register. + * @param[in] data to be written to the respective phy register. + * \return Returns 0 on success else return the error status. + */ +s32 synopGMAC_write_phy_reg(u32 *RegBase, u32 PhyBase, u32 RegOffset, u16 data) +{ + u32 addr; + u32 loop_variable; + + synopGMACWriteReg(RegBase,GmacGmiiData,data); // write the data in to GmacGmiiData register of synopGMAC ip + + addr = ((PhyBase << GmiiDevShift) & GmiiDevMask) | ((RegOffset << GmiiRegShift) & GmiiRegMask) | GmiiWrite; + + addr = addr | GmiiBusy ; //set Gmii clk to 20-35 Mhz and Gmii busy bit + + synopGMACWriteReg(RegBase,GmacGmiiAddr,addr); + for (loop_variable = 0; loop_variable < DEFAULT_LOOP_VARIABLE; loop_variable++) { + if (!(synopGMACReadReg(RegBase,GmacGmiiAddr) & GmiiBusy)){ + break; + } + __udelay(DEFAULT_DELAY_VARIABLE); + } + + if (loop_variable < DEFAULT_LOOP_VARIABLE) { + return -ESYNOPGMACNOERR; + } else { + TR("Error::: PHY not responding Busy bit didnot get cleared !!!!!!\n"); + return -ESYNOPGMACPHYERR; + } +} + +/* + * Function to read the GMAC IP Version and populates the same in device data structure. + * @param[in] pointer to synopGMACdevice. + * \return Always return 0. + */ + +s32 synopGMAC_read_version (synopGMACdevice * gmacdev) +{ + u32 data = 0; + data = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacVersion ); + gmacdev->Version = data; + TR("The synopGMAC version: %08x\n",data); + return 0; +} + +/* + * Function to reset the GMAC core. + * This reests the DMA and GMAC core. After reset all the registers holds their respective reset value + * @param[in] pointer to synopGMACdevice. + * \return 0 on success else return the error status. + */ +void synopGMAC_reset (synopGMACdevice * gmacdev ) +{ + u32 data = 0; + + synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaBusMode ,DmaResetOn); + do { + __udelay(DEFAULT_LOOP_VARIABLE); + data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaBusMode); + } while (data & DmaResetOn); + +} + +/* + * Function to program DMA bus mode register. + * + * The Bus Mode register is programmed with the value given. The bits to be set are + * bit wise or'ed and sent as the second argument to this function. + * @param[in] pointer to synopGMACdevice. + * @param[in] the data to be programmed. + * \return 0 on success else return the error status. + */ +s32 synopGMAC_dma_bus_mode_init(synopGMACdevice * gmacdev, u32 init_value ) +{ + synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaBusMode ,init_value); + return 0; +} + +/* + * Function to program DMA Control register. + * + * The Dma Control register is programmed with the value given. The bits to be set are + * bit wise or'ed and sent as the second argument to this function. + * @param[in] pointer to synopGMACdevice. + * @param[in] the data to be programmed. + * \return 0 on success else return the error status. + */ +s32 synopGMAC_dma_control_init(synopGMACdevice * gmacdev, u32 init_value) +{ + synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl, init_value); + return 0; +} + + +/*Gmac configuration functions*/ + +/* + * Enable the watchdog timer on the receiver. + * When enabled, Gmac enables Watchdog timer, and GMAC allows no more than + * 2048 bytes of data (10,240 if Jumbo frame enabled). + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_wd_enable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacWatchdog); +} + +/* + * Enables the Jabber frame support. + * When enabled, GMAC disabled the jabber timer, and can transfer 16,384 byte frames. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_jab_enable(synopGMACdevice * gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacJabber); +} + +/* + * Enables Frame bursting (Only in Half Duplex Mode). + * When enabled, GMAC allows frame bursting in GMII Half Duplex mode. + * Reserved in 10/100 and Full-Duplex configurations. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_frame_burst_enable(synopGMACdevice * gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacFrameBurst); +} + + +/* + * Disable Jumbo frame support. + * When Disabled GMAC does not supports jumbo frames. + * Giant frame error is reported in receive frame status. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_jumbo_frame_disable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacJumboFrame); +} + +/* + * Selects the GMII port. + * When called GMII (1000Mbps) port is selected (programmable only in 10/100/1000 Mbps configuration). + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_select_gmii(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacSelectGmii); +} + +/* + * Selects the MII port. + * When called MII (10/100Mbps) port is selected (programmable only in 10/100/1000 Mbps configuration). + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_select_mii(synopGMACdevice * gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacMiiGmii); + if (gmacdev->Speed == SPEED100) { + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacFESpeed100); + } else { + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacFESpeed100); + } +} + +/* + * Enables Receive Own bit (Only in Half Duplex Mode). + * When enaled GMAC receives all the packets given by phy while transmitting. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_rx_own_enable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRxOwn); +} + +/* + * Disables Receive Own bit (Only in Half Duplex Mode). + * When enaled GMAC disables the reception of frames when gmii_txen_o is asserted. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_rx_own_disable(synopGMACdevice * gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRxOwn); +} + +/* + * Sets the GMAC in Normal mode. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_loopback_off(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacLoopback); +} + +/* + * Sets the GMAC core in Full-Duplex mode. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_set_full_duplex(synopGMACdevice * gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacDuplex); +} + +/* + * Sets the GMAC core in Half-Duplex mode. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_set_half_duplex(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacDuplex); +} + +/* + * GMAC tries retransmission (Only in Half Duplex mode). + * If collision occurs on the GMII/MII, GMAC attempt retries based on the + * back off limit configured. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + * \note This function is tightly coupled with synopGMAC_back_off_limit(synopGMACdevice *, u32). + */ +void synopGMAC_retry_enable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRetry); +} + +/* + * GMAC tries only one transmission (Only in Half Duplex mode). + * If collision occurs on the GMII/MII, GMAC will ignore the current frami + * transmission and report a frame abort with excessive collision in tranmit frame status. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_retry_disable(synopGMACdevice * gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRetry); +} + +/* + * GMAC doesnot strips the Pad/FCS field of incoming frames. + * GMAC will pass all the incoming frames to Host unmodified. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_pad_crc_strip_disable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacPadCrcStrip); +} + +/* + * GMAC programmed with the back off limit value. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + * \note This function is tightly coupled with synopGMAC_retry_enable(synopGMACdevice * gmacdev) + */ +void synopGMAC_back_off_limit(synopGMACdevice * gmacdev, u32 value) +{ + u32 data; + data = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacConfig); + data &= (~GmacBackoffLimit); + data |= value; + synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacConfig,data); +} + +/* + * Disables the Deferral check in GMAC (Only in Half Duplex mode). + * GMAC defers until the CRS signal goes inactive. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_deferral_check_disable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacDeferralCheck); +} + +/* + * Enable the reception of frames on GMII/MII. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_rx_enable(synopGMACdevice * gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRx); +} + +/* + * Disable the reception of frames on GMII/MII. + * GMAC receive state machine is disabled after completion of reception of current frame. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_rx_disable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRx); + +} + +/* + * Enable the transmission of frames on GMII/MII. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_tx_enable(synopGMACdevice * gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacTx); +} + +/* + * Disable the transmission of frames on GMII/MII. + * GMAC transmit state machine is disabled after completion of transmission of current frame. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_tx_disable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacTx); +} + +/*Receive frame filter configuration functions*/ + +/* + * Enables reception of all the frames to application. + * GMAC passes all the frames received to application irrespective of whether they + * pass SA/DA address filtering or not. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_frame_filter_enable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacFilter); +} + +/* + * Disables Source address filtering. + * When disabled GMAC forwards the received frames with updated SAMatch bit in RxStatus. + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_src_addr_filter_disable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacSrcAddrFilter); +} +/* + * Enables the normal Destination address filtering. + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_dst_addr_filter_normal(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacDestAddrFilterNor); +} + +/* + * Enables forwarding of control frames. + * When set forwards all the control frames (incl. unicast and multicast PAUSE frames). + * @param[in] pointer to synopGMACdevice. + * \return void. + * \note Depends on RFE of FlowControlRegister[2] + */ +void synopGMAC_set_pass_control(synopGMACdevice * gmacdev,u32 passcontrol) +{ + u32 data; + data = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacFrameFilter); + data &= (~GmacPassControl); + data |= passcontrol; + synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacFrameFilter,data); +} + +/* + * Enables Broadcast frames. + * When enabled Address filtering module passes all incoming broadcast frames. + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_broadcast_enable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacBroadcast); +} + +/* + * Disable Multicast frames. + * When disabled multicast frame filtering depends on HMC bit. + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_multicast_disable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacMulticastFilter); +} + +/* + * Disables multicast hash filtering. + * When disabled GMAC performs perfect destination address filtering for multicast frames, it compares + * DA field with the value programmed in DA register. + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_multicast_hash_filter_disable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacMcastHashFilter); +} + +/* + * Enables promiscous mode. + * When enabled Address filter modules pass all incoming frames regardless of their Destination + * and source addresses. + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_promisc_enable(synopGMACdevice * gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacPromiscuousMode); +} + +#if 0 +/* + * Enables unicast hash filtering. + * When enabled GMAC performs the destination address filtering of unicast frames according to the hash table. + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_unicast_hash_filter_enable(synopGMACdevice * gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacUcastHashFilter); +} +#endif + +/* + * Disables multicast hash filtering. + * When disabled GMAC performs perfect destination address filtering for unicast frames, it compares + * DA field with the value programmed in DA register. + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_unicast_hash_filter_disable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacUcastHashFilter); +} + +#if 0 + +/*Flow control configuration functions*/ + +/* + * Enables detection of pause frames with stations unicast address. + * When enabled GMAC detects the pause frames with stations unicast address in addition to the + * detection of pause frames with unique multicast address. + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_unicast_pause_frame_detect_enable(synopGMACdevice * gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacUnicastPauseFrame); +} + +#endif + +/* + * Disables detection of pause frames with stations unicast address. + * When disabled GMAC only detects with the unique multicast address (802.3x). + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_unicast_pause_frame_detect_disable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacUnicastPauseFrame); +} + +/* + * Rx flow control enable. + * When Enabled GMAC will decode the rx pause frame and disable the tx for a specified time. + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_rx_flow_control_enable(synopGMACdevice * gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacRxFlowControl); +} + + +/* + * Rx flow control disable. + * When disabled GMAC will not decode pause frame. + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_rx_flow_control_disable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacRxFlowControl); +} + +/* + * Tx flow control enable. + * When Enabled + * - In full duplex GMAC enables flow control operation to transmit pause frames. + * - In Half duplex GMAC enables the back pressure operation + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_tx_flow_control_enable(synopGMACdevice * gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacTxFlowControl); +} + +/* + * Tx flow control disable. + * When Disabled + * - In full duplex GMAC will not transmit any pause frames. + * - In Half duplex GMAC disables the back pressure feature. + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_tx_flow_control_disable(synopGMACdevice * gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacTxFlowControl); +} + +/* + * Initiate Flowcontrol operation. + * When Set + * - In full duplex GMAC initiates pause control frame. + * - In Half duplex GMAC initiates back pressure function. + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_tx_activate_flow_control(synopGMACdevice * gmacdev) +{ + //In case of full duplex check for this bit to b'0. if it is read as b'1 indicates that + //control frame transmission is in progress. + if(gmacdev->Speed == FULLDUPLEX){ + if(!synopGMACCheckBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacFlowControlBackPressure)) + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacFlowControlBackPressure); + } else{ //if half duplex mode + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacFlowControlBackPressure); + } +} + +/* + * stops Flowcontrol operation. + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_tx_deactivate_flow_control(synopGMACdevice * gmacdev) +{ + //In full duplex this bit is automatically cleared after transmitting a pause control frame. + if(gmacdev->Speed == HALFDUPLEX){ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacFlowControlBackPressure); + } +} + +/* + * This enables the pause frame generation after programming the appropriate registers. + * Teh Ubicom design has only 4K FIFO. The activation is set at (full -) 2k and deactivation + * is set at (full -) 3k. These may have to tweaked if found any issues + * @param[in] pointer to synopGMACdevice. + * \return void. + */ +void synopGMAC_pause_control(synopGMACdevice *gmacdev) +{ + u32 omr_reg; + u32 mac_flow_control_reg; + omr_reg = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaControl); + omr_reg |= DmaRxFlowCtrlAct3K | DmaRxFlowCtrlDeact4K |DmaEnHwFlowCtrl; + synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl, omr_reg); + + mac_flow_control_reg = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacFlowControl); + mac_flow_control_reg |= GmacRxFlowControl | GmacTxFlowControl | 0xFFFF0000; + synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacFlowControl, mac_flow_control_reg); +} + +/* + * Example mac initialization sequence. + * This function calls the initialization routines to initialize the GMAC register. + * One can change the functions invoked here to have different configuration as per the requirement + * @param[in] pointer to synopGMACdevice. + * \return Returns 0 on success. + */ +s32 synopGMAC_mac_init(synopGMACdevice * gmacdev) +{ + u32 PHYreg; + + synopGMAC_wd_enable(gmacdev); + synopGMAC_jab_enable(gmacdev); + synopGMAC_frame_burst_enable(gmacdev); + synopGMAC_jumbo_frame_disable(gmacdev); + synopGMAC_loopback_off(gmacdev); + gmacdev->Speed = ipq806x_get_link_speed(gmacdev->phyid); + gmacdev->DuplexMode = ipq806x_get_duplex(gmacdev->phyid); + + if (gmacdev->Speed == SPEED1000) { + synopGMAC_select_gmii(gmacdev); + } else { + synopGMAC_select_mii(gmacdev); + } + + if (gmacdev->DuplexMode == FULLDUPLEX) { + synopGMAC_set_full_duplex(gmacdev); + synopGMAC_rx_own_enable(gmacdev); + synopGMAC_retry_disable(gmacdev); + } else { + synopGMAC_set_half_duplex(gmacdev); + synopGMAC_rx_own_disable(gmacdev); + synopGMAC_retry_enable(gmacdev); + } + + synopGMAC_pad_crc_strip_disable(gmacdev); + synopGMAC_back_off_limit(gmacdev, GmacBackoffLimit0); + synopGMAC_deferral_check_disable(gmacdev); + synopGMAC_tx_enable(gmacdev); + synopGMAC_rx_enable(gmacdev); + + /*Frame Filter Configuration*/ + synopGMAC_frame_filter_enable(gmacdev); + synopGMAC_set_pass_control(gmacdev, GmacPassControl0); + synopGMAC_broadcast_enable(gmacdev); + synopGMAC_src_addr_filter_disable(gmacdev); + synopGMAC_multicast_disable(gmacdev); + synopGMAC_dst_addr_filter_normal(gmacdev); + synopGMAC_multicast_hash_filter_disable(gmacdev); + synopGMAC_promisc_enable(gmacdev); + synopGMAC_unicast_hash_filter_disable(gmacdev); + + /*Flow Control Configuration*/ + synopGMAC_unicast_pause_frame_detect_disable(gmacdev); + if (gmacdev->DuplexMode == FULLDUPLEX) { + synopGMAC_rx_flow_control_disable(gmacdev); + synopGMAC_tx_flow_control_disable(gmacdev); + } else { + synopGMAC_rx_flow_control_disable(gmacdev); + synopGMAC_tx_flow_control_disable(gmacdev); + + /*To set PHY register to enable CRS on Transmit*/ + synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacGmiiAddr, GmiiBusy | 0x00000408); + PHYreg = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacGmiiData); + synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacGmiiData, PHYreg | 0x00000800); + synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacGmiiAddr, GmiiBusy | 0x0000040a); + } + + synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacConfig, \ + GmacFrameBurstEnable | GmacJumboFrameEnable | GmacSelectMii \ + | GmacFullDuplex | GmacTxEnable | GmacRxEnable); + synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacFrameFilter, \ + GmacFilterOff | GmacPromiscuousModeOn); + + return 0; +} + +/* + * Checks and initialze phy. + * This function checks whether the phy initialization is complete. + * @param[in] pointer to synopGMACdevice. + * \return 0 if success else returns the error number. + */ +s32 synopGMAC_check_phy_init (synopGMACdevice * gmacdev) +{ + u16 data; + s32 status = -ESYNOPGMACNOERR; + s32 loop_count; + + loop_count = DEFAULT_LOOP_VARIABLE; + while (loop_count-- > 0) + { + status = synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase, gmacdev->PhyBase, + PHY_STATUS_REG, &data); + if(status) + return status; + + if ((data & Mii_AutoNegCmplt) != 0) { + TR("Autonegotiation Complete\n"); + break; + } + } + + status = synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase, gmacdev->PhyBase, + PHY_SPECIFIC_STATUS_REG, &data); + if(status) + return status; + + if((data & Mii_phy_status_link_up) == 0){ + TR("No Link\n"); + gmacdev->LinkState = LINKDOWN; + return -ESYNOPGMACPHYERR; + } + else{ + gmacdev->LinkState = LINKUP; + TR("Link UP\n"); + } + + status = synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase, gmacdev->PhyBase, + PHY_SPECIFIC_STATUS_REG, &data); + if(status) + return status; + + gmacdev->DuplexMode = (data & Mii_phy_status_full_duplex) ? FULLDUPLEX: HALFDUPLEX ; + TR("Link is up in %s mode\n",(gmacdev->DuplexMode == FULLDUPLEX) ? "FULL DUPLEX": "HALF DUPLEX"); + + /*if not set to Master configuration in case of Half duplex mode set it manually as Master*/ + if(gmacdev->DuplexMode == HALFDUPLEX){ + status = synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase, gmacdev->PhyBase, + PHY_CONTROL_REG, &data); + if(status) + return status; + + status = synopGMAC_write_phy_reg((u32 *)gmacdev->MacBase, gmacdev->PhyBase, + PHY_CONTROL_REG, data | Mii_Manual_Master_Config ); + if(status) + return status; + } + + status = synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase,gmacdev->PhyBase,PHY_SPECIFIC_STATUS_REG, &data); + if(status) + return status; + if (data & Mii_phy_status_speed_1000) + gmacdev->Speed = SPEED1000; + else if(data & Mii_phy_status_speed_100) + gmacdev->Speed = SPEED100; + else + gmacdev->Speed = SPEED10; + + if (gmacdev->Speed == SPEED1000) + TR("Link is with 1000M Speed \n"); + if (gmacdev->Speed == SPEED100) + TR("Link is with 100M Speed \n"); + if (gmacdev->Speed == SPEED10) + TR("Link is with 10M Speed \n"); + + return -ESYNOPGMACNOERR; +} + +s32 synopGMAC_check_link(synopGMACdevice *gmacdev) +{ + uint16_t lnkstat ; + + lnkstat = mii_read_reg(gmacdev, gmacdev->PhyBase, MII_BMSR); + + if (lnkstat & 0x4) + { + printf("\r\n LINKUP LINKstat %x ***********\r\n ", lnkstat); + return LINKUP; + } + else + { + printf("\r\n**LINKDOWN** LINKstat %x *********\r\n ", lnkstat); + return LINKDOWN; + } +} + +/* + * Sets the Mac address in to GMAC register. + * This function sets the MAC address to the MAC register in question. + * @param[in] pointer to synopGMACdevice to populate mac dma and phy addresses. + * @param[in] Register offset for Mac address high + * @param[in] Register offset for Mac address low + * @param[in] buffer containing mac address to be programmed. + * \return 0 upon success. Error code upon failure. + */ +s32 synopGMAC_set_mac_addr(synopGMACdevice *gmacdev, u32 MacHigh, u32 MacLow, u8 *MacAddr) +{ + u32 data; + + data = (MacAddr[5] << 8) | MacAddr[4]; + synopGMACWriteReg((u32 *)gmacdev->MacBase,MacHigh,data); + data = (MacAddr[3] << 24) | (MacAddr[2] << 16) | (MacAddr[1] << 8) | MacAddr[0] ; + synopGMACWriteReg((u32 *)gmacdev->MacBase, MacLow, data); + return 0; +} + +/* + * Get the Mac address in to the address specified. + * The mac register contents are read and written to buffer passed. + * @param[in] pointer to synopGMACdevice to populate mac dma and phy addresses. + * @param[in] Register offset for Mac address high + * @param[in] Register offset for Mac address low + * @param[out] buffer containing the device mac address. + * \return 0 upon success. Error code upon failure. + */ +s32 synopGMAC_get_mac_addr(synopGMACdevice *gmacdev, u32 MacHigh, u32 MacLow, u8 *MacAddr) +{ + u32 data; + + data = synopGMACReadReg((u32 *)gmacdev->MacBase, MacHigh); + MacAddr[5] = (data >> 8) & 0xff; + MacAddr[4] = (data) & 0xff; + + data = synopGMACReadReg((u32 *)gmacdev->MacBase, MacLow); + MacAddr[3] = (data >> 24) & 0xff; + MacAddr[2] = (data >> 16) & 0xff; + MacAddr[1] = (data >> 8 ) & 0xff; + MacAddr[0] = (data ) & 0xff; + + return 0; +} + +/* + * Attaches the synopGMAC device structure to the hardware. + * Device structure is populated with MAC/DMA and PHY base addresses. + * @param[in] pointer to synopGMACdevice to populate mac dma and phy addresses. + * @param[in] GMAC IP mac base address. + * @param[in] GMAC IP dma base address. + * @param[in] GMAC IP phy base address. + * \return 0 upon success. Error code upon failure. + * \note This is important function. No kernel api provided by Synopsys + */ + +s32 synopGMAC_attach (synopGMACdevice * gmacdev, u32 regBase) +{ + /*Make sure the Device data strucure is cleared before we proceed further*/ + memset((void *)gmacdev, 0, sizeof(synopGMACdevice)); + /*Populate the mac and dma base addresses*/ + gmacdev->NbrBase = regBase; + + gmacdev->MacBase = regBase + MACBASE; + gmacdev->DmaBase = regBase + DMABASE; + + if (gboard_param->machid == MACH_TYPE_IPQ806X_RUMI3) + gmacdev->PhyBase = GMAC0_MDIO_ID; + + return 0; +} + + +s32 synopGMAC_init_tx_rx_desc_queue(synopGMACdevice *gmacdev) +{ + s32 i; + for (i =0; i < gmacdev -> TxDescCount; i++) { + synopGMAC_tx_desc_init_ring(gmacdev->TxDesc + i, i == gmacdev->TxDescCount-1); + } + + for (i =0; i < gmacdev -> RxDescCount; i++) { + synopGMAC_rx_desc_init_ring(gmacdev->RxDesc + i, i == gmacdev->RxDescCount-1); + } + + gmacdev->TxNext = 0; + gmacdev->TxBusy = 0; + gmacdev->RxNext = 0; + gmacdev->RxBusy = 0; + + return -ESYNOPGMACNOERR; +} + +/* + * Programs the DmaRxBaseAddress with the Rx descriptor base address. + * Rx Descriptor's base address is available in the gmacdev structure. This function progrms the + * Dma Rx Base address with the starting address of the descriptor ring or chain. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_init_rx_desc_base(synopGMACdevice *gmacdev) +{ + synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaRxBaseAddr, (u32)gmacdev->RxDescDma); +} + +/* + * Programs the DmaTxBaseAddress with the Tx descriptor base address. + * Tx Descriptor's base address is available in the gmacdev structure. This function progrms the + * Dma Tx Base address with the starting address of the descriptor ring or chain. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_init_tx_desc_base(synopGMACdevice *gmacdev) +{ + synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaTxBaseAddr, (u32)gmacdev->TxDescDma); +} + +/* + * Makes the Dma as owner for this descriptor. + * This function sets the own bit of status field of the DMA descriptor, + * indicating the DMA is the owner for this descriptor. + * @param[in] pointer to DmaDesc structure. + * \return returns void. + */ +void synopGMAC_set_owner_dma(DmaDesc *desc) +{ + desc->status |= DescOwnByDma; +} + +/* + * set tx descriptor to indicate SOF. + * This Descriptor contains the start of ethernet frame. + * @param[in] pointer to DmaDesc structure. + * \return returns void. + */ +void synopGMAC_set_desc_sof(DmaDesc *desc) +{ + #ifdef ENH_DESC + desc->status |= DescTxFirst;//ENH_DESC + #else + desc->length |= DescTxFirst; + #endif +} + +/* + * set tx descriptor to indicate EOF. + * This descriptor contains the End of ethernet frame. + * @param[in] pointer to DmaDesc structure. + * \return returns void. + */ +void synopGMAC_set_desc_eof(DmaDesc *desc) +{ + #ifdef ENH_DESC + desc->status |= DescTxLast;//ENH_DESC + #else + desc->length |= DescTxLast; + #endif +} + +/* + * checks whether this descriptor contains start of frame. + * This function is to check whether the descriptor's data buffer + * contains a fresh ethernet frame? + * @param[in] pointer to DmaDesc structure. + * \return returns true if SOF in current descriptor, else returns fail. + */ +bool synopGMAC_is_sof_in_rx_desc(DmaDesc *desc) +{ + return ((desc->status & DescRxFirst) == DescRxFirst); +} + +/* + * checks whether this descriptor contains end of frame. + * This function is to check whether the descriptor's data buffer + * contains end of ethernet frame? + * @param[in] pointer to DmaDesc structure. + * \return returns true if SOF in current descriptor, else returns fail. + */ +bool synopGMAC_is_eof_in_rx_desc(DmaDesc *desc) +{ + return ((desc->status & DescRxLast) == DescRxLast); +} + +/* + * checks whether destination address filter failed in the rx frame. + * @param[in] pointer to DmaDesc structure. + * \return returns true if Failed, false if not. + */ +bool synopGMAC_is_da_filter_failed(DmaDesc *desc) +{ + return ((desc->status & DescDAFilterFail) == DescDAFilterFail); +} + +/* + * checks whether source address filter failed in the rx frame. + * @param[in] pointer to DmaDesc structure. + * \return returns true if Failed, false if not. + */ +bool synopGMAC_is_sa_filter_failed(DmaDesc *desc) +{ + return ((desc->status & DescSAFilterFail) == DescSAFilterFail); +} + +/* + * Checks whether the tx is aborted due to collisions. + * @param[in] pointer to DmaDesc structure. + * \return returns true if collisions, else returns false. + */ +bool synopGMAC_is_tx_aborted(u32 status) +{ + return (((status & DescTxLateCollision) == DescTxLateCollision) | ((status & DescTxExcCollisions) == DescTxExcCollisions)); + +} + +/* + * Checks whether the tx carrier error. + * @param[in] pointer to DmaDesc structure. + * \return returns true if carrier error occured, else returns falser. + */ +bool synopGMAC_is_tx_carrier_error(u32 status) +{ + return (((status & DescTxLostCarrier) == DescTxLostCarrier) | ((status & DescTxNoCarrier) == DescTxNoCarrier)); +} + +/* + * Check for damaged frame due to overflow or collision. + * Retruns true if rx frame was damaged due to buffer overflow in MTL or late collision in half duplex mode. + * @param[in] pointer to DmaDesc structure. + * \return returns true if error else returns false. + */ +bool synopGMAC_is_rx_frame_damaged(u32 status) +{ +//bool synopGMAC_dma_rx_collisions(u32 status) + return (((status & DescRxDamaged) == DescRxDamaged) | ((status & DescRxCollision) == DescRxCollision)); +} + +/* + * Check for damaged frame due to collision. + * Retruns true if rx frame was damaged due to late collision in half duplex mode. + * @param[in] pointer to DmaDesc structure. + * \return returns true if error else returns false. + */ +bool synopGMAC_is_rx_frame_collision(u32 status) +{ +//bool synopGMAC_dma_rx_collisions(u32 status) + return ((status & DescRxCollision) == DescRxCollision); +} + +/* + * Check for receive CRC error. + * Retruns true if rx frame CRC error occured. + * @param[in] pointer to DmaDesc structure. + * \return returns true if error else returns false. + */ +bool synopGMAC_is_rx_crc(u32 status) +{ +//u32 synopGMAC_dma_rx_crc(u32 status) + return ((status & DescRxCrc) == DescRxCrc); +} + +/* + * Indicates rx frame has non integer multiple of bytes. (odd nibbles). + * Retruns true if dribbling error in rx frame. + * @param[in] pointer to DmaDesc structure. + * \return returns true if error else returns false. + */ +bool synopGMAC_is_frame_dribbling_errors(u32 status) +{ + return ((status & DescRxDribbling) == DescRxDribbling); +} + +/* + * Indicates error in rx frame length. + * Retruns true if received frame length doesnot match with the length field + * @param[in] pointer to DmaDesc structure. + * \return returns true if error else returns false. + */ +bool synopGMAC_is_rx_frame_length_errors(u32 status) +{ + return((status & DescRxLengthError) == DescRxLengthError); +} + +/* + * Driver Api to get the descriptor field information. + * This returns the status, dma-able address of buffer1, the length of buffer1, virtual address of buffer1 + * dma-able address of buffer2, length of buffer2, virtural adddress of buffer2. + * @param[in] pointer to DmaDesc structure. + * @param[out] pointer to status field fo descriptor. + * @param[out] dma-able address of buffer1. + * @param[out] length of buffer1. + * @param[out] virtual address of buffer1. + * @param[out] dma-able address of buffer2. + * @param[out] length of buffer2. + * @param[out] virtual address of buffer2. + * \return returns void. + */ +void synopGMAC_get_desc_data(DmaDesc * desc, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1) +{ + + /* + * The first time, we map the descriptor as DMA_TO_DEVICE. + * Then we only wait for changes from device, so we use DMA_FROM_DEVICE. + */ + + if (Status != 0) + *Status = desc->status; + + if (Buffer1 != 0) + *Buffer1 = desc->buffer1; + if (Length1 != 0) + *Length1 = (desc->length & DescSize1Mask) >> DescSize1Shift; + if (Data1 != 0) + *Data1 = desc->data1; +} + +/* + * Enable the DMA Reception. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_enable_dma_rx(synopGMACdevice * gmacdev) +{ + u32 data; + data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaControl); + data |= DmaRxStart; + synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl ,data); +} + +/* + * Enable the DMA Transmission. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_enable_dma_tx(synopGMACdevice * gmacdev) +{ + u32 data; + data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaControl); + data |= DmaTxStart; + synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl ,data); +} + +/* + * Take ownership of this Descriptor. + * The function is same for both the ring mode and the chain mode DMA structures. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_take_desc_ownership(DmaDesc * desc) +{ + if (desc) { + desc->status &= ~DescOwnByDma; //Clear the DMA own bit + } +} + +/* + * Take ownership of all the rx Descriptors. + * This function is called when there is fatal error in DMA transmission. + * When called it takes the ownership of all the rx descriptor in rx descriptor pool/queue from DMA. + * The function is same for both the ring mode and the chain mode DMA structures. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + * \note Make sure to disable the transmission before calling this function, otherwise may result in racing situation. + */ +void synopGMAC_take_desc_ownership_rx(synopGMACdevice * gmacdev) +{ + s32 i; + DmaDesc *desc; + desc = gmacdev->RxDesc; + for (i = 0; i < gmacdev->RxDescCount; i++) { + synopGMAC_take_desc_ownership(desc + i); + } +} + +/* + * Take ownership of all the rx Descriptors. + * This function is called when there is fatal error in DMA transmission. + * When called it takes the ownership of all the tx descriptor in tx descriptor pool/queue from DMA. + * The function is same for both the ring mode and the chain mode DMA structures. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + * \note Make sure to disable the transmission before calling this function, otherwise may result in racing situation. + */ +void synopGMAC_take_desc_ownership_tx(synopGMACdevice * gmacdev) +{ + s32 i; + DmaDesc *desc; + desc = gmacdev->TxDesc; + for (i = 0; i < gmacdev->TxDescCount; i++) { + synopGMAC_take_desc_ownership(desc + i); + } +} + + +/* + * Enables the ip checksum offloading in receive path. + * When set GMAC calculates 16 bit 1's complement of all received ethernet frame payload. + * It also checks IPv4 Header checksum is correct. GMAC core appends the 16 bit checksum calculated + * for payload of IP datagram and appends it to Ethernet frame transferred to the application. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_enable_rx_chksum_offload(synopGMACdevice *gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRxIpcOffload); +} + + +/* + * Disable the DMA for Transmission. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ + +void synopGMAC_disable_dma_tx(synopGMACdevice * gmacdev) +{ + u32 data; + + data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaControl); + data &= (~DmaTxStart); + synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl ,data); +} + +/* + * Disable the DMA for Reception. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_disable_dma_rx(synopGMACdevice * gmacdev) +{ + u32 data; + + data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaControl); + data &= (~DmaRxStart); + synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl ,data); +} + +/* + * Checks whether the packet received is a magic packet?. + * @param[in] pointer to synopGMACdevice. + * \return returns True if magic packet received else returns false. + */ +bool synopGMAC_is_magic_packet_received(synopGMACdevice *gmacdev) +{ + u32 data; + data = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacPmtCtrlStatus); + return ((data & GmacPmtMagicPktReceived) == GmacPmtMagicPktReceived); +} + +/* + * Checks whether the packet received is a wakeup frame?. + * @param[in] pointer to synopGMACdevice. + * \return returns true if wakeup frame received else returns false. + */ +bool synopGMAC_is_wakeup_frame_received(synopGMACdevice *gmacdev) +{ + u32 data; + data = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacPmtCtrlStatus); + return ((data & GmacPmtWakeupFrameReceived) == GmacPmtWakeupFrameReceived); +} + +/* + * Disables the assertion of PMT interrupt. + * This disables the assertion of PMT interrupt due to Magic Pkt or Wakeup frame + * reception. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_pmt_int_disable(synopGMACdevice *gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacInterruptMask, GmacPmtIntMask); +} + +/* + * Instruct the DMA to drop the packets fails tcp ip checksum. + * This is to instruct the receive DMA engine to drop the recevied packet if they + * fails the tcp/ip checksum in hardware. Valid only when full checksum offloading is enabled(type-2). + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_rx_tcpip_chksum_drop_enable(synopGMACdevice *gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaControl, DmaDisableDropTcpCs); +} + + +/* + * Disable the MMC Rx interrupt. + * The MMC rx interrupts are masked out as per the mask specified. + * @param[in] pointer to synopGMACdevice. + * @param[in] rx interrupt bit mask for which interrupts needs to be disabled. + * \return returns void. + */ +void synopGMAC_disable_mmc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacMmcIntrMaskRx, mask); +} + +/* + * Disable the MMC ipc rx checksum offload interrupt. + * The MMC ipc rx checksum offload interrupts are masked out as per the mask specified. + * @param[in] pointer to synopGMACdevice. + * @param[in] rx interrupt bit mask for which interrupts needs to be disabled. + * \return returns void. + */ +void synopGMAC_disable_mmc_ipc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacMmcRxIpcIntrMask, mask); +} + + +/* + * Disable the MMC Tx interrupt. + * The MMC tx interrupts are masked out as per the mask specified. + * @param[in] pointer to synopGMACdevice. + * @param[in] tx interrupt bit mask for which interrupts needs to be disabled. + * \return returns void. + */ +void synopGMAC_disable_mmc_tx_interrupt(synopGMACdevice *gmacdev, u32 mask) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacMmcIntrMaskTx, mask); +} + + + + +#if 0 + +/*******************PMT APIs***************************************/ + +/* + * Enables the assertion of PMT interrupt. + * This enables the assertion of PMT interrupt due to Magic Pkt or Wakeup frame + * reception. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_pmt_int_enable(synopGMACdevice *gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacInterruptMask, GmacPmtIntMask); +} + +/* + * Disables the assertion of PMT interrupt. + * This disables the assertion of PMT interrupt due to Magic Pkt or Wakeup frame + * reception. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_pmt_int_disable(synopGMACdevice *gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacInterruptMask, GmacPmtIntMask); +} + +/* + * Enables the power down mode of GMAC. + * This function puts the Gmac in power down mode. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_power_down_enable(synopGMACdevice *gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacPmtCtrlStatus, GmacPmtPowerDown); +} + +/* + * Disables the powerd down setting of GMAC. + * If the driver wants to bring up the GMAC from powerdown mode, even though the magic packet or the + * wake up frames received from the network, this function should be called. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_power_down_disable(synopGMACdevice *gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacPmtCtrlStatus, GmacPmtPowerDown); +} + +/* + * Enables GMAC to look for Magic packet. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_magic_packet_enable(synopGMACdevice *gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacPmtCtrlStatus, GmacPmtMagicPktEnable); +} + +/* + * Enables GMAC to look for wake up frame. + * Wake up frame is defined by the user. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_wakeup_frame_enable(synopGMACdevice *gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacPmtCtrlStatus, GmacPmtWakeupFrameEnable); +} + +/* + * Enables wake-up frame filter to handle unicast packets. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_pmt_unicast_enable(synopGMACdevice *gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus,GmacPmtGlobalUnicast); +} + +/* + * Checks whether the packet received is a magic packet?. + * @param[in] pointer to synopGMACdevice. + * \return returns True if magic packet received else returns false. + */ +bool synopGMAC_is_magic_packet_received(synopGMACdevice *gmacdev) +{ + u32 data; + data = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacPmtCtrlStatus); + return ((data & GmacPmtMagicPktReceived) == GmacPmtMagicPktReceived); +} + +/* + * Checks whether the packet received is a wakeup frame?. + * @param[in] pointer to synopGMACdevice. + * \return returns true if wakeup frame received else returns false. + */ +bool synopGMAC_is_wakeup_frame_received(synopGMACdevice *gmacdev) +{ + u32 data; + data = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacPmtCtrlStatus); + return ((data & GmacPmtWakeupFrameReceived) == GmacPmtWakeupFrameReceived); +} + +/* + * Populates the remote wakeup frame registers. + * Consecutive 8 writes to GmacWakeupAddr writes the wakeup frame filter registers. + * Before commensing a new write, frame filter pointer is reset to 0x0000. + * A small delay is introduced to allow frame filter pointer reset operation. + * @param[in] pointer to synopGMACdevice. + * @param[in] pointer to frame filter contents array. + * \return returns void. + */ +void synopGMAC_write_wakeup_frame_register(synopGMACdevice *gmacdev, u32 * filter_contents) +{ + s32 i; + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacPmtCtrlStatus, GmacPmtFrmFilterPtrReset); + __udelay(10); + for (i = 0; i < WAKEUP_REG_LENGTH; i++) + synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacWakeupAddr, *(filter_contents + i)); +} + +/*******************PMT APIs***************************************/ + +/*******************MMC APIs***************************************/ + +/* + * Freezes the MMC counters. + * This function call freezes the MMC counters. None of the MMC counters are updated + * due to any tx or rx frames until synopGMAC_mmc_counters_resume is called. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_mmc_counters_stop(synopGMACdevice *gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacMmcCntrl, GmacMmcCounterFreeze); +} + +/* + * Resumes the MMC counter updation. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_mmc_counters_resume(synopGMACdevice *gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacMmcCntrl, GmacMmcCounterFreeze); +} + +/* + * Configures the MMC in Self clearing mode. + * Programs MMC interface so that counters are cleared when the counters are read. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_mmc_counters_set_selfclear(synopGMACdevice *gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacMmcCntrl, GmacMmcCounterResetOnRead); +} + +/* + * Configures the MMC in non-Self clearing mode. + * Programs MMC interface so that counters are cleared when the counters are read. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_mmc_counters_reset_selfclear(synopGMACdevice *gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacMmcCntrl, GmacMmcCounterResetOnRead); +} + +/* + * Configures the MMC to stop rollover. + * Programs MMC interface so that counters will not rollover after reaching maximum value. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_mmc_counters_disable_rollover(synopGMACdevice *gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacMmcCntrl, GmacMmcCounterStopRollover); +} + +/* + * Configures the MMC to rollover. + * Programs MMC interface so that counters will rollover after reaching maximum value. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_mmc_counters_enable_rollover(synopGMACdevice *gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacMmcCntrl, GmacMmcCounterStopRollover); +} + +/* + * Read the MMC Counter. + * @param[in] pointer to synopGMACdevice. + * @param[in] the counter to be read. + * \return returns the read count value. + */ +u32 synopGMAC_read_mmc_counter(synopGMACdevice *gmacdev, u32 counter) +{ + return( synopGMACReadReg((u32 *)gmacdev->MacBase, counter)); +} + +/* + * Read the MMC Rx interrupt status. + * @param[in] pointer to synopGMACdevice. + * \return returns the Rx interrupt status. + */ +u32 synopGMAC_read_mmc_rx_int_status(synopGMACdevice *gmacdev) +{ + return( synopGMACReadReg((u32 *)gmacdev->MacBase, GmacMmcIntrRx)); +} + +/* + * Read the MMC Tx interrupt status. + * @param[in] pointer to synopGMACdevice. + * \return returns the Tx interrupt status. + */ +u32 synopGMAC_read_mmc_tx_int_status(synopGMACdevice *gmacdev) +{ + return( synopGMACReadReg((u32 *)gmacdev->MacBase, GmacMmcIntrTx)); +} + +/* + * Disable the MMC Tx interrupt. + * The MMC tx interrupts are masked out as per the mask specified. + * @param[in] pointer to synopGMACdevice. + * @param[in] tx interrupt bit mask for which interrupts needs to be disabled. + * \return returns void. + */ +void synopGMAC_disable_mmc_tx_interrupt(synopGMACdevice *gmacdev, u32 mask) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacMmcIntrMaskTx, mask); +} + +/* + * Enable the MMC Tx interrupt. + * The MMC tx interrupts are enabled as per the mask specified. + * @param[in] pointer to synopGMACdevice. + * @param[in] tx interrupt bit mask for which interrupts needs to be enabled. + * \return returns void. + */ +void synopGMAC_enable_mmc_tx_interrupt(synopGMACdevice *gmacdev, u32 mask) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacMmcIntrMaskTx, mask); +} + +/* + * Disable the MMC Rx interrupt. + * The MMC rx interrupts are masked out as per the mask specified. + * @param[in] pointer to synopGMACdevice. + * @param[in] rx interrupt bit mask for which interrupts needs to be disabled. + * \return returns void. + */ +void synopGMAC_disable_mmc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacMmcIntrMaskRx, mask); +} + +/* + * Enable the MMC Rx interrupt. + * The MMC rx interrupts are enabled as per the mask specified. + * @param[in] pointer to synopGMACdevice. + * @param[in] rx interrupt bit mask for which interrupts needs to be enabled. + * \return returns void. + */ +void synopGMAC_enable_mmc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacMmcIntrMaskRx, mask); +} + +/* + * Disable the MMC ipc rx checksum offload interrupt. + * The MMC ipc rx checksum offload interrupts are masked out as per the mask specified. + * @param[in] pointer to synopGMACdevice. + * @param[in] rx interrupt bit mask for which interrupts needs to be disabled. + * \return returns void. + */ +void synopGMAC_disable_mmc_ipc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacMmcRxIpcIntrMask, mask); +} + +/* + * Enable the MMC ipc rx checksum offload interrupt. + * The MMC ipc rx checksum offload interrupts are enabled as per the mask specified. + * @param[in] pointer to synopGMACdevice. + * @param[in] rx interrupt bit mask for which interrupts needs to be enabled. + * \return returns void. + */ +void synopGMAC_enable_mmc_ipc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacMmcRxIpcIntrMask, mask); +} + +/*******************MMC APIs***************************************/ + +/*******************Ip checksum offloading APIs***************************************/ + +/* + * Enables the ip checksum offloading in receive path. + * When set GMAC calculates 16 bit 1's complement of all received ethernet frame payload. + * It also checks IPv4 Header checksum is correct. GMAC core appends the 16 bit checksum calculated + * for payload of IP datagram and appends it to Ethernet frame transferred to the application. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_enable_rx_chksum_offload(synopGMACdevice *gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRxIpcOffload); +} + +/* + * Disable the ip checksum offloading in receive path. + * Ip checksum offloading is disabled in the receive path. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_disable_rx_Ipchecksum_offload(synopGMACdevice *gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRxIpcOffload); +} + +/* + * Instruct the DMA to drop the packets fails tcp ip checksum. + * This is to instruct the receive DMA engine to drop the recevied packet if they + * fails the tcp/ip checksum in hardware. Valid only when full checksum offloading is enabled(type-2). + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_rx_tcpip_chksum_drop_enable(synopGMACdevice *gmacdev) +{ + synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaControl, DmaDisableDropTcpCs); +} + +/* + * Instruct the DMA not to drop the packets even if it fails tcp ip checksum. + * This is to instruct the receive DMA engine to allow the packets even if recevied packet + * fails the tcp/ip checksum in hardware. Valid only when full checksum offloading is enabled(type-2). + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +void synopGMAC_rx_tcpip_chksum_drop_disable(synopGMACdevice *gmacdev) +{ + synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaControl, DmaDisableDropTcpCs); +} + +#endif diff --git a/root/package/utils/sysupgrade-helper/src/drivers/net/nss/synopGMAC_Dev.h b/root/package/utils/sysupgrade-helper/src/drivers/net/nss/synopGMAC_Dev.h new file mode 100644 index 00000000..7bee279b --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/drivers/net/nss/synopGMAC_Dev.h @@ -0,0 +1,2240 @@ +/* * Copyright (c) 2012 The Linux Foundation. All rights reserved.* */ + +/*\file + * This file defines the function prototypes for the Synopsys GMAC device and the + * Marvell 88E1011/88E1011S integrated 10/100/1000 Gigabit Ethernet Transceiver. + * Since the phy register mapping are standardised, the phy register map and the + * bit definitions remain the same for other phy as well. + * This also defines some of the Ethernet related parmeters. + * \internal + * -----------------------------REVISION HISTORY------------------------------------ + * Synopsys 01/Aug/2007 Created + */ + + +#ifndef SYNOP_GMAC_DEV_H +#define SYNOP_GMAC_DEV_H 1 + +#include "synopGMAC_plat.h" + +#define GMAC_POLL_BUDGET 64 +#include "../../../board/qcom/ipq806x_cdp/ipq806x_cdp.h" +/* + * SynopGMAC can support up to 32 phys + */ +enum GMACPhyBase +{ + PHY0 = 0, // The device can support 32 phys, but we use first phy only + PHY1 = 1, + PHY31 = 31, +}; +/* +#define NSS_GMAC0_MDIO_ID 4 +#define NSS_GMAC1_MDIO_ID 6 +*/ +#define DEFAULT_PHY_BASE PHY0 // We use First Phy +#define MACBASE 0x0000 // The Mac Base address offset is 0x0000 +#define DMABASE 0x1000 // Dma base address starts with an offset 0x1000 + +#define TRANSMIT_DESC_SIZE 32 //Tx Descriptors needed in the Descriptor pool/queue +#define RECEIVE_DESC_SIZE 32 //Rx Descriptors needed in the Descriptor pool/queue + +#define ENH_DESC +#define ENH_DESC_8W +#define IPC_OFFLOAD + +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, +}; + +#define VLAN_ETH_FRAME_LEN 1518 // Max. octets in payload for VLAN frame +#define ETH_ZLEN 60 +#define ETH_HLEN 12 +#define ETH_FCS_LEN 4 +#define VLAN_HLEN 4 +#define NET_IP_ALIGN 2 + +#define ETHERNET_EXTRA (NET_IP_ALIGN + 2 * CACHE_LINE_SIZE) +#define ETH_MAX_FRAME_LEN (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN + ((4 - NET_IP_ALIGN) & 0x3)) +#define ETH_JUMBO_FRAME_LEN 9000 //Jumbo frame payload size + +/* +DMA Descriptor Structure +The structure is common for both receive and transmit descriptors +The descriptor is of 4 words, but our structrue contains 6 words where +last two words are to hold the virtual address of the network buffer pointers +for driver's use +From the GMAC core release 3.50a onwards, the Enhanced Descriptor structure got changed. +The descriptor (both transmit and receive) are of 8 words each rather the 4 words of normal +descriptor structure. +Whenever IEEE 1588 Timestamping is enabled TX/RX DESC6 provides the lower 32 bits of Timestamp value and + TX/RX DESC7 provides the upper 32 bits of Timestamp value +In addition to this whenever extended status bit is set (RX DESC0 bit 0), RX DESC4 contains the extended status information +*/ + +#define DESC_FLUSH_SIZE (((32 + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE) * CACHE_LINE_SIZE) + // multiple of cache line. +#ifdef ENH_DESC_8W +typedef struct DmaDescStruct +{ + volatile u32 status; /* Status */ + volatile u32 length; /* Buffer 1 and Buffer 2 length */ + volatile u32 buffer1; /* Network Buffer 1 pointer (Dma-able) */ + volatile u32 data1; /* This holds virtual address of buffer1, not used by DMA */ + /* This data below is used only by driver */ + volatile u32 extstatus; /* Extended status of a Rx Descriptor */ + volatile u32 reserved1; /* Reserved word */ + volatile u32 timestamplow; /* Lower 32 bits of the 64 bit timestamp value */ + volatile u32 timestamphigh; /* Higher 32 bits of the 64 bit timestamp value */ +} DmaDesc; +#else +typedef struct DmaDescStruct +{ + volatile u32 status; /* Status */ + volatile u32 length; /* Buffer 1 and Buffer 2 length */ + volatile u32 buffer1; /* Network Buffer 1 pointer (Dma-able) */ + volatile u32 rsvd_buffer2; /* Network Buffer 2 pointer or next descriptor pointer (chain mode) */ + /* This data below is used only by driver */ + u32 data1; /* This holds virtual address of buffer1, not used by DMA */ + u32 pad2[3]; +} DmaDesc; +#endif + +enum DescMode +{ + RINGMODE = 0x00000001, + CHAINMODE = 0x00000002, +}; + +/* + * synopGMAC device data + */ +typedef struct synopGMACDeviceStruct +{ + u32 NbrBase; /* base address of NBR registers */ + u32 MacBase; /* base address of MAC registers */ + u32 DmaBase; /* base address of DMA registers */ + u32 PhyBase; /* PHY device address on MII interface */ + u32 Version; /* Gmac Revision version */ + + dma_addr_t TxDescDma; /* Dma-able address of first tx descriptor either in ring or chain mode, this is used by the GMAC device */ + dma_addr_t RxDescDma; /* Dma-albe address of first rx descriptor either in ring or chain mode, this is used by the GMAC device */ + DmaDesc *TxDesc; /* start address of TX descriptors ring or chain, this is used by the driver */ + DmaDesc *RxDesc; /* start address of RX descriptors ring or chain, this is used by the driver */ + + volatile u32 BusyTxDesc;/* Number of Tx Descriptors owned by DMA at any given time*/ + volatile u32 BusyRxDesc;/* Number of Rx Descriptors owned by DMA at any given time*/ + + u32 RxDescCount; /* number of rx descriptors in the tx descriptor queue/pool */ + u32 TxDescCount; /* number of tx descriptors in the rx descriptor queue/pool */ + + u32 TxBusy; /* index of the tx descriptor owned by DMA, is obtained by synopGMAC_get_tx_qptr() */ + u32 TxNext; /* index of the tx descriptor next available with driver, given to DMA by synopGMAC_set_tx_qptr() */ + u32 RxBusy; /* index of the rx descriptor owned by DMA, obtained by synopGMAC_get_rx_qptr() */ + u32 RxNext; /* index of the rx descriptor next available with driver, given to DMA by synopGMAC_set_rx_qptr() */ + + DmaDesc * TxBusyDesc; /* Tx Descriptor address corresponding to the index TxBusy */ + DmaDesc * TxNextDesc; /* Tx Descriptor address corresponding to the index TxNext */ + DmaDesc * RxBusyDesc; /* Rx Descriptor address corresponding to the index TxBusy */ + DmaDesc * RxNextDesc; /* Rx Descriptor address corresponding to the index RxNext */ + + /* + * Phy related stuff + */ + u32 ClockDivMdc; /* Clock divider value programmed in the hardware */ + u32 LinkState; /* Link status as reported by the Marvel Phy */ + u32 DuplexMode; /* Duplex mode of the Phy */ + u32 Speed; /* Speed of the Phy */ + u32 LoopBackMode; /* Loopback status of the Phy */ + + struct eth_device *synopGMACnetdev; + + u32 synopGMACMappedAddr; /* GMAC port address */ + u32 GMAC_Power_down; /* indicate to ISR whether the interrupts occured in the process of powering down */ + + u32 macid; + u32 phyid; + u32 phy_mii_type; + u32 state; + +} synopGMACdevice; + +/* + * Below is "88E1011/88E1011S Integrated 10/100/1000 Gigabit Ethernet Transceiver" + * Register and their layouts. This Phy has been used in the Dot Aster GMAC Phy daughter. + * Since the Phy register map is standard, this map hardly changes to a different Ppy + */ +enum MiiRegisters +{ + PHY_CONTROL_REG = 0x0000, /*Control Register*/ + PHY_STATUS_REG = 0x0001, /*Status Register */ + PHY_ID_HI_REG = 0x0002, /*PHY Identifier High Register*/ + PHY_ID_LOW_REG = 0x0003, /*PHY Identifier High Register*/ + PHY_AN_ADV_REG = 0x0004, /*Auto-Negotiation Advertisement Register*/ + PHY_LNK_PART_ABl_REG = 0x0005, /*Link Partner Ability Register (Base Page)*/ + PHY_AN_EXP_REG = 0x0006, /*Auto-Negotiation Expansion Register*/ + PHY_AN_NXT_PAGE_TX_REG = 0x0007, /*Next Page Transmit Register*/ + PHY_LNK_PART_NXT_PAGE_REG = 0x0008, /*Link Partner Next Page Register*/ + PHY_1000BT_CTRL_REG = 0x0009, /*1000BASE-T Control Register*/ + PHY_1000BT_STATUS_REG = 0x000a, /*1000BASE-T Status Register*/ + PHY_SPECIFIC_CTRL_REG = 0x0010, /*Phy specific control register*/ + PHY_SPECIFIC_STATUS_REG = 0x0011, /*Phy specific status register*/ + PHY_INTERRUPT_ENABLE_REG = 0x0012, /*Phy interrupt enable register*/ + PHY_INTERRUPT_STATUS_REG = 0x0013, /*Phy interrupt status register*/ + PHY_EXT_PHY_SPC_CTRL = 0x0014, /*Extended Phy specific control*/ + PHY_RX_ERR_COUNTER = 0x0015, /*Receive Error Counter*/ + PHY_EXT_ADDR_CBL_DIAG = 0x0016, /*Extended address for cable diagnostic register*/ + PHY_LED_CONTROL = 0x0018, /*LED Control*/ + PHY_MAN_LED_OVERIDE = 0x0019, /*Manual LED override register*/ + PHY_EXT_PHY_SPC_CTRL2 = 0x001a, /*Extended Phy specific control 2*/ + PHY_EXT_PHY_SPC_STATUS = 0x001b, /*Extended Phy specific status*/ + PHY_CBL_DIAG_REG = 0x001c, /*Cable diagnostic registers*/ +}; + + +/* This is Control register layout. Control register is of 16 bit wide. +*/ + +enum Mii_GEN_CTRL +{ /* Description bits R/W default value */ + Mii_reset = 0x8000, + Mii_Speed_10 = 0x0000, /* 10 Mbps 6:13 RW */ + Mii_Speed_100 = 0x2000, /* 100 Mbps 6:13 RW */ + Mii_Speed_1000 = 0x0040, /* 1000 Mbit/s 6:13 RW */ + + Mii_Duplex = 0x0100, /* Full Duplex mode 8 RW */ + + Mii_Manual_Master_Config = 0x0800, /* Manual Master Config 11 RW */ + + Mii_Loopback = 0x4000, /* Enable Loop back 14 RW */ + Mii_NoLoopback = 0x0000, /* Enable Loop back 14 RW */ +}; + +enum Mii_Phy_Status +{ + Mii_phy_status_speed_10 = 0x0000, + Mii_phy_status_speed_100 = 0x4000, + Mii_phy_status_speed_1000 = 0x8000, + + Mii_phy_status_full_duplex = 0x2000, + Mii_phy_status_half_duplex = 0x0000, + + Mii_phy_status_link_up = 0x0400, +}; +/* This is Status register layout. Status register is of 16 bit wide. +*/ +enum Mii_GEN_STATUS +{ + Mii_AutoNegCmplt = 0x0020, /* Autonegotiation completed 5 RW */ + Mii_Link = 0x0004, /* Link status 2 RW */ +}; + +enum Mii_Link_Status +{ + LINKDOWN = 0, + LINKUP = 1, +}; + +enum Mii_Duplex_Mode +{ + HALFDUPLEX = 1, + FULLDUPLEX = 2, +}; +enum Mii_Link_Speed +{ + SPEED10 = 1, + SPEED100 = 2, + SPEED1000 = 3, +}; + +enum Mii_Loop_Back +{ + NOLOOPBACK = 0, + LOOPBACK = 1, +}; + +/********************************************************** + * GMAC registers Map + * For Pci based system address is BARx + GmacRegisterBase + * For any other system translation is done accordingly + **********************************************************/ +enum GmacRegisters +{ + GmacConfig = 0x0000, /* Mac config Register */ + GmacFrameFilter = 0x0004, /* Mac frame filtering controls */ + GmacHashHigh = 0x0008, /* Multi-cast hash table high */ + GmacHashLow = 0x000C, /* Multi-cast hash table low */ + GmacGmiiAddr = 0x0010, /* GMII address Register(ext. Phy) */ + GmacGmiiData = 0x0014, /* GMII data Register(ext. Phy) */ + GmacFlowControl = 0x0018, /* Flow control Register */ + GmacVlan = 0x001C, /* VLAN tag Register (IEEE 802.1Q) */ + + GmacVersion = 0x0020, /* GMAC Core Version Register */ + GmacWakeupAddr = 0x0028, /* GMAC wake-up frame filter adrress reg */ + GmacPmtCtrlStatus = 0x002C, /* PMT control and status register */ + + GmacInterruptStatus = 0x0038, /* Mac Interrupt ststus register */ + GmacInterruptMask = 0x003C, /* Mac Interrupt Mask register */ + + GmacAddr0High = 0x0040, /* Mac address0 high Register */ + GmacAddr0Low = 0x0044, /* Mac address0 low Register */ + GmacAddr1High = 0x0048, /* Mac address1 high Register */ + GmacAddr1Low = 0x004C, /* Mac address1 low Register */ + GmacAddr2High = 0x0050, /* Mac address2 high Register */ + GmacAddr2Low = 0x0054, /* Mac address2 low Register */ + GmacAddr3High = 0x0058, /* Mac address3 high Register */ + GmacAddr3Low = 0x005C, /* Mac address3 low Register */ + GmacAddr4High = 0x0060, /* Mac address4 high Register */ + GmacAddr4Low = 0x0064, /* Mac address4 low Register */ + GmacAddr5High = 0x0068, /* Mac address5 high Register */ + GmacAddr5Low = 0x006C, /* Mac address5 low Register */ + GmacAddr6High = 0x0070, /* Mac address6 high Register */ + GmacAddr6Low = 0x0074, /* Mac address6 low Register */ + GmacAddr7High = 0x0078, /* Mac address7 high Register */ + GmacAddr7Low = 0x007C, /* Mac address7 low Register */ + GmacAddr8High = 0x0080, /* Mac address8 high Register */ + GmacAddr8Low = 0x0084, /* Mac address8 low Register */ + GmacAddr9High = 0x0088, /* Mac address9 high Register */ + GmacAddr9Low = 0x008C, /* Mac address9 low Register */ + GmacAddr10High = 0x0090, /* Mac address10 high Register */ + GmacAddr10Low = 0x0094, /* Mac address10 low Register */ + GmacAddr11High = 0x0098, /* Mac address11 high Register */ + GmacAddr11Low = 0x009C, /* Mac address11 low Register */ + GmacAddr12High = 0x00A0, /* Mac address12 high Register */ + GmacAddr12Low = 0x00A4, /* Mac address12 low Register */ + GmacAddr13High = 0x00A8, /* Mac address13 high Register */ + GmacAddr13Low = 0x00AC, /* Mac address13 low Register */ + GmacAddr14High = 0x00B0, /* Mac address14 high Register */ + GmacAddr14Low = 0x00B4, /* Mac address14 low Register */ + GmacAddr15High = 0x00B8, /* Mac address15 high Register */ + GmacAddr15Low = 0x00BC, /* Mac address15 low Register */ + + /*Time Stamp Register Map*/ + GmacTSControl = 0x0700, /* Controls the Timestamp update logic : only when IEEE 1588 time stamping is enabled in corekit */ + + GmacTSSubSecIncr = 0x0704, /* 8 bit value by which sub second register is incremented : only when IEEE 1588 time stamping without external timestamp input */ + + GmacTSHigh = 0x0708, /* 32 bit seconds(MS) : only when IEEE 1588 time stamping without external timestamp input */ + GmacTSLow = 0x070C, /* 32 bit nano seconds(MS) : only when IEEE 1588 time stamping without external timestamp input */ + + GmacTSHighUpdate = 0x0710, /* 32 bit seconds(MS) to be written/added/subtracted : only when IEEE 1588 time stamping without external timestamp input */ + GmacTSLowUpdate = 0x0714, /* 32 bit nano seconds(MS) to be writeen/added/subtracted : only when IEEE 1588 time stamping without external timestamp input */ + + GmacTSAddend = 0x0718, /* Used by Software to readjust the clock frequency linearly : only when IEEE 1588 time stamping without external timestamp input */ + + GmacTSTargetTimeHigh = 0x071C, /* 32 bit seconds(MS) to be compared with system time : only when IEEE 1588 time stamping without external timestamp input */ + GmacTSTargetTimeLow = 0x0720, /* 32 bit nano seconds(MS) to be compared with system time : only when IEEE 1588 time stamping without external timestamp input */ + + GmacTSHighWord = 0x0724, /* Time Stamp Higher Word Register (Version 2 only); only lower 16 bits are valid */ + + GmacTSStatus = 0x0728, /* Time Stamp Status Register */ +}; + +/********************************************************** + * GMAC Network interface registers + * This explains the Register's Layout + + * FES is Read only by default and is enabled only when Tx + * Config Parameter is enabled for RGMII/SGMII interface + * during CoreKit Config. + + * DM is Read only with value 1'b1 in Full duplex only Config + **********************************************************/ + +/* GmacConfig = 0x0000, Mac config Register Layout */ +enum GmacConfigReg +{ + /* Bit description Bits R/W Reset value */ + GmacWatchdog = 0x00800000, + GmacWatchdogDisable = 0x00800000, /* (WD)Disable watchdog timer on Rx 23 RW */ + GmacWatchdogEnable = 0x00000000, /* Enable watchdog timer 0 */ + + GmacJabber = 0x00400000, + GmacJabberDisable = 0x00400000, /* (JD)Disable jabber timer on Tx 22 RW */ + GmacJabberEnable = 0x00000000, /* Enable jabber timer 0 */ + + GmacFrameBurst = 0x00200000, + GmacFrameBurstEnable = 0x00200000, /* (BE)Enable frame bursting during Tx 21 RW */ + GmacFrameBurstDisable = 0x00000000, /* Disable frame bursting 0 */ + + GmacJumboFrame = 0x00100000, + GmacJumboFrameEnable = 0x00100000, /* (JE)Enable jumbo frame for Tx 20 RW */ + GmacJumboFrameDisable = 0x00000000, /* Disable jumbo frame 0 */ + + GmacInterFrameGap7 = 0x000E0000, /* (IFG) Config7 - 40 bit times 19:17 RW */ + GmacInterFrameGap6 = 0x000C0000, /* (IFG) Config6 - 48 bit times */ + GmacInterFrameGap5 = 0x000A0000, /* (IFG) Config5 - 56 bit times */ + GmacInterFrameGap4 = 0x00080000, /* (IFG) Config4 - 64 bit times */ + GmacInterFrameGap3 = 0x00040000, /* (IFG) Config3 - 72 bit times */ + GmacInterFrameGap2 = 0x00020000, /* (IFG) Config2 - 80 bit times */ + GmacInterFrameGap1 = 0x00010000, /* (IFG) Config1 - 88 bit times */ + GmacInterFrameGap0 = 0x00000000, /* (IFG) Config0 - 96 bit times 000 */ + + GmacDisableCrs = 0x00010000, + GmacMiiGmii = 0x00008000, + GmacSelectMii = 0x00008000, /* (PS)Port Select-MII mode 15 RW */ + GmacSelectGmii = 0x00000000, /* GMII mode 0 */ + + GmacFESpeed100 = 0x00004000, /*(FES)Fast Ethernet speed 100Mbps 14 RW */ + GmacFESpeed10 = 0x00000000, /* 10Mbps 0 */ + + GmacRxOwn = 0x00002000, + GmacDisableRxOwn = 0x00002000, /* (DO)Disable receive own packets 13 RW */ + GmacEnableRxOwn = 0x00000000, /* Enable receive own packets 0 */ + + GmacLoopback = 0x00001000, + GmacLoopbackOn = 0x00001000, /* (LM)Loopback mode for GMII/MII 12 RW */ + GmacLoopbackOff = 0x00000000, /* Normal mode 0 */ + + GmacDuplex = 0x00000800, + GmacFullDuplex = 0x00000800, /* (DM)Full duplex mode 11 RW */ + GmacHalfDuplex = 0x00000000, /* Half duplex mode 0 */ + + GmacRxIpcOffload = 0x00000400, /*IPC checksum offload 10 RW 0 */ + + GmacRetry = 0x00000200, + GmacRetryDisable = 0x00000200, /* (DR)Disable Retry 9 RW */ + GmacRetryEnable = 0x00000000, /* Enable retransmission as per BL 0 */ + + GmacLinkUp = 0x00000100, /* (LUD)Link UP 8 RW */ + GmacLinkDown = 0x00000100, /* Link Down 0 */ + + GmacPadCrcStrip = 0x00000080, + GmacPadCrcStripEnable = 0x00000080, /* (ACS) Automatic Pad/Crc strip enable 7 RW */ + GmacPadCrcStripDisable = 0x00000000, /* Automatic Pad/Crc stripping disable 0 */ + + GmacBackoffLimit = 0x00000060, + GmacBackoffLimit3 = 0x00000060, /* (BL)Back-off limit in HD mode 6:5 RW */ + GmacBackoffLimit2 = 0x00000040, /* */ + GmacBackoffLimit1 = 0x00000020, /* */ + GmacBackoffLimit0 = 0x00000000, /* 00 */ + + GmacDeferralCheck = 0x00000010, + GmacDeferralCheckEnable = 0x00000010, /* (DC)Deferral check enable in HD mode 4 RW */ + GmacDeferralCheckDisable = 0x00000000, /* Deferral check disable 0 */ + + GmacTx = 0x00000008, + GmacTxEnable = 0x00000008, /* (TE)Transmitter enable 3 RW */ + GmacTxDisable = 0x00000000, /* Transmitter disable 0 */ + + GmacRx = 0x00000004, + GmacRxEnable = 0x00000004, /* (RE)Receiver enable 2 RW */ + GmacRxDisable = 0x00000000, /* Receiver disable 0 */ +}; + +/* GmacFrameFilter = 0x0004, Mac frame filtering controls Register Layout*/ +enum GmacFrameFilterReg +{ + GmacFilter = 0x80000000, + GmacFilterOff = 0x80000000, /* (RA)Receive all incoming packets 31 RW */ + GmacFilterOn = 0x00000000, /* Receive filtered packets only 0 */ + + GmacHashPerfectFilter = 0x00000400, /*Hash or Perfect Filter enable 10 RW 0 */ + + GmacSrcAddrFilter = 0x00000200, + GmacSrcAddrFilterEnable = 0x00000200, /* (SAF)Source Address Filter enable 9 RW */ + GmacSrcAddrFilterDisable = 0x00000000, /* 0 */ + + GmacSrcInvaAddrFilter = 0x00000100, + GmacSrcInvAddrFilterEn = 0x00000100, /* (SAIF)Inv Src Addr Filter enable 8 RW */ + GmacSrcInvAddrFilterDis = 0x00000000, /* 0 */ + + GmacPassControl = 0x000000C0, + GmacPassControl3 = 0x000000C0, /* (PCS)Forwards ctrl frms that pass AF 7:6 RW */ + GmacPassControl2 = 0x00000080, /* Forwards all control frames */ + GmacPassControl1 = 0x00000040, /* Does not pass control frames */ + GmacPassControl0 = 0x00000000, /* Does not pass control frames 00 */ + + GmacBroadcast = 0x00000020, + GmacBroadcastDisable = 0x00000020, /* (DBF)Disable Rx of broadcast frames 5 RW */ + GmacBroadcastEnable = 0x00000000, /* Enable broadcast frames 0 */ + + GmacMulticastFilter = 0x00000010, + GmacMulticastFilterOff = 0x00000010, /* (PM) Pass all multicast packets 4 RW */ + GmacMulticastFilterOn = 0x00000000, /* Pass filtered multicast packets 0 */ + + GmacDestAddrFilter = 0x00000008, + GmacDestAddrFilterInv = 0x00000008, /* (DAIF)Inverse filtering for DA 3 RW */ + GmacDestAddrFilterNor = 0x00000000, /* Normal filtering for DA 0 */ + + GmacMcastHashFilter = 0x00000004, + GmacMcastHashFilterOn = 0x00000004, /* (HMC)perfom multicast hash filtering 2 RW */ + GmacMcastHashFilterOff = 0x00000000, /* perfect filtering only 0 */ + + GmacUcastHashFilter = 0x00000002, + GmacUcastHashFilterOn = 0x00000002, /* (HUC)Unicast Hash filtering only 1 RW */ + GmacUcastHashFilterOff = 0x00000000, /* perfect filtering only 0 */ + + GmacPromiscuousMode = 0x00000001, + GmacPromiscuousModeOn = 0x00000001, /* Receive all frames 0 RW */ + GmacPromiscuousModeOff = 0x00000000, /* Receive filtered packets only 0 */ +}; + + +/*GmacGmiiAddr = 0x0010, GMII address Register(ext. Phy) Layout */ +enum GmacGmiiAddrReg +{ + GmiiDevMask = 0x0000F800, /* (PA)GMII device address 15:11 RW 0x00 */ + GmiiDevShift = 11, + + GmiiRegMask = 0x000007C0, /* (GR)GMII register in selected Phy 10:6 RW 0x00 */ + GmiiRegShift = 6, + + GmiiCsrClkMask = 0x0000003C, /*CSR Clock bit Mask 4:2 */ + GmiiCsrClk5 = 0x00000014, /* (CR)CSR Clock Range 250-300 MHz 4:2 RW 000 */ + GmiiCsrClk4 = 0x00000010, /* 150-250 MHz */ + GmiiCsrClk3 = 0x0000000C, /* 35-60 MHz */ + GmiiCsrClk2 = 0x00000008, /* 20-35 MHz */ + GmiiCsrClk1 = 0x00000004, /* 100-150 MHz */ + GmiiCsrClk0 = 0x00000000, /* 60-100 MHz */ + + GmiiWrite = 0x00000002, /* (GW)Write to register 1 RW */ + GmiiRead = 0x00000000, /* Read from register 0 */ + + GmiiBusy = 0x00000001, /* (GB)GMII interface is busy 0 RW 0 */ +}; + +/* GmacGmiiData = 0x0014, GMII data Register(ext. Phy) Layout */ +enum GmacGmiiDataReg +{ + GmiiDataMask = 0x0000FFFF, /* (GD)GMII Data 15:0 RW 0x0000 */ +}; + + +/*GmacFlowControl = 0x0018, Flow control Register Layout */ +enum GmacFlowControlReg +{ + GmacPauseTimeMask = 0xFFFF0000, /* (PT) PAUSE TIME field in the control frame 31:16 RW 0x0000 */ + GmacPauseTimeShift = 16, + + GmacPauseLowThresh = 0x00000030, + GmacPauseLowThresh3 = 0x00000030, /* (PLT)thresh for pause tmr 256 slot time 5:4 RW */ + GmacPauseLowThresh2 = 0x00000020, /* 144 slot time */ + GmacPauseLowThresh1 = 0x00000010, /* 28 slot time */ + GmacPauseLowThresh0 = 0x00000000, /* 4 slot time 000 */ + + GmacUnicastPauseFrame = 0x00000008, + GmacUnicastPauseFrameOn = 0x00000008, /* (UP)Detect pause frame with unicast addr. 3 RW */ + GmacUnicastPauseFrameOff = 0x00000000, /* Detect only pause frame with multicast addr. 0 */ + + GmacRxFlowControl = 0x00000004, + GmacRxFlowControlEnable = 0x00000004, /* (RFE)Enable Rx flow control 2 RW */ + GmacRxFlowControlDisable = 0x00000000, /* Disable Rx flow control 0 */ + + GmacTxFlowControl = 0x00000002, + GmacTxFlowControlEnable = 0x00000002, /* (TFE)Enable Tx flow control 1 RW */ + GmacTxFlowControlDisable = 0x00000000, /* Disable flow control 0 */ + + GmacFlowControlBackPressure= 0x00000001, + GmacSendPauseFrame = 0x00000001, /* (FCB/PBA)send pause frm/Apply back pressure 0 RW 0 */ +}; + +/* GmacInterruptStatus = 0x0038, Mac Interrupt ststus register */ +enum GmacInterruptStatusBitDefinition +{ + GmacTSIntSts = 0x00000200, /* set if int generated due to TS (Read Time Stamp Status Register to know details)*/ + GmacMmcRxChksumOffload = 0x00000080, /* set if int generated in MMC RX CHECKSUM OFFLOAD int register */ + GmacMmcTxIntSts = 0x00000040, /* set if int generated in MMC TX Int register */ + GmacMmcRxIntSts = 0x00000020, /* set if int generated in MMC RX Int register */ + GmacMmcIntSts = 0x00000010, /* set if any of the above bit [7:5] is set */ + GmacPmtIntSts = 0x00000008, /* set whenver magic pkt/wake-on-lan frame is received */ + GmacPcsAnComplete = 0x00000004, /* set when AN is complete in TBI/RTBI/SGMIII phy interface */ + GmacPcsLnkStsChange = 0x00000002, /* set if any lnk status change in TBI/RTBI/SGMII interface */ + GmacRgmiiIntSts = 0x00000001, /* set if any change in lnk status of RGMII interface */ + +}; + +/* GmacInterruptMask = 0x003C, Mac Interrupt Mask register */ +enum GmacInterruptMaskBitDefinition +{ + GmacTSIntMask = 0x00000200, /* when set disables the time stamp interrupt generation */ + GmacPmtIntMask = 0x00000008, /* when set Disables the assertion of PMT interrupt */ + GmacPcsAnIntMask = 0x00000004, /* When set disables the assertion of PCS AN complete interrupt */ + GmacPcsLnkStsIntMask = 0x00000002, /* when set disables the assertion of PCS lnk status change interrupt */ + GmacRgmiiIntMask = 0x00000001, /* when set disables the assertion of RGMII int */ +}; + +/********************************************************** + * GMAC DMA registers + * For Pci based system address is BARx + GmaDmaBase + * For any other system translation is done accordingly + **********************************************************/ + +enum DmaRegisters +{ + DmaBusMode = 0x0000, /* CSR0 - Bus Mode Register */ + DmaTxPollDemand = 0x0004, /* CSR1 - Transmit Poll Demand Register */ + DmaRxPollDemand = 0x0008, /* CSR2 - Receive Poll Demand Register */ + DmaRxBaseAddr = 0x000C, /* CSR3 - Receive Descriptor list base address */ + DmaTxBaseAddr = 0x0010, /* CSR4 - Transmit Descriptor list base address */ + DmaStatus = 0x0014, /* CSR5 - Dma status Register */ + DmaControl = 0x0018, /* CSR6 - Dma Operation Mode Register */ + DmaInterrupt = 0x001C, /* CSR7 - Interrupt enable */ + DmaMissedFr = 0x0020, /* CSR8 - Missed Frame & Buffer overflow Counter */ + DmaTxCurrDesc = 0x0048, /* - Current host Tx Desc Register */ + DmaRxCurrDesc = 0x004C, /* - Current host Rx Desc Register */ + DmaTxCurrAddr = 0x0050, /* CSR20 - Current host transmit buffer address */ + DmaRxCurrAddr = 0x0054, /* CSR21 - Current host receive buffer address */ +}; + +/********************************************************** + * DMA Engine registers Layout + **********************************************************/ + +/*DmaBusMode = 0x0000, CSR0 - Bus Mode */ +enum DmaBusModeReg +{ /* Bit description Bits R/W Reset value */ + DmaFixedBurstEnable = 0x00010000, /* (FB)Fixed Burst SINGLE, INCR4, INCR8 or INCR16 16 RW */ + DmaFixedBurstDisable = 0x00000000, /* SINGLE, INCR 0 */ + + DmaTxPriorityRatio11 = 0x00000000, /* (PR)TX:RX DMA priority ratio 1:1 15:14 RW 00 */ + DmaTxPriorityRatio21 = 0x00004000, /* (PR)TX:RX DMA priority ratio 2:1 */ + DmaTxPriorityRatio31 = 0x00008000, /* (PR)TX:RX DMA priority ratio 3:1 */ + DmaTxPriorityRatio41 = 0x0000C000, /* (PR)TX:RX DMA priority ratio 4:1 */ + + DmaBurstLengthx8 = 0x01000000, /* When set mutiplies the PBL by 8 24 RW 0 */ + + DmaBurstLength256 = 0x01002000, /*(DmaBurstLengthx8 | DmaBurstLength32) = 256 [24]:13:8 */ + DmaBurstLength128 = 0x01001000, /*(DmaBurstLengthx8 | DmaBurstLength16) = 128 [24]:13:8 */ + DmaBurstLength64 = 0x01000800, /*(DmaBurstLengthx8 | DmaBurstLength8) = 64 [24]:13:8 */ + DmaBurstLength32 = 0x00002000, /* (PBL) programmable Dma burst length = 32 13:8 RW */ + DmaBurstLength16 = 0x00001000, /* Dma burst length = 16 */ + DmaBurstLength8 = 0x00000800, /* Dma burst length = 8 */ + DmaBurstLength4 = 0x00000400, /* Dma burst length = 4 */ + DmaBurstLength2 = 0x00000200, /* Dma burst length = 2 */ + DmaBurstLength1 = 0x00000100, /* Dma burst length = 1 */ + DmaBurstLength0 = 0x00000000, /* Dma burst length = 0 0x00 */ + + DmaDescriptor8Words = 0x00000080, /* Enh Descriptor works 1=> 8 word descriptor 7 0 */ + DmaDescriptor4Words = 0x00000000, /* Enh Descriptor works 0=> 4 word descriptor 7 0 */ + + DmaDescriptorSkip16 = 0x00000040, /* (DSL)Descriptor skip length (no.of dwords) 6:2 RW */ + DmaDescriptorSkip8 = 0x00000020, /* between two unchained descriptors */ + DmaDescriptorSkip4 = 0x00000010, /* */ + DmaDescriptorSkip2 = 0x00000008, /* */ + DmaDescriptorSkip1 = 0x00000004, /* */ + DmaDescriptorSkip0 = 0x00000000, /* 0x00 */ + + DmaArbitRr = 0x00000000, /* (DA) DMA RR arbitration 1 RW 0 */ + DmaArbitPr = 0x00000002, /* Rx has priority over Tx */ + + DmaResetOn = 0x00000001, /* (SWR)Software Reset DMA engine 0 RW */ + DmaResetOff = 0x00000000, /* 0 */ +}; + + +/*DmaStatus = 0x0014, CSR5 - Dma status Register */ +enum DmaStatusReg +{ + /*Bit 28 27 and 26 indicate whether the interrupt due to PMT GMACMMC or GMAC LINE Remaining bits are DMA interrupts*/ + GmacPmtIntr = 0x10000000, /* (GPI)Gmac subsystem interrupt 28 RO 0 */ + GmacMmcIntr = 0x08000000, /* (GMI)Gmac MMC subsystem interrupt 27 RO 0 */ + GmacLineIntfIntr = 0x04000000, /* Line interface interrupt 26 RO 0 */ + + DmaErrorBit2 = 0x02000000, /* (EB)Error bits 0-data buffer, 1-desc. access 25 RO 0 */ + DmaErrorBit1 = 0x01000000, /* (EB)Error bits 0-write trnsf, 1-read transfr 24 RO 0 */ + DmaErrorBit0 = 0x00800000, /* (EB)Error bits 0-Rx DMA, 1-Tx DMA 23 RO 0 */ + + DmaTxState = 0x00700000, /* (TS)Transmit process state 22:20 RO */ + DmaTxStopped = 0x00000000, /* Stopped - Reset or Stop Tx Command issued 000 */ + DmaTxFetching = 0x00100000, /* Running - fetching the Tx descriptor */ + DmaTxWaiting = 0x00200000, /* Running - waiting for status */ + DmaTxReading = 0x00300000, /* Running - reading the data from host memory */ + DmaTxSuspended = 0x00600000, /* Suspended - Tx Descriptor unavailabe */ + DmaTxClosing = 0x00700000, /* Running - closing Rx descriptor */ + + DmaRxState = 0x000E0000, /* (RS)Receive process state 19:17 RO */ + DmaRxStopped = 0x00000000, /* Stopped - Reset or Stop Rx Command issued 000 */ + DmaRxFetching = 0x00020000, /* Running - fetching the Rx descriptor */ + DmaRxWaiting = 0x00060000, /* Running - waiting for packet */ + DmaRxSuspended = 0x00080000, /* Suspended - Rx Descriptor unavailable */ + DmaRxClosing = 0x000A0000, /* Running - closing descriptor */ + DmaRxQueuing = 0x000E0000, /* Running - queuing the recieve frame into host memory */ + + DmaIntNormal = 0x00010000, /* (NIS)Normal interrupt summary 16 RW 0 */ + DmaIntAbnormal = 0x00008000, /* (AIS)Abnormal interrupt summary 15 RW 0 */ + + DmaIntEarlyRx = 0x00004000, /* Early receive interrupt (Normal) RW 0 */ + DmaIntBusError = 0x00002000, /* Fatal bus error (Abnormal) RW 0 */ + DmaIntEarlyTx = 0x00000400, /* Early transmit interrupt (Abnormal) RW 0 */ + DmaIntRxWdogTO = 0x00000200, /* Receive Watchdog Timeout (Abnormal) RW 0 */ + DmaIntRxStopped = 0x00000100, /* Receive process stopped (Abnormal) RW 0 */ + DmaIntRxNoBuffer = 0x00000080, /* Receive buffer unavailable (Abnormal) RW 0 */ + DmaIntRxCompleted = 0x00000040, /* Completion of frame reception (Normal) RW 0 */ + DmaIntTxUnderflow = 0x00000020, /* Transmit underflow (Abnormal) RW 0 */ + DmaIntRcvOverflow = 0x00000010, /* Receive Buffer overflow interrupt RW 0 */ + DmaIntTxJabberTO = 0x00000008, /* Transmit Jabber Timeout (Abnormal) RW 0 */ + DmaIntTxNoBuffer = 0x00000004, /* Transmit buffer unavailable (Normal) RW 0 */ + DmaIntTxStopped = 0x00000002, /* Transmit process stopped (Abnormal) RW 0 */ + DmaIntTxCompleted = 0x00000001, /* Transmit completed (Normal) RW 0 */ +}; + +/*DmaControl = 0x0018, CSR6 - Dma Operation Mode Register */ +enum DmaControlReg +{ + DmaDisableDropTcpCs = 0x04000000, /* (DT) Dis. drop. of tcp/ip CS error frames 26 RW 0 */ + + DmaStoreAndForward = 0x00200000, /* (SF)Store and forward 21 RW 0 */ + DmaFlushTxFifo = 0x00100000, /* (FTF)Tx FIFO controller is reset to default 20 RW 0 */ + + DmaTxThreshCtrl = 0x0001C000, /* (TTC)Controls thre Threh of MTL tx Fifo 16:14 RW */ + DmaTxThreshCtrl16 = 0x0001C000, /* (TTC)Controls thre Threh of MTL tx Fifo 16 16:14 RW */ + DmaTxThreshCtrl24 = 0x00018000, /* (TTC)Controls thre Threh of MTL tx Fifo 24 16:14 RW */ + DmaTxThreshCtrl32 = 0x00014000, /* (TTC)Controls thre Threh of MTL tx Fifo 32 16:14 RW */ + DmaTxThreshCtrl40 = 0x00010000, /* (TTC)Controls thre Threh of MTL tx Fifo 40 16:14 RW */ + DmaTxThreshCtrl256 = 0x0000c000, /* (TTC)Controls thre Threh of MTL tx Fifo 256 16:14 RW */ + DmaTxThreshCtrl192 = 0x00008000, /* (TTC)Controls thre Threh of MTL tx Fifo 192 16:14 RW */ + DmaTxThreshCtrl128 = 0x00004000, /* (TTC)Controls thre Threh of MTL tx Fifo 128 16:14 RW */ + DmaTxThreshCtrl64 = 0x00000000, /* (TTC)Controls thre Threh of MTL tx Fifo 64 16:14 RW 000 */ + + DmaTxStart = 0x00002000, /* (ST)Start/Stop transmission 13 RW 0 */ + + DmaRxFlowCtrlDeact = 0x00401800, /* (RFD)Rx flow control deact. threhold [22]:12:11 RW */ + DmaRxFlowCtrlDeact1K = 0x00000000, /* (RFD)Rx flow control deact. threhold (1kbytes) [22]:12:11 RW 00 */ + DmaRxFlowCtrlDeact2K = 0x00000800, /* (RFD)Rx flow control deact. threhold (2kbytes) [22]:12:11 RW */ + DmaRxFlowCtrlDeact3K = 0x00001000, /* (RFD)Rx flow control deact. threhold (3kbytes) [22]:12:11 RW */ + DmaRxFlowCtrlDeact4K = 0x00001800, /* (RFD)Rx flow control deact. threhold (4kbytes) [22]:12:11 RW */ + DmaRxFlowCtrlDeact5K = 0x00400000, /* (RFD)Rx flow control deact. threhold (4kbytes) [22]:12:11 RW */ + DmaRxFlowCtrlDeact6K = 0x00400800, /* (RFD)Rx flow control deact. threhold (4kbytes) [22]:12:11 RW */ + DmaRxFlowCtrlDeact7K = 0x00401000, /* (RFD)Rx flow control deact. threhold (4kbytes) [22]:12:11 RW */ + + DmaRxFlowCtrlAct = 0x00800600, /* (RFA)Rx flow control Act. threhold [23]:10:09 RW */ + DmaRxFlowCtrlAct1K = 0x00000000, /* (RFA)Rx flow control Act. threhold (1kbytes) [23]:10:09 RW 00 */ + DmaRxFlowCtrlAct2K = 0x00000200, /* (RFA)Rx flow control Act. threhold (2kbytes) [23]:10:09 RW */ + DmaRxFlowCtrlAct3K = 0x00000400, /* (RFA)Rx flow control Act. threhold (3kbytes) [23]:10:09 RW */ + DmaRxFlowCtrlAct4K = 0x00000600, /* (RFA)Rx flow control Act. threhold (4kbytes) [23]:10:09 RW */ + DmaRxFlowCtrlAct5K = 0x00800000, /* (RFA)Rx flow control Act. threhold (5kbytes) [23]:10:09 RW */ + DmaRxFlowCtrlAct6K = 0x00800200, /* (RFA)Rx flow control Act. threhold (6kbytes) [23]:10:09 RW */ + DmaRxFlowCtrlAct7K = 0x00800400, /* (RFA)Rx flow control Act. threhold (7kbytes) [23]:10:09 RW */ + + DmaRxThreshCtrl = 0x00000018, /* (RTC)Controls thre Threh of MTL rx Fifo 4:3 RW */ + DmaRxThreshCtrl64 = 0x00000000, /* (RTC)Controls thre Threh of MTL tx Fifo 64 4:3 RW */ + DmaRxThreshCtrl32 = 0x00000008, /* (RTC)Controls thre Threh of MTL tx Fifo 32 4:3 RW */ + DmaRxThreshCtrl96 = 0x00000010, /* (RTC)Controls thre Threh of MTL tx Fifo 96 4:3 RW */ + DmaRxThreshCtrl128 = 0x00000018, /* (RTC)Controls thre Threh of MTL tx Fifo 128 4:3 RW */ + + DmaEnHwFlowCtrl = 0x00000100, /* (EFC)Enable HW flow control 8 RW */ + DmaDisHwFlowCtrl = 0x00000000, /* Disable HW flow control 0 */ + + DmaFwdErrorFrames = 0x00000080, /* (FEF)Forward error frames 7 RW 0 */ + DmaFwdUnderSzFrames = 0x00000040, /* (FUF)Forward undersize frames 6 RW 0 */ + DmaTxSecondFrame = 0x00000004, /* (OSF)Operate on second frame 4 RW 0 */ + DmaRxStart = 0x00000002, /* (SR)Start/Stop reception 1 RW 0 */ +}; + + +/*DmaInterrupt = 0x001C, CSR7 - Interrupt enable Register Layout */ +enum DmaInterruptReg +{ + DmaIeNormal = DmaIntNormal , /* Normal interrupt enable RW 0 */ + DmaIeAbnormal = DmaIntAbnormal , /* Abnormal interrupt enable RW 0 */ + + DmaIeEarlyRx = DmaIntEarlyRx , /* Early receive interrupt enable RW 0 */ + DmaIeBusError = DmaIntBusError , /* Fatal bus error enable RW 0 */ + DmaIeEarlyTx = DmaIntEarlyTx , /* Early transmit interrupt enable RW 0 */ + DmaIeRxWdogTO = DmaIntRxWdogTO , /* Receive Watchdog Timeout enable RW 0 */ + DmaIeRxStopped = DmaIntRxStopped , /* Receive process stopped enable RW 0 */ + DmaIeRxNoBuffer = DmaIntRxNoBuffer , /* Receive buffer unavailable enable RW 0 */ + DmaIeRxCompleted = DmaIntRxCompleted, /* Completion of frame reception enable RW 0 */ + DmaIeTxUnderflow = DmaIntTxUnderflow, /* Transmit underflow enable RW 0 */ + + DmaIeRxOverflow = DmaIntRcvOverflow, /* Receive Buffer overflow interrupt RW 0 */ + DmaIeTxJabberTO = DmaIntTxJabberTO , /* Transmit Jabber Timeout enable RW 0 */ + DmaIeTxNoBuffer = DmaIntTxNoBuffer , /* Transmit buffer unavailable enable RW 0 */ + DmaIeTxStopped = DmaIntTxStopped , /* Transmit process stopped enable RW 0 */ + DmaIeTxCompleted = DmaIntTxCompleted, /* Transmit completed enable RW 0 */ +}; + + + +/********************************************************** + * DMA Engine descriptors + **********************************************************/ + +/* +**********Enhanced Descritpor structure to support 8K buffer per buffer **************************** + +DmaRxBaseAddr = 0x000C, CSR3 - Receive Descriptor list base address +DmaRxBaseAddr is the pointer to the first Rx Descriptors. the Descriptor format in Little endian with a +32 bit Data bus is as shown below + +Similarly +DmaTxBaseAddr = 0x0010, CSR4 - Transmit Descriptor list base address +DmaTxBaseAddr is the pointer to the first Rx Descriptors. the Descriptor format in Little endian with a +32 bit Data bus is as shown below + -------------------------------------------------------------------------- + RDES0 |OWN (31)| Status | + -------------------------------------------------------------------------- + RDES1 | Ctrl | Res | Byte Count Buffer 2 | Ctrl | Res | Byte Count Buffer 1 | + -------------------------------------------------------------------------- + RDES2 | Buffer 1 Address | + -------------------------------------------------------------------------- + RDES3 | Buffer 2 Address / Next Descriptor Address | + -------------------------------------------------------------------------- + + -------------------------------------------------------------------------- + TDES0 |OWN (31)| Ctrl | Res | Ctrl | Res | Status | + -------------------------------------------------------------------------- + TDES1 | Res | Byte Count Buffer 2 | Res | Byte Count Buffer 1 | + -------------------------------------------------------------------------- + TDES2 | Buffer 1 Address | + -------------------------------------------------------------------------- + TDES3 | Buffer 2 Address / Next Descriptor Address | + -------------------------------------------------------------------------- + +*/ + +enum DmaDescriptorStatus /* status word of DMA descriptor */ +{ + DescOwnByDma = 0x80000000, /* (OWN)Descriptor is owned by DMA engine 31 RW */ + + DescDAFilterFail = 0x40000000, /* (AFM)Rx - DA Filter Fail for the rx frame 30 */ + + DescFrameLengthMask = 0x3FFF0000, /* (FL)Receive descriptor frame length 29:16 */ + DescFrameLengthShift = 16, + + DescError = 0x00008000, /* (ES)Error summary bit - OR of the follo. bits: 15 */ + /* DE || OE || IPC || LC || RWT || RE || CE */ + DescRxTruncated = 0x00004000, /* (DE)Rx - no more descriptors for receive frame 14 */ + DescSAFilterFail = 0x00002000, /* (SAF)Rx - SA Filter Fail for the received frame 13 */ + DescRxLengthError = 0x00001000, /* (LE)Rx - frm size not matching with len field 12 */ + DescRxDamaged = 0x00000800, /* (OE)Rx - frm was damaged due to buffer overflow 11 */ + DescRxVLANTag = 0x00000400, /* (VLAN)Rx - received frame is a VLAN frame 10 */ + DescRxFirst = 0x00000200, /* (FS)Rx - first descriptor of the frame 9 */ + DescRxLast = 0x00000100, /* (LS)Rx - last descriptor of the frame 8 */ + DescRxLongFrame = 0x00000080, /* (Giant Frame)Rx - frame is longer than 1518/1522 7 */ + DescRxCollision = 0x00000040, /* (LC)Rx - late collision occurred during reception 6 */ + DescRxFrameEther = 0x00000020, /* (FT)Rx - Frame type - Ethernet, otherwise 802.3 5 */ + DescRxWatchdog = 0x00000010, /* (RWT)Rx - watchdog timer expired during reception 4 */ + DescRxMiiError = 0x00000008, /* (RE)Rx - error reported by MII interface 3 */ + DescRxDribbling = 0x00000004, /* (DE)Rx - frame contains non int multiple of 8 bits 2 */ + DescRxCrc = 0x00000002, /* (CE)Rx - CRC error 1 */ + + DescRxEXTsts = 0x00000001, /* Extended Status Available (RDES4) 0 */ + + DescTxIntEnable = 0x40000000, /* (IC)Tx - interrupt on completion 30 */ + DescTxLast = 0x20000000, /* (LS)Tx - Last segment of the frame 29 */ + DescTxFirst = 0x10000000, /* (FS)Tx - First segment of the frame 28 */ + DescTxDisableCrc = 0x08000000, /* (DC)Tx - Add CRC disabled (first segment only) 27 */ + DescTxDisablePadd = 0x04000000, /* (DP)disable padding, added by - reyaz 26 */ + + DescTxCisMask = 0x00c00000, /* Tx checksum offloading control mask 23:22 */ + DescTxCisBypass = 0x00000000, /* Checksum bypass */ + DescTxCisIpv4HdrCs = 0x00400000, /* IPv4 header checksum */ + DescTxCisTcpOnlyCs = 0x00800000, /* TCP/UDP/ICMP checksum. Pseudo header checksum is assumed to be present */ + DescTxCisTcpPseudoCs = 0x00c00000, /* TCP/UDP/ICMP checksum fully in hardware including pseudo header */ + + TxDescEndOfRing = 0x00200000, /* (TER)End of descriptors ring 21 */ + TxDescChain = 0x00100000, /* (TCH)Second buffer address is chain address 20 */ + + DescRxChkBit0 = 0x00000001, /*() Rx - Rx Payload Checksum Error 0 */ + DescRxChkBit7 = 0x00000080, /* (IPC CS ERROR)Rx - Ipv4 header checksum error 7 */ + DescRxChkBit5 = 0x00000020, /* (FT)Rx - Frame type - Ethernet, otherwise 802.3 5 */ + + DescRxTSavail = 0x00000080, /* Time stamp available 7 */ + DescRxFrameType = 0x00000020, /* (FT)Rx - Frame type - Ethernet, otherwise 802.3 5 */ + + DescTxIpv4ChkError = 0x00010000, /* (IHE) Tx Ip header error 16 */ + DescTxTimeout = 0x00004000, /* (JT)Tx - Transmit jabber timeout 14 */ + DescTxFrameFlushed = 0x00002000, /* (FF)Tx - DMA/MTL flushed the frame due to SW flush 13 */ + DescTxPayChkError = 0x00001000, /* (PCE) Tx Payload checksum Error 12 */ + DescTxLostCarrier = 0x00000800, /* (LC)Tx - carrier lost during tramsmission 11 */ + DescTxNoCarrier = 0x00000400, /* (NC)Tx - no carrier signal from the tranceiver 10 */ + DescTxLateCollision = 0x00000200, /* (LC)Tx - transmission aborted due to collision 9 */ + DescTxExcCollisions = 0x00000100, /* (EC)Tx - transmission aborted after 16 collisions 8 */ + DescTxVLANFrame = 0x00000080, /* (VF)Tx - VLAN-type frame 7 */ + + DescTxCollMask = 0x00000078, /* (CC)Tx - Collision count 6:3 */ + DescTxCollShift = 3, + + DescTxExcDeferral = 0x00000004, /* (ED)Tx - excessive deferral 2 */ + DescTxUnderflow = 0x00000002, /* (UF)Tx - late data arrival from the memory 1 */ + DescTxDeferred = 0x00000001, /* (DB)Tx - frame transmision deferred 0 */ + + /* + This explains the RDES1/TDES1 bits layout + -------------------------------------------------------------------- + RDES1/TDES1 | Control Bits | Byte Count Buffer 2 | Byte Count Buffer 1 | + -------------------------------------------------------------------- + + */ +// DmaDescriptorLength length word of DMA descriptor + + + RxDisIntCompl = 0x80000000, /* (Disable Rx int on completion) 31 */ + RxDescEndOfRing = 0x00008000, /* (TER)End of descriptors ring 15 */ + RxDescChain = 0x00004000, /* (TCH)Second buffer address is chain address 14 */ + + + //DescSize2Mask = 0x1FFF0000, /* (TBS2) Buffer 2 size 28:16 */ + //DescSize2Shift = 16, + DescSize1Mask = 0x00001FFF, /* (TBS1) Buffer 1 size 12:0 */ + DescSize1Shift = 0, + + + /* + This explains the RDES4 Extended Status bits layout + -------------------------------------------------------------------- + RDES4 | Extended Status | + -------------------------------------------------------------------- + */ + DescRxPtpAvail = 0x00004000, /* PTP snapshot available 14 */ + DescRxPtpVer = 0x00002000, /* When set indicates IEEE1584 Version 2 (else Ver1) 13 */ + DescRxPtpFrameType = 0x00001000, /* PTP frame type Indicates PTP sent over ethernet 12 */ + DescRxPtpMessageType = 0x00000F00, /* Message Type 11:8 */ + DescRxPtpNo = 0x00000000, /* 0000 => No PTP message received */ + DescRxPtpSync = 0x00000100, /* 0001 => Sync (all clock types) received */ + DescRxPtpFollowUp = 0x00000200, /* 0010 => Follow_Up (all clock types) received */ + DescRxPtpDelayReq = 0x00000300, /* 0011 => Delay_Req (all clock types) received */ + DescRxPtpDelayResp = 0x00000400, /* 0100 => Delay_Resp (all clock types) received */ + DescRxPtpPdelayReq = 0x00000500, /* 0101 => Pdelay_Req (in P to P tras clk) or Announce in Ord and Bound clk */ + DescRxPtpPdelayResp = 0x00000600, /* 0110 => Pdealy_Resp(in P to P trans clk) or Management in Ord and Bound clk */ + DescRxPtpPdelayRespFP = 0x00000700, /* 0111 => Pdealy_Resp_Follow_Up (in P to P trans clk) or Signaling in Ord and Bound clk */ + DescRxPtpIPV6 = 0x00000080, /* Received Packet is in IPV6 Packet 7 */ + DescRxPtpIPV4 = 0x00000040, /* Received Packet is in IPV4 Packet 6 */ + + DescRxChkSumBypass = 0x00000020, /* When set indicates checksum offload engine 5 + is bypassed */ + DescRxIpPayloadError = 0x00000010, /* When set indicates 16bit IP payload CS is in error 4 */ + DescRxIpHeaderError = 0x00000008, /* When set indicates 16bit IPV4 header CS is in 3 + error or IP datagram version is not consistent + with Ethernet type value */ + DescRxIpPayloadType = 0x00000007, /* Indicate the type of payload encapsulated 2:0 + in IPdatagram processed by COE (Rx) */ + DescRxIpPayloadUnknown= 0x00000000, /* Unknown or didnot process IP payload */ + DescRxIpPayloadUDP = 0x00000001, /* UDP */ + DescRxIpPayloadTCP = 0x00000002, /* TCP */ + DescRxIpPayloadICMP = 0x00000003, /* ICMP */ + +}; + + +/********************************************************** + * Initial register values + **********************************************************/ +enum InitialRegisters +{ + /* Full-duplex mode with perfect filter on */ + GmacConfigInitFdx1000 = GmacWatchdogEnable | GmacJabberEnable | GmacFrameBurstEnable | GmacJumboFrameDisable + | GmacSelectGmii | GmacEnableRxOwn | GmacLoopbackOff + | GmacFullDuplex | GmacRetryEnable | GmacPadCrcStripDisable + | GmacBackoffLimit0 | GmacDeferralCheckDisable | GmacTxEnable | GmacRxEnable, + + /* Full-duplex mode with perfect filter on */ + GmacConfigInitFdx110 = GmacWatchdogEnable | GmacJabberEnable | GmacFrameBurstEnable | GmacJumboFrameDisable + | GmacSelectMii | GmacEnableRxOwn | GmacLoopbackOff + | GmacFullDuplex | GmacRetryEnable | GmacPadCrcStripDisable + | GmacBackoffLimit0 | GmacDeferralCheckDisable | GmacTxEnable | GmacRxEnable, + + /* Full-duplex mode */ + // CHANGED: Pass control config, dest addr filter normal, added source address filter, multicast & unicast + // Hash filter. + /* = GmacFilterOff | GmacPassControlOff | GmacBroadcastEnable */ + GmacFrameFilterInitFdx = GmacFilterOn | GmacPassControl0 | GmacBroadcastEnable | GmacSrcAddrFilterDisable + | GmacMulticastFilterOn | GmacDestAddrFilterNor | GmacMcastHashFilterOff + | GmacPromiscuousModeOff | GmacUcastHashFilterOff, + + /* Full-duplex mode */ + GmacFlowControlInitFdx = GmacUnicastPauseFrameOff | GmacRxFlowControlEnable | GmacTxFlowControlEnable, + + /* Full-duplex mode */ + GmacGmiiAddrInitFdx = GmiiCsrClk2, + + + /* Half-duplex mode with perfect filter on */ + // CHANGED: Removed Endian configuration, added single bit config for PAD/CRC strip, + /*| GmacSelectMii | GmacLittleEndian | GmacDisableRxOwn | GmacLoopbackOff*/ + GmacConfigInitHdx1000 = GmacWatchdogEnable | GmacJabberEnable | GmacFrameBurstEnable | GmacJumboFrameDisable + | GmacSelectGmii | GmacDisableRxOwn | GmacLoopbackOff + | GmacHalfDuplex | GmacRetryEnable | GmacPadCrcStripDisable + | GmacBackoffLimit0 | GmacDeferralCheckDisable | GmacTxEnable | GmacRxEnable, + + /* Half-duplex mode with perfect filter on */ + GmacConfigInitHdx110 = GmacWatchdogEnable | GmacJabberEnable | GmacFrameBurstEnable | GmacJumboFrameDisable + | GmacSelectMii | GmacDisableRxOwn | GmacLoopbackOff + | GmacHalfDuplex | GmacRetryEnable | GmacPadCrcStripDisable + | GmacBackoffLimit0 | GmacDeferralCheckDisable | GmacTxEnable | GmacRxEnable, + + /* Half-duplex mode */ + GmacFrameFilterInitHdx = GmacFilterOn | GmacPassControl0 | GmacBroadcastEnable | GmacSrcAddrFilterDisable + | GmacMulticastFilterOn | GmacDestAddrFilterNor | GmacMcastHashFilterOff + | GmacUcastHashFilterOff| GmacPromiscuousModeOff, + + /* Half-duplex mode */ + GmacFlowControlInitHdx = GmacUnicastPauseFrameOff | GmacRxFlowControlDisable | GmacTxFlowControlDisable, + + /* Half-duplex mode */ + GmacGmiiAddrInitHdx = GmiiCsrClk2, + + + + /********************************************* + *DMA configurations + **********************************************/ + + DmaBusModeInit = DmaFixedBurstEnable | DmaBurstLength8 | DmaDescriptorSkip2 | DmaResetOff, +// DmaBusModeInit = DmaFixedBurstEnable | DmaBurstLength8 | DmaDescriptorSkip4 | DmaResetOff, + + /* 1000 Mb/s mode */ + DmaControlInit1000 = DmaStoreAndForward,// | DmaTxSecondFrame , + + /* 100 Mb/s mode */ + DmaControlInit100 = DmaStoreAndForward, + + /* 10 Mb/s mode */ + DmaControlInit10 = DmaStoreAndForward, + + /* Interrupt groups */ + DmaIntErrorMask = DmaIntBusError, /* Error */ + DmaIntRxAbnMask = DmaIntRxNoBuffer, /* receiver abnormal interrupt */ + DmaIntRxNormMask = DmaIntRxCompleted, /* receiver normal interrupt */ + DmaIntRxStoppedMask = DmaIntRxStopped, /* receiver stopped */ + DmaIntTxAbnMask = DmaIntTxUnderflow, /* transmitter abnormal interrupt */ + DmaIntTxNormMask = DmaIntTxCompleted, /* transmitter normal interrupt */ + DmaIntTxStoppedMask = DmaIntTxStopped, /* transmitter stopped */ + + DmaIntEnable = DmaIeNormal | DmaIeAbnormal | DmaIntErrorMask + | DmaIntRxAbnMask | DmaIntRxNormMask | DmaIntRxStoppedMask + | DmaIntTxAbnMask | DmaIntTxNormMask | DmaIntTxStoppedMask, + DmaIntDisable = 0, +}; + + +/********************************************************** + * Mac Management Counters (MMC) + **********************************************************/ + +enum MMC_ENABLE +{ + GmacMmcCntrl = 0x0100, /* mmc control for operating mode of MMC */ + GmacMmcIntrRx = 0x0104, /* maintains interrupts generated by rx counters */ + GmacMmcIntrTx = 0x0108, /* maintains interrupts generated by tx counters */ + GmacMmcIntrMaskRx = 0x010C, /* mask for interrupts generated from rx counters */ + GmacMmcIntrMaskTx = 0x0110, /* mask for interrupts generated from tx counters */ +}; +enum MMC_TX +{ + GmacMmcTxOctetCountGb = 0x0114, /*Bytes Tx excl. of preamble and retried bytes (Good or Bad) */ + GmacMmcTxFrameCountGb = 0x0118, /*Frames Tx excl. of retried frames (Good or Bad) */ + GmacMmcTxBcFramesG = 0x011C, /*Broadcast Frames Tx (Good) */ + GmacMmcTxMcFramesG = 0x0120, /*Multicast Frames Tx (Good) */ + + GmacMmcTx64OctetsGb = 0x0124, /*Tx with len 64 bytes excl. of pre and retried (Good or Bad) */ + GmacMmcTx65To127OctetsGb = 0x0128, /*Tx with len >64 bytes <=127 excl. of pre and retried (Good or Bad) */ + GmacMmcTx128To255OctetsGb = 0x012C, /*Tx with len >128 bytes <=255 excl. of pre and retried (Good or Bad) */ + GmacMmcTx256To511OctetsGb = 0x0130, /*Tx with len >256 bytes <=511 excl. of pre and retried (Good or Bad) */ + GmacMmcTx512To1023OctetsGb = 0x0134, /*Tx with len >512 bytes <=1023 excl. of pre and retried (Good or Bad) */ + GmacMmcTx1024ToMaxOctetsGb = 0x0138, /*Tx with len >1024 bytes <=MaxSize excl. of pre and retried (Good or Bad) */ + + GmacMmcTxUcFramesGb = 0x013C, /*Unicast Frames Tx (Good or Bad) */ + GmacMmcTxMcFramesGb = 0x0140, /*Multicast Frames Tx (Good and Bad) */ + GmacMmcTxBcFramesGb = 0x0144, /*Broadcast Frames Tx (Good and Bad) */ + GmacMmcTxUnderFlowError = 0x0148, /*Frames aborted due to Underflow error */ + GmacMmcTxSingleColG = 0x014C, /*Successfully Tx Frames after singel collision in Half duplex mode */ + GmacMmcTxMultiColG = 0x0150, /*Successfully Tx Frames after more than singel collision in Half duplex mode */ + GmacMmcTxDeferred = 0x0154, /*Successfully Tx Frames after a deferral in Half duplex mode */ + GmacMmcTxLateCol = 0x0158, /*Frames aborted due to late collision error */ + GmacMmcTxExessCol = 0x015C, /*Frames aborted due to excessive (16) collision errors */ + GmacMmcTxCarrierError = 0x0160, /*Frames aborted due to carrier sense error (No carrier or Loss of carrier) */ + GmacMmcTxOctetCountG = 0x0164, /*Bytes Tx excl. of preamble and retried bytes (Good) */ + GmacMmcTxFrameCountG = 0x0168, /*Frames Tx (Good) */ + GmacMmcTxExessDef = 0x016C, /*Frames aborted due to excessive deferral errors (deferred for more than 2 max-sized frame times)*/ + + GmacMmcTxPauseFrames = 0x0170, /*Number of good pause frames Tx. */ + GmacMmcTxVlanFramesG = 0x0174, /*Number of good Vlan frames Tx excl. retried frames */ +}; +enum MMC_RX +{ + GmacMmcRxFrameCountGb = 0x0180, /*Frames Rx (Good or Bad) */ + GmacMmcRxOctetCountGb = 0x0184, /*Bytes Rx excl. of preamble and retried bytes (Good or Bad) */ + GmacMmcRxOctetCountG = 0x0188, /*Bytes Rx excl. of preamble and retried bytes (Good) */ + GmacMmcRxBcFramesG = 0x018C, /*Broadcast Frames Rx (Good) */ + GmacMmcRxMcFramesG = 0x0190, /*Multicast Frames Rx (Good) */ + + GmacMmcRxCrcError = 0x0194, /*Number of frames received with CRC error */ + GmacMmcRxAlignError = 0x0198, /*Number of frames received with alignment (dribble) error. Only in 10/100mode */ + GmacMmcRxRuntError = 0x019C, /*Number of frames received with runt (<64 bytes and CRC error) error */ + GmacMmcRxJabberError = 0x01A0, /*Number of frames rx with jabber (>1518/1522 or >9018/9022 and CRC) */ + GmacMmcRxUnderSizeG = 0x01A4, /*Number of frames received with <64 bytes without any error */ + GmacMmcRxOverSizeG = 0x01A8, /*Number of frames received with >1518/1522 bytes without any error */ + + GmacMmcRx64OctetsGb = 0x01AC, /*Rx with len 64 bytes excl. of pre and retried (Good or Bad) */ + GmacMmcRx65To127OctetsGb = 0x01B0, /*Rx with len >64 bytes <=127 excl. of pre and retried (Good or Bad) */ + GmacMmcRx128To255OctetsGb = 0x01B4, /*Rx with len >128 bytes <=255 excl. of pre and retried (Good or Bad) */ + GmacMmcRx256To511OctetsGb = 0x01B8, /*Rx with len >256 bytes <=511 excl. of pre and retried (Good or Bad) */ + GmacMmcRx512To1023OctetsGb = 0x01BC, /*Rx with len >512 bytes <=1023 excl. of pre and retried (Good or Bad) */ + GmacMmcRx1024ToMaxOctetsGb = 0x01C0, /*Rx with len >1024 bytes <=MaxSize excl. of pre and retried (Good or Bad) */ + + GmacMmcRxUcFramesG = 0x01C4, /*Unicast Frames Rx (Good) */ + GmacMmcRxLengthError = 0x01C8, /*Number of frames received with Length type field != frame size */ + GmacMmcRxOutOfRangeType = 0x01CC, /*Number of frames received with length field != valid frame size */ + + GmacMmcRxPauseFrames = 0x01D0, /*Number of good pause frames Rx. */ + GmacMmcRxFifoOverFlow = 0x01D4, /*Number of missed rx frames due to FIFO overflow */ + GmacMmcRxVlanFramesGb = 0x01D8, /*Number of good Vlan frames Rx */ + + GmacMmcRxWatchdobError = 0x01DC, /*Number of frames rx with error due to watchdog timeout error */ +}; +enum MMC_IP_RELATED +{ + GmacMmcRxIpcIntrMask = 0x0200, /*Maintains the mask for interrupt generated from rx IPC statistic counters */ + GmacMmcRxIpcIntr = 0x0208, /*Maintains the interrupt that rx IPC statistic counters generate */ + + GmacMmcRxIpV4FramesG = 0x0210, /*Good IPV4 datagrams received */ + GmacMmcRxIpV4HdrErrFrames = 0x0214, /*Number of IPV4 datagrams received with header errors */ + GmacMmcRxIpV4NoPayFrames = 0x0218, /*Number of IPV4 datagrams received which didnot have TCP/UDP/ICMP payload */ + GmacMmcRxIpV4FragFrames = 0x021C, /*Number of IPV4 datagrams received with fragmentation */ + GmacMmcRxIpV4UdpChkDsblFrames = 0x0220, /*Number of IPV4 datagrams received that had a UDP payload checksum disabled */ + + GmacMmcRxIpV6FramesG = 0x0224, /*Good IPV6 datagrams received */ + GmacMmcRxIpV6HdrErrFrames = 0x0228, /*Number of IPV6 datagrams received with header errors */ + GmacMmcRxIpV6NoPayFrames = 0x022C, /*Number of IPV6 datagrams received which didnot have TCP/UDP/ICMP payload */ + + GmacMmcRxUdpFramesG = 0x0230, /*Number of good IP datagrams with good UDP payload */ + GmacMmcRxUdpErrorFrames = 0x0234, /*Number of good IP datagrams with UDP payload having checksum error */ + + GmacMmcRxTcpFramesG = 0x0238, /*Number of good IP datagrams with good TDP payload */ + GmacMmcRxTcpErrorFrames = 0x023C, /*Number of good IP datagrams with TCP payload having checksum error */ + + GmacMmcRxIcmpFramesG = 0x0240, /*Number of good IP datagrams with good Icmp payload */ + GmacMmcRxIcmpErrorFrames = 0x0244, /*Number of good IP datagrams with Icmp payload having checksum error */ + + GmacMmcRxIpV4OctetsG = 0x0250, /*Good IPV4 datagrams received excl. Ethernet hdr,FCS,Pad,Ip Pad bytes */ + GmacMmcRxIpV4HdrErrorOctets = 0x0254, /*Number of bytes in IPV4 datagram with header errors */ + GmacMmcRxIpV4NoPayOctets = 0x0258, /*Number of bytes in IPV4 datagram with no TCP/UDP/ICMP payload */ + GmacMmcRxIpV4FragOctets = 0x025C, /*Number of bytes received in fragmented IPV4 datagrams */ + GmacMmcRxIpV4UdpChkDsblOctets = 0x0260, /*Number of bytes received in UDP segment that had UDP checksum disabled */ + + GmacMmcRxIpV6OctetsG = 0x0264, /*Good IPV6 datagrams received excl. Ethernet hdr,FCS,Pad,Ip Pad bytes */ + GmacMmcRxIpV6HdrErrorOctets = 0x0268, /*Number of bytes in IPV6 datagram with header errors */ + GmacMmcRxIpV6NoPayOctets = 0x026C, /*Number of bytes in IPV6 datagram with no TCP/UDP/ICMP payload */ + + GmacMmcRxUdpOctetsG = 0x0270, /*Number of bytes in IP datagrams with good UDP payload */ + GmacMmcRxUdpErrorOctets = 0x0274, /*Number of bytes in IP datagrams with UDP payload having checksum error */ + + GmacMmcRxTcpOctetsG = 0x0278, /*Number of bytes in IP datagrams with good TDP payload */ + GmacMmcRxTcpErrorOctets = 0x027C, /*Number of bytes in IP datagrams with TCP payload having checksum error */ + + GmacMmcRxIcmpOctetsG = 0x0280, /*Number of bytes in IP datagrams with good Icmp payload */ + GmacMmcRxIcmpErrorOctets = 0x0284, /*Number of bytes in IP datagrams with Icmp payload having checksum error */ +}; + + +enum MMC_CNTRL_REG_BIT_DESCRIPTIONS +{ + GmacMmcCounterFreeze = 0x00000008, /* when set MMC counters freeze to current value */ + GmacMmcCounterResetOnRead = 0x00000004, /* when set MMC counters will be reset to 0 after read */ + GmacMmcCounterStopRollover = 0x00000002, /* when set counters will not rollover after max value */ + GmacMmcCounterReset = 0x00000001, /* when set all counters wil be reset (automatically cleared after 1 clk) */ + +}; + +enum MMC_RX_INTR_MASK_AND_STATUS_BIT_DESCRIPTIONS +{ + GmacMmcRxWDInt = 0x00800000, /* set when rxwatchdog error reaches half of max value */ + GmacMmcRxVlanInt = 0x00400000, /* set when GmacMmcRxVlanFramesGb counter reaches half of max value */ + GmacMmcRxFifoOverFlowInt = 0x00200000, /* set when GmacMmcRxFifoOverFlow counter reaches half of max value */ + GmacMmcRxPauseFrameInt = 0x00100000, /* set when GmacMmcRxPauseFrames counter reaches half of max value */ + GmacMmcRxOutOfRangeInt = 0x00080000, /* set when GmacMmcRxOutOfRangeType counter reaches half of max value */ + GmacMmcRxLengthErrorInt = 0x00040000, /* set when GmacMmcRxLengthError counter reaches half of max value */ + GmacMmcRxUcFramesInt = 0x00020000, /* set when GmacMmcRxUcFramesG counter reaches half of max value */ + GmacMmcRx1024OctInt = 0x00010000, /* set when GmacMmcRx1024ToMaxOctetsGb counter reaches half of max value */ + GmacMmcRx512OctInt = 0x00008000, /* set when GmacMmcRx512To1023OctetsGb counter reaches half of max value */ + GmacMmcRx256OctInt = 0x00004000, /* set when GmacMmcRx256To511OctetsGb counter reaches half of max value */ + GmacMmcRx128OctInt = 0x00002000, /* set when GmacMmcRx128To255OctetsGb counter reaches half of max value */ + GmacMmcRx65OctInt = 0x00001000, /* set when GmacMmcRx65To127OctetsG counter reaches half of max value */ + GmacMmcRx64OctInt = 0x00000800, /* set when GmacMmcRx64OctetsGb counter reaches half of max value */ + GmacMmcRxOverSizeInt = 0x00000400, /* set when GmacMmcRxOverSizeG counter reaches half of max value */ + GmacMmcRxUnderSizeInt = 0x00000200, /* set when GmacMmcRxUnderSizeG counter reaches half of max value */ + GmacMmcRxJabberErrorInt = 0x00000100, /* set when GmacMmcRxJabberError counter reaches half of max value */ + GmacMmcRxRuntErrorInt = 0x00000080, /* set when GmacMmcRxRuntError counter reaches half of max value */ + GmacMmcRxAlignErrorInt = 0x00000040, /* set when GmacMmcRxAlignError counter reaches half of max value */ + GmacMmcRxCrcErrorInt = 0x00000020, /* set when GmacMmcRxCrcError counter reaches half of max value */ + GmacMmcRxMcFramesInt = 0x00000010, /* set when GmacMmcRxMcFramesG counter reaches half of max value */ + GmacMmcRxBcFramesInt = 0x00000008, /* set when GmacMmcRxBcFramesG counter reaches half of max value */ + GmacMmcRxOctetGInt = 0x00000004, /* set when GmacMmcRxOctetCountG counter reaches half of max value */ + GmacMmcRxOctetGbInt = 0x00000002, /* set when GmacMmcRxOctetCountGb counter reaches half of max value */ + GmacMmcRxFrameInt = 0x00000001, /* set when GmacMmcRxFrameCountGb counter reaches half of max value */ +}; + +enum MMC_TX_INTR_MASK_AND_STATUS_BIT_DESCRIPTIONS +{ + + GmacMmcTxVlanInt = 0x01000000, /* set when GmacMmcTxVlanFramesG counter reaches half of max value */ + GmacMmcTxPauseFrameInt = 0x00800000, /* set when GmacMmcTxPauseFrames counter reaches half of max value */ + GmacMmcTxExessDefInt = 0x00400000, /* set when GmacMmcTxExessDef counter reaches half of max value */ + GmacMmcTxFrameInt = 0x00200000, /* set when GmacMmcTxFrameCount counter reaches half of max value */ + GmacMmcTxOctetInt = 0x00100000, /* set when GmacMmcTxOctetCountG counter reaches half of max value */ + GmacMmcTxCarrierErrorInt = 0x00080000, /* set when GmacMmcTxCarrierError counter reaches half of max value */ + GmacMmcTxExessColInt = 0x00040000, /* set when GmacMmcTxExessCol counter reaches half of max value */ + GmacMmcTxLateColInt = 0x00020000, /* set when GmacMmcTxLateCol counter reaches half of max value */ + GmacMmcTxDeferredInt = 0x00010000, /* set when GmacMmcTxDeferred counter reaches half of max value */ + GmacMmcTxMultiColInt = 0x00008000, /* set when GmacMmcTxMultiColG counter reaches half of max value */ + GmacMmcTxSingleCol = 0x00004000, /* set when GmacMmcTxSingleColG counter reaches half of max value */ + GmacMmcTxUnderFlowErrorInt = 0x00002000, /* set when GmacMmcTxUnderFlowError counter reaches half of max value */ + GmacMmcTxBcFramesGbInt = 0x00001000, /* set when GmacMmcTxBcFramesGb counter reaches half of max value */ + GmacMmcTxMcFramesGbInt = 0x00000800, /* set when GmacMmcTxMcFramesGb counter reaches half of max value */ + GmacMmcTxUcFramesInt = 0x00000400, /* set when GmacMmcTxUcFramesGb counter reaches half of max value */ + GmacMmcTx1024OctInt = 0x00000200, /* set when GmacMmcTx1024ToMaxOctetsGb counter reaches half of max value */ + GmacMmcTx512OctInt = 0x00000100, /* set when GmacMmcTx512To1023OctetsGb counter reaches half of max value */ + GmacMmcTx256OctInt = 0x00000080, /* set when GmacMmcTx256To511OctetsGb counter reaches half of max value */ + GmacMmcTx128OctInt = 0x00000040, /* set when GmacMmcTx128To255OctetsGb counter reaches half of max value */ + GmacMmcTx65OctInt = 0x00000020, /* set when GmacMmcTx65To127OctetsGb counter reaches half of max value */ + GmacMmcTx64OctInt = 0x00000010, /* set when GmacMmcTx64OctetsGb counter reaches half of max value */ + GmacMmcTxMcFramesInt = 0x00000008, /* set when GmacMmcTxMcFramesG counter reaches half of max value */ + GmacMmcTxBcFramesInt = 0x00000004, /* set when GmacMmcTxBcFramesG counter reaches half of max value */ + GmacMmcTxFrameGbInt = 0x00000002, /* set when GmacMmcTxFrameCountGb counter reaches half of max value */ + GmacMmcTxOctetGbInt = 0x00000001, /* set when GmacMmcTxOctetCountGb counter reaches half of max value */ + +}; + + +/********************************************************** + * Power Management (PMT) Block + **********************************************************/ + +/* + * PMT supports the reception of network (remote) wake-up frames and Magic packet frames. + * It generates interrupts for wake-up frames and Magic packets received by GMAC. + * PMT sits in Rx path and is enabled with remote wake-up frame enable and Magic packet enable. + * These enable are in PMT control and Status register and are programmed by apllication. + * + * When power down mode is enabled in PMT, all rx frames are dropped by the core. Core comes + * out of power down mode only when either Magic packe tor a Remote wake-up frame is received + * and the corresponding detection is enabled. + * + * Driver need not be modified to support this feature. Only Api to put the device in to power + * down mode is sufficient + */ + +#define WAKEUP_REG_LENGTH 8 /*This is the reg length for wake up register configuration*/ + +enum GmacPmtCtrlStatusBitDefinition +{ + GmacPmtFrmFilterPtrReset = 0x80000000, /* when set remote wake-up frame filter register pointer to 3'b000 */ + GmacPmtGlobalUnicast = 0x00000200, /* When set enables any unicast packet to be a wake-up frame */ + GmacPmtWakeupFrameReceived = 0x00000040, /* Wake up frame received */ + GmacPmtMagicPktReceived = 0x00000020, /* Magic Packet received */ + GmacPmtWakeupFrameEnable = 0x00000004, /* Wake-up frame enable */ + GmacPmtMagicPktEnable = 0x00000002, /* Magic packet enable */ + GmacPmtPowerDown = 0x00000001, /* Power Down */ +}; + + + + +/********************************************************** + * IEEE 1588-2008 Precision Time Protocol (PTP) Support + **********************************************************/ +enum PTPMessageType +{ + SYNC = 0x0, + Delay_Req = 0x1, + Pdelay_Req = 0x2, + Pdelay_Resp = 0x3, + Follow_up = 0x8, + Delay_Resp = 0x9, + Pdelay_Resp_Follow_Up = 0xA, + Announce = 0xB, + Signaling = 0xC, + Management = 0xD, +}; + + +/* + * IEEE 1588-2008 is the optional module to support Ethernet frame time stamping. + * Sixty four (+16) bit time stamps are given in each frames transmit and receive status. + * The driver assumes the following + * 1. "IEEE 1588 Time Stamping" "TIME_STAMPING"is ENABLED in corekit + * 2. "IEEE 1588 External Time Stamp Input Enable" "EXT_TIME_STAMPING" is DISABLED in corekit + * 3. "IEEE 1588 Advanced Time Stamp support" "ADV_TIME_STAMPING" is ENABLED in corekit + * 4. "IEEE 1588 Higher Word Register Enable" "ADV_TIME_HIGH_WORD" is ENABLED in corekit + */ + +/* GmacTSControl = 0x0700, Controls the Timestamp update logic : only when IEEE 1588 time stamping is enabled in corekit */ +enum GmacTSControlReg +{ + GmacTSENMACADDR = 0x00040000, /* Enable Mac Addr for PTP filtering 18 RW 0 */ + + GmacTSCLKTYPE = 0x00030000, /* Select the type of clock node 17:16 RW 00 */ + /* + TSCLKTYPE TSMSTRENA TSEVNTENA Messages for wihich TS snapshot is taken + 00/01 X 0 SYNC, FOLLOW_UP, DELAY_REQ, DELAY_RESP + 00/01 1 0 DELAY_REQ + 00/01 0 1 SYNC + 10 NA 0 SYNC, FOLLOW_UP, DELAY_REQ, DELAY_RESP + 10 NA 1 SYNC, FOLLOW_UP + 11 NA 0 SYNC, FOLLOW_UP, DELAY_REQ, DELAY_RESP, PDELAY_REQ, PDELAY_RESP + 11 NA 1 SYNC, PDELAY_REQ, PDELAY_RESP + */ + GmacTSOrdClk = 0x00000000, /* 00=> Ordinary clock*/ + GmacTSBouClk = 0x00010000, /* 01=> Boundary clock*/ + GmacTSEtoEClk = 0x00020000, /* 10=> End-to-End transparent clock*/ + GmacTSPtoPClk = 0x00030000, /* 11=> P-to-P transparent clock*/ + + GmacTSMSTRENA = 0x00008000, /* Ena TS Snapshot for Master Messages 15 RW 0 */ + GmacTSEVNTENA = 0x00004000, /* Ena TS Snapshot for Event Messages 14 RW 0 */ + GmacTSIPV4ENA = 0x00002000, /* Ena TS snapshot for IPv4 13 RW 1 */ + GmacTSIPV6ENA = 0x00001000, /* Ena TS snapshot for IPv6 12 RW 0 */ + GmacTSIPENA = 0x00000800, /* Ena TS snapshot for PTP over E'net 11 RW 0 */ + GmacTSVER2ENA = 0x00000400, /* Ena PTP snooping for version 2 10 RW 0 */ + + GmacTSCTRLSSR = 0x00000200, /* Digital or Binary Rollover 9 RW 0 */ + + GmacTSENALL = 0x00000100, /* Enable TS fro all frames (Ver2 only) 8 RW 0 */ + + GmacTSADDREG = 0x00000020, /* Addend Register Update 5 RW_SC 0 */ + GmacTSUPDT = 0x00000008, /* Time Stamp Update 3 RW_SC 0 */ + GmacTSINT = 0x00000004, /* Time Atamp Initialize 2 RW_SC 0 */ + + GmacTSTRIG = 0x00000010, /* Time stamp interrupt Trigger Enable 4 RW_SC 0 */ + + GmacTSCFUPDT = 0x00000002, /* Time Stamp Fine/Coarse 1 RW 0 */ + GmacTSCUPDTCoarse = 0x00000000, /* 0=> Time Stamp update method is coarse */ + GmacTSCUPDTFine = 0x00000002, /* 1=> Time Stamp update method is fine */ + + GmacTSENA = 0x00000001, /* Time Stamp Enable 0 RW 0 */ +}; + + +/* GmacTSSubSecIncr = 0x0704, 8 bit value by which sub second register is incremented : only when IEEE 1588 time stamping without external timestamp input */ +enum GmacTSSubSecIncrReg +{ + GmacSSINCMsk = 0x000000FF, /* Only Lower 8 bits are valid bits 7:0 RW 00 */ +}; + +/* GmacTSLow = 0x070C, Indicates whether the timestamp low count is positive or negative; for Adv timestamp it is always zero */ +enum GmacTSSign +{ + GmacTSSign = 0x80000000, /* PSNT 31 RW 0 */ + GmacTSPositive = 0x00000000, + GmacTSNegative = 0x80000000, +}; + +/*GmacTargetTimeLow = 0x0718, 32 bit nano seconds(MS) to be compared with system time : only when IEEE 1588 time stamping without external timestamp input */ +enum GmacTSLowReg +{ + GmacTSDecThr = 0x3B9AC9FF, /*when TSCTRLSSR is set the max value for GmacTargetTimeLowReg and GmacTimeStampLow register is 0x3B9AC9FF at 1ns precision */ +}; + +/* GmacTSHighWord = 0x0724, Time Stamp Higher Word Register (Version 2 only); only lower 16 bits are valid */ +enum GmacTSHighWordReg +{ + GmacTSHighWordMask = 0x0000FFFF, /* Time Stamp Higher work register has only lower 16 bits valid */ +}; +/*GmacTSStatus = 0x0728, Time Stamp Status Register */ +enum GmacTSStatusReg +{ + GmacTSTargTimeReached = 0x00000002, /* Time Stamp Target Time Reached 1 RO 0 */ + GmacTSSecondsOverflow = 0x00000001, /* Time Stamp Seconds Overflow 0 RO 0 */ +}; + +/********************************************************** + * Time stamp related functions + **********************************************************/ +void synopGMAC_TS_enable(synopGMACdevice *gmacdev); +void synopGMAC_TS_disable(synopGMACdevice *gmacdev); + +void synopGMAC_TS_int_enable(synopGMACdevice *gmacdev); +void synopGMAC_TS_int_disable(synopGMACdevice *gmacdev); + +void synopGMAC_TS_mac_addr_filt_enable(synopGMACdevice *gmacdev); +void synopGMAC_TS_mac_addr_filt_disable(synopGMACdevice *gmacdev); +void synopGMAC_TS_set_clk_type(synopGMACdevice *gmacdev, u32 clk_type); +void synopGMAC_TS_master_enable(synopGMACdevice *gmacdev); // Only for Ordinary clock and Boundary clock and "Advanced Time Stamp" +void synopGMAC_TS_master_disable(synopGMACdevice *gmacdev); // Only for Ordinary clock and Boundary clock and "Advanced Time Stamp" +void synopGMAC_TS_event_enable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" +void synopGMAC_TS_event_disable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" +void synopGMAC_TS_IPV4_enable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" +void synopGMAC_TS_IPV4_disable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" +void synopGMAC_TS_IPV6_enable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" +void synopGMAC_TS_IPV6_disable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" +void synopGMAC_TS_ptp_over_ethernet_enable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" +void synopGMAC_TS_ptp_over_ethernet_disable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" +void synopGMAC_TS_pkt_snoop_ver2(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" +void synopGMAC_TS_pkt_snoop_ver1(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" + +void synopGMAC_TS_digital_rollover_enable(synopGMACdevice *gmacdev); +void synopGMAC_TS_binary_rollover_enable(synopGMACdevice *gmacdev); +void synopGMAC_TS_all_frames_enable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" +void synopGMAC_TS_all_frames_disable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" + +s32 synopGMAC_TS_addend_update(synopGMACdevice *gmacdev, u32 addend_value); +s32 synopGMAC_TS_timestamp_update(synopGMACdevice *gmacdev, u32 high_value, u32 low_value); +s32 synopGMAC_TS_timestamp_init(synopGMACdevice *gmacdev, u32 high_value, u32 low_value); + +void synopGMAC_TS_coarse_update(synopGMACdevice *gmacdev); // Only if "fine correction" enabled +void synopGMAC_TS_fine_update(synopGMACdevice *gmacdev); // Only if "fine correction" enabled + +void synopGMAC_TS_subsecond_init(synopGMACdevice *gmacdev, u32 sub_sec_inc_val); // Update should happen making use of subsecond mask +void synopGMAC_TS_read_timestamp(synopGMACdevice *gmacdev, u16 * higher_sec_val, + u32 * sec_val, u32 * sub_sec_val); // Reads the timestamp low,high and higher(Ver2) registers in the the struct pointer; readonly contents +void synopGMAC_TS_load_target_timestamp(synopGMACdevice *gmacdev, u32 sec_val, u32 sub_sec_val); //Loads the timestamp target register with the values provided + +void synopGMAC_TS_load_timestamp_higher_val(synopGMACdevice *gmacdev, u32 higher_sec_val); +void synopGMAC_TS_read_timestamp_higher_val(synopGMACdevice *gmacdev, u16 * higher_sec_val); +void synopGMAC_TS_read_target_timestamp(synopGMACdevice *gmacdev, u32 * sec_val, u32 * sub_sec_val); //Read the target time stamp register contents + +/*******************Ip checksum offloading APIs***************************************/ +void synopGMAC_enable_rx_chksum_offload(synopGMACdevice *gmacdev); +void synopGMAC_disable_rx_Ipchecksum_offload(synopGMACdevice *gmacdev); +void synopGMAC_rx_tcpip_chksum_drop_enable(synopGMACdevice *gmacdev); +void synopGMAC_rx_tcpip_chksum_drop_disable(synopGMACdevice *gmacdev); + +/* + * Decodes the Rx Descriptor status to various checksum error conditions. + * @param[in] pointer to synopGMACdevice. + * @param[in] u32 status field of the corresponding descriptor. + * \return returns decoded enum (u32) indicating the status. + */ +static inline u32 synopGMAC_is_rx_checksum_error(synopGMACdevice *gmacdev, u32 status) +{ + return (status & (DescRxChkBit7 | DescRxChkBit5 | DescRxChkBit0)); +} + +/* + * Checks if any Ipv4 header checksum error in the frame just transmitted. + * This serves as indication that error occureed in the IPv4 header checksum insertion. + * The sent out frame doesnot carry any ipv4 header checksum inserted by the hardware. + * @param[in] pointer to synopGMACdevice. + * @param[in] u32 status field of the corresponding descriptor. + * \return returns true if error in ipv4 header checksum, else returns false. + */ +static inline bool synopGMAC_is_tx_ipv4header_checksum_error(synopGMACdevice *gmacdev, u32 status) +{ + return((status & DescTxIpv4ChkError) == DescTxIpv4ChkError); +} + +/* + * Checks if any payload checksum error in the frame just transmitted. + * This serves as indication that error occureed in the payload checksum insertion. + * The sent out frame doesnot carry any payload checksum inserted by the hardware. + * @param[in] pointer to synopGMACdevice. + * @param[in] u32 status field of the corresponding descriptor. + * \return returns true if error in ipv4 header checksum, else returns false. + */ +static inline bool synopGMAC_is_tx_payload_checksum_error(synopGMACdevice *gmacdev, u32 status) +{ + return((status & DescTxPayChkError) == DescTxPayChkError); +} + +/* + * The check summ offload engine is bypassed in the tx path. + * Checksum is not computed in the Hardware. + * @param[in] pointer to synopGMACdevice. + * @param[in] Pointer to tx descriptor for which ointer to synopGMACdevice. + * \return returns void. + */ +static inline void synopGMAC_tx_checksum_offload_bypass(synopGMACdevice *gmacdev, DmaDesc *desc) +{ + #ifdef ENH_DESC + desc->status = (desc->length & (~DescTxCisMask));//ENH_DESC + #else + desc->length = (desc->length & (~DescTxCisMask)); + #endif + +} + +/* + * The check summ offload engine is enabled to do only IPV4 header checksum. + * IPV4 header Checksum is computed in the Hardware. + * @param[in] pointer to synopGMACdevice. + * @param[in] Pointer to tx descriptor for which ointer to synopGMACdevice. + * \return returns void. + */ +static inline void synopGMAC_tx_checksum_offload_ipv4hdr(synopGMACdevice *gmacdev, DmaDesc *desc) +{ + #ifdef ENH_DESC + desc->status = ((desc->status & (~DescTxCisMask)) | DescTxCisIpv4HdrCs);//ENH_DESC + #else + desc->length = ((desc->length & (~DescTxCisMask)) | DescTxCisIpv4HdrCs); + #endif + +} + +/* + * The check summ offload engine is enabled to do TCPIP checsum assuming Pseudo header is available. + * Hardware computes the tcp ip checksum assuming pseudo header checksum is computed in software. + * Ipv4 header checksum is also inserted. + * @param[in] pointer to synopGMACdevice. + * @param[in] Pointer to tx descriptor for which ointer to synopGMACdevice. + * \return returns void. + */ +static inline void synopGMAC_tx_checksum_offload_tcponly(synopGMACdevice *gmacdev, DmaDesc *desc) +{ + #ifdef ENH_DESC + desc->status = ((desc->status & (~DescTxCisMask)) | DescTxCisTcpOnlyCs);//ENH_DESC + #else + desc->length = ((desc->length & (~DescTxCisMask)) | DescTxCisTcpOnlyCs); + #endif + +} + +/* + * The check summ offload engine is enabled to do complete checksum computation. + * Hardware computes the tcp ip checksum including the pseudo header checksum. + * Here the tcp payload checksum field should be set to 0000. + * Ipv4 header checksum is also inserted. + * @param[in] pointer to synopGMACdevice. + * @param[in] Pointer to tx descriptor for which ointer to synopGMACdevice. + * \return returns void. + */ +static inline void synopGMAC_tx_checksum_offload_tcp_pseudo(synopGMACdevice *gmacdev, DmaDesc *desc) +{ + #ifdef ENH_DESC + desc->status = ((desc->length & (~DescTxCisMask)) | DescTxCisTcpPseudoCs); + #else + desc->length = ((desc->length & (~DescTxCisMask)) | DescTxCisTcpPseudoCs); + #endif + +} + +/********************************************************** + * Common functions + **********************************************************/ +s32 synopGMAC_set_mdc_clk_div(synopGMACdevice *gmacdev,u32 clk_div_val); +u32 synopGMAC_get_mdc_clk_div(synopGMACdevice *gmacdev); +s32 synopGMAC_read_phy_reg(u32 *RegBase,u32 PhyBase, u32 RegOffset, u16 * data); +s32 synopGMAC_write_phy_reg(u32 *RegBase, u32 PhyBase, u32 RegOffset, u16 data); +s32 synopGMAC_read_version (synopGMACdevice * gmacdev) ; +void synopGMAC_reset (synopGMACdevice * gmacdev ); +s32 synopGMAC_dma_bus_mode_init(synopGMACdevice * gmacdev, u32 init_value ); +s32 synopGMAC_dma_control_init(synopGMACdevice * gmacdev, u32 init_value); +void synopGMAC_wd_enable(synopGMACdevice * gmacdev); +void synopGMAC_wd_disable(synopGMACdevice * gmacdev); +void synopGMAC_jab_enable(synopGMACdevice * gmacdev); +void synopGMAC_jab_disable(synopGMACdevice * gmacdev); +void synopGMAC_frame_burst_enable(synopGMACdevice * gmacdev); +void synopGMAC_frame_burst_disable(synopGMACdevice * gmacdev); +void synopGMAC_select_gmii(synopGMACdevice * gmacdev); +void synopGMAC_select_mii(synopGMACdevice * gmacdev); +void synopGMAC_rx_own_enable(synopGMACdevice * gmacdev); +void synopGMAC_rx_own_disable(synopGMACdevice * gmacdev); +void synopGMAC_loopback_on(synopGMACdevice * gmacdev); +void synopGMAC_loopback_off(synopGMACdevice * gmacdev); +void synopGMAC_set_full_duplex(synopGMACdevice * gmacdev); +void synopGMAC_set_half_duplex(synopGMACdevice * gmacdev); +void synopGMAC_retry_enable(synopGMACdevice * gmacdev); +void synopGMAC_retry_disable(synopGMACdevice * gmacdev); +void synopGMAC_pad_crc_strip_enable(synopGMACdevice * gmacdev); +void synopGMAC_pad_crc_strip_disable(synopGMACdevice * gmacdev); +void synopGMAC_back_off_limit(synopGMACdevice * gmacdev, u32 value); +void synopGMAC_deferral_check_enable(synopGMACdevice * gmacdev); +void synopGMAC_deferral_check_disable(synopGMACdevice * gmacdev); +void synopGMAC_rx_enable(synopGMACdevice * gmacdev); +void synopGMAC_rx_disable(synopGMACdevice * gmacdev); +void synopGMAC_tx_enable(synopGMACdevice * gmacdev); +void synopGMAC_tx_disable(synopGMACdevice * gmacdev); +void synopGMAC_frame_filter_enable(synopGMACdevice * gmacdev); +void synopGMAC_frame_filter_disable(synopGMACdevice * gmacdev); +void synopGMAC_write_hash_table_high(synopGMACdevice * gmacdev, u32 data); +void synopGMAC_write_hash_table_low(synopGMACdevice * gmacdev, u32 data); +void synopGMAC_hash_perfect_filter_enable(synopGMACdevice * gmacdev); +void synopGMAC_Hash_filter_only_enable(synopGMACdevice * gmacdev); +void synopGMAC_src_addr_filter_enable(synopGMACdevice * gmacdev); +void synopGMAC_src_addr_filter_disable(synopGMACdevice * gmacdev); +void synopGMAC_dst_addr_filter_inverse(synopGMACdevice * gmacdev); +void synopGMAC_dst_addr_filter_normal(synopGMACdevice * gmacdev); +void synopGMAC_set_pass_control(synopGMACdevice * gmacdev,u32 passcontrol); +void synopGMAC_broadcast_enable(synopGMACdevice * gmacdev); +void synopGMAC_broadcast_disable(synopGMACdevice * gmacdev); +void synopGMAC_multicast_enable(synopGMACdevice * gmacdev); +void synopGMAC_multicast_disable(synopGMACdevice * gmacdev); +void synopGMAC_multicast_hash_filter_enable(synopGMACdevice * gmacdev); +void synopGMAC_multicast_hash_filter_disable(synopGMACdevice * gmacdev); +void synopGMAC_promisc_enable(synopGMACdevice * gmacdev); +void synopGMAC_promisc_disable(synopGMACdevice * gmacdev); +void synopGMAC_unicast_hash_filter_enable(synopGMACdevice * gmacdev); +void synopGMAC_unicast_hash_filter_disable(synopGMACdevice * gmacdev); +void synopGMAC_unicast_pause_frame_detect_enable(synopGMACdevice * gmacdev); +void synopGMAC_unicast_pause_frame_detect_disable(synopGMACdevice * gmacdev); +void synopGMAC_rx_flow_control_enable(synopGMACdevice * gmacdev); +void synopGMAC_rx_flow_control_disable(synopGMACdevice * gmacdev); +void synopGMAC_tx_flow_control_enable(synopGMACdevice * gmacdev); +void synopGMAC_tx_flow_control_disable(synopGMACdevice * gmacdev); +void synopGMAC_tx_activate_flow_control(synopGMACdevice * gmacdev); +void synopGMAC_tx_deactivate_flow_control(synopGMACdevice * gmacdev); +void synopGMAC_pause_control(synopGMACdevice *gmacdev); +s32 synopGMAC_mac_init(synopGMACdevice * gmacdev); +s32 synopGMAC_check_phy_init (synopGMACdevice * gmacdev); +s32 synopGMAC_set_mac_addr(synopGMACdevice *gmacdev, u32 MacHigh, u32 MacLow, u8 *MacAddr); +s32 synopGMAC_get_mac_addr(synopGMACdevice *gmacdev, u32 MacHigh, u32 MacLow, u8 *MacAddr); +s32 synopGMAC_attach (synopGMACdevice * gmacdev, u32 regBase); + +/* + * Initialize the rx descriptors for ring or chain mode operation. + * - Status field is initialized to 0. + * - EndOfRing set for the last descriptor. + * - buffer1 and buffer2 set to 0 for ring mode of operation. (note) + * - data1 and data2 set to 0. (note) + * @param[in] pointer to DmaDesc structure. + * @param[in] whether end of ring + * \return void. + * \note Initialization of the buffer1, buffer2, data1,data2 and status are not done here. This only initializes whether one wants to use this descriptor + * in chain mode or ring mode. For chain mode of operation the buffer2 and data2 are programmed before calling this function. + */ +static inline void synopGMAC_rx_desc_init_ring(DmaDesc *desc, bool last_ring_desc) +{ + desc->status = 0; + desc->length = last_ring_desc ? RxDescEndOfRing : 0; + desc->buffer1 = 0; + desc->data1 = 0; + return; +} + +/* + * Initialize the tx descriptors for ring or chain mode operation. + * - Status field is initialized to 0. + * - EndOfRing set for the last descriptor. + * - buffer1 and buffer2 set to 0 for ring mode of operation. (note) + * - data1 and data2 set to 0. (note) + * @param[in] pointer to DmaDesc structure. + * @param[in] whether end of ring + * \return void. + * \note Initialization of the buffer1, buffer2, data1,data2 and status are not done here. This only initializes whether one wants to use this descriptor + * in chain mode or ring mode. For chain mode of operation the buffer2 and data2 are programmed before calling this function. + */ +static inline void synopGMAC_tx_desc_init_ring(DmaDesc *desc, bool last_ring_desc) +{ + #ifdef ENH_DESC + desc->status = last_ring_desc? TxDescEndOfRing : 0; + desc->length = 0; + #else + desc->length = last_ring_desc? TxDescEndOfRing : 0; + #endif + desc->buffer1 = 0; + desc->data1 = 0; + return; +} + +/* + * Initialize the rx descriptors for chain mode of operation. + * - Status field is initialized to 0. + * - EndOfRing set for the last descriptor. + * - buffer1 and buffer2 set to 0. + * - data1 and data2 set to 0. + * @param[in] pointer to DmaDesc structure. + * @param[in] whether end of ring + * \return void. + +static inline void synopGMAC_rx_desc_init_chain(DmaDesc * desc) +{ + desc->status = 0; + desc->length = RxDescChain; + desc->buffer1 = 0; + desc->data1 = 0; + return; +} + */ + +/* + * Initialize the rx descriptors for chain mode of operation. + * - Status field is initialized to 0. + * - EndOfRing set for the last descriptor. + * - buffer1 and buffer2 set to 0. + * - data1 and data2 set to 0. + * @param[in] pointer to DmaDesc structure. + * @param[in] whether end of ring + * \return void. +static inline void synopGMAC_tx_desc_init_chain(DmaDesc * desc) +{ + #ifdef ENH_DESC + desc->status = TxDescChain; + desc->length = 0; + #else + desc->length = TxDescChain; + #endif + desc->buffer1 = 0; + desc->data1 = 0; + return; +} + */ + +s32 synopGMAC_init_tx_rx_desc_queue(synopGMACdevice *gmacdev); +void synopGMAC_init_rx_desc_base(synopGMACdevice *gmacdev); +void synopGMAC_init_tx_desc_base(synopGMACdevice *gmacdev); +void synopGMAC_set_owner_dma(DmaDesc *desc); +void synopGMAC_set_desc_sof(DmaDesc *desc); +void synopGMAC_set_desc_eof(DmaDesc *desc); +bool synopGMAC_is_sof_in_rx_desc(DmaDesc *desc); +bool synopGMAC_is_eof_in_rx_desc(DmaDesc *desc); +bool synopGMAC_is_da_filter_failed(DmaDesc *desc); +bool synopGMAC_is_sa_filter_failed(DmaDesc *desc); + +/* + * Checks whether the descriptor is owned by DMA. + * If descriptor is owned by DMA then the OWN bit is set to 1. This API is same for both ring and chain mode. + * @param[in] pointer to DmaDesc structure. + * \return returns true if Dma owns descriptor and false if not. + */ +static inline bool synopGMAC_is_desc_owned_by_dma(DmaDesc *desc) +{ +return ((desc->status & DescOwnByDma) == DescOwnByDma ); +} + +/* + * returns the byte length of received frame including CRC. + * This returns the no of bytes received in the received ethernet frame including CRC(FCS). + * @param[in] pointer to DmaDesc structure. + * \return returns the length of received frame lengths in bytes. + */ +static inline u32 synopGMAC_get_rx_desc_frame_length(u32 status) +{ + return ((status & DescFrameLengthMask) >> DescFrameLengthShift); +} + +/* + * Checks whether the descriptor is valid + * if no errors such as CRC/Receive Error/Watchdog Timeout/Late collision/Giant Frame/Overflow/Descriptor + * error the descritpor is said to be a valid descriptor. + * @param[in] pointer to DmaDesc structure. + * \return True if desc valid. false if error. + */ +static inline bool synopGMAC_is_desc_valid(u32 status) +{ + return ((status & DescError) == 0); +} + +/* + * Checks whether the descriptor is empty. + * If the buffer1 and buffer2 lengths are zero in ring mode descriptor is empty. + * In chain mode buffer2 length is 0 but buffer2 itself contains the next descriptor address. + * @param[in] pointer to DmaDesc structure. + * \return returns true if descriptor is empty, false if not empty. + */ +static inline bool synopGMAC_is_desc_empty(DmaDesc *desc) +{ + //if both the buffer1 length and buffer2 length are zero desc is empty + return ((desc->length & DescSize1Mask) == 0); +} + +/* + * Checks whether the rx descriptor is valid. + * if rx descripor is not in error and complete frame is available in the same descriptor + * @param[in] pointer to DmaDesc structure. + * \return returns true if no error and first and last desc bits are set, otherwise it returns false. + */ +static inline bool synopGMAC_is_rx_desc_valid(u32 status) +{ + return ((status & (DescError|DescRxFirst|DescRxLast)) == (DescRxFirst|DescRxLast)); +} + +bool synopGMAC_is_tx_aborted(u32 status); +bool synopGMAC_is_tx_carrier_error(u32 status); + +/* + * Gives the transmission collision count. + * returns the transmission collision count indicating number of collisions occured before the frame was transmitted. + * Make sure to check excessive collision didnot happen to ensure the count is valid. + * @param[in] pointer to DmaDesc structure. + * \return returns the count value of collision. + */ +static inline u32 synopGMAC_get_tx_collision_count(u32 status) +{ + return ((status & DescTxCollMask) >> DescTxCollShift); +} + +static inline u32 synopGMAC_is_exc_tx_collisions(u32 status) +{ + return ((status & DescTxExcCollisions) == DescTxExcCollisions); +} + +bool synopGMAC_is_rx_frame_damaged(u32 status); +bool synopGMAC_is_rx_frame_collision(u32 status); +bool synopGMAC_is_rx_crc(u32 status); +bool synopGMAC_is_frame_dribbling_errors(u32 status); +bool synopGMAC_is_rx_frame_length_errors(u32 status); + +/* + * Checks whether this rx descriptor is last rx descriptor. + * This returns true if it is last descriptor either in ring mode or in chain mode. + * @param[in] pointer to devic structure. + * @param[in] pointer to DmaDesc structure. + * \return returns true if it is last descriptor, false if not. + * \note This function should not be called before initializing the descriptor using synopGMAC_desc_init(). + */ +static inline bool synopGMAC_is_last_rx_desc(synopGMACdevice * gmacdev,DmaDesc *desc) +{ + return (unlikely((desc->length & RxDescEndOfRing) != 0)); +} + +/* + * Checks whether this tx descriptor is last tx descriptor. + * This returns true if it is last descriptor either in ring mode or in chain mode. + * @param[in] pointer to devic structure. + * @param[in] pointer to DmaDesc structure. + * \return returns true if it is last descriptor, false if not. + * \note This function should not be called before initializing the descriptor using synopGMAC_desc_init(). + */ +static inline bool synopGMAC_is_last_tx_desc(synopGMACdevice * gmacdev,DmaDesc *desc) +{ +#ifdef ENH_DESC + return (unlikely((desc->status & TxDescEndOfRing) != 0)); +#else + return (unlikely((desc->length & TxDescEndOfRing) != 0)); +#endif +} + +/* + * Checks whether this rx descriptor is in chain mode. + * This returns true if it is this descriptor is in chain mode. + * @param[in] pointer to DmaDesc structure. + * \return returns true if chain mode is set, false if not. + */ +static inline bool synopGMAC_is_rx_desc_chained(DmaDesc * desc) +{ + /* + * This is also the only way to support jumbo in the futrue. + */ + return 0; //((desc->length & RxDescChain) == RxDescChain); +} + +/* + * Checks whether this tx descriptor is in chain mode. + * This returns true if it is this descriptor is in chain mode. + * @param[in] pointer to DmaDesc structure. + * \return returns true if chain mode is set, false if not. + */ +static inline bool synopGMAC_is_tx_desc_chained(DmaDesc * desc) +{ + /* + * This is also the only way to support jumbo in the futrue. + */ + return 0; +#ifdef ENH_DESC + //return((desc->status & TxDescChain) == TxDescChain); +#else + //return((desc->length & TxDescChain) == TxDescChain); +#endif +} + +void synopGMAC_get_desc_data(DmaDesc * desc, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1); + +/* + * This function is defined two times. Once when the code is compiled for ENHANCED DESCRIPTOR SUPPORT and Once for Normal descriptor + * Get the index and address of Tx desc. + * This api is same for both ring mode and chain mode. + * This function tracks the tx descriptor the DMA just closed after the transmission of data from this descriptor is + * over. This returns the descriptor fields to the caller. + * @param[in] pointer to synopGMACdevice. + * @param[out] status field of the descriptor. + * @param[out] Dma-able buffer1 pointer. + * @param[out] length of buffer1 (Max is 2048). + * @param[out] virtual pointer for buffer1. + * @param[out] Dma-able buffer2 pointer. + * @param[out] length of buffer2 (Max is 2048). + * @param[out] virtual pointer for buffer2. + * @param[out] u32 data indicating whether the descriptor is in ring mode or chain mode. + * \return returns present tx descriptor index on success. Negative value if error. + */ +static inline DmaDesc *synopGMAC_get_tx_qptr(synopGMACdevice * gmacdev) +{ + DmaDesc * txdesc = gmacdev->TxBusyDesc; + + if (unlikely(gmacdev->BusyTxDesc == 0)) { + return NULL; + } + + if(synopGMAC_is_desc_owned_by_dma(txdesc)) { + return NULL; + } + BUG_ON(synopGMAC_is_desc_empty(txdesc)); + + return txdesc; +} + +static inline void synopGMAC_reset_tx_qptr(synopGMACdevice * gmacdev) +{ + u32 txover = gmacdev->TxBusy; + DmaDesc * txdesc = gmacdev->TxBusyDesc; + + BUG_ON(txdesc != (gmacdev->TxDesc + txover)); + gmacdev->TxBusy = (txover + 1) & (gmacdev->TxDescCount -1); + gmacdev->TxBusyDesc = gmacdev->TxDesc + gmacdev->TxBusy; + + #ifdef ENH_DESC + txdesc->status &= TxDescEndOfRing; + txdesc->length = 0; + #else + txdesc->length &= TxDescEndOfRing; + #endif + txdesc->buffer1 = 0; + txdesc->data1 = 0; + + (gmacdev->BusyTxDesc)--; //busy tx descriptor is reduced by one as it will be handed over to Processor now //Akronite +// asm volatile ("sub.4 %0, %0, %1" : : "U4"(gmacdev->BusyTxDesc), "d"(1) : "cc", "memory"); //Akronite +} + +/* + * Populate the tx desc structure with the buffer address. + * Once the driver has a packet ready to be transmitted, this function is called with the + * valid dma-able buffer addresses and their lengths. This function populates the descriptor + * and make the DMA the owner for the descriptor. This function also controls whetther Checksum + * offloading to be done in hardware or not. + * This api is same for both ring mode and chain mode. + * @param[in] pointer to synopGMACdevice. + * @param[in] Dma-able buffer1 pointer. + * @param[in] length of buffer1 (Max is 2048). + * @param[in] virtual pointer for buffer1. + * @param[in] Dma-able buffer2 pointer. + * @param[in] length of buffer2 (Max is 2048). + * @param[in] virtual pointer for buffer2. + * @param[in] u32 data indicating whether the descriptor is in ring mode or chain mode. + * @param[in] u32 indicating whether the checksum offloading in HW/SW. + * \return returns present tx descriptor index on success. Negative value if error. + */ +static inline s32 synopGMAC_set_tx_qptr(synopGMACdevice * gmacdev, u32 Buffer1, u32 Length1, u32 Data1,u32 offload_needed) +{ + u32 txnext = gmacdev->TxNext; + DmaDesc * txdesc = gmacdev->TxNextDesc; + + BUG_ON(gmacdev->BusyTxDesc > gmacdev->TxDescCount); + BUG_ON(txdesc != (gmacdev->TxDesc + txnext)); + BUG_ON(!synopGMAC_is_desc_empty(txdesc)); + BUG_ON(synopGMAC_is_desc_owned_by_dma(txdesc)); + + txdesc->length |= ((Length1 <status |= (DescTxFirst | DescTxLast | DescTxIntEnable); //ENH_DESC + #else + txdesc->length |= (DescTxFirst | DescTxLast | DescTxIntEnable); //Its always assumed that complete data will fit in to one descriptor + #endif + + txdesc->buffer1 = Buffer1; + txdesc->data1 = Data1; + + if (likely(offload_needed)) { + /* + Make sure that the OS you are running supports the IP and TCP checkusm offloaidng, + before calling any of the functions given below. + */ + //synopGMAC_tx_checksum_offload_ipv4hdr(gmacdev, txdesc); + synopGMAC_tx_checksum_offload_tcponly(gmacdev, txdesc); + //synopGMAC_tx_checksum_offload_tcp_pseudo(gmacdev, txdesc); + } + + #ifdef ENH_DESC + txdesc->status |= DescOwnByDma;//ENH_DESC + #else + txdesc->status = DescOwnByDma; + #endif + TR("%02d %08x %08x %08x %08x %08x\n", txnext, (u32)txdesc, + txdesc->status, txdesc->length, txdesc->buffer1, txdesc->data1); + + gmacdev->TxNext = (txnext + 1) & (gmacdev->TxDescCount - 1); + gmacdev->TxNextDesc = gmacdev->TxDesc + gmacdev->TxNext; + + (gmacdev->BusyTxDesc)++; //busy tx descriptor is reduced by one as it will be handed over to Processor now + + return txnext; +} + +/* + * Prepares the descriptor to receive packets. + * The descriptor is allocated with the valid buffer addresses (sk_buff address) and the length fields + * and handed over to DMA by setting the ownership. After successful return from this function the + * descriptor is added to the receive descriptor pool/queue. + * This api is same for both ring mode and chain mode. + * @param[in] pointer to synopGMACdevice. + * @param[in] Dma-able buffer1 pointer. + * @param[in] length of buffer1 (Max is 2048). + * @param[in] Dma-able buffer2 pointer. + * @param[in] length of buffer2 (Max is 2048). + * @param[in] u32 data indicating whether the descriptor is in ring mode or chain mode. + * \return returns present rx descriptor index on success. Negative value if error. + */ +static inline s32 synopGMAC_set_rx_qptr(synopGMACdevice * gmacdev, u32 Buffer1, u32 Length1, u32 Data1) +{ + u32 rxnext = gmacdev->RxNext; + DmaDesc * rxdesc = gmacdev->RxNextDesc; + + BUG_ON(gmacdev->BusyRxDesc >= gmacdev->RxDescCount); + BUG_ON(rxdesc != (gmacdev->RxDesc + rxnext)); + BUG_ON(!synopGMAC_is_desc_empty(rxdesc)); + BUG_ON(synopGMAC_is_desc_owned_by_dma(rxdesc)); + + rxdesc->length |= ((Length1 <buffer1 = Buffer1; + rxdesc->data1 = Data1; + +#ifdef ENH_DESC_8W + rxdesc->extstatus = 0; + rxdesc->reserved1 = 0; + rxdesc->timestamplow = 0; + rxdesc->timestamphigh = 0; +#endif + + rxdesc->status = DescOwnByDma; + TR("%02d %08x %08x %08x %08x %08x\n", rxnext, (u32)rxdesc, + rxdesc->status, rxdesc->length, rxdesc->buffer1, rxdesc->data1); + + gmacdev->RxNext = (rxnext + 1) & (gmacdev->RxDescCount - 1); + gmacdev->RxNextDesc = gmacdev->RxDesc + gmacdev->RxNext; + + (gmacdev->BusyRxDesc)++; //One descriptor will be given to Hardware. So busy count incremented by one + return rxnext; +} + +/* + * This function is defined two times. Once when the code is compiled for ENHANCED DESCRIPTOR SUPPORT and Once for Normal descriptor + * Get back the descriptor from DMA after data has been received. + * When the DMA indicates that the data is received (interrupt is generated), this function should be + * called to get the descriptor and hence the data buffers received. With successful return from this + * function caller gets the descriptor fields for processing. check the parameters to understand the + * fields returned.` + * @param[in] pointer to synopGMACdevice. + * @param[out] pointer to hold the status of DMA. + * @param[out] Dma-able buffer1 pointer. + * @param[out] pointer to hold length of buffer1 (Max is 2048). + * @param[out] virtual pointer for buffer1. + * @param[out] Dma-able buffer2 pointer. + * @param[out] pointer to hold length of buffer2 (Max is 2048). + * @param[out] virtual pointer for buffer2. + * \return returns present rx descriptor index on success. Negative value if error. + */ +static inline DmaDesc *synopGMAC_get_rx_qptr(synopGMACdevice * gmacdev) +{ + DmaDesc * rxdesc = gmacdev->RxBusyDesc; + + if (unlikely(gmacdev->BusyRxDesc == 0)) { + return NULL; + } + + if((gmacdev->state == ETH_STATE_PASSIVE) || synopGMAC_is_desc_owned_by_dma(rxdesc)) { + return NULL; + } + BUG_ON(synopGMAC_is_desc_empty(rxdesc)); + + return rxdesc; +} + +static inline void synopGMAC_reset_rx_qptr(synopGMACdevice * gmacdev) +{ + u32 rxnext = gmacdev->RxBusy; // index of descriptor the DMA just completed. May be useful when data + //is spread over multiple buffers/descriptors + DmaDesc * rxdesc = gmacdev->RxBusyDesc; + + BUG_ON(rxdesc != (gmacdev->RxDesc + rxnext)); + gmacdev->RxBusy = (rxnext + 1) & (gmacdev->RxDescCount - 1); + gmacdev->RxBusyDesc = gmacdev->RxDesc + gmacdev->RxBusy; + + rxdesc->status = 0; + rxdesc->length &= RxDescEndOfRing; + rxdesc->buffer1 = 0; + rxdesc->data1 = 0; + + (gmacdev->BusyRxDesc)--; //This returns one descriptor to processor. So busy count will be decremented by one //Akronite + +// asm volatile ("sub.4 %0, %0, %1" : : "U4"(gmacdev->BusyRxDesc), "d"(1) : "cc", "memory"); //Akronite +} + +/* + * Clears all the pending interrupts. + * If the Dma status register is read then all the interrupts gets cleared + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +static inline void synopGMAC_clear_interrupt(synopGMACdevice *gmacdev) +{ + u32 data; + data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaStatus); + synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaStatus ,data); +} + +/* + * Returns the all unmasked interrupt status after reading the DmaStatus register. + * @param[in] pointer to synopGMACdevice. + * \return 0 upon success. Error code upon failure. + */ +static inline u32 synopGMAC_get_interrupt_type(synopGMACdevice *gmacdev) +{ + u32 interrupts = 0; + interrupts = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaStatus); + synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaStatus ,interrupts); // Clear interrupt here + + return interrupts; +} + +/* + * Returns the interrupt mask. + * @param[in] pointer to synopGMACdevice. + * \return 0 upon success. Error code upon failure. + */ +static inline u32 synopGMAC_get_interrupt_mask(synopGMACdevice *gmacdev) +{ + return(synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaInterrupt)); +} + +/* + * Enable all the interrupts. + * Enables the DMA interrupt as specified by the bit mask. + * @param[in] pointer to synopGMACdevice. + * @param[in] bit mask of interrupts to be enabled. + * \return returns void. + */ +static inline void synopGMAC_enable_interrupt(synopGMACdevice *gmacdev, u32 interrupts) +{ + synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaInterrupt, interrupts); +} + +/* + * Disable all the interrupts. + * Disables all DMA interrupts. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + * \note This function disabled all the interrupts, if you want to disable a particular interrupt then + * use synopGMAC_disable_interrupt(). + */ +static inline void synopGMAC_disable_interrupt_all(synopGMACdevice *gmacdev) +{ + synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaInterrupt, DmaIntDisable); +} + +/* + * Disable interrupt according to the bitfield supplied. + * Disables only those interrupts specified in the bit mask in second argument. + * @param[in] pointer to synopGMACdevice. + * @param[in] bit mask for interrupts to be disabled. + * \return returns void. + */ +static inline void synopGMAC_disable_interrupt(synopGMACdevice *gmacdev, u32 interrupts) +{ + synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaInterrupt, interrupts); +} + +void synopGMAC_enable_dma_rx(synopGMACdevice * gmacdev); +void synopGMAC_enable_dma_tx(synopGMACdevice * gmacdev); + +/* + * Resumes the DMA Transmission. + * the DmaTxPollDemand is written. (the data writeen could be anything). + * This forces the DMA to resume transmission. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +static inline void synopGMAC_resume_dma_tx(synopGMACdevice * gmacdev) +{ + synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaTxPollDemand, 0); + +} + +/* + * Resumes the DMA Reception. + * the DmaRxPollDemand is written. (the data writeen could be anything). + * This forces the DMA to resume reception. + * @param[in] pointer to synopGMACdevice. + * \return returns void. + */ +static inline void synopGMAC_resume_dma_rx(synopGMACdevice * gmacdev) +{ + synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaRxPollDemand, 0); + +} + +void synopGMAC_take_desc_ownership(DmaDesc * desc); +void synopGMAC_take_desc_ownership_rx(synopGMACdevice * gmacdev); +void synopGMAC_take_desc_ownership_tx(synopGMACdevice * gmacdev); +void synopGMAC_disable_dma_tx(synopGMACdevice * gmacdev); +void synopGMAC_disable_dma_rx(synopGMACdevice * gmacdev); + +/******Following APIs are valid only for Enhanced Descriptor from 3.50a release onwards*******/ +/* + * When the Enhanced Descriptor is enabled then the bit 0 of RDES0 indicates whether the + * Extended Status is available (RDES4). Time Stamp feature and the Checksum Offload Engine2 + * makes use of this extended status to provide the status of the received packet. + * @param[in] pointer to synopGMACdevice + * \return returns TRUE or FALSE + */ + +#ifdef ENH_DESC_8W +/* + * This function indicates whether extended status is available in the RDES0. + * Any function which accesses the fields of extended status register must ensure a check on this has been made + * This is valid only for Enhanced Descriptor. + * @param[in] pointer to synopGMACdevice. + * @param[in] u32 status field of the corresponding descriptor. + * \return returns TRUE or FALSE. + */ +static inline bool synopGMAC_is_ext_status(synopGMACdevice *gmacdev,u32 status) // extended status present indicates that the RDES4 need to be probed +{ + return((status & DescRxEXTsts ) != 0 ); // if extstatus set then it returns 1 +} + +/* + * This function returns true if the IP header checksum bit is set in the extended status. + * Valid only when enhaced status available is set in RDES0 bit 0. + * This is valid only for Enhanced Descriptor. + * @param[in] pointer to synopGMACdevice. + * @param[in] u32 status field of the corresponding descriptor. + * \return returns TRUE or FALSE. + */ +static inline bool synopGMAC_ES_is_IP_header_error(synopGMACdevice *gmacdev, u32 ext_status) // IP header (IPV4) checksum error +{ + return((ext_status & DescRxIpHeaderError) != 0 ); // if IPV4 header error return 1 +} + +/* + * This function returns true if the Checksum is bypassed in the hardware. + * Valid only when enhaced status available is set in RDES0 bit 0. + * This is valid only for Enhanced Descriptor. + * @param[in] pointer to synopGMACdevice. + * @param[in] u32 status field of the corresponding descriptor. + * \return returns TRUE or FALSE. + */ +static inline bool synopGMAC_ES_is_rx_checksum_bypassed(synopGMACdevice *gmacdev, u32 ext_status) // Hardware engine bypassed the checksum computation/checking +{ + return((ext_status & DescRxChkSumBypass ) != 0 ); // if checksum offloading bypassed return 1 +} + +/* + * This function returns true if payload checksum error is set in the extended status. + * Valid only when enhaced status available is set in RDES0 bit 0. + * This is valid only for Enhanced Descriptor. + * @param[in] pointer to synopGMACdevice. + * @param[in] u32 status field of the corresponding descriptor. + * \return returns TRUE or FALSE. + */ +static inline bool synopGMAC_ES_is_IP_payload_error(synopGMACdevice *gmacdev, u32 ext_status) // IP payload checksum is in error (UDP/TCP/ICMP checksum error) +{ + return((ext_status & DescRxIpPayloadError) != 0 ); // if IP payload error return 1 +} +#endif + +/*******************PMT APIs***************************************/ +void synopGMAC_pmt_int_enable(synopGMACdevice *gmacdev); +void synopGMAC_pmt_int_disable(synopGMACdevice *gmacdev); +void synopGMAC_power_down_enable(synopGMACdevice *gmacdev); +void synopGMAC_power_down_disable(synopGMACdevice *gmacdev); +void synopGMAC_magic_packet_enable(synopGMACdevice *gmacdev); +void synopGMAC_wakeup_frame_enable(synopGMACdevice *gmacdev); +void synopGMAC_pmt_unicast_enable(synopGMACdevice *gmacdev); +bool synopGMAC_is_magic_packet_received(synopGMACdevice *gmacdev); +bool synopGMAC_is_wakeup_frame_received(synopGMACdevice *gmacdev); +void synopGMAC_write_wakeup_frame_register(synopGMACdevice *gmacdev, u32 * filter_contents); +/*******************MMC APIs***************************************/ +void synopGMAC_mmc_counters_stop(synopGMACdevice *gmacdev); +void synopGMAC_mmc_counters_resume(synopGMACdevice *gmacdev); +void synopGMAC_mmc_counters_set_selfclear(synopGMACdevice *gmacdev); +void synopGMAC_mmc_counters_reset_selfclear(synopGMACdevice *gmacdev); +void synopGMAC_mmc_counters_disable_rollover(synopGMACdevice *gmacdev); +void synopGMAC_mmc_counters_enable_rollover(synopGMACdevice *gmacdev); +u32 synopGMAC_read_mmc_counter(synopGMACdevice *gmacdev, u32 counter); +u32 synopGMAC_read_mmc_rx_int_status(synopGMACdevice *gmacdev); +u32 synopGMAC_read_mmc_tx_int_status(synopGMACdevice *gmacdev); +void synopGMAC_disable_mmc_tx_interrupt(synopGMACdevice *gmacdev, u32 mask); +void synopGMAC_enable_mmc_tx_interrupt(synopGMACdevice *gmacdev, u32 mask); +void synopGMAC_disable_mmc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask); +void synopGMAC_enable_mmc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask); +void synopGMAC_enable_mmc_ipc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask); +void synopGMAC_disable_mmc_ipc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask); +void nss_gmac_qsgmii_dev_init(synopGMACdevice *gmacdev); +void ipq806x_dev_board_init(synopGMACdevice *gmacdev); +int32_t nss_gmac_common_init(void); +extern board_ipq806x_params_t *gboard_param ; +void nss_gmac_reset_phy( uint32_t phyid); +int32_t ipq806x_get_link_speed(uint32_t phyid); +int32_t ipq806x_get_duplex(uint32_t phyid); +int32_t nss_gmac_dev_set_speed(synopGMACdevice *gmacdev); +#endif /* End of file */ diff --git a/root/package/utils/sysupgrade-helper/src/drivers/net/nss/synopGMAC_network_interface.c b/root/package/utils/sysupgrade-helper/src/drivers/net/nss/synopGMAC_network_interface.c new file mode 100644 index 00000000..edd0f9bd --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/drivers/net/nss/synopGMAC_network_interface.c @@ -0,0 +1,1526 @@ +/* * Copyright (c) 2012 - 2013 The Linux Foundation. All rights reserved.* */ + +/* + * This is the network dependent layer to handle network related functionality. + * This file is tightly coupled to neworking frame work of linux 2.6.xx kernel. + * The functionality carried out in this file should be treated as an example only + * if the underlying operating system is not Linux. + * + * \note Many of the functions other than the device specific functions + * changes for operating system other than Linux 2.6.xx + * \internal + *-----------------------------REVISION HISTORY----------------------------------- + * Ubicom 01/Mar/2010 Modified for Ubicom32 + * Synopsys 01/Aug/2007 Created + */ + +#include "synopGMAC_plat.h" +#include "synopGMAC_Dev.h" +#include +#include +#include +#include +#include +#include +#include + + +#define CONFIG_ARCH_IPQ806X +/* + * u-boot API + */ +extern int eth_rx(void); +extern void eth_halt(void); +extern int eth_init(bd_t *bd); +extern void cleanup_skb(void); + +extern int synop_phy_link_status(int speed); +void synop_phy_outofreset(void); +extern s32 synopGMAC_check_link(synopGMACdevice *gmacdev); +extern uint16_t mii_read_reg(synopGMACdevice *gmacdev, uint32_t phy, uint32_t reg); +int eth_init_done; +u32 nss_base; +u32 gmac_base; +u32 qsgmii_base; +uint16_t ipq_mii_read_reg(uint32_t phy, uint32_t reg); +void ipq_mii_write_reg(uint32_t phy, uint32_t reg, uint16_t data); + +#define GMAC_PORT 1 /* after bringup will be moved to board specific params */ +#define TX_TOTAL_BUFSIZE 1700 + +u8 txbuffs[TX_TOTAL_BUFSIZE]; +u8 TxSkbuf[sizeof(struct sk_buff)]; + +/* + * These are the global pointers for their respecive structures + */ +static synopGMACdevice *synopGMACDev[1] = {NULL}; + +synopGMACdevice *netdev_priv(struct eth_device *dev) { + return (synopGMACdevice *)(dev->priv); +} + +static s32 gmac_plat_init(void) +{ + + /*XXX: needs cleanup. need better way to share registers between different modules. */ + nss_base = NSS_REG_BASE ; + gmac_base = gboard_param->gmac_base; + qsgmii_base = QSGMII_REG_BASE; + + TR("%s: ipq806x: NSS base done. \n",__FUNCTION__); + + return 0; +} + + +static s32 gmac_dev_init(u32 id) +{ + u32 val; + + /* Set GMACn Ctl */ + val = GMAC_PHY_RGMII | GMAC_IFG_CTL(GMAC_IFG) + | GMAC_IFG_LIMIT(GMAC_IFG); + synopGMACSetBits((u32 *)nss_base, NSS_GMACn_CTL(id), val); + + val = synopGMACReadReg((u32 *)nss_base, NSS_GMACn_CTL(id)); + TR("%s: IPQ806X_GMAC%d_CTL(0x%x) - 0x%x\n", __FUNCTION__, id , + NSS_GMACn_CTL(id), val); + + /* Enable clk for GMACn */ + val = GMACn_RGMII_RX_CLK(id) | GMACn_RGMII_TX_CLK(id) + | GMACn_PTP_CLK(id); + synopGMACSetBits((u32 *)nss_base, NSS_ETH_CLK_GATE_CTL, val); + + val = synopGMACReadReg((u32 *)nss_base, NSS_ETH_CLK_GATE_CTL); + TR("%s:NSS_ETHERNET_CLK_GATE_CTL(0x%x) - 0x%x \n", __FUNCTION__ , + NSS_ETH_CLK_GATE_CTL, val); + + /* Select GMACn clk source. + * TODO: support for SGMII/QSGMII\ + */ + + val = synopGMACReadReg((u32 *)nss_base, NSS_ETH_CLK_SRC_CTL); + TR("%s:NSS_ETHERNET_CLK_SRC_CTL(0x%x)- 0x%x\n", __FUNCTION__, + NSS_ETH_CLK_SRC_CTL, val); + + /* Read status registers */ + val = synopGMACReadReg((u32 *)nss_base, NSS_ETH_CLK_ROOT_STAT ); + TR("%s:CLK_ROOT_STAT - 0x%x \n", __FUNCTION__, val); + + val = synopGMACReadReg((u32 *)nss_base, NSS_QSGMII_CLK_CTL); + TR("%s:QSGMII_CLK_CTL - 0x%x \n", __FUNCTION__, val); + + synopGMACSetBits((u32 *)nss_base, NSS_ETH_CLK_SRC_CTL, (0x1 << id)); + + return 0; +} + + +static s32 gmac_spare_ctl(synopGMACdevice *gmacdev) +{ + u32 val; + u32 count; + u32 id = 0; + + val = 1 << id; + synopGMACSetBits((u32 *)nss_base, NSS_ETH_SPARE_CTL , val); + + val = synopGMACReadReg((u32 *)nss_base, NSS_ETH_SPARE_CTL ); + TR("NSS_ETHERNET_SPARE_CTL - 0x%x\n",val); + + val = 1 << id; + synopGMACClearBits((u32 *)nss_base, NSS_ETH_SPARE_CTL , val); + + val = synopGMACReadReg((u32 *)nss_base, NSS_ETH_SPARE_CTL); + TR("NSS_ETHERNET_SPARE_CTL - 0x%x after clear for gmac %d\n",val,id); + + val = synopGMACReadReg((u32 *)nss_base, NSS_ETH_SPARE_STAT) ; + TR("NSS_ETHERNET_SPARE_STAT - 0x%x; gmac %d spare ctl reset...\n",val,id); + count =0; + while((val & (1 << id)) != (1 << id)) { + __udelay(1000); + val = synopGMACReadReg((u32 *)nss_base, NSS_ETH_SPARE_STAT) ; + if(count++ > 20) { + TR0("!!!!!!!!!!! Timeout waiting for ETH_SPARE_STAT bit to set. Moving on...\n"); + break; + } + } + + return 0; +} + +static void synopGMAC_linux_powerup_mac(synopGMACdevice *gmacdev) +{ + gmacdev->GMAC_Power_down = 0; // Let ISR know that MAC is out of power down now + if (synopGMAC_is_magic_packet_received(gmacdev)) + TR("GMAC wokeup due to Magic Pkt Received\n"); + if (synopGMAC_is_wakeup_frame_received(gmacdev)) + TR("GMAC wokeup due to Wakeup Frame Received\n"); + /*Disable the assertion of PMT interrupt*/ + synopGMAC_pmt_int_disable(gmacdev); + /*Enable the mac and Dma rx and tx paths*/ + synopGMAC_rx_enable(gmacdev); + synopGMAC_enable_dma_rx(gmacdev); + + synopGMAC_tx_enable(gmacdev); + synopGMAC_enable_dma_tx(gmacdev); +} + +/* + * This sets up the transmit Descriptor queue in ring or chain mode. + * This function is tightly coupled to the platform and operating system + * Device is interested only after the descriptors are setup. Therefore this function + * is not included in the device driver API. This function should be treated as an + * example code to design the descriptor structures for ring mode or chain mode. + * This function depends on the device structure for allocation consistent dma-able memory in case of linux. + * - Allocates the memory for the descriptors. + * - Initialize the Busy and Next descriptors indices to 0(Indicating first descriptor). + * - Initialize the Busy and Next descriptors to first descriptor address. + * - Initialize the last descriptor with the endof ring in case of ring mode. + * - Initialize the descriptors in chain mode. + * @param[in] pointer to synopGMACdevice. + * @param[in] pointer to device structure. + * @param[in] number of descriptor expected in tx descriptor queue. + * @param[in] whether descriptors to be created in RING mode or CHAIN mode. + * \return 0 upon success. Error code upon failure. + * \note This function fails if allocation fails for required number of descriptors in Ring mode, but in chain mode + * function returns -ESYNOPGMACNOMEM in the process of descriptor chain creation. once returned from this function + * user should for gmacdev->TxDescCount to see how many descriptors are there in the chain. Should continue further + * only if the number of descriptors in the chain meets the requirements + */ +static s32 synopGMAC_setup_tx_desc_queue(synopGMACdevice * gmacdev, void * dev,u32 no_of_desc, u32 desc_mode) +{ + s32 i; + DmaDesc *first_desc = NULL; + dma_addr_t dma_addr; + gmacdev->TxDescCount = 0; + + BUG_ON(desc_mode != RINGMODE); + BUG_ON((no_of_desc & (no_of_desc - 1)) != 0); /* Must be power-of-2 */ + + TR("Total size of memory required for Tx Descriptors in Ring Mode = 0x%08x\n", + (u32)((sizeof(DmaDesc) * no_of_desc))); + first_desc = plat_alloc_consistent_dmaable_memory(dev, sizeof(DmaDesc) * no_of_desc,&dma_addr); + if (first_desc == NULL) { + TR("Error in Tx Descriptors memory allocation\n"); + return -ESYNOPGMACNOMEM; + } + + BUG_ON((int)first_desc & (CACHE_LINE_SIZE - 1)); + gmacdev->TxDescCount = no_of_desc; + gmacdev->TxDesc = first_desc; + gmacdev->TxDescDma = dma_addr; + TR("Tx Descriptors in Ring Mode: No. of descriptors = %d base = 0x%08x dma = 0x%08x\n", + no_of_desc, (u32)first_desc, dma_addr); + + for (i =0; i < gmacdev -> TxDescCount; i++) { + synopGMAC_tx_desc_init_ring(gmacdev->TxDesc + i, i == (gmacdev->TxDescCount - 1)); + TR("%02d %08x \n",i, (unsigned int)(gmacdev->TxDesc + i) ); + } + + gmacdev->TxNext = 0; + gmacdev->TxBusy = 0; + gmacdev->TxNextDesc = gmacdev->TxDesc; + gmacdev->TxBusyDesc = gmacdev->TxDesc; + gmacdev->BusyTxDesc = 0; + + return -ESYNOPGMACNOERR; +} + +/* + * This sets up the receive Descriptor queue in ring or chain mode. + * This function is tightly coupled to the platform and operating system + * Device is interested only after the descriptors are setup. Therefore this function + * is not included in the device driver API. This function should be treated as an + * example code to design the descriptor structures in ring mode or chain mode. + * This function depends on the device structure for allocation of consistent dma-able memory in case of linux. + * - Allocates the memory for the descriptors. + * - Initialize the Busy and Next descriptors indices to 0(Indicating first descriptor). + * - Initialize the Busy and Next descriptors to first descriptor address. + * - Initialize the last descriptor with the endof ring in case of ring mode. + * - Initialize the descriptors in chain mode. + * @param[in] pointer to synopGMACdevice. + * @param[in] pointer to device structure. + * @param[in] number of descriptor expected in rx descriptor queue. + * @param[in] whether descriptors to be created in RING mode or CHAIN mode. + * \return 0 upon success. Error code upon failure. + * \note This function fails if allocation fails for required number of descriptors in Ring mode, but in chain mode + * function returns -ESYNOPGMACNOMEM in the process of descriptor chain creation. once returned from this function + * user should for gmacdev->RxDescCount to see how many descriptors are there in the chain. Should continue further + * only if the number of descriptors in the chain meets the requirements + */ +static s32 synopGMAC_setup_rx_desc_queue(synopGMACdevice * gmacdev,void * dev,u32 no_of_desc, u32 desc_mode) +{ + s32 i; + DmaDesc *first_desc = NULL; + dma_addr_t dma_addr; + gmacdev->RxDescCount = 0; + + BUG_ON(desc_mode != RINGMODE); + BUG_ON((no_of_desc & (no_of_desc - 1)) != 0); /* Must be power-of-2 */ + + TR("total size of memory required for Rx Descriptors in Ring Mode = 0x%08x\n", + (u32)((sizeof(DmaDesc) * no_of_desc))); + first_desc = plat_alloc_consistent_dmaable_memory (dev, sizeof(DmaDesc) * no_of_desc, &dma_addr); + if (first_desc == NULL) { + TR("Error in Rx Descriptor Memory allocation in Ring mode\n"); + return -ESYNOPGMACNOMEM; + } + BUG_ON((int)first_desc & (CACHE_LINE_SIZE - 1)); + gmacdev->RxDescCount = no_of_desc; + gmacdev->RxDesc = first_desc; + gmacdev->RxDescDma = dma_addr; + TR("Rx Descriptors in Ring Mode: No. of descriptors = %d base = 0x%08x dma = 0x%08x\n", + no_of_desc, (u32)first_desc, dma_addr); + + for (i =0; i < gmacdev -> RxDescCount; i++) { + synopGMAC_rx_desc_init_ring(gmacdev->RxDesc + i, i == (gmacdev->RxDescCount - 1)); + TR("%02d %08x \n",i, (unsigned int)(gmacdev->RxDesc + i)); + } + + gmacdev->RxNext = 0; + gmacdev->RxBusy = 0; + gmacdev->RxNextDesc = gmacdev->RxDesc; + gmacdev->RxBusyDesc = gmacdev->RxDesc; + gmacdev->BusyRxDesc = 0; + + return -ESYNOPGMACNOERR; +} + +/* + * This gives up the receive Descriptor queue in ring or chain mode. + * This function is tightly coupled to the platform and operating system + * Once device's Dma is stopped the memory descriptor memory and the buffer memory deallocation, + * is completely handled by the operating system, this call is kept outside the device driver Api. + * This function should be treated as an example code to de-allocate the descriptor structures in ring mode or chain mode + * and network buffer deallocation. + * This function depends on the device structure for dma-able memory deallocation for both descriptor memory and the + * network buffer memory under linux. + * The responsibility of this function is to + * - Free the network buffer memory if any. + * - Fee the memory allocated for the descriptors. + * @param[in] pointer to synopGMACdevice. + * @param[in] pointer to device structure. + * @param[in] number of descriptor expected in rx descriptor queue. + * @param[in] whether descriptors to be created in RING mode or CHAIN mode. + * \return 0 upon success. Error code upon failure. + * \note No referece should be made to descriptors once this function is called. This function is invoked when the device is closed. + */ +static void synopGMAC_giveup_rx_desc_queue(synopGMACdevice * gmacdev, void *dev, u32 desc_mode) +{ + s32 i; + u32 status; + dma_addr_t dma_addr1; + u32 length1; + u32 data1; + + for (i = 0; i < gmacdev->RxDescCount; i++) { + synopGMAC_get_desc_data(gmacdev->RxDesc + i, &status, &dma_addr1, &length1, &data1); + if ((length1 != 0) && (data1 != 0)) { + dev_kfree_skb_any((struct sk_buff *) data1); + TR("(Ring mode) rx buffer1 %08x of size %d from %d rx descriptor is given back\n", data1, length1, i); + } + } + free(gmacdev->RxDesc); + TR("Memory allocated %08x for Rx Desriptors (ring) is given back\n", (u32)gmacdev->RxDesc); + TR("rx-------------------------------------------------------------------rx\n"); + + gmacdev->RxDesc = NULL; + gmacdev->RxDescDma = 0; +} + +/* + * This gives up the transmit Descriptor queue in ring or chain mode. + * This function is tightly coupled to the platform and operating system + * Once device's Dma is stopped the memory descriptor memory and the buffer memory deallocation, + * is completely handled by the operating system, this call is kept outside the device driver Api. + * This function should be treated as an example code to de-allocate the descriptor structures in ring mode or chain mode + * and network buffer deallocation. + * This function depends on the device structure for dma-able memory deallocation for both descriptor memory and the + * network buffer memory under linux. + * The responsibility of this function is to + * - Free the network buffer memory if any. + * - Fee the memory allocated for the descriptors. + * @param[in] pointer to synopGMACdevice. + * @param[in] pointer to device structure. + * @param[in] number of descriptor expected in tx descriptor queue. + * @param[in] whether descriptors to be created in RING mode or CHAIN mode. + * \return 0 upon success. Error code upon failure. + * \note No reference should be made to descriptors once this function is called. This function is invoked when the device is closed. + */ +static void synopGMAC_giveup_tx_desc_queue(synopGMACdevice * gmacdev,void * dev, u32 desc_mode) +{ + s32 i; + u32 status; + dma_addr_t dma_addr1; + u32 length1; + u32 data1; + + for (i = 0; i < gmacdev->TxDescCount; i++) { + synopGMAC_get_desc_data(gmacdev->TxDesc + i, &status, &dma_addr1, &length1, &data1); + if((length1 != 0) && (data1 != 0)){ + dev_kfree_skb_any((struct sk_buff *) data1); + TR("(Ring mode) tx buffer1 %08x of size %d from %d rx descriptor is given back\n", data1, length1, i); + } + } + free(gmacdev->TxDesc); + TR("Memory allocated %08x for Tx Desriptors (ring) is given back\n", (u32)gmacdev->TxDesc); + TR("tx-------------------------------------------------------------------tx\n"); + + gmacdev->TxDesc = NULL; + gmacdev->TxDescDma = 0; +} + +/* + * Function to handle housekeeping after a packet is transmitted over the wire. + * After the transmission of a packet DMA generates corresponding interrupt + * (if it is enabled). It takes care of returning the sk_buff to the linux + * kernel, updating the networking statistics and tracking the descriptors. + * @param[in] pointer to net_device structure. + * \return void. + * \note This function runs in interrupt context + */ +static void synopGMAC_handle_transmit_over(struct eth_device *netdev) +{ + synopGMACdevice *gmacdev = netdev_priv(netdev); + DmaDesc *txdesc; + u32 status; + + /* + * Handle the transmit Descriptors + */ + while (1) { + txdesc = synopGMAC_get_tx_qptr(gmacdev); + if (unlikely(txdesc == NULL)) { + break; + } + + status = txdesc->status; + synopGMAC_reset_tx_qptr(gmacdev); + + if (unlikely(synopGMAC_is_tx_ipv4header_checksum_error(gmacdev, status))) { + TR0("Harware Failed to Insert IPV4 Header Checksum\n"); + } + + if (unlikely(synopGMAC_is_tx_payload_checksum_error(gmacdev, status))) { + TR0("Harware Failed to Insert Payload Checksum\n"); + } + + if (likely(synopGMAC_is_desc_valid(status))) { + } + else { + TR0("Error in Status %08x\n",status); + } + } + netif_wake_queue(netdev); +} + + +/* + * Function to Receive a packet from the interface. + * After Receiving a packet, DMA transfers the received packet to the system memory + * and generates corresponding interrupt (if it is enabled). This function prepares + * the sk_buff for received packet after removing the ethernet CRC, and hands it over + * to linux networking stack. + * - Updataes the networking interface statistics + * - Keeps track of the rx descriptors + * @param[in] pointer to net_device structure. + * \return void. + * \note This function runs in interrupt context. + */ +static u32 synopGMAC_handle_received_data(struct eth_device *netdev, u32 quota) +{ + synopGMACdevice *gmacdev = netdev_priv(netdev); + DmaDesc *rxdesc; + u32 status; + u32 len; + u32 data1; + u32 dma_addr1; + struct sk_buff *skb; + u32 count = 0, refill_count = 0, reserve_len; + + /* + * Handle the Receive Descriptors + */ + while (count < quota) { + rxdesc = synopGMAC_get_rx_qptr(gmacdev); + + if (unlikely(rxdesc == NULL)) { + + break; + } + + status = rxdesc->status; + dma_addr1 = rxdesc->buffer1; + data1 = rxdesc->data1; + synopGMAC_reset_rx_qptr(gmacdev); + + BUG_ON(data1 == 0); + + /* + * Perform prefetch on skbuff structure data + */ + skb = (struct sk_buff *)data1; + + /* + * Validate RX frame: + * The max frame size check is implied by buffer's limited length + * and the presence of both first and last descritpor flags. + */ + len = synopGMAC_get_rx_desc_frame_length(status); + + if (unlikely(!synopGMAC_is_rx_desc_valid(status)) || + unlikely(len < (ETH_ZLEN + ETH_FCS_LEN))) { + /* + * At first step unmapped the dma address + */ + //dma_unmap_single_buf(dma_addr1, 0); + + /* + * Now the present skb should be set free + */ + dev_kfree_skb_any(skb); + TR0("%s: Invalid RX status = %08x\n", __FUNCTION__, status); + + count++; + + continue; + } + + /* + * At first step unmapped the dma address + */ + len -= ETH_FCS_LEN; //Not interested in Ethernet CRC bytes + skb_put(skb, len); + count++; + NetReceive(skb->data, skb->len); + dev_kfree_skb_any(skb); + } + + /* U-Boot could invoke eth_halt and halt our operations. */ + if (gmacdev->state == ETH_STATE_PASSIVE) + return count; + + /* + * Now allocate more RX buffer and let GMAC DMA engine know about them. + */ + reserve_len = ETHERNET_EXTRA; + while (gmacdev->BusyRxDesc < gmacdev->RxDescCount) { + + skb = alloc_skb(ETHERNET_EXTRA + ETH_MAX_FRAME_LEN + + CACHE_LINE_SIZE, 0); + if(skb == NULL){ + TR("SKB memory allocation failed \n"); + break; + } + + skb_reserve(skb, reserve_len); + dma_addr1 = virt_to_phys(skb->data); + synopGMAC_set_rx_qptr(gmacdev, dma_addr1, ETH_MAX_FRAME_LEN, + (u32)skb); + refill_count++; + } + + if (refill_count > 0) { + synopGMAC_resume_dma_rx(gmacdev); + } + + return count; +} + + +/* + * Tasklet poll callback + * This is the Tasklet callback function + * @param[in] tasklet structure. + * + */ +static void synopGMAC_task_poll(unsigned long arg) +{ + struct eth_device *netdev; + synopGMACdevice *gmacdev; + u32 interrupt; + u32 budget = GMAC_POLL_BUDGET; + + gmacdev = (synopGMACdevice *)arg; + BUG_ON(gmacdev == NULL); + + netdev = gmacdev->synopGMACnetdev; + BUG_ON(netdev == NULL); + + /* + * Now lets handle the DMA interrupts + */ + interrupt = synopGMAC_get_interrupt_type(gmacdev); + TR("%s:Interrupts to be handled: 0x%08x\n", __FUNCTION__, interrupt); + + if (unlikely(interrupt & GmacPmtIntr)) { + TR("%s:: Interrupt due to PMT module\n",__FUNCTION__); + synopGMAC_linux_powerup_mac(gmacdev); + } + + if (unlikely(interrupt & GmacMmcIntr)) { + TR("%s:: Interrupt due to MMC module\n",__FUNCTION__); + TR("%s:: synopGMAC_rx_int_status = %08x\n",__FUNCTION__,synopGMAC_read_mmc_rx_int_status(gmacdev)); + TR("%s:: synopGMAC_tx_int_status = %08x\n",__FUNCTION__,synopGMAC_read_mmc_tx_int_status(gmacdev)); + } + + if (unlikely(interrupt & GmacLineIntfIntr)) { + TR("%s:: Interrupt due to GMAC LINE module\n",__FUNCTION__); + TR("GMAC status reg is %08x mask is %08x\n", + synopGMACReadReg((u32 *)gmacdev->MacBase, GmacInterruptStatus), + synopGMACReadReg((u32 *)gmacdev->MacBase, GmacInterruptMask)); + if (synopGMACReadReg((u32 *)gmacdev->MacBase, GmacInterruptStatus) & GmacRgmiiIntSts) { + TR("GMAC RGMII status is %08x\n", synopGMACReadReg((u32 *)gmacdev->MacBase, 0x00D8)); + synopGMACReadReg((u32 *)gmacdev->MacBase, 0x00D8); + } + } + if (interrupt && DmaIntRxCompleted) { + synopGMAC_handle_received_data(netdev, budget); + } + + if (gmacdev->BusyTxDesc > 0) { + synopGMAC_handle_transmit_over(netdev); + } + + if (unlikely(interrupt & (DmaIntErrorMask + | DmaIntRxAbnMask | DmaIntRxStoppedMask + | DmaIntTxAbnMask | DmaIntTxStoppedMask))) { + + if (interrupt & DmaIntErrorMask) { + TR0("%s::Fatal Bus Error Inetrrupt Seen (DMA status = 0x%08x)\n",__FUNCTION__,interrupt); + BUG(); + + } + + if (interrupt & DmaIntRxAbnMask) { + TR0("%s::Abnormal Rx Interrupt Seen (DMA status = 0x%08x)\n", __FUNCTION__, interrupt); + if (gmacdev->GMAC_Power_down == 0) { + /* + * Just issue a poll demand to resume DMA operation + * (May happen when too few RX desciptors are in use) + */ + synopGMAC_handle_received_data(netdev, 0); + synopGMAC_resume_dma_rx(gmacdev); + } + } + + if (interrupt & DmaIntRxStoppedMask) { + if (gmacdev->GMAC_Power_down == 0) { + TR0("%s::Receiver stopped (DMA status = 0x%08x)\n", __FUNCTION__, interrupt); + BUG(); + synopGMAC_handle_received_data(netdev, 0); + synopGMAC_enable_dma_rx(gmacdev); + } + } + + if (interrupt & DmaIntTxAbnMask) { + TR0("%s::Abnormal Tx Interrupt Seen (DMA status = 0x%08x)\n", __FUNCTION__, interrupt); + if (gmacdev->GMAC_Power_down == 0) { + synopGMAC_handle_transmit_over(netdev); + } + } + + if (interrupt & DmaIntTxStoppedMask) { + if (gmacdev->GMAC_Power_down == 0) { + TR0("%s::Transmitter stopped (DMA status = 0x%08x)\n", __FUNCTION__, interrupt); + BUG(); + + synopGMAC_disable_dma_tx(gmacdev); + synopGMAC_take_desc_ownership_tx(gmacdev); + synopGMAC_enable_dma_tx(gmacdev); + netif_wake_queue(netdev); + } + } + } +} + +/* + * Function used when the interface is opened for use. + * We register synopGMAC_linux_open function to linux open(). Basically this + * function prepares the the device for operation . This function is called whenever ifconfig (in Linux) + * activates the device (for example "ifconfig eth0 up"). This function registers + * system resources needed + * - Attaches device to device specific structure + * - Programs the MDC clock for PHY configuration + * - Check and initialize the PHY interface + * - ISR registration + * - Setup and initialize Tx and Rx descriptors + * - Initialize MAC and DMA + * - Allocate Memory for RX descriptors (The should be DMAable) + * - Initialize one second timer to detect cable plug/unplug + * - Configure and Enable Interrupts + * - Enable Tx and Rx + * - start the Linux network queue interface + * @param[in] pointer to net_device structure. + * \return Returns 0 on success and error status upon failure. + * + */ +static s32 synopGMAC_linux_open(struct eth_device *netdev, + struct eth_device *device) +{ + void *dev = NULL;; + synopGMACdevice *gmacdev = (synopGMACdevice *) netdev_priv(netdev); + + TR("%s called \n",__FUNCTION__); + TR("gmacdev = %08x netdev = %08x dev= %08x\n", (u32)gmacdev, (u32)netdev, (u32)dev); + BUG_ON(gmacdev->synopGMACnetdev != netdev); + + /* + * Now platform dependent initialization. + */ + synopGMAC_disable_interrupt_all(gmacdev); + + /* + * Lets reset the IP + */ + synopGMAC_reset(gmacdev); + + /* + * Lets read the version of ip in to device structure + */ + synopGMAC_read_version(gmacdev); + synopGMAC_set_mac_addr(gmacdev, GmacAddr0High, GmacAddr0Low, device->enetaddr); + + + /* + * Set up the tx and rx descriptor queue/ring + */ + if (synopGMAC_setup_tx_desc_queue(gmacdev, dev, TRANSMIT_DESC_SIZE, RINGMODE) < 0) { + TR0("Error in setup TX descriptor\n"); + return -ESYNOPGMACNOMEM; + } + synopGMAC_init_tx_desc_base(gmacdev); //Program the transmit descriptor base address in to DmaTxBase addr + + if (synopGMAC_setup_rx_desc_queue(gmacdev, dev, RECEIVE_DESC_SIZE, RINGMODE) < 0) { + TR0("Error in setup RX descriptor\n"); + synopGMAC_giveup_tx_desc_queue(gmacdev, dev, RINGMODE); + return -ESYNOPGMACNOMEM; + } + synopGMAC_init_rx_desc_base(gmacdev); /*Program the receive descriptor base address in to DmaTxBase addr*/ + + synopGMAC_dma_bus_mode_init(gmacdev, DmaFixedBurstEnable | DmaBurstLength16 | DmaDescriptorSkip0 | DmaDescriptor8Words | DmaArbitPr); /*pbl32 incr with rxthreshold 128 and Desc is 8 Words */ + synopGMAC_dma_control_init(gmacdev, DmaStoreAndForward | DmaRxThreshCtrl128 | DmaTxSecondFrame); + + /* + * Initialize the mac interface + */ + synopGMAC_mac_init(gmacdev); + synopGMAC_pause_control(gmacdev); // This enables the pause control in Full duplex mode of operation + /* + * IPC Checksum offloading is enabled for this driver. Should only be used if Full Ip checksumm offload engine is configured in the hardware + */ + synopGMAC_enable_rx_chksum_offload(gmacdev); //Enable the offload engine in the receive path + synopGMAC_rx_tcpip_chksum_drop_enable(gmacdev); // This is default configuration, DMA drops the packets if error in encapsulated ethernet payload + // The FEF bit in DMA control register is configured to 0 indicating DMA to drop the errored frames. + + synopGMAC_handle_received_data(netdev, 0); + + synopGMAC_clear_interrupt(gmacdev); + + /* + * Disable the interrupts generated by MMC and IPC counters. + * If these are not disabled ISR should be modified accordingly to handle these interrupts. + */ + synopGMAC_disable_mmc_tx_interrupt(gmacdev, 0xFFFFFFFF); + synopGMAC_disable_mmc_rx_interrupt(gmacdev, 0xFFFFFFFF); + synopGMAC_disable_mmc_ipc_rx_interrupt(gmacdev, 0xFFFFFFFF); + + synopGMAC_enable_dma_rx(gmacdev); + synopGMAC_enable_dma_tx(gmacdev); + + netif_start_queue(netdev); + synopGMAC_enable_interrupt(gmacdev, DmaIntEnable); + + return 0; +} + +/* + * Function used when the interface is closed. + * + * This function is registered to linux stop() function. This function is + * called whenever ifconfig (in Linux) closes the device (for example "ifconfig eth0 down"). + * This releases all the system resources allocated during open call. + * system resources int needs + * - Disable the device interrupts + * - Stop the receiver and get back all the rx descriptors from the DMA + * - Stop the transmitter and get back all the tx descriptors from the DMA + * - Stop the Linux network queue interface + * - Free the irq (ISR registered is removed from the kernel) + * - Release the TX and RX descripor memory + * - De-initialize one second timer rgistered for cable plug/unplug tracking + * @param[in] pointer to net_device structure. + * \return Returns 0 on success and error status upon failure. + * \callgraph + */ +static s32 synopGMAC_linux_close(struct eth_device *netdev) +{ + synopGMACdevice *gmacdev = (synopGMACdevice *) netdev_priv(netdev); + void *dev = NULL; + + TR("%s\n",__FUNCTION__); + BUG_ON(gmacdev->synopGMACnetdev != netdev); + + /* + * Disable all the interrupts + */ + synopGMAC_disable_interrupt_all(gmacdev); + TR("the synopGMAC interrupt has been disabled\n"); + + /* + * Disable the reception + */ + synopGMAC_rx_disable(gmacdev); + /*Allow any pending buffer to be read by host */ + __udelay(10000); + synopGMAC_disable_dma_rx(gmacdev); + synopGMAC_take_desc_ownership_rx(gmacdev); + TR("the synopGMAC Reception has been disabled\n"); + + /* + * Disable the transmission + */ + synopGMAC_disable_dma_tx(gmacdev); + /* allow any pending transmission to complete */ + __udelay(10000); + synopGMAC_tx_disable(gmacdev); + synopGMAC_take_desc_ownership_tx(gmacdev); + TR("the synopGMAC Transmission has been disabled\n"); + netif_stop_queue(netdev); + + /* + * Free the Rx Descriptor contents + */ + TR("Now calling synopGMAC_giveup_rx_desc_queue \n"); + synopGMAC_giveup_rx_desc_queue(gmacdev, dev, RINGMODE); + TR("Now calling synopGMAC_giveup_tx_desc_queue \n"); + synopGMAC_giveup_tx_desc_queue(gmacdev, dev, RINGMODE); + + return -ESYNOPGMACNOERR; +} + +/* + * Function to transmit a given packet on the wire. + * Whenever Linux Kernel has a packet ready to be transmitted, this function is called. + * The function prepares a packet and prepares the descriptor and + * enables/resumes the transmission. + * @param[in] pointer to sk_buff structure. + * @param[in] pointer to net_device structure. + * \return Returns 0 on success and Error code on failure. + * \note structure sk_buff is used to hold packet in Linux networking stacks. + */ +static s32 synopGMAC_linux_xmit_frames(struct sk_buff *skb, struct eth_device *netdev) +{ + u32 dma_addr; + synopGMACdevice *gmacdev; + + TR("%s called \n",__FUNCTION__); + BUG_ON(skb == NULL); + BUG_ON((skb->len < ETH_HLEN) || (skb->len > ETH_MAX_FRAME_LEN)); + if ((skb->len < ETH_HLEN) || (skb->len > ETH_MAX_FRAME_LEN)) + goto drop; + + gmacdev = (synopGMACdevice *) netdev_priv(netdev); + if (gmacdev == NULL) + goto drop; + BUG_ON(gmacdev->synopGMACnetdev != netdev); + + if (gmacdev->BusyTxDesc == gmacdev->TxDescCount) { + /* + * Return busy here. The TX will be re-tried + */ + TR0("%s No More Free Tx Descriptors\n",__FUNCTION__); + netif_stop_queue(netdev); + return NETDEV_TX_BUSY; + } + + /* + * Now we have skb ready and OS invoked this function. Lets make our DMA know about this + */ + dma_addr = virt_to_phys(skb->data); + synopGMAC_set_tx_qptr(gmacdev, dma_addr, skb->len, (u32)skb, 0); + + /* + * Now force the DMA to start transmission + */ + synopGMAC_resume_dma_tx(gmacdev); + TR("%s called \n",__FUNCTION__); + BUG_ON(skb == NULL); + return NETDEV_TX_OK; + +drop: + /* + * Now drop it + */ + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} + +/* + * Function to initialize the Linux network interface. + * + * Linux dependent Network interface is setup here. This provides + * an example to handle the network dependent functionality. + * + * \return Returns 0 on success and Error code on failure. + */ +s32 synopGMAC_init_network_interface(void) +{ + u32 i; + u32 id; + s32 err = 0; + struct eth_device *netdev; + synopGMACdevice *gmacdev; + const char *eth_name[2] = {"eth_lan", "eth_wan"};; + + cleanup_skb(); + + for (i = 0; i < 1; i++) { + + /* + * Lets allocate and set up an ethernet device, it takes the sizeof the private structure. + * This is mandatory as a 32 byte allignment is required for the private data structure. + */ + netdev = malloc(sizeof(struct eth_device)); + if(!netdev){ + TR0("Problem in alloc_etherdev()..Take Necessary action\n"); + err = -ESYNOPGMACNOMEM; + break; + } + memcpy(netdev->name, eth_name[i], sizeof(netdev->name) - 1); + + /* + * Allocate Memory for the the GMACip structure + */ + gmacdev = malloc(sizeof(synopGMACdevice)); + if(!gmacdev){ + TR0("Error in Memory Allocataion \n"); + free(netdev); + err = -ESYNOPGMACNOMEM; + break; + } + netdev->priv = gmacdev; + gmac_plat_init(); + gmacdev->phyid = gboard_param->phy_id; /* 6 or 4 */ + gmacdev->synopGMACMappedAddr = gmac_base; + TR("Initializing synopsys GMAC interface at port = 0x%x\n", + gmacdev->synopGMACMappedAddr) ; + + id = ((gmac_base - NSS_GMAC0_BASE) / NSS_GMAC_REG_LEN); + if (id > 3) + return -EINVAL; + + gmac_dev_init(id); + + /* + * Attach the device to MAC struct This will configure all the required base addresses + * such as Mac base, configuration base, phy base address (out of 32 possible phys) + */ + synopGMAC_attach(gmacdev, gmacdev->synopGMACMappedAddr); + gmacdev->synopGMACnetdev = netdev; + + /* + * This just fill in some default MAC address + */ + eth_getenv_enetaddr("ethaddr", netdev->dev_addr); + synopGMACDev[i] = gmacdev; + } + + if (synopGMACDev[0] == NULL) { + TR0("no native Ethernet interface found\n"); + return err; + } + + return 0; +} + +/* + * Function to initialize the Linux network interface. + * Linux dependent Network interface is setup here. This provides + * an example to handle the network dependent functionality. + * \return Returns 0 on success and Error code on failure. + */ +void synopGMAC_exit_network_interface(void) +{ + u32 i; + synopGMACdevice *gmacdev; + + TR0("Now Calling network_unregister\n"); + for (i = 0; i < 1; i++) { + gmacdev = synopGMACDev[i]; + if (gmacdev) { + free(gmacdev->synopGMACnetdev); + free(gmacdev); + synopGMACDev[i] = NULL; + } + } + + cleanup_skb(); +} + +/***************************************************/ + +void ubi32_eth_cleanup(void) +{ + TR("ubi32_eth_cleanup\n"); + + eth_init_done = 0; + synopGMAC_exit_network_interface(); +} + +int ipq_gmac_eth_send(struct eth_device *dev, void *packet, int len) +{ + synopGMACdevice *gmacdev = synopGMACDev[0]; + + struct sk_buff *skb = (struct sk_buff *)TxSkbuf; + + skb->data = (u8*)txbuffs; + + if (!gmacdev) { + goto dropped; + } + if (!skb) { + printf("ipq_gmac_eth_send: alloc_skb return NULL \n"); + goto dropped; + } + + skb->len=len; + memcpy(skb->data, (void *)packet, len); + synopGMAC_linux_xmit_frames(skb, gmacdev->synopGMACnetdev); + return NETDEV_TX_OK; + +dropped: +printf("dropped\n"); + return 1; +} + +int ipq_gmac_eth_rx(struct eth_device *dev) +{ + synopGMACdevice *gmacdev = synopGMACDev[0]; + + if (!gmacdev) { + return 0; + } + + synopGMAC_task_poll((unsigned long)gmacdev); + + return 1; +} + +void ipq_gmac_eth_halt(struct eth_device *dev) +{ + TR("eth_halt\n"); + + /* + * We are not initialized yet, so nothing to stop + */ + if (!eth_init_done) { + return; + } + + synopGMAC_linux_close(synopGMACDev[0]->synopGMACnetdev); + synopGMACDev[0]->state = ETH_STATE_PASSIVE; +} + +int ipq_gmac_eth_init(struct eth_device *dev,bd_t *bd) +{ + TR("eth_init\n"); + + if (!eth_init_done) { + TR("eth_init: init GMAC\n"); + synopGMAC_init_network_interface(); + athrs17_reg_init(); + synopGMACDev[0]->state = ETH_STATE_INIT; + eth_init_done = 1; + } + + synopGMAC_linux_open(synopGMACDev[0]->synopGMACnetdev, dev); + synopGMACDev[0]->state = ETH_STATE_ACTIVE; + + return 0; +} + +uint16_t mii_read_reg(synopGMACdevice *gmacdev, uint32_t phy, uint32_t reg) +{ + u16 data = 0; + + synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase , phy, reg, &data); + return (uint16_t)data; +} + +/* + * mii_write_reg() + * Write a register of an external PHY/Switch + */ +void mii_write_reg(synopGMACdevice *gmacdev, uint32_t phy, uint32_t reg, uint16_t data) +{ + synopGMAC_write_phy_reg((u32 *)gmacdev->MacBase, phy, reg, (uint16_t)data); +} + + +#define MII_BMCR 0x00 +#define BMCR_RESET 0x8000 +#define BMCR_ANENABLE 0x1000 + +void synopGMAC_reset_phy(synopGMACdevice *gmacdev, u32 phyid) +{ + mii_write_reg(gmacdev, phyid , MII_BMCR, BMCR_RESET); + mii_write_reg(gmacdev, phyid , MII_BMCR, mii_read_reg(gmacdev, phyid, MII_BMCR) | BMCR_ANENABLE); + + TR("Reset Phy %u successful\n",phyid); +} + + +int ipq_gmac_eth_initialize(const char *ethaddr) +{ + struct eth_device *dev; + unsigned int m = 5, not_n = 0xF4, not_2d = 0xF5; + int i; + gpio_func_data_t *gpio_func = gboard_param->gmac_gpio; + + gmac_clock_config(m, not_n, not_2d); + + TR("\r\n ***** ipqg_mac_eth_initialize ***** \r\n"); + dev = malloc(sizeof(*dev)); + if (dev == NULL) + return -1; + memset(dev, 0, sizeof(*dev)); + dev->iobase = gboard_param->gmac_base; + dev->init = ipq_gmac_eth_init; + dev->halt = ipq_gmac_eth_halt; + dev->send = ipq_gmac_eth_send; + dev->recv = ipq_gmac_eth_rx; + memcpy(dev->enetaddr, ethaddr, 6); + strcpy(dev->name, "ipq_gmac"); + eth_register(dev); + + for (i = 0; i < gboard_param->gmac_gpio_count; i++) { + gpio_tlmm_config(gpio_func->gpio, gpio_func->func, gpio_func->dir, + gpio_func->pull, gpio_func->drvstr, gpio_func->enable); + gpio_func++; + } + + return 0; +} + +#include "nss_gmac_clocks.h" + + +/** + * @brief Return clock divider value for RGMII PHY. + * @param[in] nss_gmac_dev * + * @return returns RGMII clock divider value. + */ +static uint32_t clk_div_rgmii(synopGMACdevice *gmacdev) +{ + uint32_t div; + + switch (gmacdev->Speed) { + case SPEED1000: + div = RGMII_CLK_DIV_1000; + break; + + case SPEED100: + div = RGMII_CLK_DIV_100; + break; + + case SPEED10: + div = RGMII_CLK_DIV_10; + break; + + default: + div = RGMII_CLK_DIV_1000; + break; + } + + return div; +} + +/** + * @brief Return clock divider value for SGMII PHY. + * @param[in] nss_gmac_dev * + * @return returns SGMII clock divider value. + */ +static uint32_t clk_div_sgmii(synopGMACdevice *gmacdev) +{ + uint32_t div; + + switch (gmacdev->Speed) { + case SPEED1000: + div = SGMII_CLK_DIV_1000; + break; + + case SPEED100: + div = SGMII_CLK_DIV_100; + break; + + case SPEED10: + div = SGMII_CLK_DIV_10; + break; + + default: + div = SGMII_CLK_DIV_1000; + break; + } + + return div; +} + + +/* + * @brief Return clock divider value for QSGMII PHY. + * @param[in] nss_gmac_dev * + * @return returns QSGMII clock divider value. + */ +static uint32_t clk_div_qsgmii(synopGMACdevice *gmacdev) +{ + uint32_t div; + + switch (gmacdev->Speed) { + case SPEED1000: + div = QSGMII_CLK_DIV_1000; + break; + + case SPEED100: + div = QSGMII_CLK_DIV_100; + break; + + case SPEED10: + div = QSGMII_CLK_DIV_10; + break; + + default: + div = QSGMII_CLK_DIV_1000; + break; + } + + return div; +} + + +void nss_gmac_dev_init(synopGMACdevice *gmacdev) +{ + uint32_t val = 0; + uint32_t id = 0, div; + + val = GMAC_IFG_CTL(GMAC_IFG) | GMAC_IFG_LIMIT(GMAC_IFG) | GMAC_CSYS_REQ; + if (gmacdev->phy_mii_type == GMAC_INTF_RGMII) { + val |= GMAC_PHY_RGMII; + } else { + val &= ~GMAC_PHY_RGMII; + } + + synopGMACSetBits((u32 *)nss_base, NSS_GMACn_CTL(id), val); + + synopGMACClearBits((u32 *)MSM_CLK_CTL_BASE, GMAC_COREn_RESET(id), 0x1); + + /* Configure clock dividers for 1000Mbps default */ + gmacdev->Speed = SPEED1000; + switch (gmacdev->phy_mii_type) { + case GMAC_INTF_RGMII: + div = clk_div_rgmii(gmacdev); + break; + + case GMAC_INTF_SGMII: + div = clk_div_sgmii(gmacdev); + break; + + case GMAC_INTF_QSGMII: + div = clk_div_qsgmii(gmacdev); + break; + } + + val = synopGMACReadReg((u32 *)nss_base, NSS_ETH_CLK_DIV0); + + val &= ~GMACn_CLK_DIV(id, GMACn_CLK_DIV_SIZE); + val |= GMACn_CLK_DIV(id, div); + synopGMACWriteReg((u32 *)nss_base, NSS_ETH_CLK_DIV0, val); + + /* Select Tx/Rx CLK source */ + val = 0; + if (id == 0 || id == 1) { + if (gmacdev->phy_mii_type == GMAC_INTF_RGMII) { + val |= (1 << id); + } + } else { + if (gmacdev->phy_mii_type == GMAC_INTF_SGMII) { + val |= (1 << id); + } + } + + synopGMACSetBits((u32 *)nss_base, NSS_ETH_CLK_SRC_CTL, val); + + synopGMACSetBits((u32 *)nss_base, NSS_QSGMII_CLK_CTL, 0x1); + + /* Enable xGMII clk for GMACn */ + val = 0; + if (gmacdev->phy_mii_type == GMAC_INTF_RGMII) { + val |= GMACn_RGMII_RX_CLK(id) | GMACn_RGMII_TX_CLK(id); + } else { + val |= GMACn_GMII_RX_CLK(id) | GMACn_GMII_TX_CLK(id); + } + + /* Optionally configure RGMII CDC delay */ + + /* Enable PTP clock */ + val |= GMACn_PTP_CLK(id); + + synopGMACSetBits((u32 *)nss_base, NSS_ETH_CLK_GATE_CTL, val); +} + +/** + * @brief QSGMII dev init + * + * @param[in] nss_gmac_dev * + * @return void + */ +void nss_gmac_qsgmii_dev_init(synopGMACdevice *gmacdev) +{ + uint32_t val; + uint32_t id = gmacdev->macid; + +#ifdef CONFIG_MACH_IPQ806X_RUMI3 + nss_gmac_rumi_qsgmii_init(gmacdev); +#endif + /* Enable clk for GMACn */ + val = 0; + if ((gmacdev->phy_mii_type == GMAC_INTF_SGMII) || (gmacdev->phy_mii_type == GMAC_INTF_QSGMII)) { + val |= GMACn_QSGMII_RX_CLK(id) | GMACn_QSGMII_TX_CLK(id); + } + + synopGMACSetBits((uint32_t *)nss_base, NSS_QSGMII_CLK_CTL, val); + + val = synopGMACReadReg((uint32_t *)nss_base, NSS_QSGMII_CLK_CTL); + TR("%s: NSS_QSGMII_CLK_CTL(0x%x) - 0x%x", + __FUNCTION__, NSS_QSGMII_CLK_CTL, val); +} + + + +/** + * @brief Clear all NSS GMAC interface registers. + * @return returns 0 on success. + */ +static void nss_gmac_clear_all_regs(void) +{ + synopGMACClearBits((uint32_t *)nss_base, + NSS_ETH_CLK_GATE_CTL, 0xFFFFFFFF); + synopGMACClearBits((uint32_t *)nss_base, + NSS_ETH_CLK_DIV0, 0xFFFFFFFF); + synopGMACClearBits((uint32_t *)nss_base, + NSS_ETH_CLK_DIV1, 0xFFFFFFFF); + synopGMACClearBits((uint32_t *)nss_base, + NSS_ETH_CLK_SRC_CTL, 0xFFFFFFFF); + synopGMACClearBits((uint32_t *)nss_base, + NSS_ETH_CLK_INV_CTL, 0xFFFFFFFF); + synopGMACClearBits((uint32_t *)nss_base, + NSS_GMAC0_CTL, 0xFFFFFFFF); + synopGMACClearBits((uint32_t *)nss_base, + NSS_GMAC1_CTL, 0xFFFFFFFF); + synopGMACClearBits((uint32_t *)nss_base, + NSS_GMAC2_CTL, 0xFFFFFFFF); + synopGMACClearBits((uint32_t *)nss_base, + NSS_GMAC3_CTL, 0xFFFFFFFF); + synopGMACClearBits((uint32_t *)nss_base, + NSS_QSGMII_CLK_CTL, 0xFFFFFFFF); +} + + +static void nss_gmac_qsgmii_common_init(uint32_t *qsgmii_base) +{ +#if defined(CONFIG_IPQ_GMAC_PHY_PROFILE_QS) + /* Configure QSGMII Block for QSGMII mode */ + + /* Put PHY in QSGMII Mode */ + synopGMACWriteReg(qsgmii_base, QSGMII_PHY_MODE_CTL, QSGMII_PHY_MODE_QSGMII); + + /* Put PCS in QSGMII Mode */ + synopGMACWriteReg(qsgmii_base, PCS_QSGMII_SGMII_MODE, PCS_QSGMII_MODE_QSGMII); +#else + /* Configure QSGMII Block for 3xSGMII mode */ + + /* Put PHY in SGMII Mode */ + synopGMACWriteReg(qsgmii_base, QSGMII_PHY_MODE_CTL, QSGMII_PHY_MODE_SGMII); + + /* Put PCS in SGMII Mode */ + synopGMACWriteReg(qsgmii_base, PCS_QSGMII_SGMII_MODE, PCS_QSGMII_MODE_SGMII); +#endif +} + + +/** + * @brief Set GMAC speed. + * @param[in] nss_gmac_dev * + * @return returns 0 on success. + */ +int32_t nss_gmac_dev_set_speed(synopGMACdevice *gmacdev) +{ + uint32_t val; + uint32_t id = gmacdev->macid; + uint32_t div; + uint32_t clk; + + gmacdev->phy_mii_type = GMAC_INTF_RGMII; + switch (gmacdev->phy_mii_type) { + case GMAC_INTF_RGMII: + div = clk_div_rgmii(gmacdev); + break; + + case GMAC_INTF_SGMII: + div = clk_div_sgmii(gmacdev); + break; + + case GMAC_INTF_QSGMII: + div = clk_div_qsgmii(gmacdev); + break; + + default: + return -EINVAL; + TR0("%s: Invalid MII type", __FUNCTION__); + break; + } + + clk = 0; + /* Disable GMACn Tx/Rx clk */ + if (gmacdev->phy_mii_type == GMAC_INTF_RGMII) { + clk |= GMACn_RGMII_RX_CLK(id) | GMACn_RGMII_TX_CLK(id); + } else { + clk |= GMACn_GMII_RX_CLK(id) | GMACn_GMII_TX_CLK(id); + } + synopGMACClearBits((u32*)nss_base, NSS_ETH_CLK_GATE_CTL, clk); + + /* set clock divider */ + val = synopGMACReadReg((u32*)nss_base, NSS_ETH_CLK_DIV0); + val &= ~GMACn_CLK_DIV(id, GMACn_CLK_DIV_SIZE); + val |= GMACn_CLK_DIV(id, div); + synopGMACWriteReg((u32*)nss_base, NSS_ETH_CLK_DIV0, val); + + /* Enable GMACn Tx/Rx clk */ + synopGMACSetBits((u32*)nss_base, NSS_ETH_CLK_GATE_CTL, clk); + + val = synopGMACReadReg((u32*)nss_base, NSS_ETH_CLK_DIV0); + TR0("%s:NSS_ETH_CLK_DIV0(0x%x) - 0x%x", + __FUNCTION__, NSS_ETH_CLK_DIV0, val); + + return 0; +} + + +void ipq806x_dev_board_init(synopGMACdevice *gmacdev) +{ + nss_gmac_common_init(); + switch (gmacdev->macid) { + case 0: + gmacdev->phy_mii_type = NSS_GMAC0_MII_MODE; + break; + + case 1: + gmacdev->phy_mii_type = NSS_GMAC1_MII_MODE; + break; + + case 2: + gmacdev->phy_mii_type = NSS_GMAC2_MII_MODE; + break; + + case 3: + gmacdev->phy_mii_type = NSS_GMAC3_MII_MODE; + break; + + default: + TR0("%s: Invalid MII type", __FUNCTION__); + return ; + break; + } + + nss_gmac_dev_init(gmacdev); +} + +/* + * @brief Initialization commom to all GMACs. + * @return returns 0 on success. + */ +int32_t nss_gmac_common_init(void) +{ + volatile uint32_t val; + + nss_gmac_clear_all_regs(); + + synopGMACWriteReg(qsgmii_base, NSS_QSGMII_PHY_SERDES_CTL, + PLL_PUMP_CURRENT_600uA | PLL_TANK_CURRENT_7mA | + PCIE_MAX_POWER_MODE | PLL_LOOP_FILTER_RESISTOR_DEFAULT | + PLL_ENABLE | SERDES_ENABLE_LCKDT); + + synopGMACWriteReg(qsgmii_base, NSS_PCS_CAL_LCKDT_CTL, LCKDT_RST_n); + + synopGMACWriteReg(qsgmii_base, NSS_QSGMII_PHY_QSGMII_CTL, + QSGMII_TX_AMPLITUDE_600mV | QSGMII_TX_SLC_10 | + QSGMII_THRESHOLD_DEFAULT | QSGMII_SLEW_RATE_DEFAULT | + QSGMII_RX_EQUALIZER_DEFAULT | QSGMII_RX_DC_BIAS_DEFAULT | + QSGMII_PHASE_LOOP_GAIN_DEFAULT | QSGMII_TX_DE_EMPHASIS_DEFAULT | + QSGMII_ENABLE | QSGMII_ENABLE_TX | + QSGMII_ENABLE_SD | QSGMII_ENABLE_RX | + QSGMII_ENABLE_CDR); + + synopGMACWriteReg(qsgmii_base, NSS_PCS_QSGMII_BERT_THLD_CTL, 0x0); + + /* + * Deaassert GMAC AHB reset + */ + synopGMACClearBits((uint32_t *)(MSM_CLK_CTL_BASE), GMAC_AHB_RESET, 0x1); + + /* Bypass MACSEC */ + synopGMACSetBits((uint32_t *)nss_base, NSS_MACSEC_CTL, 0x7); + + val = synopGMACReadReg((uint32_t *)nss_base, NSS_MACSEC_CTL); + TR("%s:NSS_MACSEC_CTL(0x%x) - 0x%x", + __FUNCTION__, NSS_MACSEC_CTL, val); + + /* + * Initialize ACC_GMAC_CUST field of NSS_ACC_REG register + * for GMAC and MACSEC memories. + */ + synopGMACClearBits((uint32_t *)(MSM_CLK_CTL_BASE), NSS_ACC_REG, GMAC_ACC_CUST_MASK); + + return 0; +} + + +void nss_gmac_reset_phy( uint32_t phyid) +{ + ipq_mii_write_reg( phyid, MII_BMCR, BMCR_RESET); + ipq_mii_write_reg( phyid, MII_BMCR, + ipq_mii_read_reg( phyid, MII_BMCR) + | BMCR_ANENABLE); +} + +int32_t ipq806x_get_link_speed(uint32_t phyid) +{ + int32_t lpa = 0, media, adv; + lpa = ipq_mii_read_reg(phyid, MII_LPA); + TR(" get_link_speed LPA %x \r\n ", lpa); + adv = ipq_mii_read_reg(phyid, MII_ADVERTISE); + TR(" get_link_speed LPA %x ADV %x \r\n ", lpa, adv); + media = mii_nway_result(lpa & adv); + if((media & ADVERTISE_1000XFULL)) + return SPEED1000; + else if (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)) + return SPEED100; + else if (media & (ADVERTISE_10FULL | ADVERTISE_10HALF)) + return SPEED10; + else return SPEED1000; /* fix to 1000 for bringup */ +} + +int32_t ipq806x_get_duplex(uint32_t phyid) +{ + int32_t lpa = 0, media, duplex, adv; + lpa = ipq_mii_read_reg(phyid, MII_LPA); + TR(" get_link_speed LPA %x \r\n ", lpa); + adv = ipq_mii_read_reg(phyid, MII_ADVERTISE); + TR(" get_link_speed LPA %x ADV %x \r\n ", lpa, adv); + media = mii_nway_result(lpa & adv); + duplex = (media & (ADVERTISE_FULL | ADVERTISE_1000XFULL)) ? FULLDUPLEX : HALFDUPLEX; + + return duplex; +} + diff --git a/root/package/utils/sysupgrade-helper/src/drivers/net/nss/synopGMAC_plat.h b/root/package/utils/sysupgrade-helper/src/drivers/net/nss/synopGMAC_plat.h new file mode 100644 index 00000000..2130668a --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/drivers/net/nss/synopGMAC_plat.h @@ -0,0 +1,149 @@ + +/* * Copyright (c) 2012 The Linux Foundation. All rights reserved.* */ + +/**\file + * This file serves as the wrapper for the platform/OS dependent functions + * It is needed to modify these functions accordingly based on the platform and the + * OS. Whenever the synopsys GMAC driver ported on to different platform, this file + * should be handled at most care. + * The corresponding function definitions for non-inline functions are available in + * synopGMAC_plat.c file. + * \internal + * -------------------------------------REVISION HISTORY--------------------------- + * Ubicom 01/Mar/2010 Modified for Ubicom32 + * Synopsys 01/Aug/2007 Created + */ + +#ifndef SYNOP_GMAC_PLAT_H +#define SYNOP_GMAC_PLAT_H 1 + +#include +#include +#include +#include "uboot_skb.h" +#include + +#define CACHE_LINE_SHIFT 5 +#define CACHE_LINE_SIZE (1 << CACHE_LINE_SHIFT) /* in bytes */ + +#define TR0(fmt, args...) printf("SynopGMAC: " fmt, ##args) +# define TR(fmt, args...) /* not debugging: nothing */ + +typedef int bool; + +#define virt_to_phys(x) ((unsigned long)(x)) + +#ifdef __GNUC__ +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#else +#define likely(x) (x) +#define unlikely(x) (x) +#endif + +#define NETDEV_TX_OK 0 +#define NETDEV_TX_BUSY 1 /* driver tx path was busy*/ + +#define DEFAULT_DELAY_VARIABLE 10 +#define DEFAULT_LOOP_VARIABLE 10/*000*/ + +/* There are platform related endian conversions + * + */ + +/* Error Codes */ +#define ESYNOPGMACNOERR 0 +#define ESYNOPGMACNOMEM ENOMEM +#define ESYNOPGMACPHYERR EIO + +static void __inline__ *plat_alloc_consistent_dmaable_memory(void *dev, size_t size, dma_addr_t *dma_addr) +{ + void *buf = memalign(CACHE_LINE_SIZE, size); + *dma_addr = (dma_addr_t)(virt_to_phys(buf)); + return buf; +} + +/** + * The Low level function to read register contents from Hardware. + * + * @param[in] pointer to the base of register map + * @param[in] Offset from the base + * \return Returns the register contents + */ +static u32 __inline__ synopGMACReadReg(u32 *RegBase, u32 RegOffset) +{ + u32 addr = (u32)RegBase + RegOffset; + u32 data; + + data = readl(addr); + TR("%s RegBase = 0x%08x RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__, (u32)RegBase, RegOffset, data ); + return data; +} + +/** + * The Low level function to write to a register in Hardware. + * + * @param[in] pointer to the base of register map + * @param[in] Offset from the base + * @param[in] Data to be written + * \return void + */ +static void __inline__ synopGMACWriteReg(u32 *RegBase, u32 RegOffset, u32 RegData) +{ + u32 addr = (u32)RegBase + RegOffset; + + writel(RegData, addr); + TR("%s RegBase = 0x%08x RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__,(u32) RegBase, RegOffset, RegData ); +} + +/** + * The Low level function to set bits of a register in Hardware. + * + * @param[in] pointer to the base of register map + * @param[in] Offset from the base + * @param[in] Bit mask to set bits to logical 1 + * \return void + */ +static void __inline__ synopGMACSetBits(u32 *RegBase, u32 RegOffset, u32 BitPos) +{ + u32 addr = (u32)RegBase + RegOffset; + + setbits_le32(addr,BitPos); + TR("%s !!!!!!!!!!!!! RegOffset = 0x%08x RegData = 0x%08x (| 0x%08x)\n", __FUNCTION__, RegOffset, data, BitPos); +} + +/** + * The Low level function to clear bits of a register in Hardware. + * + * @param[in] pointer to the base of register map + * @param[in] Offset from the base + * @param[in] Bit mask to clear bits to logical 0 + * \return void + */ +static void __inline__ synopGMACClearBits(u32 *RegBase, u32 RegOffset, u32 BitPos) +{ + u32 addr = (u32)RegBase + RegOffset; + + clrbits_le32( addr, BitPos); + TR("%s !!!!!!!!!!! RegOffset = 0x%08x RegData = 0x%08x (& ~0x%08x)\n", __FUNCTION__, RegOffset, data, BitPos); +} + +/** + * The Low level function to Check the setting of the bits. + * + * @param[in] pointer to the base of register map + * @param[in] Offset from the base + * @param[in] Bit mask to set bits to logical 1 + * \return returns TRUE if set to '1' returns FALSE if set to '0'. Result undefined there are no bit set in the BitPos argument. + * + */ +static bool __inline__ synopGMACCheckBits(u32 *RegBase, u32 RegOffset, u32 BitPos) +{ + u32 addr = (u32)RegBase + RegOffset; + u32 data; + + data = readl(addr) & BitPos ; + return (data != 0); +} + +#endif diff --git a/root/package/utils/sysupgrade-helper/src/drivers/net/nss/uboot_skb.c b/root/package/utils/sysupgrade-helper/src/drivers/net/nss/uboot_skb.c new file mode 100644 index 00000000..655bed2e --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/drivers/net/nss/uboot_skb.c @@ -0,0 +1,128 @@ +/* + * Definitions for the 'struct sk_buff' memory handlers in U-Boot. + * + n (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "uboot_skb.h" + +#define MAX_SKB 1024 + +static struct sk_buff *sk_table[MAX_SKB]; + +struct sk_buff * alloc_skb(u32 size, int dummy) +{ + int i; + struct sk_buff * ret = NULL; + + for (i = 0; i < MAX_SKB; i++) + { + if (sk_table[i]) + { + /* Already allocated. + */ + continue; + } + + sk_table[i] = malloc(sizeof(struct sk_buff)); + if (! sk_table[i]) + { + printf("alloc_skb: malloc failed\n"); + break; + } + + memset(sk_table[i], 0, sizeof(struct sk_buff)); + sk_table[i]->data = sk_table[i]->data_unaligned = + malloc(size + 48); + if (! sk_table[i]->data) + { + printf("alloc_skb: malloc failed\n"); + free(sk_table[i]); + sk_table[i] = NULL; + break; + } + + sk_table[i]->data += 48 - ((u32)sk_table[i]->data & 31); + sk_table[i]->len = size; + + break; + } + + if (i < MAX_SKB) + { + ret = sk_table[i]; + } + + if (! ret) + { + printf("Unable to allocate skb!\n"); + } + + return ret; +} + +void dev_kfree_skb_any(struct sk_buff *skb) +{ + int i; + + for (i = 0; i < MAX_SKB; i++) + { + if (sk_table[i] != skb) + { + continue; + } + + free(skb->data_unaligned); + free(skb); + sk_table[i] = NULL; + break; + } + +} + +void skb_reserve(struct sk_buff *skb, unsigned int len) +{ + skb->data+=len; +} + +void skb_put(struct sk_buff *skb, unsigned int len) +{ + skb->len+=len; +} + +void cleanup_skb(void) +{ + int i; + for (i = 0; i < MAX_SKB; i++) + { + if (sk_table[i]) + { + /* Already allocated. + */ + free(sk_table[i]->data_unaligned); + free(sk_table[i]); + sk_table[i] = NULL; + } + } +} diff --git a/root/package/utils/sysupgrade-helper/src/drivers/net/nss/uboot_skb.h b/root/package/utils/sysupgrade-helper/src/drivers/net/nss/uboot_skb.h new file mode 100644 index 00000000..b40a30a8 --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/drivers/net/nss/uboot_skb.h @@ -0,0 +1,53 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _UBOOT_COMPAT_H__ +#define _UBOOT_COMPAT_H__ + +#include +#include +#include + +#define netif_start_queue(x) +#define netif_stop_queue(x) +#define netif_wake_queue(x) + +#define dev_addr enetaddr +struct sk_buff +{ + u8 * data; + u32 len; + u8 * data_unaligned; + u32 padding; + char cb[16]; +}; + +struct sk_buff * alloc_skb(u32 size, int dummy); +void dev_kfree_skb_any(struct sk_buff *skb); +void skb_reserve(struct sk_buff *skb, unsigned int len); +void skb_put(struct sk_buff *skb, unsigned int len); + +#define dev_kfree_skb dev_kfree_skb_any +#define dev_kfree_skb_irq dev_kfree_skb_any + +#endif /* _UBOOT_COMPAT_H__ */ diff --git a/root/package/utils/sysupgrade-helper/src/mkconfig b/root/package/utils/sysupgrade-helper/src/mkconfig new file mode 100644 index 00000000..801f9212 --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/mkconfig @@ -0,0 +1,181 @@ +#!/bin/sh -e + +# Script to create header files and links to configure +# U-Boot for a specific board. +# +# Parameters: Target Architecture CPU Board [VENDOR] [SOC] +# +# (C) 2002-2010 DENX Software Engineering, Wolfgang Denk +# + +APPEND=no # Default: Create new config file +BOARD_NAME="" # Name to print in make output +TARGETS="" + +arch="" +cpu="" +board="" +vendor="" +soc="" +options="" + +if [ \( $# -eq 2 \) -a \( "$1" = "-A" \) ] ; then + # Automatic mode + line=`egrep -i "^[[:space:]]*${2}[[:space:]]" boards.cfg` || { + echo "make: *** No rule to make target \`$2_config'. Stop." >&2 + exit 1 + } + + set ${line} + # add default board name if needed + [ $# = 3 ] && set ${line} ${1} +elif [ "${MAKEFLAGS+set}${MAKELEVEL+set}" = "setset" ] ; then + # only warn when using a config target in the Makefile + cat <<-EOF + + warning: Please migrate to boards.cfg. Failure to do so will + mean removal of your board in the next release. + + EOF + sleep 5 +fi + +while [ $# -gt 0 ] ; do + case "$1" in + --) shift ; break ;; + -a) shift ; APPEND=yes ;; + -n) shift ; BOARD_NAME="${1%_config}" ; shift ;; + -t) shift ; TARGETS="`echo $1 | sed 's:_: :g'` ${TARGETS}" ; shift ;; + *) break ;; + esac +done + +[ $# -lt 4 ] && exit 1 +[ $# -gt 7 ] && exit 1 + +# Strip all options and/or _config suffixes +CONFIG_NAME="${1%_config}" + +[ "${BOARD_NAME}" ] || BOARD_NAME="${1%_config}" + +arch="$2" +cpu="$3" +if [ "$4" = "-" ] ; then + board=${BOARD_NAME} +else + board="$4" +fi +[ $# -gt 4 ] && [ "$5" != "-" ] && vendor="$5" +[ $# -gt 5 ] && [ "$6" != "-" ] && soc="$6" +[ $# -gt 6 ] && [ "$7" != "-" ] && { + # check if we have a board config name in the options field + # the options field mave have a board config name and a list + # of options, both separated by a colon (':'); the options are + # separated by commas (','). + # + # Check for board name + tmp="${7%:*}" + if [ "$tmp" ] ; then + CONFIG_NAME="$tmp" + fi + # Check if we only have a colon... + if [ "${tmp}" != "$7" ] ; then + options=${7#*:} + TARGETS="`echo ${options} | sed 's:,: :g'` ${TARGETS}" + fi +} + +if [ "${ARCH}" -a "${ARCH}" != "${arch}" ]; then + echo "Failed: \$ARCH=${ARCH}, should be '${arch}' for ${BOARD_NAME}" 1>&2 + exit 1 +fi + +if [ "$options" ] ; then + echo "Configuring for ${BOARD_NAME} - Board: ${CONFIG_NAME}, Options: ${options}" +else + echo "Configuring for ${BOARD_NAME} board..." +fi + +# +# Create link to architecture specific headers +# +if [ "$SRCTREE" != "$OBJTREE" ] ; then + mkdir -p ${OBJTREE}/include + mkdir -p ${OBJTREE}/include2 + cd ${OBJTREE}/include2 + rm -f asm + ln -s ${SRCTREE}/arch/${arch}/include/asm asm + LNPREFIX=${SRCTREE}/arch/${arch}/include/asm/ + cd ../include + mkdir -p asm +else + cd ./include + rm -f asm + ln -s ../arch/${arch}/include/asm asm +fi + +rm -f asm/arch + +if [ -z "${soc}" ] ; then + ln -s ${LNPREFIX}arch-${cpu} asm/arch +else + ln -s ${LNPREFIX}arch-${soc} asm/arch +fi + +if [ "${arch}" = "arm" ] ; then + rm -f asm/proc + ln -s ${LNPREFIX}proc-armv asm/proc +fi + +# +# Create include file for Make +# +echo "ARCH = ${arch}" > config.mk +echo "CPU = ${cpu}" >> config.mk +echo "BOARD = ${board}" >> config.mk + +[ "${vendor}" ] && echo "VENDOR = ${vendor}" >> config.mk + +[ "${soc}" ] && echo "SOC = ${soc}" >> config.mk + +# Assign board directory to BOARDIR variable +if [ -z "${vendor}" ] ; then + BOARDDIR=${board} +else + BOARDDIR=${vendor}/${board} +fi + +# +# Create board specific header file +# +if [ "$APPEND" = "yes" ] # Append to existing config file +then + echo >> config.h +else + > config.h # Create new config file +fi +echo "/* Automatically generated - do not edit */" >>config.h + +for i in ${TARGETS} ; do + i="`echo ${i} | sed '/=/ {s/=/ /;q; } ; { s/$/ 1/; }'`" + echo "#define CONFIG_${i}" >>config.h ; +done + +echo "#define CONFIG_SYS_ARCH \"${arch}\"" >> config.h +echo "#define CONFIG_SYS_CPU \"${cpu}\"" >> config.h +echo "#define CONFIG_SYS_BOARD \"${board}\"" >> config.h + +[ "${vendor}" ] && echo "#define CONFIG_SYS_VENDOR \"${vendor}\"" >> config.h + +[ "${soc}" ] && echo "#define CONFIG_SYS_SOC \"${soc}\"" >> config.h + +cat << EOF >> config.h +#define CONFIG_BOARDDIR board/$BOARDDIR +#include +#include +#include +#include +#include +EOF + +exit 0 diff --git a/root/package/utils/sysupgrade-helper/src/tools/checkpatch.pl b/root/package/utils/sysupgrade-helper/src/tools/checkpatch.pl new file mode 100644 index 00000000..c7475f9e --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/tools/checkpatch.pl @@ -0,0 +1,3343 @@ +#!/usr/bin/perl -w +# (c) 2001, Dave Jones. (the file handling bit) +# (c) 2005, Joel Schopp (the ugly bit) +# (c) 2007,2008, Andy Whitcroft (new conditions, test suite) +# (c) 2008-2010 Andy Whitcroft +# Licensed under the terms of the GNU GPL License version 2 + +use strict; + +my $P = $0; +$P =~ s@.*/@@g; + +my $V = '0.32'; + +use Getopt::Long qw(:config no_auto_abbrev); + +my $quiet = 0; +my $tree = 1; +my $chk_signoff = 1; +my $chk_patch = 1; +my $tst_only; +my $emacs = 0; +my $terse = 0; +my $file = 0; +my $check = 0; +my $summary = 1; +my $mailback = 0; +my $summary_file = 0; +my $show_types = 0; +my $root; +my %debug; +my %ignore_type = (); +my @ignore = (); +my $help = 0; +my $configuration_file = ".checkpatch.conf"; + +sub help { + my ($exitcode) = @_; + + print << "EOM"; +Usage: $P [OPTION]... [FILE]... +Version: $V + +Options: + -q, --quiet quiet + --no-tree run without a kernel tree + --no-signoff do not check for 'Signed-off-by' line + --patch treat FILE as patchfile (default) + --emacs emacs compile window format + --terse one line per report + -f, --file treat FILE as regular source file + --subjective, --strict enable more subjective tests + --ignore TYPE(,TYPE2...) ignore various comma separated message types + --show-types show the message "types" in the output + --root=PATH PATH to the kernel tree root + --no-summary suppress the per-file summary + --mailback only produce a report in case of warnings/errors + --summary-file include the filename in summary + --debug KEY=[0|1] turn on/off debugging of KEY, where KEY is one of + 'values', 'possible', 'type', and 'attr' (default + is all off) + --test-only=WORD report only warnings/errors containing WORD + literally + -h, --help, --version display this help and exit + +When FILE is - read standard input. +EOM + + exit($exitcode); +} + +my $conf = which_conf($configuration_file); +if (-f $conf) { + my @conf_args; + open(my $conffile, '<', "$conf") + or warn "$P: Can't find a readable $configuration_file file $!\n"; + + while (<$conffile>) { + my $line = $_; + + $line =~ s/\s*\n?$//g; + $line =~ s/^\s*//g; + $line =~ s/\s+/ /g; + + next if ($line =~ m/^\s*#/); + next if ($line =~ m/^\s*$/); + + my @words = split(" ", $line); + foreach my $word (@words) { + last if ($word =~ m/^#/); + push (@conf_args, $word); + } + } + close($conffile); + unshift(@ARGV, @conf_args) if @conf_args; +} + +GetOptions( + 'q|quiet+' => \$quiet, + 'tree!' => \$tree, + 'signoff!' => \$chk_signoff, + 'patch!' => \$chk_patch, + 'emacs!' => \$emacs, + 'terse!' => \$terse, + 'f|file!' => \$file, + 'subjective!' => \$check, + 'strict!' => \$check, + 'ignore=s' => \@ignore, + 'show-types!' => \$show_types, + 'root=s' => \$root, + 'summary!' => \$summary, + 'mailback!' => \$mailback, + 'summary-file!' => \$summary_file, + + 'debug=s' => \%debug, + 'test-only=s' => \$tst_only, + 'h|help' => \$help, + 'version' => \$help +) or help(1); + +help(0) if ($help); + +my $exit = 0; + +if ($#ARGV < 0) { + print "$P: no input files\n"; + exit(1); +} + +@ignore = split(/,/, join(',',@ignore)); +foreach my $word (@ignore) { + $word =~ s/\s*\n?$//g; + $word =~ s/^\s*//g; + $word =~ s/\s+/ /g; + $word =~ tr/[a-z]/[A-Z]/; + + next if ($word =~ m/^\s*#/); + next if ($word =~ m/^\s*$/); + + $ignore_type{$word}++; +} + +my $dbg_values = 0; +my $dbg_possible = 0; +my $dbg_type = 0; +my $dbg_attr = 0; +for my $key (keys %debug) { + ## no critic + eval "\${dbg_$key} = '$debug{$key}';"; + die "$@" if ($@); +} + +my $rpt_cleaners = 0; + +if ($terse) { + $emacs = 1; + $quiet++; +} + +if ($tree) { + if (defined $root) { + if (!top_of_kernel_tree($root)) { + die "$P: $root: --root does not point at a valid tree\n"; + } + } else { + if (top_of_kernel_tree('.')) { + $root = '.'; + } elsif ($0 =~ m@(.*)/scripts/[^/]*$@ && + top_of_kernel_tree($1)) { + $root = $1; + } + } + + if (!defined $root) { + print "Must be run from the top-level dir. of a kernel tree\n"; + exit(2); + } +} + +my $emitted_corrupt = 0; + +our $Ident = qr{ + [A-Za-z_][A-Za-z\d_]* + (?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)* + }x; +our $Storage = qr{extern|static|asmlinkage}; +our $Sparse = qr{ + __user| + __kernel| + __force| + __iomem| + __must_check| + __init_refok| + __kprobes| + __ref| + __rcu + }x; + +# Notes to $Attribute: +# We need \b after 'init' otherwise 'initconst' will cause a false positive in a check +our $Attribute = qr{ + const| + __percpu| + __nocast| + __safe| + __bitwise__| + __packed__| + __packed2__| + __naked| + __maybe_unused| + __always_unused| + __noreturn| + __used| + __cold| + __noclone| + __deprecated| + __read_mostly| + __kprobes| + __(?:mem|cpu|dev|)(?:initdata|initconst|init\b)| + ____cacheline_aligned| + ____cacheline_aligned_in_smp| + ____cacheline_internodealigned_in_smp| + __weak + }x; +our $Modifier; +our $Inline = qr{inline|__always_inline|noinline}; +our $Member = qr{->$Ident|\.$Ident|\[[^]]*\]}; +our $Lval = qr{$Ident(?:$Member)*}; + +our $Constant = qr{(?:[0-9]+|0x[0-9a-fA-F]+)[UL]*}; +our $Assignment = qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)}; +our $Compare = qr{<=|>=|==|!=|<|>}; +our $Operators = qr{ + <=|>=|==|!=| + =>|->|<<|>>|<|>|!|~| + &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|% + }x; + +our $NonptrType; +our $Type; +our $Declare; + +our $UTF8 = qr { + [\x09\x0A\x0D\x20-\x7E] # ASCII + | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 + | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 +}x; + +our $typeTypedefs = qr{(?x: + (?:__)?(?:u|s|be|le)(?:8|16|32|64)| + atomic_t +)}; + +our $logFunctions = qr{(?x: + printk(?:_ratelimited|_once|)| + [a-z0-9]+_(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)| + WARN(?:_RATELIMIT|_ONCE|)| + panic| + MODULE_[A-Z_]+ +)}; + +our $signature_tags = qr{(?xi: + Signed-off-by:| + Acked-by:| + Tested-by:| + Reviewed-by:| + Reported-by:| + To:| + Cc: +)}; + +our @typeList = ( + qr{void}, + qr{(?:unsigned\s+)?char}, + qr{(?:unsigned\s+)?short}, + qr{(?:unsigned\s+)?int}, + qr{(?:unsigned\s+)?long}, + qr{(?:unsigned\s+)?long\s+int}, + qr{(?:unsigned\s+)?long\s+long}, + qr{(?:unsigned\s+)?long\s+long\s+int}, + qr{unsigned}, + qr{float}, + qr{double}, + qr{bool}, + qr{struct\s+$Ident}, + qr{union\s+$Ident}, + qr{enum\s+$Ident}, + qr{${Ident}_t}, + qr{${Ident}_handler}, + qr{${Ident}_handler_fn}, +); +our @modifierList = ( + qr{fastcall}, +); + +our $allowed_asm_includes = qr{(?x: + irq| + memory +)}; +# memory.h: ARM has a custom one + +sub build_types { + my $mods = "(?x: \n" . join("|\n ", @modifierList) . "\n)"; + my $all = "(?x: \n" . join("|\n ", @typeList) . "\n)"; + $Modifier = qr{(?:$Attribute|$Sparse|$mods)}; + $NonptrType = qr{ + (?:$Modifier\s+|const\s+)* + (?: + (?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)| + (?:$typeTypedefs\b)| + (?:${all}\b) + ) + (?:\s+$Modifier|\s+const)* + }x; + $Type = qr{ + $NonptrType + (?:[\s\*]+\s*const|[\s\*]+|(?:\s*\[\s*\])+)? + (?:\s+$Inline|\s+$Modifier)* + }x; + $Declare = qr{(?:$Storage\s+)?$Type}; +} +build_types(); + +our $match_balanced_parentheses = qr/(\((?:[^\(\)]+|(-1))*\))/; + +our $Typecast = qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*}; +our $LvalOrFunc = qr{($Lval)\s*($match_balanced_parentheses{0,1})\s*}; + +sub deparenthesize { + my ($string) = @_; + return "" if (!defined($string)); + $string =~ s@^\s*\(\s*@@g; + $string =~ s@\s*\)\s*$@@g; + $string =~ s@\s+@ @g; + return $string; +} + +$chk_signoff = 0 if ($file); + +my @dep_includes = (); +my @dep_functions = (); +my $removal = "Documentation/feature-removal-schedule.txt"; +if ($tree && -f "$root/$removal") { + open(my $REMOVE, '<', "$root/$removal") || + die "$P: $removal: open failed - $!\n"; + while (<$REMOVE>) { + if (/^Check:\s+(.*\S)/) { + for my $entry (split(/[, ]+/, $1)) { + if ($entry =~ m@include/(.*)@) { + push(@dep_includes, $1); + + } elsif ($entry !~ m@/@) { + push(@dep_functions, $entry); + } + } + } + } + close($REMOVE); +} + +my @rawlines = (); +my @lines = (); +my $vname; +for my $filename (@ARGV) { + my $FILE; + if ($file) { + open($FILE, '-|', "diff -u /dev/null $filename") || + die "$P: $filename: diff failed - $!\n"; + } elsif ($filename eq '-') { + open($FILE, '<&STDIN'); + } else { + open($FILE, '<', "$filename") || + die "$P: $filename: open failed - $!\n"; + } + if ($filename eq '-') { + $vname = 'Your patch'; + } else { + $vname = $filename; + } + while (<$FILE>) { + chomp; + push(@rawlines, $_); + } + close($FILE); + if (!process($filename)) { + $exit = 1; + } + @rawlines = (); + @lines = (); +} + +exit($exit); + +sub top_of_kernel_tree { + my ($root) = @_; + + my @tree_check = ( + "COPYING", "CREDITS", "Kbuild", "MAINTAINERS", "Makefile", + "README", "Documentation", "arch", "include", "drivers", + "fs", "init", "ipc", "kernel", "lib", "scripts", + ); + + foreach my $check (@tree_check) { + if (! -e $root . '/' . $check) { + return 0; + } + } + return 1; + } + +sub parse_email { + my ($formatted_email) = @_; + + my $name = ""; + my $address = ""; + my $comment = ""; + + if ($formatted_email =~ /^(.*)<(\S+\@\S+)>(.*)$/) { + $name = $1; + $address = $2; + $comment = $3 if defined $3; + } elsif ($formatted_email =~ /^\s*<(\S+\@\S+)>(.*)$/) { + $address = $1; + $comment = $2 if defined $2; + } elsif ($formatted_email =~ /(\S+\@\S+)(.*)$/) { + $address = $1; + $comment = $2 if defined $2; + $formatted_email =~ s/$address.*$//; + $name = $formatted_email; + $name =~ s/^\s+|\s+$//g; + $name =~ s/^\"|\"$//g; + # If there's a name left after stripping spaces and + # leading quotes, and the address doesn't have both + # leading and trailing angle brackets, the address + # is invalid. ie: + # "joe smith joe@smith.com" bad + # "joe smith ]+>$/) { + $name = ""; + $address = ""; + $comment = ""; + } + } + + $name =~ s/^\s+|\s+$//g; + $name =~ s/^\"|\"$//g; + $address =~ s/^\s+|\s+$//g; + $address =~ s/^\<|\>$//g; + + if ($name =~ /[^\w \-]/i) { ##has "must quote" chars + $name =~ s/(?"; + } + + return $formatted_email; +} + +sub which_conf { + my ($conf) = @_; + + foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) { + if (-e "$path/$conf") { + return "$path/$conf"; + } + } + + return ""; +} + +sub expand_tabs { + my ($str) = @_; + + my $res = ''; + my $n = 0; + for my $c (split(//, $str)) { + if ($c eq "\t") { + $res .= ' '; + $n++; + for (; ($n % 8) != 0; $n++) { + $res .= ' '; + } + next; + } + $res .= $c; + $n++; + } + + return $res; +} +sub copy_spacing { + (my $res = shift) =~ tr/\t/ /c; + return $res; +} + +sub line_stats { + my ($line) = @_; + + # Drop the diff line leader and expand tabs + $line =~ s/^.//; + $line = expand_tabs($line); + + # Pick the indent from the front of the line. + my ($white) = ($line =~ /^(\s*)/); + + return (length($line), length($white)); +} + +my $sanitise_quote = ''; + +sub sanitise_line_reset { + my ($in_comment) = @_; + + if ($in_comment) { + $sanitise_quote = '*/'; + } else { + $sanitise_quote = ''; + } +} +sub sanitise_line { + my ($line) = @_; + + my $res = ''; + my $l = ''; + + my $qlen = 0; + my $off = 0; + my $c; + + # Always copy over the diff marker. + $res = substr($line, 0, 1); + + for ($off = 1; $off < length($line); $off++) { + $c = substr($line, $off, 1); + + # Comments we are wacking completly including the begin + # and end, all to $;. + if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') { + $sanitise_quote = '*/'; + + substr($res, $off, 2, "$;$;"); + $off++; + next; + } + if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') { + $sanitise_quote = ''; + substr($res, $off, 2, "$;$;"); + $off++; + next; + } + if ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') { + $sanitise_quote = '//'; + + substr($res, $off, 2, $sanitise_quote); + $off++; + next; + } + + # A \ in a string means ignore the next character. + if (($sanitise_quote eq "'" || $sanitise_quote eq '"') && + $c eq "\\") { + substr($res, $off, 2, 'XX'); + $off++; + next; + } + # Regular quotes. + if ($c eq "'" || $c eq '"') { + if ($sanitise_quote eq '') { + $sanitise_quote = $c; + + substr($res, $off, 1, $c); + next; + } elsif ($sanitise_quote eq $c) { + $sanitise_quote = ''; + } + } + + #print "c<$c> SQ<$sanitise_quote>\n"; + if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") { + substr($res, $off, 1, $;); + } elsif ($off != 0 && $sanitise_quote eq '//' && $c ne "\t") { + substr($res, $off, 1, $;); + } elsif ($off != 0 && $sanitise_quote && $c ne "\t") { + substr($res, $off, 1, 'X'); + } else { + substr($res, $off, 1, $c); + } + } + + if ($sanitise_quote eq '//') { + $sanitise_quote = ''; + } + + # The pathname on a #include may be surrounded by '<' and '>'. + if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) { + my $clean = 'X' x length($1); + $res =~ s@\<.*\>@<$clean>@; + + # The whole of a #error is a string. + } elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) { + my $clean = 'X' x length($1); + $res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@; + } + + return $res; +} + +sub ctx_statement_block { + my ($linenr, $remain, $off) = @_; + my $line = $linenr - 1; + my $blk = ''; + my $soff = $off; + my $coff = $off - 1; + my $coff_set = 0; + + my $loff = 0; + + my $type = ''; + my $level = 0; + my @stack = (); + my $p; + my $c; + my $len = 0; + + my $remainder; + while (1) { + @stack = (['', 0]) if ($#stack == -1); + + #warn "CSB: blk<$blk> remain<$remain>\n"; + # If we are about to drop off the end, pull in more + # context. + if ($off >= $len) { + for (; $remain > 0; $line++) { + last if (!defined $lines[$line]); + next if ($lines[$line] =~ /^-/); + $remain--; + $loff = $len; + $blk .= $lines[$line] . "\n"; + $len = length($blk); + $line++; + last; + } + # Bail if there is no further context. + #warn "CSB: blk<$blk> off<$off> len<$len>\n"; + if ($off >= $len) { + last; + } + } + $p = $c; + $c = substr($blk, $off, 1); + $remainder = substr($blk, $off); + + #warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n"; + + # Handle nested #if/#else. + if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) { + push(@stack, [ $type, $level ]); + } elsif ($remainder =~ /^#\s*(?:else|elif)\b/) { + ($type, $level) = @{$stack[$#stack - 1]}; + } elsif ($remainder =~ /^#\s*endif\b/) { + ($type, $level) = @{pop(@stack)}; + } + + # Statement ends at the ';' or a close '}' at the + # outermost level. + if ($level == 0 && $c eq ';') { + last; + } + + # An else is really a conditional as long as its not else if + if ($level == 0 && $coff_set == 0 && + (!defined($p) || $p =~ /(?:\s|\}|\+)/) && + $remainder =~ /^(else)(?:\s|{)/ && + $remainder !~ /^else\s+if\b/) { + $coff = $off + length($1) - 1; + $coff_set = 1; + #warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n"; + #warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n"; + } + + if (($type eq '' || $type eq '(') && $c eq '(') { + $level++; + $type = '('; + } + if ($type eq '(' && $c eq ')') { + $level--; + $type = ($level != 0)? '(' : ''; + + if ($level == 0 && $coff < $soff) { + $coff = $off; + $coff_set = 1; + #warn "CSB: mark coff<$coff>\n"; + } + } + if (($type eq '' || $type eq '{') && $c eq '{') { + $level++; + $type = '{'; + } + if ($type eq '{' && $c eq '}') { + $level--; + $type = ($level != 0)? '{' : ''; + + if ($level == 0) { + if (substr($blk, $off + 1, 1) eq ';') { + $off++; + } + last; + } + } + $off++; + } + # We are truly at the end, so shuffle to the next line. + if ($off == $len) { + $loff = $len + 1; + $line++; + $remain--; + } + + my $statement = substr($blk, $soff, $off - $soff + 1); + my $condition = substr($blk, $soff, $coff - $soff + 1); + + #warn "STATEMENT<$statement>\n"; + #warn "CONDITION<$condition>\n"; + + #print "coff<$coff> soff<$off> loff<$loff>\n"; + + return ($statement, $condition, + $line, $remain + 1, $off - $loff + 1, $level); +} + +sub statement_lines { + my ($stmt) = @_; + + # Strip the diff line prefixes and rip blank lines at start and end. + $stmt =~ s/(^|\n)./$1/g; + $stmt =~ s/^\s*//; + $stmt =~ s/\s*$//; + + my @stmt_lines = ($stmt =~ /\n/g); + + return $#stmt_lines + 2; +} + +sub statement_rawlines { + my ($stmt) = @_; + + my @stmt_lines = ($stmt =~ /\n/g); + + return $#stmt_lines + 2; +} + +sub statement_block_size { + my ($stmt) = @_; + + $stmt =~ s/(^|\n)./$1/g; + $stmt =~ s/^\s*{//; + $stmt =~ s/}\s*$//; + $stmt =~ s/^\s*//; + $stmt =~ s/\s*$//; + + my @stmt_lines = ($stmt =~ /\n/g); + my @stmt_statements = ($stmt =~ /;/g); + + my $stmt_lines = $#stmt_lines + 2; + my $stmt_statements = $#stmt_statements + 1; + + if ($stmt_lines > $stmt_statements) { + return $stmt_lines; + } else { + return $stmt_statements; + } +} + +sub ctx_statement_full { + my ($linenr, $remain, $off) = @_; + my ($statement, $condition, $level); + + my (@chunks); + + # Grab the first conditional/block pair. + ($statement, $condition, $linenr, $remain, $off, $level) = + ctx_statement_block($linenr, $remain, $off); + #print "F: c<$condition> s<$statement> remain<$remain>\n"; + push(@chunks, [ $condition, $statement ]); + if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) { + return ($level, $linenr, @chunks); + } + + # Pull in the following conditional/block pairs and see if they + # could continue the statement. + for (;;) { + ($statement, $condition, $linenr, $remain, $off, $level) = + ctx_statement_block($linenr, $remain, $off); + #print "C: c<$condition> s<$statement> remain<$remain>\n"; + last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s)); + #print "C: push\n"; + push(@chunks, [ $condition, $statement ]); + } + + return ($level, $linenr, @chunks); +} + +sub ctx_block_get { + my ($linenr, $remain, $outer, $open, $close, $off) = @_; + my $line; + my $start = $linenr - 1; + my $blk = ''; + my @o; + my @c; + my @res = (); + + my $level = 0; + my @stack = ($level); + for ($line = $start; $remain > 0; $line++) { + next if ($rawlines[$line] =~ /^-/); + $remain--; + + $blk .= $rawlines[$line]; + + # Handle nested #if/#else. + if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) { + push(@stack, $level); + } elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) { + $level = $stack[$#stack - 1]; + } elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) { + $level = pop(@stack); + } + + foreach my $c (split(//, $lines[$line])) { + ##print "C<$c>L<$level><$open$close>O<$off>\n"; + if ($off > 0) { + $off--; + next; + } + + if ($c eq $close && $level > 0) { + $level--; + last if ($level == 0); + } elsif ($c eq $open) { + $level++; + } + } + + if (!$outer || $level <= 1) { + push(@res, $rawlines[$line]); + } + + last if ($level == 0); + } + + return ($level, @res); +} +sub ctx_block_outer { + my ($linenr, $remain) = @_; + + my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0); + return @r; +} +sub ctx_block { + my ($linenr, $remain) = @_; + + my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0); + return @r; +} +sub ctx_statement { + my ($linenr, $remain, $off) = @_; + + my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off); + return @r; +} +sub ctx_block_level { + my ($linenr, $remain) = @_; + + return ctx_block_get($linenr, $remain, 0, '{', '}', 0); +} +sub ctx_statement_level { + my ($linenr, $remain, $off) = @_; + + return ctx_block_get($linenr, $remain, 0, '(', ')', $off); +} + +sub ctx_locate_comment { + my ($first_line, $end_line) = @_; + + # Catch a comment on the end of the line itself. + my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@); + return $current_comment if (defined $current_comment); + + # Look through the context and try and figure out if there is a + # comment. + my $in_comment = 0; + $current_comment = ''; + for (my $linenr = $first_line; $linenr < $end_line; $linenr++) { + my $line = $rawlines[$linenr - 1]; + #warn " $line\n"; + if ($linenr == $first_line and $line =~ m@^.\s*\*@) { + $in_comment = 1; + } + if ($line =~ m@/\*@) { + $in_comment = 1; + } + if (!$in_comment && $current_comment ne '') { + $current_comment = ''; + } + $current_comment .= $line . "\n" if ($in_comment); + if ($line =~ m@\*/@) { + $in_comment = 0; + } + } + + chomp($current_comment); + return($current_comment); +} +sub ctx_has_comment { + my ($first_line, $end_line) = @_; + my $cmt = ctx_locate_comment($first_line, $end_line); + + ##print "LINE: $rawlines[$end_line - 1 ]\n"; + ##print "CMMT: $cmt\n"; + + return ($cmt ne ''); +} + +sub raw_line { + my ($linenr, $cnt) = @_; + + my $offset = $linenr - 1; + $cnt++; + + my $line; + while ($cnt) { + $line = $rawlines[$offset++]; + next if (defined($line) && $line =~ /^-/); + $cnt--; + } + + return $line; +} + +sub cat_vet { + my ($vet) = @_; + my ($res, $coded); + + $res = ''; + while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) { + $res .= $1; + if ($2 ne '') { + $coded = sprintf("^%c", unpack('C', $2) + 64); + $res .= $coded; + } + } + $res =~ s/$/\$/; + + return $res; +} + +my $av_preprocessor = 0; +my $av_pending; +my @av_paren_type; +my $av_pend_colon; + +sub annotate_reset { + $av_preprocessor = 0; + $av_pending = '_'; + @av_paren_type = ('E'); + $av_pend_colon = 'O'; +} + +sub annotate_values { + my ($stream, $type) = @_; + + my $res; + my $var = '_' x length($stream); + my $cur = $stream; + + print "$stream\n" if ($dbg_values > 1); + + while (length($cur)) { + @av_paren_type = ('E') if ($#av_paren_type < 0); + print " <" . join('', @av_paren_type) . + "> <$type> <$av_pending>" if ($dbg_values > 1); + if ($cur =~ /^(\s+)/o) { + print "WS($1)\n" if ($dbg_values > 1); + if ($1 =~ /\n/ && $av_preprocessor) { + $type = pop(@av_paren_type); + $av_preprocessor = 0; + } + + } elsif ($cur =~ /^(\(\s*$Type\s*)\)/ && $av_pending eq '_') { + print "CAST($1)\n" if ($dbg_values > 1); + push(@av_paren_type, $type); + $type = 'C'; + + } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) { + print "DECLARE($1)\n" if ($dbg_values > 1); + $type = 'T'; + + } elsif ($cur =~ /^($Modifier)\s*/) { + print "MODIFIER($1)\n" if ($dbg_values > 1); + $type = 'T'; + + } elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) { + print "DEFINE($1,$2)\n" if ($dbg_values > 1); + $av_preprocessor = 1; + push(@av_paren_type, $type); + if ($2 ne '') { + $av_pending = 'N'; + } + $type = 'E'; + + } elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) { + print "UNDEF($1)\n" if ($dbg_values > 1); + $av_preprocessor = 1; + push(@av_paren_type, $type); + + } elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) { + print "PRE_START($1)\n" if ($dbg_values > 1); + $av_preprocessor = 1; + + push(@av_paren_type, $type); + push(@av_paren_type, $type); + $type = 'E'; + + } elsif ($cur =~ /^(\#\s*(?:else|elif))/o) { + print "PRE_RESTART($1)\n" if ($dbg_values > 1); + $av_preprocessor = 1; + + push(@av_paren_type, $av_paren_type[$#av_paren_type]); + + $type = 'E'; + + } elsif ($cur =~ /^(\#\s*(?:endif))/o) { + print "PRE_END($1)\n" if ($dbg_values > 1); + + $av_preprocessor = 1; + + # Assume all arms of the conditional end as this + # one does, and continue as if the #endif was not here. + pop(@av_paren_type); + push(@av_paren_type, $type); + $type = 'E'; + + } elsif ($cur =~ /^(\\\n)/o) { + print "PRECONT($1)\n" if ($dbg_values > 1); + + } elsif ($cur =~ /^(__attribute__)\s*\(?/o) { + print "ATTR($1)\n" if ($dbg_values > 1); + $av_pending = $type; + $type = 'N'; + + } elsif ($cur =~ /^(sizeof)\s*(\()?/o) { + print "SIZEOF($1)\n" if ($dbg_values > 1); + if (defined $2) { + $av_pending = 'V'; + } + $type = 'N'; + + } elsif ($cur =~ /^(if|while|for)\b/o) { + print "COND($1)\n" if ($dbg_values > 1); + $av_pending = 'E'; + $type = 'N'; + + } elsif ($cur =~/^(case)/o) { + print "CASE($1)\n" if ($dbg_values > 1); + $av_pend_colon = 'C'; + $type = 'N'; + + } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) { + print "KEYWORD($1)\n" if ($dbg_values > 1); + $type = 'N'; + + } elsif ($cur =~ /^(\()/o) { + print "PAREN('$1')\n" if ($dbg_values > 1); + push(@av_paren_type, $av_pending); + $av_pending = '_'; + $type = 'N'; + + } elsif ($cur =~ /^(\))/o) { + my $new_type = pop(@av_paren_type); + if ($new_type ne '_') { + $type = $new_type; + print "PAREN('$1') -> $type\n" + if ($dbg_values > 1); + } else { + print "PAREN('$1')\n" if ($dbg_values > 1); + } + + } elsif ($cur =~ /^($Ident)\s*\(/o) { + print "FUNC($1)\n" if ($dbg_values > 1); + $type = 'V'; + $av_pending = 'V'; + + } elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) { + if (defined $2 && $type eq 'C' || $type eq 'T') { + $av_pend_colon = 'B'; + } elsif ($type eq 'E') { + $av_pend_colon = 'L'; + } + print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1); + $type = 'V'; + + } elsif ($cur =~ /^($Ident|$Constant)/o) { + print "IDENT($1)\n" if ($dbg_values > 1); + $type = 'V'; + + } elsif ($cur =~ /^($Assignment)/o) { + print "ASSIGN($1)\n" if ($dbg_values > 1); + $type = 'N'; + + } elsif ($cur =~/^(;|{|})/) { + print "END($1)\n" if ($dbg_values > 1); + $type = 'E'; + $av_pend_colon = 'O'; + + } elsif ($cur =~/^(,)/) { + print "COMMA($1)\n" if ($dbg_values > 1); + $type = 'C'; + + } elsif ($cur =~ /^(\?)/o) { + print "QUESTION($1)\n" if ($dbg_values > 1); + $type = 'N'; + + } elsif ($cur =~ /^(:)/o) { + print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1); + + substr($var, length($res), 1, $av_pend_colon); + if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') { + $type = 'E'; + } else { + $type = 'N'; + } + $av_pend_colon = 'O'; + + } elsif ($cur =~ /^(\[)/o) { + print "CLOSE($1)\n" if ($dbg_values > 1); + $type = 'N'; + + } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) { + my $variant; + + print "OPV($1)\n" if ($dbg_values > 1); + if ($type eq 'V') { + $variant = 'B'; + } else { + $variant = 'U'; + } + + substr($var, length($res), 1, $variant); + $type = 'N'; + + } elsif ($cur =~ /^($Operators)/o) { + print "OP($1)\n" if ($dbg_values > 1); + if ($1 ne '++' && $1 ne '--') { + $type = 'N'; + } + + } elsif ($cur =~ /(^.)/o) { + print "C($1)\n" if ($dbg_values > 1); + } + if (defined $1) { + $cur = substr($cur, length($1)); + $res .= $type x length($1); + } + } + + return ($res, $var); +} + +sub possible { + my ($possible, $line) = @_; + my $notPermitted = qr{(?: + ^(?: + $Modifier| + $Storage| + $Type| + DEFINE_\S+ + )$| + ^(?: + goto| + return| + case| + else| + asm|__asm__| + do + )(?:\s|$)| + ^(?:typedef|struct|enum)\b + )}x; + warn "CHECK<$possible> ($line)\n" if ($dbg_possible > 2); + if ($possible !~ $notPermitted) { + # Check for modifiers. + $possible =~ s/\s*$Storage\s*//g; + $possible =~ s/\s*$Sparse\s*//g; + if ($possible =~ /^\s*$/) { + + } elsif ($possible =~ /\s/) { + $possible =~ s/\s*$Type\s*//g; + for my $modifier (split(' ', $possible)) { + if ($modifier !~ $notPermitted) { + warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible); + push(@modifierList, $modifier); + } + } + + } else { + warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible); + push(@typeList, $possible); + } + build_types(); + } else { + warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1); + } +} + +my $prefix = ''; + +sub show_type { + return !defined $ignore_type{$_[0]}; +} + +sub report { + if (!show_type($_[1]) || + (defined $tst_only && $_[2] !~ /\Q$tst_only\E/)) { + return 0; + } + my $line; + if ($show_types) { + $line = "$prefix$_[0]:$_[1]: $_[2]\n"; + } else { + $line = "$prefix$_[0]: $_[2]\n"; + } + $line = (split('\n', $line))[0] . "\n" if ($terse); + + push(our @report, $line); + + return 1; +} +sub report_dump { + our @report; +} + +sub ERROR { + if (report("ERROR", $_[0], $_[1])) { + our $clean = 0; + our $cnt_error++; + } +} +sub WARN { + if (report("WARNING", $_[0], $_[1])) { + our $clean = 0; + our $cnt_warn++; + } +} +sub CHK { + if ($check && report("CHECK", $_[0], $_[1])) { + our $clean = 0; + our $cnt_chk++; + } +} + +sub check_absolute_file { + my ($absolute, $herecurr) = @_; + my $file = $absolute; + + ##print "absolute<$absolute>\n"; + + # See if any suffix of this path is a path within the tree. + while ($file =~ s@^[^/]*/@@) { + if (-f "$root/$file") { + ##print "file<$file>\n"; + last; + } + } + if (! -f _) { + return 0; + } + + # It is, so see if the prefix is acceptable. + my $prefix = $absolute; + substr($prefix, -length($file)) = ''; + + ##print "prefix<$prefix>\n"; + if ($prefix ne ".../") { + WARN("USE_RELATIVE_PATH", + "use relative pathname instead of absolute in changelog text\n" . $herecurr); + } +} + +sub process { + my $filename = shift; + + my $linenr=0; + my $prevline=""; + my $prevrawline=""; + my $stashline=""; + my $stashrawline=""; + + my $length; + my $indent; + my $previndent=0; + my $stashindent=0; + + our $clean = 1; + my $signoff = 0; + my $is_patch = 0; + + our @report = (); + our $cnt_lines = 0; + our $cnt_error = 0; + our $cnt_warn = 0; + our $cnt_chk = 0; + + # Trace the real file/line as we go. + my $realfile = ''; + my $realline = 0; + my $realcnt = 0; + my $here = ''; + my $in_comment = 0; + my $comment_edge = 0; + my $first_line = 0; + my $p1_prefix = ''; + + my $prev_values = 'E'; + + # suppression flags + my %suppress_ifbraces; + my %suppress_whiletrailers; + my %suppress_export; + + # Pre-scan the patch sanitizing the lines. + # Pre-scan the patch looking for any __setup documentation. + # + my @setup_docs = (); + my $setup_docs = 0; + + sanitise_line_reset(); + my $line; + foreach my $rawline (@rawlines) { + $linenr++; + $line = $rawline; + + if ($rawline=~/^\+\+\+\s+(\S+)/) { + $setup_docs = 0; + if ($1 =~ m@Documentation/kernel-parameters.txt$@) { + $setup_docs = 1; + } + #next; + } + if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { + $realline=$1-1; + if (defined $2) { + $realcnt=$3+1; + } else { + $realcnt=1+1; + } + $in_comment = 0; + + # Guestimate if this is a continuing comment. Run + # the context looking for a comment "edge". If this + # edge is a close comment then we must be in a comment + # at context start. + my $edge; + my $cnt = $realcnt; + for (my $ln = $linenr + 1; $cnt > 0; $ln++) { + next if (defined $rawlines[$ln - 1] && + $rawlines[$ln - 1] =~ /^-/); + $cnt--; + #print "RAW<$rawlines[$ln - 1]>\n"; + last if (!defined $rawlines[$ln - 1]); + if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ && + $rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) { + ($edge) = $1; + last; + } + } + if (defined $edge && $edge eq '*/') { + $in_comment = 1; + } + + # Guestimate if this is a continuing comment. If this + # is the start of a diff block and this line starts + # ' *' then it is very likely a comment. + if (!defined $edge && + $rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@) + { + $in_comment = 1; + } + + ##print "COMMENT:$in_comment edge<$edge> $rawline\n"; + sanitise_line_reset($in_comment); + + } elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) { + # Standardise the strings and chars within the input to + # simplify matching -- only bother with positive lines. + $line = sanitise_line($rawline); + } + push(@lines, $line); + + if ($realcnt > 1) { + $realcnt-- if ($line =~ /^(?:\+| |$)/); + } else { + $realcnt = 0; + } + + #print "==>$rawline\n"; + #print "-->$line\n"; + + if ($setup_docs && $line =~ /^\+/) { + push(@setup_docs, $line); + } + } + + $prefix = ''; + + $realcnt = 0; + $linenr = 0; + foreach my $line (@lines) { + $linenr++; + + my $rawline = $rawlines[$linenr - 1]; + +#extract the line range in the file after the patch is applied + if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { + $is_patch = 1; + $first_line = $linenr + 1; + $realline=$1-1; + if (defined $2) { + $realcnt=$3+1; + } else { + $realcnt=1+1; + } + annotate_reset(); + $prev_values = 'E'; + + %suppress_ifbraces = (); + %suppress_whiletrailers = (); + %suppress_export = (); + next; + +# track the line number as we move through the hunk, note that +# new versions of GNU diff omit the leading space on completely +# blank context lines so we need to count that too. + } elsif ($line =~ /^( |\+|$)/) { + $realline++; + $realcnt-- if ($realcnt != 0); + + # Measure the line length and indent. + ($length, $indent) = line_stats($rawline); + + # Track the previous line. + ($prevline, $stashline) = ($stashline, $line); + ($previndent, $stashindent) = ($stashindent, $indent); + ($prevrawline, $stashrawline) = ($stashrawline, $rawline); + + #warn "line<$line>\n"; + + } elsif ($realcnt == 1) { + $realcnt--; + } + + my $hunk_line = ($realcnt != 0); + +#make up the handle for any error we report on this line + $prefix = "$filename:$realline: " if ($emacs && $file); + $prefix = "$filename:$linenr: " if ($emacs && !$file); + + $here = "#$linenr: " if (!$file); + $here = "#$realline: " if ($file); + + # extract the filename as it passes + if ($line =~ /^diff --git.*?(\S+)$/) { + $realfile = $1; + $realfile =~ s@^([^/]*)/@@; + + } elsif ($line =~ /^\+\+\+\s+(\S+)/) { + $realfile = $1; + $realfile =~ s@^([^/]*)/@@; + + $p1_prefix = $1; + if (!$file && $tree && $p1_prefix ne '' && + -e "$root/$p1_prefix") { + WARN("PATCH_PREFIX", + "patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n"); + } + + if ($realfile =~ m@^include/asm/@) { + ERROR("MODIFIED_INCLUDE_ASM", + "do not modify files in include/asm, change architecture specific files in include/asm-\n" . "$here$rawline\n"); + } + next; + } + + $here .= "FILE: $realfile:$realline:" if ($realcnt != 0); + + my $hereline = "$here\n$rawline\n"; + my $herecurr = "$here\n$rawline\n"; + my $hereprev = "$here\n$prevrawline\n$rawline\n"; + + $cnt_lines++ if ($realcnt != 0); + +# Check for incorrect file permissions + if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) { + my $permhere = $here . "FILE: $realfile\n"; + if ($realfile =~ /(Makefile|Kconfig|\.c|\.h|\.S|\.tmpl)$/) { + ERROR("EXECUTE_PERMISSIONS", + "do not set execute permissions for source files\n" . $permhere); + } + } + +# Check the patch for a signoff: + if ($line =~ /^\s*signed-off-by:/i) { + $signoff++; + } + +# Check signature styles + if ($line =~ /^(\s*)($signature_tags)(\s*)(.*)/) { + my $space_before = $1; + my $sign_off = $2; + my $space_after = $3; + my $email = $4; + my $ucfirst_sign_off = ucfirst(lc($sign_off)); + + if (defined $space_before && $space_before ne "") { + WARN("BAD_SIGN_OFF", + "Do not use whitespace before $ucfirst_sign_off\n" . $herecurr); + } + if ($sign_off =~ /-by:$/i && $sign_off ne $ucfirst_sign_off) { + WARN("BAD_SIGN_OFF", + "'$ucfirst_sign_off' is the preferred signature form\n" . $herecurr); + } + if (!defined $space_after || $space_after ne " ") { + WARN("BAD_SIGN_OFF", + "Use a single space after $ucfirst_sign_off\n" . $herecurr); + } + + my ($email_name, $email_address, $comment) = parse_email($email); + my $suggested_email = format_email(($email_name, $email_address)); + if ($suggested_email eq "") { + ERROR("BAD_SIGN_OFF", + "Unrecognized email address: '$email'\n" . $herecurr); + } else { + my $dequoted = $suggested_email; + $dequoted =~ s/^"//; + $dequoted =~ s/" $comment" ne $email && + "$suggested_email$comment" ne $email) { + WARN("BAD_SIGN_OFF", + "email address '$email' might be better as '$suggested_email$comment'\n" . $herecurr); + } + } + } + +# Check for wrappage within a valid hunk of the file + if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) { + ERROR("CORRUPTED_PATCH", + "patch seems to be corrupt (line wrapped?)\n" . + $herecurr) if (!$emitted_corrupt++); + } + +# Check for absolute kernel paths. + if ($tree) { + while ($line =~ m{(?:^|\s)(/\S*)}g) { + my $file = $1; + + if ($file =~ m{^(.*?)(?::\d+)+:?$} && + check_absolute_file($1, $herecurr)) { + # + } else { + check_absolute_file($file, $herecurr); + } + } + } + +# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php + if (($realfile =~ /^$/ || $line =~ /^\+/) && + $rawline !~ m/^$UTF8*$/) { + my ($utf8_prefix) = ($rawline =~ /^($UTF8*)/); + + my $blank = copy_spacing($rawline); + my $ptr = substr($blank, 0, length($utf8_prefix)) . "^"; + my $hereptr = "$hereline$ptr\n"; + + CHK("INVALID_UTF8", + "Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr); + } + +# ignore non-hunk lines and lines being removed + next if (!$hunk_line || $line =~ /^-/); + +#trailing whitespace + if ($line =~ /^\+.*\015/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + ERROR("DOS_LINE_ENDINGS", + "DOS line endings\n" . $herevet); + + } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + ERROR("TRAILING_WHITESPACE", + "trailing whitespace\n" . $herevet); + $rpt_cleaners = 1; + } + +# check for Kconfig help text having a real description +# Only applies when adding the entry originally, after that we do not have +# sufficient context to determine whether it is indeed long enough. + if ($realfile =~ /Kconfig/ && + $line =~ /\+\s*(?:---)?help(?:---)?$/) { + my $length = 0; + my $cnt = $realcnt; + my $ln = $linenr + 1; + my $f; + my $is_end = 0; + while ($cnt > 0 && defined $lines[$ln - 1]) { + $f = $lines[$ln - 1]; + $cnt-- if ($lines[$ln - 1] !~ /^-/); + $is_end = $lines[$ln - 1] =~ /^\+/; + $ln++; + + next if ($f =~ /^-/); + $f =~ s/^.//; + $f =~ s/#.*//; + $f =~ s/^\s+//; + next if ($f =~ /^$/); + if ($f =~ /^\s*config\s/) { + $is_end = 1; + last; + } + $length++; + } + WARN("CONFIG_DESCRIPTION", + "please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($is_end && $length < 4); + #print "is_end<$is_end> length<$length>\n"; + } + +# check we are in a valid source file if not then ignore this hunk + next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/); + +#80 column limit + if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ && + $rawline !~ /^.\s*\*\s*\@$Ident\s/ && + !($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:|,|\)\s*;)\s*$/ || + $line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) && + $length > 80) + { + WARN("LONG_LINE", + "line over 80 characters\n" . $herecurr); + } + +# check for spaces before a quoted newline + if ($rawline =~ /^.*\".*\s\\n/) { + WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE", + "unnecessary whitespace before a quoted newline\n" . $herecurr); + } + +# check for adding lines without a newline. + if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) { + WARN("MISSING_EOF_NEWLINE", + "adding a line without newline at end of file\n" . $herecurr); + } + +# Blackfin: use hi/lo macros + if ($realfile =~ m@arch/blackfin/.*\.S$@) { + if ($line =~ /\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) { + my $herevet = "$here\n" . cat_vet($line) . "\n"; + ERROR("LO_MACRO", + "use the LO() macro, not (... & 0xFFFF)\n" . $herevet); + } + if ($line =~ /\.[hH][[:space:]]*=.*>>[[:space:]]*16/) { + my $herevet = "$here\n" . cat_vet($line) . "\n"; + ERROR("HI_MACRO", + "use the HI() macro, not (... >> 16)\n" . $herevet); + } + } + +# check we are in a valid source file C or perl if not then ignore this hunk + next if ($realfile !~ /\.(h|c|pl)$/); + +# at the beginning of a line any tabs must come first and anything +# more than 8 must use tabs. + if ($rawline =~ /^\+\s* \t\s*\S/ || + $rawline =~ /^\+\s* \s*/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + ERROR("CODE_INDENT", + "code indent should use tabs where possible\n" . $herevet); + $rpt_cleaners = 1; + } + +# check for space before tabs. + if ($rawline =~ /^\+/ && $rawline =~ / \t/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + WARN("SPACE_BEFORE_TAB", + "please, no space before tabs\n" . $herevet); + } + +# check for spaces at the beginning of a line. +# Exceptions: +# 1) within comments +# 2) indented preprocessor commands +# 3) hanging labels + if ($rawline =~ /^\+ / && $line !~ /\+ *(?:$;|#|$Ident:)/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + WARN("LEADING_SPACE", + "please, no spaces at the start of a line\n" . $herevet); + } + +# check we are in a valid C source file if not then ignore this hunk + next if ($realfile !~ /\.(h|c)$/); + +# check for RCS/CVS revision markers + if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) { + WARN("CVS_KEYWORD", + "CVS style keyword markers, these will _not_ be updated\n". $herecurr); + } + +# Blackfin: don't use __builtin_bfin_[cs]sync + if ($line =~ /__builtin_bfin_csync/) { + my $herevet = "$here\n" . cat_vet($line) . "\n"; + ERROR("CSYNC", + "use the CSYNC() macro in asm/blackfin.h\n" . $herevet); + } + if ($line =~ /__builtin_bfin_ssync/) { + my $herevet = "$here\n" . cat_vet($line) . "\n"; + ERROR("SSYNC", + "use the SSYNC() macro in asm/blackfin.h\n" . $herevet); + } + +# Check for potential 'bare' types + my ($stat, $cond, $line_nr_next, $remain_next, $off_next, + $realline_next); + if ($realcnt && $line =~ /.\s*\S/) { + ($stat, $cond, $line_nr_next, $remain_next, $off_next) = + ctx_statement_block($linenr, $realcnt, 0); + $stat =~ s/\n./\n /g; + $cond =~ s/\n./\n /g; + + # Find the real next line. + $realline_next = $line_nr_next; + if (defined $realline_next && + (!defined $lines[$realline_next - 1] || + substr($lines[$realline_next - 1], $off_next) =~ /^\s*$/)) { + $realline_next++; + } + + my $s = $stat; + $s =~ s/{.*$//s; + + # Ignore goto labels. + if ($s =~ /$Ident:\*$/s) { + + # Ignore functions being called + } elsif ($s =~ /^.\s*$Ident\s*\(/s) { + + } elsif ($s =~ /^.\s*else\b/s) { + + # declarations always start with types + } elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+?)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))(?:\s*$Modifier)?\s*(?:;|=|,|\()/s) { + my $type = $1; + $type =~ s/\s+/ /g; + possible($type, "A:" . $s); + + # definitions in global scope can only start with types + } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) { + possible($1, "B:" . $s); + } + + # any (foo ... *) is a pointer cast, and foo is a type + while ($s =~ /\(($Ident)(?:\s+$Sparse)*[\s\*]+\s*\)/sg) { + possible($1, "C:" . $s); + } + + # Check for any sort of function declaration. + # int foo(something bar, other baz); + # void (*store_gdt)(x86_descr_ptr *); + if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) { + my ($name_len) = length($1); + + my $ctx = $s; + substr($ctx, 0, $name_len + 1, ''); + $ctx =~ s/\)[^\)]*$//; + + for my $arg (split(/\s*,\s*/, $ctx)) { + if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $arg =~ /^($Ident)$/s) { + + possible($1, "D:" . $s); + } + } + } + + } + +# +# Checks which may be anchored in the context. +# + +# Check for switch () and associated case and default +# statements should be at the same indent. + if ($line=~/\bswitch\s*\(.*\)/) { + my $err = ''; + my $sep = ''; + my @ctx = ctx_block_outer($linenr, $realcnt); + shift(@ctx); + for my $ctx (@ctx) { + my ($clen, $cindent) = line_stats($ctx); + if ($ctx =~ /^\+\s*(case\s+|default:)/ && + $indent != $cindent) { + $err .= "$sep$ctx\n"; + $sep = ''; + } else { + $sep = "[...]\n"; + } + } + if ($err ne '') { + ERROR("SWITCH_CASE_INDENT_LEVEL", + "switch and case should be at the same indent\n$hereline$err"); + } + } + +# if/while/etc brace do not go on next line, unless defining a do while loop, +# or if that brace on the next line is for something else + if ($line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) { + my $pre_ctx = "$1$2"; + + my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0); + my $ctx_cnt = $realcnt - $#ctx - 1; + my $ctx = join("\n", @ctx); + + my $ctx_ln = $linenr; + my $ctx_skip = $realcnt; + + while ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt && + defined $lines[$ctx_ln - 1] && + $lines[$ctx_ln - 1] =~ /^-/)) { + ##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n"; + $ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/); + $ctx_ln++; + } + + #print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n"; + #print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n"; + + if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) { + ERROR("OPEN_BRACE", + "that open brace { should be on the previous line\n" . + "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); + } + if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ && + $ctx =~ /\)\s*\;\s*$/ && + defined $lines[$ctx_ln - 1]) + { + my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]); + if ($nindent > $indent) { + WARN("TRAILING_SEMICOLON", + "trailing semicolon indicates no statements, indent implies otherwise\n" . + "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); + } + } + } + +# Check relative indent for conditionals and blocks. + if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) { + my ($s, $c) = ($stat, $cond); + + substr($s, 0, length($c), ''); + + # Make sure we remove the line prefixes as we have + # none on the first line, and are going to readd them + # where necessary. + $s =~ s/\n./\n/gs; + + # Find out how long the conditional actually is. + my @newlines = ($c =~ /\n/gs); + my $cond_lines = 1 + $#newlines; + + # We want to check the first line inside the block + # starting at the end of the conditional, so remove: + # 1) any blank line termination + # 2) any opening brace { on end of the line + # 3) any do (...) { + my $continuation = 0; + my $check = 0; + $s =~ s/^.*\bdo\b//; + $s =~ s/^\s*{//; + if ($s =~ s/^\s*\\//) { + $continuation = 1; + } + if ($s =~ s/^\s*?\n//) { + $check = 1; + $cond_lines++; + } + + # Also ignore a loop construct at the end of a + # preprocessor statement. + if (($prevline =~ /^.\s*#\s*define\s/ || + $prevline =~ /\\\s*$/) && $continuation == 0) { + $check = 0; + } + + my $cond_ptr = -1; + $continuation = 0; + while ($cond_ptr != $cond_lines) { + $cond_ptr = $cond_lines; + + # If we see an #else/#elif then the code + # is not linear. + if ($s =~ /^\s*\#\s*(?:else|elif)/) { + $check = 0; + } + + # Ignore: + # 1) blank lines, they should be at 0, + # 2) preprocessor lines, and + # 3) labels. + if ($continuation || + $s =~ /^\s*?\n/ || + $s =~ /^\s*#\s*?/ || + $s =~ /^\s*$Ident\s*:/) { + $continuation = ($s =~ /^.*?\\\n/) ? 1 : 0; + if ($s =~ s/^.*?\n//) { + $cond_lines++; + } + } + } + + my (undef, $sindent) = line_stats("+" . $s); + my $stat_real = raw_line($linenr, $cond_lines); + + # Check if either of these lines are modified, else + # this is not this patch's fault. + if (!defined($stat_real) || + $stat !~ /^\+/ && $stat_real !~ /^\+/) { + $check = 0; + } + if (defined($stat_real) && $cond_lines > 1) { + $stat_real = "[...]\n$stat_real"; + } + + #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n"; + + if ($check && (($sindent % 8) != 0 || + ($sindent <= $indent && $s ne ''))) { + WARN("SUSPECT_CODE_INDENT", + "suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n"); + } + } + + # Track the 'values' across context and added lines. + my $opline = $line; $opline =~ s/^./ /; + my ($curr_values, $curr_vars) = + annotate_values($opline . "\n", $prev_values); + $curr_values = $prev_values . $curr_values; + if ($dbg_values) { + my $outline = $opline; $outline =~ s/\t/ /g; + print "$linenr > .$outline\n"; + print "$linenr > $curr_values\n"; + print "$linenr > $curr_vars\n"; + } + $prev_values = substr($curr_values, -1); + +#ignore lines not being added + if ($line=~/^[^\+]/) {next;} + +# TEST: allow direct testing of the type matcher. + if ($dbg_type) { + if ($line =~ /^.\s*$Declare\s*$/) { + ERROR("TEST_TYPE", + "TEST: is type\n" . $herecurr); + } elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) { + ERROR("TEST_NOT_TYPE", + "TEST: is not type ($1 is)\n". $herecurr); + } + next; + } +# TEST: allow direct testing of the attribute matcher. + if ($dbg_attr) { + if ($line =~ /^.\s*$Modifier\s*$/) { + ERROR("TEST_ATTR", + "TEST: is attr\n" . $herecurr); + } elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) { + ERROR("TEST_NOT_ATTR", + "TEST: is not attr ($1 is)\n". $herecurr); + } + next; + } + +# check for initialisation to aggregates open brace on the next line + if ($line =~ /^.\s*{/ && + $prevline =~ /(?:^|[^=])=\s*$/) { + ERROR("OPEN_BRACE", + "that open brace { should be on the previous line\n" . $hereprev); + } + +# +# Checks which are anchored on the added line. +# + +# check for malformed paths in #include statements (uses RAW line) + if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) { + my $path = $1; + if ($path =~ m{//}) { + ERROR("MALFORMED_INCLUDE", + "malformed #include filename\n" . + $herecurr); + } + } + +# no C99 // comments + if ($line =~ m{//}) { + ERROR("C99_COMMENTS", + "do not use C99 // comments\n" . $herecurr); + } + # Remove C99 comments. + $line =~ s@//.*@@; + $opline =~ s@//.*@@; + +# EXPORT_SYMBOL should immediately follow the thing it is exporting, consider +# the whole statement. +#print "APW <$lines[$realline_next - 1]>\n"; + if (defined $realline_next && + exists $lines[$realline_next - 1] && + !defined $suppress_export{$realline_next} && + ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ || + $lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) { + # Handle definitions which produce identifiers with + # a prefix: + # XXX(foo); + # EXPORT_SYMBOL(something_foo); + my $name = $1; + if ($stat =~ /^.([A-Z_]+)\s*\(\s*($Ident)/ && + $name =~ /^${Ident}_$2/) { +#print "FOO C name<$name>\n"; + $suppress_export{$realline_next} = 1; + + } elsif ($stat !~ /(?: + \n.}\s*$| + ^.DEFINE_$Ident\(\Q$name\E\)| + ^.DECLARE_$Ident\(\Q$name\E\)| + ^.LIST_HEAD\(\Q$name\E\)| + ^.(?:$Storage\s+)?$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(| + \b\Q$name\E(?:\s+$Attribute)*\s*(?:;|=|\[|\() + )/x) { +#print "FOO A<$lines[$realline_next - 1]> stat<$stat> name<$name>\n"; + $suppress_export{$realline_next} = 2; + } else { + $suppress_export{$realline_next} = 1; + } + } + if (!defined $suppress_export{$linenr} && + $prevline =~ /^.\s*$/ && + ($line =~ /EXPORT_SYMBOL.*\((.*)\)/ || + $line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) { +#print "FOO B <$lines[$linenr - 1]>\n"; + $suppress_export{$linenr} = 2; + } + if (defined $suppress_export{$linenr} && + $suppress_export{$linenr} == 2) { + WARN("EXPORT_SYMBOL", + "EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr); + } + +# check for global initialisers. + if ($line =~ /^.$Type\s*$Ident\s*(?:\s+$Modifier)*\s*=\s*(0|NULL|false)\s*;/) { + ERROR("GLOBAL_INITIALISERS", + "do not initialise globals to 0 or NULL\n" . + $herecurr); + } +# check for static initialisers. + if ($line =~ /\bstatic\s.*=\s*(0|NULL|false)\s*;/) { + ERROR("INITIALISED_STATIC", + "do not initialise statics to 0 or NULL\n" . + $herecurr); + } + +# check for static const char * arrays. + if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) { + WARN("STATIC_CONST_CHAR_ARRAY", + "static const char * array should probably be static const char * const\n" . + $herecurr); + } + +# check for static char foo[] = "bar" declarations. + if ($line =~ /\bstatic\s+char\s+(\w+)\s*\[\s*\]\s*=\s*"/) { + WARN("STATIC_CONST_CHAR_ARRAY", + "static char array declaration should probably be static const char\n" . + $herecurr); + } + +# check for declarations of struct pci_device_id + if ($line =~ /\bstruct\s+pci_device_id\s+\w+\s*\[\s*\]\s*\=\s*\{/) { + WARN("DEFINE_PCI_DEVICE_TABLE", + "Use DEFINE_PCI_DEVICE_TABLE for struct pci_device_id\n" . $herecurr); + } + +# check for new typedefs, only function parameters and sparse annotations +# make sense. + if ($line =~ /\btypedef\s/ && + $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ && + $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ && + $line !~ /\b$typeTypedefs\b/ && + $line !~ /\b__bitwise(?:__|)\b/) { + WARN("NEW_TYPEDEFS", + "do not add new typedefs\n" . $herecurr); + } + +# * goes on variable not on type + # (char*[ const]) + if ($line =~ m{\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\)}) { + my ($from, $to) = ($1, $1); + + # Should start with a space. + $to =~ s/^(\S)/ $1/; + # Should not end with a space. + $to =~ s/\s+$//; + # '*'s should not have spaces between. + while ($to =~ s/\*\s+\*/\*\*/) { + } + + #print "from<$from> to<$to>\n"; + if ($from ne $to) { + ERROR("POINTER_LOCATION", + "\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr); + } + } elsif ($line =~ m{\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident)}) { + my ($from, $to, $ident) = ($1, $1, $2); + + # Should start with a space. + $to =~ s/^(\S)/ $1/; + # Should not end with a space. + $to =~ s/\s+$//; + # '*'s should not have spaces between. + while ($to =~ s/\*\s+\*/\*\*/) { + } + # Modifiers should have spaces. + $to =~ s/(\b$Modifier$)/$1 /; + + #print "from<$from> to<$to> ident<$ident>\n"; + if ($from ne $to && $ident !~ /^$Modifier$/) { + ERROR("POINTER_LOCATION", + "\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr); + } + } + +# # no BUG() or BUG_ON() +# if ($line =~ /\b(BUG|BUG_ON)\b/) { +# print "Try to use WARN_ON & Recovery code rather than BUG() or BUG_ON()\n"; +# print "$herecurr"; +# $clean = 0; +# } + + if ($line =~ /\bLINUX_VERSION_CODE\b/) { + WARN("LINUX_VERSION_CODE", + "LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr); + } + +# check for uses of printk_ratelimit + if ($line =~ /\bprintk_ratelimit\s*\(/) { + WARN("PRINTK_RATELIMITED", +"Prefer printk_ratelimited or pr__ratelimited to printk_ratelimit\n" . $herecurr); + } + +# printk should use KERN_* levels. Note that follow on printk's on the +# same line do not need a level, so we use the current block context +# to try and find and validate the current printk. In summary the current +# printk includes all preceding printk's which have no newline on the end. +# we assume the first bad printk is the one to report. + if ($line =~ /\bprintk\((?!KERN_)\s*"/) { + my $ok = 0; + for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) { + #print "CHECK<$lines[$ln - 1]\n"; + # we have a preceding printk if it ends + # with "\n" ignore it, else it is to blame + if ($lines[$ln - 1] =~ m{\bprintk\(}) { + if ($rawlines[$ln - 1] !~ m{\\n"}) { + $ok = 1; + } + last; + } + } + if ($ok == 0) { + WARN("PRINTK_WITHOUT_KERN_LEVEL", + "printk() should include KERN_ facility level\n" . $herecurr); + } + } + +# function brace can't be on same line, except for #defines of do while, +# or if closed on same line + if (($line=~/$Type\s*$Ident\(.*\).*\s{/) and + !($line=~/\#\s*define.*do\s{/) and !($line=~/}/)) { + ERROR("OPEN_BRACE", + "open brace '{' following function declarations go on the next line\n" . $herecurr); + } + +# open braces for enum, union and struct go on the same line. + if ($line =~ /^.\s*{/ && + $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) { + ERROR("OPEN_BRACE", + "open brace '{' following $1 go on the same line\n" . $hereprev); + } + +# missing space after union, struct or enum definition + if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) { + WARN("SPACING", + "missing space after $1 definition\n" . $herecurr); + } + +# check for spacing round square brackets; allowed: +# 1. with a type on the left -- int [] a; +# 2. at the beginning of a line for slice initialisers -- [0...10] = 5, +# 3. inside a curly brace -- = { [0...10] = 5 } + while ($line =~ /(.*?\s)\[/g) { + my ($where, $prefix) = ($-[1], $1); + if ($prefix !~ /$Type\s+$/ && + ($where != 0 || $prefix !~ /^.\s+$/) && + $prefix !~ /{\s+$/) { + ERROR("BRACKET_SPACE", + "space prohibited before open square bracket '['\n" . $herecurr); + } + } + +# check for spaces between functions and their parentheses. + while ($line =~ /($Ident)\s+\(/g) { + my $name = $1; + my $ctx_before = substr($line, 0, $-[1]); + my $ctx = "$ctx_before$name"; + + # Ignore those directives where spaces _are_ permitted. + if ($name =~ /^(?: + if|for|while|switch|return|case| + volatile|__volatile__| + __attribute__|format|__extension__| + asm|__asm__)$/x) + { + + # cpp #define statements have non-optional spaces, ie + # if there is a space between the name and the open + # parenthesis it is simply not a parameter group. + } elsif ($ctx_before =~ /^.\s*\#\s*define\s*$/) { + + # cpp #elif statement condition may start with a ( + } elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) { + + # If this whole things ends with a type its most + # likely a typedef for a function. + } elsif ($ctx =~ /$Type$/) { + + } else { + WARN("SPACING", + "space prohibited between function name and open parenthesis '('\n" . $herecurr); + } + } +# Check operator spacing. + if (!($line=~/\#\s*include/)) { + my $ops = qr{ + <<=|>>=|<=|>=|==|!=| + \+=|-=|\*=|\/=|%=|\^=|\|=|&=| + =>|->|<<|>>|<|>|=|!|~| + &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%| + \?|: + }x; + my @elements = split(/($ops|;)/, $opline); + my $off = 0; + + my $blank = copy_spacing($opline); + + for (my $n = 0; $n < $#elements; $n += 2) { + $off += length($elements[$n]); + + # Pick up the preceding and succeeding characters. + my $ca = substr($opline, 0, $off); + my $cc = ''; + if (length($opline) >= ($off + length($elements[$n + 1]))) { + $cc = substr($opline, $off + length($elements[$n + 1])); + } + my $cb = "$ca$;$cc"; + + my $a = ''; + $a = 'V' if ($elements[$n] ne ''); + $a = 'W' if ($elements[$n] =~ /\s$/); + $a = 'C' if ($elements[$n] =~ /$;$/); + $a = 'B' if ($elements[$n] =~ /(\[|\()$/); + $a = 'O' if ($elements[$n] eq ''); + $a = 'E' if ($ca =~ /^\s*$/); + + my $op = $elements[$n + 1]; + + my $c = ''; + if (defined $elements[$n + 2]) { + $c = 'V' if ($elements[$n + 2] ne ''); + $c = 'W' if ($elements[$n + 2] =~ /^\s/); + $c = 'C' if ($elements[$n + 2] =~ /^$;/); + $c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/); + $c = 'O' if ($elements[$n + 2] eq ''); + $c = 'E' if ($elements[$n + 2] =~ /^\s*\\$/); + } else { + $c = 'E'; + } + + my $ctx = "${a}x${c}"; + + my $at = "(ctx:$ctx)"; + + my $ptr = substr($blank, 0, $off) . "^"; + my $hereptr = "$hereline$ptr\n"; + + # Pull out the value of this operator. + my $op_type = substr($curr_values, $off + 1, 1); + + # Get the full operator variant. + my $opv = $op . substr($curr_vars, $off, 1); + + # Ignore operators passed as parameters. + if ($op_type ne 'V' && + $ca =~ /\s$/ && $cc =~ /^\s*,/) { + +# # Ignore comments +# } elsif ($op =~ /^$;+$/) { + + # ; should have either the end of line or a space or \ after it + } elsif ($op eq ';') { + if ($ctx !~ /.x[WEBC]/ && + $cc !~ /^\\/ && $cc !~ /^;/) { + ERROR("SPACING", + "space required after that '$op' $at\n" . $hereptr); + } + + # // is a comment + } elsif ($op eq '//') { + + # No spaces for: + # -> + # : when part of a bitfield + } elsif ($op eq '->' || $opv eq ':B') { + if ($ctx =~ /Wx.|.xW/) { + ERROR("SPACING", + "spaces prohibited around that '$op' $at\n" . $hereptr); + } + + # , must have a space on the right. + } elsif ($op eq ',') { + if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) { + ERROR("SPACING", + "space required after that '$op' $at\n" . $hereptr); + } + + # '*' as part of a type definition -- reported already. + } elsif ($opv eq '*_') { + #warn "'*' is part of type\n"; + + # unary operators should have a space before and + # none after. May be left adjacent to another + # unary operator, or a cast + } elsif ($op eq '!' || $op eq '~' || + $opv eq '*U' || $opv eq '-U' || + $opv eq '&U' || $opv eq '&&U') { + if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { + ERROR("SPACING", + "space required before that '$op' $at\n" . $hereptr); + } + if ($op eq '*' && $cc =~/\s*$Modifier\b/) { + # A unary '*' may be const + + } elsif ($ctx =~ /.xW/) { + ERROR("SPACING", + "space prohibited after that '$op' $at\n" . $hereptr); + } + + # unary ++ and unary -- are allowed no space on one side. + } elsif ($op eq '++' or $op eq '--') { + if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) { + ERROR("SPACING", + "space required one side of that '$op' $at\n" . $hereptr); + } + if ($ctx =~ /Wx[BE]/ || + ($ctx =~ /Wx./ && $cc =~ /^;/)) { + ERROR("SPACING", + "space prohibited before that '$op' $at\n" . $hereptr); + } + if ($ctx =~ /ExW/) { + ERROR("SPACING", + "space prohibited after that '$op' $at\n" . $hereptr); + } + + + # << and >> may either have or not have spaces both sides + } elsif ($op eq '<<' or $op eq '>>' or + $op eq '&' or $op eq '^' or $op eq '|' or + $op eq '+' or $op eq '-' or + $op eq '*' or $op eq '/' or + $op eq '%') + { + if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) { + ERROR("SPACING", + "need consistent spacing around '$op' $at\n" . + $hereptr); + } + + # A colon needs no spaces before when it is + # terminating a case value or a label. + } elsif ($opv eq ':C' || $opv eq ':L') { + if ($ctx =~ /Wx./) { + ERROR("SPACING", + "space prohibited before that '$op' $at\n" . $hereptr); + } + + # All the others need spaces both sides. + } elsif ($ctx !~ /[EWC]x[CWE]/) { + my $ok = 0; + + # Ignore email addresses + if (($op eq '<' && + $cc =~ /^\S+\@\S+>/) || + ($op eq '>' && + $ca =~ /<\S+\@\S+$/)) + { + $ok = 1; + } + + # Ignore ?: + if (($opv eq ':O' && $ca =~ /\?$/) || + ($op eq '?' && $cc =~ /^:/)) { + $ok = 1; + } + + if ($ok == 0) { + ERROR("SPACING", + "spaces required around that '$op' $at\n" . $hereptr); + } + } + $off += length($elements[$n + 1]); + } + } + +# check for multiple assignments + if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) { + CHK("MULTIPLE_ASSIGNMENTS", + "multiple assignments should be avoided\n" . $herecurr); + } + +## # check for multiple declarations, allowing for a function declaration +## # continuation. +## if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ && +## $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) { +## +## # Remove any bracketed sections to ensure we do not +## # falsly report the parameters of functions. +## my $ln = $line; +## while ($ln =~ s/\([^\(\)]*\)//g) { +## } +## if ($ln =~ /,/) { +## WARN("MULTIPLE_DECLARATION", +## "declaring multiple variables together should be avoided\n" . $herecurr); +## } +## } + +#need space before brace following if, while, etc + if (($line =~ /\(.*\){/ && $line !~ /\($Type\){/) || + $line =~ /do{/) { + ERROR("SPACING", + "space required before the open brace '{'\n" . $herecurr); + } + +# closing brace should have a space following it when it has anything +# on the line + if ($line =~ /}(?!(?:,|;|\)))\S/) { + ERROR("SPACING", + "space required after that close brace '}'\n" . $herecurr); + } + +# check spacing on square brackets + if ($line =~ /\[\s/ && $line !~ /\[\s*$/) { + ERROR("SPACING", + "space prohibited after that open square bracket '['\n" . $herecurr); + } + if ($line =~ /\s\]/) { + ERROR("SPACING", + "space prohibited before that close square bracket ']'\n" . $herecurr); + } + +# check spacing on parentheses + if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ && + $line !~ /for\s*\(\s+;/) { + ERROR("SPACING", + "space prohibited after that open parenthesis '('\n" . $herecurr); + } + if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ && + $line !~ /for\s*\(.*;\s+\)/ && + $line !~ /:\s+\)/) { + ERROR("SPACING", + "space prohibited before that close parenthesis ')'\n" . $herecurr); + } + +#goto labels aren't indented, allow a single space however + if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and + !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) { + WARN("INDENTED_LABEL", + "labels should not be indented\n" . $herecurr); + } + +# Return is not a function. + if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) { + my $spacing = $1; + my $value = $2; + + # Flatten any parentheses + $value =~ s/\(/ \(/g; + $value =~ s/\)/\) /g; + while ($value =~ s/\[[^\{\}]*\]/1/ || + $value !~ /(?:$Ident|-?$Constant)\s* + $Compare\s* + (?:$Ident|-?$Constant)/x && + $value =~ s/\([^\(\)]*\)/1/) { + } +#print "value<$value>\n"; + if ($value =~ /^\s*(?:$Ident|-?$Constant)\s*$/) { + ERROR("RETURN_PARENTHESES", + "return is not a function, parentheses are not required\n" . $herecurr); + + } elsif ($spacing !~ /\s+/) { + ERROR("SPACING", + "space required before the open parenthesis '('\n" . $herecurr); + } + } +# Return of what appears to be an errno should normally be -'ve + if ($line =~ /^.\s*return\s*(E[A-Z]*)\s*;/) { + my $name = $1; + if ($name ne 'EOF' && $name ne 'ERROR') { + WARN("USE_NEGATIVE_ERRNO", + "return of an errno should typically be -ve (return -$1)\n" . $herecurr); + } + } + +# typecasts on min/max could be min_t/max_t + if ($line =~ /^\+(?:.*?)\b(min|max)\s*\($Typecast{0,1}($LvalOrFunc)\s*,\s*$Typecast{0,1}($LvalOrFunc)\s*\)/) { + if (defined $2 || defined $8) { + my $call = $1; + my $cast1 = deparenthesize($2); + my $arg1 = $3; + my $cast2 = deparenthesize($8); + my $arg2 = $9; + my $cast; + + if ($cast1 ne "" && $cast2 ne "") { + $cast = "$cast1 or $cast2"; + } elsif ($cast1 ne "") { + $cast = $cast1; + } else { + $cast = $cast2; + } + WARN("MINMAX", + "$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . $herecurr); + } + } + +# Need a space before open parenthesis after if, while etc + if ($line=~/\b(if|while|for|switch)\(/) { + ERROR("SPACING", "space required before the open parenthesis '('\n" . $herecurr); + } + +# Check for illegal assignment in if conditional -- and check for trailing +# statements after the conditional. + if ($line =~ /do\s*(?!{)/) { + my ($stat_next) = ctx_statement_block($line_nr_next, + $remain_next, $off_next); + $stat_next =~ s/\n./\n /g; + ##print "stat<$stat> stat_next<$stat_next>\n"; + + if ($stat_next =~ /^\s*while\b/) { + # If the statement carries leading newlines, + # then count those as offsets. + my ($whitespace) = + ($stat_next =~ /^((?:\s*\n[+-])*\s*)/s); + my $offset = + statement_rawlines($whitespace) - 1; + + $suppress_whiletrailers{$line_nr_next + + $offset} = 1; + } + } + if (!defined $suppress_whiletrailers{$linenr} && + $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) { + my ($s, $c) = ($stat, $cond); + + if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) { + ERROR("ASSIGN_IN_IF", + "do not use assignment in if condition\n" . $herecurr); + } + + # Find out what is on the end of the line after the + # conditional. + substr($s, 0, length($c), ''); + $s =~ s/\n.*//g; + $s =~ s/$;//g; # Remove any comments + if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ && + $c !~ /}\s*while\s*/) + { + # Find out how long the conditional actually is. + my @newlines = ($c =~ /\n/gs); + my $cond_lines = 1 + $#newlines; + my $stat_real = ''; + + $stat_real = raw_line($linenr, $cond_lines) + . "\n" if ($cond_lines); + if (defined($stat_real) && $cond_lines > 1) { + $stat_real = "[...]\n$stat_real"; + } + + ERROR("TRAILING_STATEMENTS", + "trailing statements should be on next line\n" . $herecurr . $stat_real); + } + } + +# Check for bitwise tests written as boolean + if ($line =~ / + (?: + (?:\[|\(|\&\&|\|\|) + \s*0[xX][0-9]+\s* + (?:\&\&|\|\|) + | + (?:\&\&|\|\|) + \s*0[xX][0-9]+\s* + (?:\&\&|\|\||\)|\]) + )/x) + { + WARN("HEXADECIMAL_BOOLEAN_TEST", + "boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr); + } + +# if and else should not have general statements after it + if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) { + my $s = $1; + $s =~ s/$;//g; # Remove any comments + if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) { + ERROR("TRAILING_STATEMENTS", + "trailing statements should be on next line\n" . $herecurr); + } + } +# if should not continue a brace + if ($line =~ /}\s*if\b/) { + ERROR("TRAILING_STATEMENTS", + "trailing statements should be on next line\n" . + $herecurr); + } +# case and default should not have general statements after them + if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g && + $line !~ /\G(?: + (?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$| + \s*return\s+ + )/xg) + { + ERROR("TRAILING_STATEMENTS", + "trailing statements should be on next line\n" . $herecurr); + } + + # Check for }else {, these must be at the same + # indent level to be relevant to each other. + if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ and + $previndent == $indent) { + ERROR("ELSE_AFTER_BRACE", + "else should follow close brace '}'\n" . $hereprev); + } + + if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ and + $previndent == $indent) { + my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0); + + # Find out what is on the end of the line after the + # conditional. + substr($s, 0, length($c), ''); + $s =~ s/\n.*//g; + + if ($s =~ /^\s*;/) { + ERROR("WHILE_AFTER_BRACE", + "while should follow close brace '}'\n" . $hereprev); + } + } + +#studly caps, commented out until figure out how to distinguish between use of existing and adding new +# if (($line=~/[\w_][a-z\d]+[A-Z]/) and !($line=~/print/)) { +# print "No studly caps, use _\n"; +# print "$herecurr"; +# $clean = 0; +# } + +#no spaces allowed after \ in define + if ($line=~/\#\s*define.*\\\s$/) { + WARN("WHITESPACE_AFTER_LINE_CONTINUATION", + "Whitepspace after \\ makes next lines useless\n" . $herecurr); + } + +#warn if is #included and is available (uses RAW line) + if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\}) { + my $file = "$1.h"; + my $checkfile = "include/linux/$file"; + if (-f "$root/$checkfile" && + $realfile ne $checkfile && + $1 !~ /$allowed_asm_includes/) + { + if ($realfile =~ m{^arch/}) { + CHK("ARCH_INCLUDE_LINUX", + "Consider using #include instead of \n" . $herecurr); + } else { + WARN("INCLUDE_LINUX", + "Use #include instead of \n" . $herecurr); + } + } + } + +# multi-statement macros should be enclosed in a do while loop, grab the +# first statement and ensure its the whole macro if its not enclosed +# in a known good container + if ($realfile !~ m@/vmlinux.lds.h$@ && + $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) { + my $ln = $linenr; + my $cnt = $realcnt; + my ($off, $dstat, $dcond, $rest); + my $ctx = ''; + + my $args = defined($1); + + # Find the end of the macro and limit our statement + # search to that. + while ($cnt > 0 && defined $lines[$ln - 1] && + $lines[$ln - 1] =~ /^(?:-|..*\\$)/) + { + $ctx .= $rawlines[$ln - 1] . "\n"; + $cnt-- if ($lines[$ln - 1] !~ /^-/); + $ln++; + } + $ctx .= $rawlines[$ln - 1]; + + ($dstat, $dcond, $ln, $cnt, $off) = + ctx_statement_block($linenr, $ln - $linenr + 1, 0); + #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n"; + #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n"; + + # Extract the remainder of the define (if any) and + # rip off surrounding spaces, and trailing \'s. + $rest = ''; + while ($off != 0 || ($cnt > 0 && $rest =~ /\\\s*$/)) { + #print "ADDING cnt<$cnt> $off <" . substr($lines[$ln - 1], $off) . "> rest<$rest>\n"; + if ($off != 0 || $lines[$ln - 1] !~ /^-/) { + $rest .= substr($lines[$ln - 1], $off) . "\n"; + $cnt--; + } + $ln++; + $off = 0; + } + $rest =~ s/\\\n.//g; + $rest =~ s/^\s*//s; + $rest =~ s/\s*$//s; + + # Clean up the original statement. + if ($args) { + substr($dstat, 0, length($dcond), ''); + } else { + $dstat =~ s/^.\s*\#\s*define\s+$Ident\s*//; + } + $dstat =~ s/$;//g; + $dstat =~ s/\\\n.//g; + $dstat =~ s/^\s*//s; + $dstat =~ s/\s*$//s; + + # Flatten any parentheses and braces + while ($dstat =~ s/\([^\(\)]*\)/1/ || + $dstat =~ s/\{[^\{\}]*\}/1/ || + $dstat =~ s/\[[^\{\}]*\]/1/) + { + } + + my $exceptions = qr{ + $Declare| + module_param_named| + MODULE_PARAM_DESC| + DECLARE_PER_CPU| + DEFINE_PER_CPU| + __typeof__\(| + union| + struct| + \.$Ident\s*=\s*| + ^\"|\"$ + }x; + #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n"; + if ($rest ne '' && $rest ne ',') { + if ($rest !~ /while\s*\(/ && + $dstat !~ /$exceptions/) + { + ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE", + "Macros with multiple statements should be enclosed in a do - while loop\n" . "$here\n$ctx\n"); + } + + } elsif ($ctx !~ /;/) { + if ($dstat ne '' && + $dstat !~ /^(?:$Ident|-?$Constant)$/ && + $dstat !~ /$exceptions/ && + $dstat !~ /^\.$Ident\s*=/ && + $dstat =~ /$Operators/) + { + ERROR("COMPLEX_MACRO", + "Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n"); + } + } + } + +# make sure symbols are always wrapped with VMLINUX_SYMBOL() ... +# all assignments may have only one of the following with an assignment: +# . +# ALIGN(...) +# VMLINUX_SYMBOL(...) + if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) { + WARN("MISSING_VMLINUX_SYMBOL", + "vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr); + } + +# check for redundant bracing round if etc + if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) { + my ($level, $endln, @chunks) = + ctx_statement_full($linenr, $realcnt, 1); + #print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n"; + #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n"; + if ($#chunks > 0 && $level == 0) { + my $allowed = 0; + my $seen = 0; + my $herectx = $here . "\n"; + my $ln = $linenr - 1; + for my $chunk (@chunks) { + my ($cond, $block) = @{$chunk}; + + # If the condition carries leading newlines, then count those as offsets. + my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s); + my $offset = statement_rawlines($whitespace) - 1; + + #print "COND<$cond> whitespace<$whitespace> offset<$offset>\n"; + + # We have looked at and allowed this specific line. + $suppress_ifbraces{$ln + $offset} = 1; + + $herectx .= "$rawlines[$ln + $offset]\n[...]\n"; + $ln += statement_rawlines($block) - 1; + + substr($block, 0, length($cond), ''); + + $seen++ if ($block =~ /^\s*{/); + + #print "cond<$cond> block<$block> allowed<$allowed>\n"; + if (statement_lines($cond) > 1) { + #print "APW: ALLOWED: cond<$cond>\n"; + $allowed = 1; + } + if ($block =~/\b(?:if|for|while)\b/) { + #print "APW: ALLOWED: block<$block>\n"; + $allowed = 1; + } + if (statement_block_size($block) > 1) { + #print "APW: ALLOWED: lines block<$block>\n"; + $allowed = 1; + } + } + if ($seen && !$allowed) { + WARN("BRACES", + "braces {} are not necessary for any arm of this statement\n" . $herectx); + } + } + } + if (!defined $suppress_ifbraces{$linenr - 1} && + $line =~ /\b(if|while|for|else)\b/) { + my $allowed = 0; + + # Check the pre-context. + if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) { + #print "APW: ALLOWED: pre<$1>\n"; + $allowed = 1; + } + + my ($level, $endln, @chunks) = + ctx_statement_full($linenr, $realcnt, $-[0]); + + # Check the condition. + my ($cond, $block) = @{$chunks[0]}; + #print "CHECKING<$linenr> cond<$cond> block<$block>\n"; + if (defined $cond) { + substr($block, 0, length($cond), ''); + } + if (statement_lines($cond) > 1) { + #print "APW: ALLOWED: cond<$cond>\n"; + $allowed = 1; + } + if ($block =~/\b(?:if|for|while)\b/) { + #print "APW: ALLOWED: block<$block>\n"; + $allowed = 1; + } + if (statement_block_size($block) > 1) { + #print "APW: ALLOWED: lines block<$block>\n"; + $allowed = 1; + } + # Check the post-context. + if (defined $chunks[1]) { + my ($cond, $block) = @{$chunks[1]}; + if (defined $cond) { + substr($block, 0, length($cond), ''); + } + if ($block =~ /^\s*\{/) { + #print "APW: ALLOWED: chunk-1 block<$block>\n"; + $allowed = 1; + } + } + if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) { + my $herectx = $here . "\n";; + my $cnt = statement_rawlines($block); + + for (my $n = 0; $n < $cnt; $n++) { + $herectx .= raw_line($linenr, $n) . "\n";; + } + + WARN("BRACES", + "braces {} are not necessary for single statement blocks\n" . $herectx); + } + } + +# don't include deprecated include files (uses RAW line) + for my $inc (@dep_includes) { + if ($rawline =~ m@^.\s*\#\s*include\s*\<$inc>@) { + ERROR("DEPRECATED_INCLUDE", + "Don't use <$inc>: see Documentation/feature-removal-schedule.txt\n" . $herecurr); + } + } + +# don't use deprecated functions + for my $func (@dep_functions) { + if ($line =~ /\b$func\b/) { + ERROR("DEPRECATED_FUNCTION", + "Don't use $func(): see Documentation/feature-removal-schedule.txt\n" . $herecurr); + } + } + +# no volatiles please + my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b}; + if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) { + WARN("VOLATILE", + "Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr); + } + +# warn about #if 0 + if ($line =~ /^.\s*\#\s*if\s+0\b/) { + CHK("REDUNDANT_CODE", + "if this code is redundant consider removing it\n" . + $herecurr); + } + +# check for needless kfree() checks + if ($prevline =~ /\bif\s*\(([^\)]*)\)/) { + my $expr = $1; + if ($line =~ /\bkfree\(\Q$expr\E\);/) { + WARN("NEEDLESS_KFREE", + "kfree(NULL) is safe this check is probably not required\n" . $hereprev); + } + } +# check for needless usb_free_urb() checks + if ($prevline =~ /\bif\s*\(([^\)]*)\)/) { + my $expr = $1; + if ($line =~ /\busb_free_urb\(\Q$expr\E\);/) { + WARN("NEEDLESS_USB_FREE_URB", + "usb_free_urb(NULL) is safe this check is probably not required\n" . $hereprev); + } + } + +# prefer usleep_range over udelay + if ($line =~ /\budelay\s*\(\s*(\w+)\s*\)/) { + # ignore udelay's < 10, however + if (! (($1 =~ /(\d+)/) && ($1 < 10)) ) { + CHK("USLEEP_RANGE", + "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $line); + } + } + +# warn about unexpectedly long msleep's + if ($line =~ /\bmsleep\s*\((\d+)\);/) { + if ($1 < 20) { + WARN("MSLEEP", + "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $line); + } + } + +# warn about #ifdefs in C files +# if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) { +# print "#ifdef in C files should be avoided\n"; +# print "$herecurr"; +# $clean = 0; +# } + +# warn about spacing in #ifdefs + if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) { + ERROR("SPACING", + "exactly one space required after that #$1\n" . $herecurr); + } + +# check for spinlock_t definitions without a comment. + if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ || + $line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) { + my $which = $1; + if (!ctx_has_comment($first_line, $linenr)) { + CHK("UNCOMMENTED_DEFINITION", + "$1 definition without comment\n" . $herecurr); + } + } +# check for memory barriers without a comment. + if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) { + if (!ctx_has_comment($first_line, $linenr)) { + CHK("MEMORY_BARRIER", + "memory barrier without comment\n" . $herecurr); + } + } +# check of hardware specific defines + if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) { + CHK("ARCH_DEFINES", + "architecture specific defines should be avoided\n" . $herecurr); + } + +# Check that the storage class is at the beginning of a declaration + if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage\b/) { + WARN("STORAGE_CLASS", + "storage class should be at the beginning of the declaration\n" . $herecurr) + } + +# check the location of the inline attribute, that it is between +# storage class and type. + if ($line =~ /\b$Type\s+$Inline\b/ || + $line =~ /\b$Inline\s+$Storage\b/) { + ERROR("INLINE_LOCATION", + "inline keyword should sit between storage class and type\n" . $herecurr); + } + +# Check for __inline__ and __inline, prefer inline + if ($line =~ /\b(__inline__|__inline)\b/) { + WARN("INLINE", + "plain inline is preferred over $1\n" . $herecurr); + } + +# Check for __attribute__ packed, prefer __packed + if ($line =~ /\b__attribute__\s*\(\s*\(.*\bpacked\b/) { + WARN("PREFER_PACKED", + "__packed is preferred over __attribute__((packed))\n" . $herecurr); + } + +# Check for __attribute__ aligned, prefer __aligned + if ($line =~ /\b__attribute__\s*\(\s*\(.*aligned/) { + WARN("PREFER_ALIGNED", + "__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $herecurr); + } + +# check for sizeof(&) + if ($line =~ /\bsizeof\s*\(\s*\&/) { + WARN("SIZEOF_ADDRESS", + "sizeof(& should be avoided\n" . $herecurr); + } + +# check for line continuations in quoted strings with odd counts of " + if ($rawline =~ /\\$/ && $rawline =~ tr/"/"/ % 2) { + WARN("LINE_CONTINUATIONS", + "Avoid line continuations in quoted strings\n" . $herecurr); + } + +# check for new externs in .c files. + if ($realfile =~ /\.c$/ && defined $stat && + $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s) + { + my $function_name = $1; + my $paren_space = $2; + + my $s = $stat; + if (defined $cond) { + substr($s, 0, length($cond), ''); + } + if ($s =~ /^\s*;/ && + $function_name ne 'uninitialized_var') + { + WARN("AVOID_EXTERNS", + "externs should be avoided in .c files\n" . $herecurr); + } + + if ($paren_space =~ /\n/) { + WARN("FUNCTION_ARGUMENTS", + "arguments for function declarations should follow identifier\n" . $herecurr); + } + + } elsif ($realfile =~ /\.c$/ && defined $stat && + $stat =~ /^.\s*extern\s+/) + { + WARN("AVOID_EXTERNS", + "externs should be avoided in .c files\n" . $herecurr); + } + +# checks for new __setup's + if ($rawline =~ /\b__setup\("([^"]*)"/) { + my $name = $1; + + if (!grep(/$name/, @setup_docs)) { + CHK("UNDOCUMENTED_SETUP", + "__setup appears un-documented -- check Documentation/kernel-parameters.txt\n" . $herecurr); + } + } + +# check for pointless casting of kmalloc return + if ($line =~ /\*\s*\)\s*[kv][czm]alloc(_node){0,1}\b/) { + WARN("UNNECESSARY_CASTS", + "unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr); + } + +# check for multiple semicolons + if ($line =~ /;\s*;\s*$/) { + WARN("ONE_SEMICOLON", + "Statements terminations use 1 semicolon\n" . $herecurr); + } + +# check for whitespace before semicolon - not allowed at end-of-line + if ($line =~ /\s+;$/) { + WARN("SPACEBEFORE_SEMICOLON", + "Whitespace before semicolon\n" . $herecurr); + } + +# check for gcc specific __FUNCTION__ + if ($line =~ /__FUNCTION__/) { + WARN("USE_FUNC", + "__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr); + } + +# check for semaphores initialized locked + if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) { + WARN("CONSIDER_COMPLETION", + "consider using a completion\n" . $herecurr); + + } +# recommend kstrto* over simple_strto* + if ($line =~ /\bsimple_(strto.*?)\s*\(/) { + WARN("CONSIDER_KSTRTO", + "consider using kstrto* in preference to simple_$1\n" . $herecurr); + } +# check for __initcall(), use device_initcall() explicitly please + if ($line =~ /^.\s*__initcall\s*\(/) { + WARN("USE_DEVICE_INITCALL", + "please use device_initcall() instead of __initcall()\n" . $herecurr); + } +# check for various ops structs, ensure they are const. + my $struct_ops = qr{acpi_dock_ops| + address_space_operations| + backlight_ops| + block_device_operations| + dentry_operations| + dev_pm_ops| + dma_map_ops| + extent_io_ops| + file_lock_operations| + file_operations| + hv_ops| + ide_dma_ops| + intel_dvo_dev_ops| + item_operations| + iwl_ops| + kgdb_arch| + kgdb_io| + kset_uevent_ops| + lock_manager_operations| + microcode_ops| + mtrr_ops| + neigh_ops| + nlmsvc_binding| + pci_raw_ops| + pipe_buf_operations| + platform_hibernation_ops| + platform_suspend_ops| + proto_ops| + rpc_pipe_ops| + seq_operations| + snd_ac97_build_ops| + soc_pcmcia_socket_ops| + stacktrace_ops| + sysfs_ops| + tty_operations| + usb_mon_operations| + wd_ops}x; + if ($line !~ /\bconst\b/ && + $line =~ /\bstruct\s+($struct_ops)\b/) { + WARN("CONST_STRUCT", + "struct $1 should normally be const\n" . + $herecurr); + } + +# use of NR_CPUS is usually wrong +# ignore definitions of NR_CPUS and usage to define arrays as likely right + if ($line =~ /\bNR_CPUS\b/ && + $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ && + $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ && + $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ && + $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ && + $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/) + { + WARN("NR_CPUS", + "usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr); + } + +# check for %L{u,d,i} in strings + my $string; + while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { + $string = substr($rawline, $-[1], $+[1] - $-[1]); + $string =~ s/%%/__/g; + if ($string =~ /(?mutex.\n" . $herecurr); + } + } + + if ($line =~ /debugfs_create_file.*S_IWUGO/ || + $line =~ /DEVICE_ATTR.*S_IWUGO/ ) { + WARN("EXPORTED_WORLD_WRITABLE", + "Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr); + } + + # Check for memset with swapped arguments + if ($line =~ /memset.*\,(\ |)(0x|)0(\ |0|)\);/) { + ERROR("MEMSET", + "memset size is 3rd argument, not the second.\n" . $herecurr); + } + } + + # If we have no input at all, then there is nothing to report on + # so just keep quiet. + if ($#rawlines == -1) { + exit(0); + } + + # In mailback mode only produce a report in the negative, for + # things that appear to be patches. + if ($mailback && ($clean == 1 || !$is_patch)) { + exit(0); + } + + # This is not a patch, and we are are in 'no-patch' mode so + # just keep quiet. + if (!$chk_patch && !$is_patch) { + exit(0); + } + + if (!$is_patch) { + ERROR("NOT_UNIFIED_DIFF", + "Does not appear to be a unified-diff format patch\n"); + } + if ($is_patch && $chk_signoff && $signoff == 0) { + ERROR("MISSING_SIGN_OFF", + "Missing Signed-off-by: line(s)\n"); + } + + print report_dump(); + if ($summary && !($clean == 1 && $quiet == 1)) { + print "$filename " if ($summary_file); + print "total: $cnt_error errors, $cnt_warn warnings, " . + (($check)? "$cnt_chk checks, " : "") . + "$cnt_lines lines checked\n"; + print "\n" if ($quiet == 0); + } + + if ($quiet == 0) { + # If there were whitespace errors which cleanpatch can fix + # then suggest that. + if ($rpt_cleaners) { + print "NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or\n"; + print " scripts/cleanfile\n\n"; + $rpt_cleaners = 0; + } + } + + if (keys %ignore_type) { + print "NOTE: Ignored message types:"; + foreach my $ignore (sort keys %ignore_type) { + print " $ignore"; + } + print "\n"; + print "\n" if ($quiet == 0); + } + + if ($clean == 1 && $quiet == 0) { + print "$vname has no obvious style problems and is ready for submission.\n" + } + if ($clean == 0 && $quiet == 0) { + print << "EOM"; +$vname has style problems, please review. + +If any of these errors are false positives, please report +them to the maintainer, see CHECKPATCH in MAINTAINERS. +EOM + } + + return $clean; +} diff --git a/root/package/utils/sysupgrade-helper/src/tools/checkstack.pl b/root/package/utils/sysupgrade-helper/src/tools/checkstack.pl new file mode 100644 index 00000000..c1cdc0a9 --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/tools/checkstack.pl @@ -0,0 +1,171 @@ +#!/usr/bin/perl + +# Check the stack usage of functions +# +# Copyright Joern Engel +# Inspired by Linus Torvalds +# Original idea maybe from Keith Owens +# s390 port and big speedup by Arnd Bergmann +# Mips port by Juan Quintela +# IA64 port via Andreas Dilger +# Arm port by Holger Schurig +# sh64 port by Paul Mundt +# Random bits by Matt Mackall +# M68k port by Geert Uytterhoeven and Andreas Schwab +# AVR32 port by Haavard Skinnemoen (Atmel) +# PARISC port by Kyle McMartin +# sparc port by Martin Habets +# +# Usage: +# objdump -d vmlinux | scripts/checkstack.pl [arch] +# +# TODO : Port to all architectures (one regex per arch) + +use strict; + +# check for arch +# +# $re is used for two matches: +# $& (whole re) matches the complete objdump line with the stack growth +# $1 (first bracket) matches the size of the stack growth +# +# $dre is similar, but for dynamic stack redutions: +# $& (whole re) matches the complete objdump line with the stack growth +# $1 (first bracket) matches the dynamic amount of the stack growth +# +# use anything else and feel the pain ;) +my (@stack, $re, $dre, $x, $xs); +{ + my $arch = shift; + if ($arch eq "") { + $arch = `uname -m`; + chomp($arch); + } + + $x = "[0-9a-f]"; # hex character + $xs = "[0-9a-f ]"; # hex character or space + if ($arch eq 'arm') { + #c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64 + $re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o; + } elsif ($arch eq 'avr32') { + #8000008a: 20 1d sub sp,4 + #80000ca8: fa cd 05 b0 sub sp,sp,1456 + $re = qr/^.*sub.*sp.*,([0-9]{1,8})/o; + } elsif ($arch =~ /^i[3456]86$/) { + #c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp + $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%esp$/o; + $dre = qr/^.*[as][du][db] (%.*),\%esp$/o; + } elsif ($arch eq 'x86_64') { + # 2f60: 48 81 ec e8 05 00 00 sub $0x5e8,%rsp + $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%rsp$/o; + $dre = qr/^.*[as][du][db] (\%.*),\%rsp$/o; + } elsif ($arch eq 'ia64') { + #e0000000044011fc: 01 0f fc 8c adds r12=-384,r12 + $re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o; + } elsif ($arch eq 'm68k') { + # 2b6c: 4e56 fb70 linkw %fp,#-1168 + # 1df770: defc ffe4 addaw #-28,%sp + $re = qr/.*(?:linkw %fp,|addaw )#-([0-9]{1,4})(?:,%sp)?$/o; + } elsif ($arch eq 'mips64') { + #8800402c: 67bdfff0 daddiu sp,sp,-16 + $re = qr/.*daddiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; + } elsif ($arch eq 'mips') { + #88003254: 27bdffe0 addiu sp,sp,-32 + $re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; + } elsif ($arch eq 'parisc' || $arch eq 'parisc64') { + $re = qr/.*ldo ($x{1,8})\(sp\),sp/o; + } elsif ($arch eq 'ppc') { + #c00029f4: 94 21 ff 30 stwu r1,-208(r1) + $re = qr/.*stwu.*r1,-($x{1,8})\(r1\)/o; + } elsif ($arch eq 'ppc64') { + #XXX + $re = qr/.*stdu.*r1,-($x{1,8})\(r1\)/o; + } elsif ($arch eq 'powerpc') { + $re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o; + } elsif ($arch =~ /^s390x?$/) { + # 11160: a7 fb ff 60 aghi %r15,-160 + # or + # 100092: e3 f0 ff c8 ff 71 lay %r15,-56(%r15) + $re = qr/.*(?:lay|ag?hi).*\%r15,-(([0-9]{2}|[3-9])[0-9]{2}) + (?:\(\%r15\))?$/ox; + } elsif ($arch =~ /^sh64$/) { + #XXX: we only check for the immediate case presently, + # though we will want to check for the movi/sub + # pair for larger users. -- PFM. + #a00048e0: d4fc40f0 addi.l r15,-240,r15 + $re = qr/.*addi\.l.*r15,-(([0-9]{2}|[3-9])[0-9]{2}),r15/o; + } elsif ($arch =~ /^blackfin$/) { + # 0: 00 e8 38 01 LINK 0x4e0; + $re = qr/.*[[:space:]]LINK[[:space:]]*(0x$x{1,8})/o; + } elsif ($arch eq 'sparc' || $arch eq 'sparc64') { + # f0019d10: 9d e3 bf 90 save %sp, -112, %sp + $re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o; + } else { + print("wrong or unknown architecture \"$arch\"\n"); + exit + } +} + +# +# main() +# +my $funcre = qr/^$x* <(.*)>:$/; +my ($func, $file, $lastslash); + +while (my $line = ) { + if ($line =~ m/$funcre/) { + $func = $1; + } + elsif ($line =~ m/(.*):\s*file format/) { + $file = $1; + $file =~ s/\.ko//; + $lastslash = rindex($file, "/"); + if ($lastslash != -1) { + $file = substr($file, $lastslash + 1); + } + } + elsif ($line =~ m/$re/) { + my $size = $1; + $size = hex($size) if ($size =~ /^0x/); + + if ($size > 0xf0000000) { + $size = - $size; + $size += 0x80000000; + $size += 0x80000000; + } + next if ($size > 0x10000000); + + next if $line !~ m/^($xs*)/; + my $addr = $1; + $addr =~ s/ /0/g; + $addr = "0x$addr"; + + my $intro = "$addr $func [$file]:"; + my $padlen = 56 - length($intro); + while ($padlen > 0) { + $intro .= ' '; + $padlen -= 8; + } + next if ($size < 100); + push @stack, "$intro$size\n"; + } + elsif (defined $dre && $line =~ m/$dre/) { + my $size = "Dynamic ($1)"; + + next if $line !~ m/^($xs*)/; + my $addr = $1; + $addr =~ s/ /0/g; + $addr = "0x$addr"; + + my $intro = "$addr $func [$file]:"; + my $padlen = 56 - length($intro); + while ($padlen > 0) { + $intro .= ' '; + $padlen -= 8; + } + push @stack, "$intro$size\n"; + } +} + +# Sort output by size (last field) +print sort { ($b =~ /:\t*(\d+)$/)[0] <=> ($a =~ /:\t*(\d+)$/)[0] } @stack; diff --git a/root/package/utils/sysupgrade-helper/src/tools/gcc-version.sh b/root/package/utils/sysupgrade-helper/src/tools/gcc-version.sh new file mode 100644 index 00000000..debecb55 --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/tools/gcc-version.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# +# gcc-version [-p] gcc-command +# +# Prints the gcc version of `gcc-command' in a canonical 4-digit form +# such as `0295' for gcc-2.95, `0303' for gcc-3.3, etc. +# +# With the -p option, prints the patchlevel as well, for example `029503' for +# gcc-2.95.3, `030301' for gcc-3.3.1, etc. +# + +if [ "$1" = "-p" ] ; then + with_patchlevel=1; + shift; +fi + +compiler="$*" + +if [ ${#compiler} -eq 0 ]; then + echo "Error: No compiler specified." + printf "Usage:\n\t$0 \n" + exit 1 +fi + +MAJOR=$(echo __GNUC__ | $compiler -E -xc - | tail -n 1) +MINOR=$(echo __GNUC_MINOR__ | $compiler -E -xc - | tail -n 1) +if [ "x$with_patchlevel" != "x" ] ; then + PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -xc - | tail -n 1) + printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL +else + printf "%02d%02d\\n" $MAJOR $MINOR +fi diff --git a/root/package/utils/sysupgrade-helper/src/tools/img2brec.sh b/root/package/utils/sysupgrade-helper/src/tools/img2brec.sh new file mode 100644 index 00000000..0fcdba27 --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/tools/img2brec.sh @@ -0,0 +1,388 @@ +#!/bin/sh + +# This script converts binary files (u-boot.bin) into so called +# bootstrap records that are accepted by Motorola's MC9328MX1/L +# (a.k.a. DragaonBall i.MX) in "Bootstrap Mode" +# +# The code for the SynchFlash programming routines is taken from +# Bootloader\Bin\SyncFlash\programBoot_b.txt contained in +# Motorolas LINUX_BSP_0_3_8.tar.gz +# +# The script could easily extended for AMD flash routines. +# +# 2004-06-23 - steven.scholz@imc-berlin.de + +################################################################################# +# From the posting to the U-Boot-Users mailing list, 23 Jun 2004: +# =============================================================== +# I just hacked a simple script that converts u-boot.bin into a text file +# containg processor init code, SynchFlash programming code and U-Boot data in +# form of so called b-records. +# +# This can be used to programm U-Boot into (Synch)Flash using the Bootstrap +# Mode of the MC9328MX1/L +# +# 0AFE1F3410202E2E2E000000002073756363656564/ +# 0AFE1F44102E0A0000206661696C656420210A0000/ +# 0AFE100000 +# ... +# MX1ADS Sync-flash Programming Utility v0.5 2002/08/21 +# +# Source address (stored in 0x0AFE0000): 0x0A000000 +# Target address (stored in 0x0AFE0004): 0x0C000000 +# Size (stored in 0x0AFE0008): 0x0001A320 +# +# Press any key to start programming ... +# Erasing ... +# Blank checking ... +# Programming ... +# Verifying flash ... succeed. +# +# Programming finished. +# +# So no need for a BDI2000 anymore... ;-) +# +# This is working on my MX1ADS eval board. Hope this could be useful for +# someone. +################################################################################# + +if [ "$#" -lt 1 -o "$#" -gt 2 ] ; then + echo "Usage: $0 infile [outfile]" >&2 + echo " $0 u-boot.bin [u-boot.brec]" >&2 + exit 1 +fi + +if [ "$#" -ge 1 ] ; then + INFILE=$1 +fi + +if [ ! -f $INFILE ] ; then + echo "Error: file '$INFILE' does not exist." >&2 + exit 1 +fi + +FILESIZE=`filesize $INFILE` + +output_init() +{ +echo "\ +******************************************** +* Initialize I/O Pad Driving Strength * +******************************************** +0021B80CC4000003AB +******************************************** +* Initialize SDRAM * +******************************************** +00221000C492120200 ; pre-charge command +08200000E4 ; special read + +00221000C4A2120200 ; auto-refresh command +08000000E4 ; 8 special read +08000000E4 ; 8 special read +08000000E4 ; 8 special read +08000000E4 ; 8 special read +08000000E4 ; 8 special read +08000000E4 ; 8 special read +08000000E4 ; 8 special read +08000000E4 ; 8 special read + +00221000C4B2120200 ; set mode register +08111800E4 ; special read + +00221000C482124200 ; set normal mode + " +} + +output_uboot() +{ +echo "\ +******************************************** +* U-Boot image as bootstrap records * +* will be stored in SDRAM at 0x0A000000 * +******************************************** + " + +cat $INFILE | \ +hexdump -v -e "\"0A0%05.5_ax10\" 16/1 \"%02x\"\"\r\n\"" | \ +tr [:lower:] [:upper:] +} + +output_flashprog() +{ +echo "\ +******************************************** +* Address of arguments to flashProg * +* ---------------------------------------- * +* Source : 0x0A000000 * +* Destination : 0x0C000000 * " + +# get the real size of the U-Boot image +printf "* Size : 0x%08X *\r\n" $FILESIZE +printf "********************************************\r\n" +printf "0AFE0000CC0A0000000C000000%08X\r\n" $FILESIZE + +#;0AFE0000CC0A0000000C00000000006000 + +echo "\ +******************************************** +* Flash Program * +******************************************** +0AFE10001008D09FE5AC0000EA00F0A0E1A42DFE0A +0AFE1010100080FE0A0DC0A0E100D82DE904B04CE2 +0AFE1020109820A0E318309FE5003093E5033082E0 +0AFE103010003093E5013003E2FF3003E20300A0E1 +0AFE10401000A81BE9A01DFE0A0DC0A0E100D82DE9 +0AFE10501004B04CE204D04DE20030A0E10D304BE5 +0AFE1060109820A0E330309FE5003093E5033082E0 +0AFE107010003093E5013903E2000053E3F7FFFF0A +0AFE1080104020A0E310309FE5003093E5032082E0 +0AFE1090100D305BE5003082E500A81BE9A01DFE0A +0AFE10A0100DC0A0E100D82DE904B04CE20000A0E1 +0AFE10B010D7FFFFEB0030A0E1FF3003E2000053E3 +0AFE10C010FAFFFF0A10309FE5003093E5003093E5 +0AFE10D010FF3003E20300A0E100A81BE9A01DFE0A +0AFE10E0100DC0A0E100D82DE904B04CE204D04DE2 +0AFE10F0100030A0E10D304BE50D305BE52332A0E1 +0AFE1100100E304BE50E305BE5090053E30300009A +0AFE1110100E305BE5373083E20E304BE5020000EA +0AFE1120100E305BE5303083E20E304BE50E305BE5 +0AFE1130100300A0E1C3FFFFEB0D305BE50F3003E2 +0AFE1140100E304BE50E305BE5090053E30300009A +0AFE1150100E305BE5373083E20E304BE5020000EA +0AFE1160100E305BE5303083E20E304BE50E305BE5 +0AFE1170100300A0E1B3FFFFEB00A81BE90DC0A0E1 +0AFE11801000D82DE904B04CE21CD04DE210000BE5 +0AFE11901014100BE518200BE588009FE5E50200EB +0AFE11A01010301BE51C300BE514301BE520300BE5 +0AFE11B0100030A0E324300BE524201BE518301BE5 +0AFE11C010030052E10000003A120000EA1C004BE2 +0AFE11D010002090E520104BE2003091E500C093E5 +0AFE11E010043083E2003081E5003092E5042082E2 +0AFE11F010002080E50C0053E10200000A0030A0E3 +0AFE12001028300BE5050000EA24301BE5043083E2 +0AFE12101024300BE5E7FFFFEA0130A0E328300BE5 +0AFE12201028001BE500A81BE9E81EFE0A0DC0A0E1 +0AFE12301000D82DE904B04CE214D04DE210000BE5 +0AFE12401014100BE56C009FE5BA0200EB10301BE5 +0AFE12501018300BE50030A0E31C300BE51C201BE5 +0AFE12601014301BE5030052E10000003A0D0000EA +0AFE12701018304BE2002093E5001092E5042082E2 +0AFE128010002083E5010071E30200000A0030A0E3 +0AFE12901020300BE5050000EA1C301BE5043083E2 +0AFE12A0101C300BE5ECFFFFEA0130A0E320300BE5 +0AFE12B01020001BE500A81BE9001FFE0A0DC0A0E1 +0AFE12C01000D82DE904B04CE224D04DE20130A0E3 +0AFE12D01024300BE5A4229FE58139A0E3023A83E2 +0AFE12E010003082E59820A0E390329FE5003093E5 +0AFE12F010033082E0003093E5023903E2000053E3 +0AFE1300100300001A74229FE58139A0E3033A83E2 +0AFE131010003082E568029FE5860200EBAF36A0E3 +0AFE1320100E3883E2003093E510300BE554029FE5 +0AFE133010800200EB10301BE5233CA0E1FF3003E2 +0AFE1340100300A0E165FFFFEB10301BE52338A0E1 +0AFE135010FF3003E20300A0E160FFFFEB10301BE5 +0AFE1360102334A0E1FF3003E20300A0E15BFFFFEB +0AFE13701010305BE50300A0E158FFFFEB0A00A0E3 +0AFE13801030FFFFEB0D00A0E32EFFFFEBAF36A0E3 +0AFE1390100E3883E2043083E2003093E514300BE5 +0AFE13A010E4019FE5630200EB14301BE5233CA0E1 +0AFE13B010FF3003E20300A0E148FFFFEB14301BE5 +0AFE13C0102338A0E1FF3003E20300A0E143FFFFEB +0AFE13D01014301BE52334A0E1FF3003E20300A0E1 +0AFE13E0103EFFFFEB14305BE50300A0E13BFFFFEB +0AFE13F0100A00A0E313FFFFEB0D00A0E311FFFFEB +0AFE140010AF36A0E30E3883E2083083E2003093E5 +0AFE14101018300BE574019FE5460200EB18301BE5 +0AFE142010233CA0E1FF3003E20300A0E12BFFFFEB +0AFE14301018301BE52338A0E1FF3003E20300A0E1 +0AFE14401026FFFFEB18301BE52334A0E1FF3003E2 +0AFE1450100300A0E121FFFFEB18305BE50300A0E1 +0AFE1460101EFFFFEB0A00A0E3F6FEFFEB0D00A0E3 +0AFE147010F4FEFFEBE6FEFFEB0030A0E1FF3003E2 +0AFE148010000053E30000001A020000EA03FFFFEB +0AFE1490102D004BE5F6FFFFEAF4009FE5250200EB +0AFE14A010FEFEFFEB2D004BE5CD0000EBC00000EB +0AFE14B010E0009FE51F0200EB18301BE528300BE5 +0AFE14C01014301BE52C300BE52C001BE5100100EB +0AFE14D01028301BE5013643E228300BE52C301BE5 +0AFE14E010013683E22C300BE528301BE5000053E3 +0AFE14F010F4FFFFCAAE0000EB14001BE518101BE5 +0AFE15001049FFFFEB0030A0E1FF3003E2000053E3 +0AFE151010E6FFFF0A80009FE5060200EB10001BE5 +0AFE15201014101BE518201BE5D00000EB10001BE5 +0AFE15301014101BE518201BE50FFFFFEB0030A0E1 +0AFE154010FF3003E2000053E30200000A4C009FE5 +0AFE155010F80100EB010000EA44009FE5F50100EB +0AFE156010930000EB3C009FE5F20100EB0000A0E3 +0AFE157010A4FEFFEB0030A0E30300A0E100A81BE9 +0AFE158010A01DFE0AA41DFE0AE01DFE0A0C1EFE0A +0AFE159010381EFE0A641EFE0A181FFE0A281FFE0A +0AFE15A0103C1FFE0A481FFE0AB41EFE0A0DC0A0E1 +0AFE15B01000D82DE904B04CE204D04DE210000BE5 +0AFE15C01010301BE5013043E210300BE5010073E3 +0AFE15D010FAFFFF1A00A81BE90DC0A0E100D82DE9 +0AFE15E01004B04CE208D04DE210000BE510301BE5 +0AFE15F01014300BE514301BE50300A0E100A81BE9 +0AFE1600100DC0A0E100D82DE904B04CE204D04DE2 +0AFE1610102228A0E3012A82E2042082E2E134A0E3 +0AFE162010023883E2033C83E2003082E50333A0E3 +0AFE163010053983E2003093E510300BE500A81BE9 +0AFE1640100DC0A0E100D82DE904B04CE204D04DE2 +0AFE1650102228A0E3012A82E2042082E29134A0E3 +0AFE166010023883E2033C83E2003082E5C136A0E3 +0AFE167010003093E510300BE52228A0E3012A82E2 +0AFE168010042082E2E134A0E3023883E2033C83E2 +0AFE169010003082E50333A0E3073983E20020A0E3 +0AFE16A010002083E52228A0E3012A82E2042082E2 +0AFE16B0108134A0E3023883E2033C83E2003082E5 +0AFE16C0100333A0E3003093E510300BE5CBFFFFEB +0AFE16D01010301BE50300A0E100A81BE90DC0A0E1 +0AFE16E01000D82DE904B04CE208D04DE2D3FFFFEB +0AFE16F0100030A0E110300BE510301BE5023503E2 +0AFE170010000053E30500000A10301BE5073703E2 +0AFE171010000053E30100000A10001BE5ADFFFFEB +0AFE17201010301BE5803003E2000053E30500000A +0AFE17301010301BE51C3003E2000053E30100000A +0AFE17401010001BE5A3FFFFEB10201BE50235A0E3 +0AFE175010803083E2030052E10200001A0130A0E3 +0AFE17601014300BE5010000EA0030A0E314300BE5 +0AFE17701014001BE500A81BE90DC0A0E100D82DE9 +0AFE17801004B04CE204D04DE22228A0E3012A82E2 +0AFE179010042082E29134A0E3023883E2033C83E2 +0AFE17A010003082E5C136A0E3003093E510300BE5 +0AFE17B01000A81BE90DC0A0E100D82DE904B04CE2 +0AFE17C010ECFFFFEB2228A0E3012A82E2042082E2 +0AFE17D0108134A0E3023883E2033C83E2003082E5 +0AFE17E01000A81BE90DC0A0E100D82DE904B04CE2 +0AFE17F01004D04DE22228A0E3012A82E2042082E2 +0AFE1800102238A0E3013A83E2043083E2003093E5 +0AFE181010023183E3003082E52228A0E3012A82E2 +0AFE1820102238A0E3013A83E2003093E5023183E3 +0AFE183010003082E5FA0FA0E35BFFFFEB2228A0E3 +0AFE184010012A82E2042082E2B134A0E3023883E2 +0AFE185010033C83E2003082E50333A0E3233983E2 +0AFE186010033B83E2003093E510300BE500A81BE9 +0AFE1870100DC0A0E100D82DE904B04CE21CD04DE2 +0AFE18801010000BE514100BE518200BE50030A0E3 +0AFE1890101C300BE51C201BE518301BE5030052E1 +0AFE18A0100000003A190000EAB2FFFFEB2228A0E3 +0AFE18B010012A82E2042082E2F134A0E3023883E2 +0AFE18C010033C83E2003082E514201BE51C301BE5 +0AFE18D010031082E010201BE51C301BE5033082E0 +0AFE18E010003093E5003081E57BFFFFEB0030A0E1 +0AFE18F010FF3003E2000053E3FAFFFF0AACFFFFEB +0AFE1900101C301BE5043083E21C300BE5E0FFFFEA +0AFE19101000A81BE90DC0A0E100D82DE904B04CE2 +0AFE1920100CD04DE210000BE52228A0E3012A82E2 +0AFE193010042082E28134A0E3023883E2033C83E2 +0AFE194010003082E510301BE5003093E514300BE5 +0AFE1950102228A0E3012A82E2042082E29134A0E3 +0AFE196010023883E2033C83E2003082E510301BE5 +0AFE197010003093E518300BE52228A0E3012A82E2 +0AFE198010042082E2E134A0E3023883E2033C83E2 +0AFE199010003082E50229A0E310301BE5032082E0 +0AFE19A0100030A0E3003082E52228A0E3012A82E2 +0AFE19B010042082E28134A0E3023883E2033C83E2 +0AFE19C010003082E510201BE50D3AA0E3D03083E2 +0AFE19D010033883E1003082E53FFFFFEB0030A0E1 +0AFE19E010FF3003E2000053E3FAFFFF0A70FFFFEB +0AFE19F01000A81BE90DC0A0E100D82DE904B04CE2 +0AFE1A00105CFFFFEB2228A0E3012A82E2042082E2 +0AFE1A1010E134A0E3023883E2033C83E2003082E5 +0AFE1A20100333A0E3033983E20020A0E3002083E5 +0AFE1A30102228A0E3012A82E2042082E28134A0E3 +0AFE1A4010023883E2033C83E2003082E50323A0E3 +0AFE1A5010032982E20339A0E3C03083E2033883E1 +0AFE1A6010003082E500A81BE90DC0A0E100D82DE9 +0AFE1A701004B04CE23FFFFFEB2228A0E3012A82E2 +0AFE1A8010042082E2E134A0E3023883E2033C83E2 +0AFE1A9010003082E50333A0E30A3983E20020A0E3 +0AFE1AA010002083E52228A0E3012A82E2042082E2 +0AFE1AB0108134A0E3023883E2033C83E2003082E5 +0AFE1AC0100323A0E30A2982E20339A0E3C03083E2 +0AFE1AD010033883E1003082E500A81BE90DC0A0E1 +0AFE1AE01000D82DE904B04CE28729A0E3222E82E2 +0AFE1AF0108739A0E3223E83E2003093E51E3CC3E3 +0AFE1B0010003082E58729A0E38E2F82E28739A0E3 +0AFE1B10108E3F83E2003093E51E3CC3E3003082E5 +0AFE1B20108139A0E3823D83E20520A0E3002083E5 +0AFE1B30108129A0E3822D82E2042082E20139A0E3 +0AFE1B4010273083E2003082E58139A0E3823D83E2 +0AFE1B50100C3083E20120A0E3002083E58129A0E3 +0AFE1B6010822D82E2102082E22A3DA0E3013083E2 +0AFE1B7010003082E58139A0E3823D83E2243083E2 +0AFE1B80100F20A0E3002083E58139A0E3823D83E2 +0AFE1B9010283083E28A20A0E3002083E58139A0E3 +0AFE1BA010823D83E22C3083E20820A0E3002083E5 +0AFE1BB01000A81BE90DC0A0E100D82DE904B04CE2 +0AFE1BC0108139A0E3823D83E2183083E2003093E5 +0AFE1BD010013003E2FF3003E20300A0E100A81BE9 +0AFE1BE0100DC0A0E100D82DE904B04CE204D04DE2 +0AFE1BF0100030A0E10D304BE58139A0E3823D83E2 +0AFE1C0010183083E2003093E5013903E2000053E3 +0AFE1C1010F8FFFF0A8139A0E3813D83E20D205BE5 +0AFE1C2010002083E50D305BE50A0053E30A00001A +0AFE1C30108139A0E3823D83E2183083E2003093E5 +0AFE1C4010013903E2000053E3F8FFFF0A8139A0E3 +0AFE1C5010813D83E20D20A0E3002083E500A81BE9 +0AFE1C60100DC0A0E100D82DE904B04CE20000A0E1 +0AFE1C7010CFFFFFEB0030A0E1FF3003E2000053E3 +0AFE1C8010FAFFFF0A8139A0E3023A83E2003093E5 +0AFE1C9010FF3003E20300A0E100A81BE90DC0A0E1 +0AFE1CA01000D82DE904B04CE204D04DE20030A0E1 +0AFE1CB0100D304BE50D305BE52332A0E10E304BE5 +0AFE1CC0100E305BE5090053E30300009A0E305BE5 +0AFE1CD010373083E20E304BE5020000EA0E305BE5 +0AFE1CE010303083E20E304BE50E305BE50300A0E1 +0AFE1CF010BAFFFFEB0D305BE50F3003E20E304BE5 +0AFE1D00100E305BE5090053E30300009A0E305BE5 +0AFE1D1010373083E20E304BE5020000EA0E305BE5 +0AFE1D2010303083E20E304BE50E305BE50300A0E1 +0AFE1D3010AAFFFFEB00A81BE90DC0A0E100D82DE9 +0AFE1D401004B04CE204D04DE210000BE510301BE5 +0AFE1D50100030D3E5000053E30000001A080000EA +0AFE1D601010104BE2003091E50320A0E10020D2E5 +0AFE1D7010013083E2003081E50200A0E197FFFFEB +0AFE1D8008F1FFFFEA00A81BE9 +0AFE1DA4100A0D4D58314144532053796E632D666C +0AFE1DB4106173682050726F6772616D6D696E6720 +0AFE1DC4105574696C6974792076302E3520323030 +0AFE1DD410322F30382F32310A0D000000536F7572 +0AFE1DE41063652061646472657373202873746F72 +0AFE1DF410656420696E2030783041464530303030 +0AFE1E0410293A2030780000005461726765742061 +0AFE1E1410646472657373202873746F7265642069 +0AFE1E24106E2030783041464530303034293A2030 +0AFE1E34107800000053697A652020202020202020 +0AFE1E44102020202873746F72656420696E203078 +0AFE1E54103041464530303038293A203078000000 +0AFE1E6410507265737320616E79206B657920746F +0AFE1E74102073746172742070726F6772616D6D69 +0AFE1E84106E67202E2E2E00000A0D45726173696E +0AFE1E94106720666C617368202E2E2E000A0D5072 +0AFE1EA4106F6772616D6D696E67202E2E2E000000 +0AFE1EB4100A0D50726F6772616D6D696E67206669 +0AFE1EC4106E69736865642E0A0D50726573732027 +0AFE1ED410612720746F20636F6E74696E7565202E +0AFE1EE4102E2E2E000A0D566572696679696E6720 +0AFE1EF410666C617368202E2E2E0000000A0D426C +0AFE1F0410616E6B20636865636B696E67202E2E2E +0AFE1F1410000000000A45726173696E67202E2E2E +0AFE1F2410000000000A50726F6772616D6D696E67 +0AFE1F3410202E2E2E000000002073756363656564 +0AFE1F44102E0A0000206661696C656420210A0000 +0AFE100000 + " +} + +######################################################### + +if [ "$#" -eq 2 ] ; then + output_init > $2 + output_uboot >> $2 + output_flashprog >> $2 +else + output_init; + output_uboot; + output_flashprog; +fi diff --git a/root/package/utils/sysupgrade-helper/src/tools/jtagconsole b/root/package/utils/sysupgrade-helper/src/tools/jtagconsole new file mode 100644 index 00000000..d404fac5 --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/tools/jtagconsole @@ -0,0 +1,39 @@ +#!/bin/sh + +usage() { + ( + echo "Usage: $0 [board IP] [board port]" + echo "" + echo "If IP is not specified, 'localhost' will be used" + echo "If port is not specified, '2001' will be used" + [ -z "$*" ] && exit 0 + echo "" + echo "ERROR: $*" + exit 1 + ) 1>&2 + exit $? +} + +while [ -n "$1" ] ; do + case $1 in + -h|--help) usage;; + --) break;; + -*) usage "Invalid option $1";; + *) break;; + esac + shift +done + +ip=${1:-localhost} +port=${2:-2001} + +if [ -z "${ip}" ] || [ -n "$3" ] ; then + usage "Invalid number of arguments" +fi + +trap "stty icanon echo opost intr ^C" 0 2 3 5 10 13 15 +echo "NOTE: the interrupt signal (normally ^C) has been remapped to ^T" + +stty -icanon -echo -opost intr ^T +nc ${ip} ${port} +exit 0 diff --git a/root/package/utils/sysupgrade-helper/src/tools/netconsole b/root/package/utils/sysupgrade-helper/src/tools/netconsole new file mode 100644 index 00000000..c8109bb0 --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/tools/netconsole @@ -0,0 +1,59 @@ +#!/bin/sh + +usage() { + ( + echo "Usage: $0 [board port]" + echo "" + echo "If port is not specified, '6666' will be used" + [ -z "$*" ] && exit 0 + echo "" + echo "ERROR: $*" + exit 1 + ) 1>&2 + exit $? +} + +while [ -n "$1" ] ; do + case $1 in + -h|--help) usage;; + --) break;; + -*) usage "Invalid option $1";; + *) break;; + esac + shift +done + +ip=$1 +port=${2:-6666} + +if [ -z "${ip}" ] || [ -n "$3" ] ; then + usage "Invalid number of arguments" +fi + +for nc in netcat nc ; do + type ${nc} >/dev/null 2>&1 && break +done + +trap "stty icanon echo intr ^C" 0 2 3 5 10 13 15 +echo "NOTE: the interrupt signal (normally ^C) has been remapped to ^T" + +stty -icanon -echo intr ^T +( +if type ncb 2>/dev/null ; then + # see if ncb is in $PATH + exec ncb ${port} + +elif [ -x ${0%/*}/ncb ] ; then + # maybe it's in the same dir as the netconsole script + exec ${0%/*}/ncb ${port} + +else + # blah, just use regular netcat + while ${nc} -u -l -p ${port} < /dev/null ; do + : + done +fi +) & +pid=$! +${nc} -u ${ip} ${port} +kill ${pid} 2>/dev/null diff --git a/root/package/utils/sysupgrade-helper/src/tools/pack.py b/root/package/utils/sysupgrade-helper/src/tools/pack.py new file mode 100644 index 00000000..ccb269aa --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/tools/pack.py @@ -0,0 +1,1854 @@ +#!/usr/bin/env python +# +# Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. +# +""" +Script to create a U-Boot flashable multi-image blob. + +This script creates a multi-image blob, from a bunch of images, and +adds a U-Boot shell script to the blob, that can flash the images from +within U-Boot. The procedure to use this script is listed below. + + 1. Create an images folder. Ex: my-pack + + 2. Copy all the images to be flashed into the folder. + + 3. Copy the partition MBN file into the folder. The file should be + named 'partition.mbn'. This is used to determine the offsets for + each of the named partitions. + + 4. Create a flash configuration file, specifying the images be + flashed, and the partition in which the images is to be + flashed. The flash configuration file can be specified using the + -f option, default is flash.conf. + + 5. Invoke 'pack' with the folder name as argument, pass flash + parameters as arguments if required. A single image file will + be created, out side the images folder, with .img suffix. Ex: + my-pack.img + + 6. Transfer the file into a valid SDRAM address and invoke the + following U-Boot command to flash the images. Replace 0x41000000, + with address location where the image has been loaded. The script + expects the variable 'imgaddr' to be set. + + u-boot> imgaddr=0x41000000 source $imgaddr:script + +Host-side Pre-req + + * Python >= 2.6 + * ordereddict >= 1.1 (for Python 2.6) + * mkimage >= 2012.07 + * dtc >= 1.2.0 + +Target-side Pre-req + +The following U-Boot config macros should be enabled, for the +generated flashing script to work. + + * CONFIG_FIT -- FIT image format support + * CONFIG_SYS_HUSH_PARSER -- bash style scripting support + * CONFIG_SYS_NULLDEV -- redirecting command output support + * CONFIG_CMD_XIMG -- extracting sub-images support + * CONFIG_CMD_NAND -- NAND Flash commands support + * CONFIG_CMD_NAND_YAFFS -- NAND YAFFS2 write support + * CONFIG_CMD_SF -- SPI Flash commands support +""" + +from ConfigParser import ConfigParser +from ConfigParser import Error as ConfigParserError +from os.path import getsize +from getopt import getopt +from getopt import GetoptError +from collections import namedtuple +from string import Template +from unittest import TestCase +from tempfile import mkdtemp +from shutil import rmtree + +import os +import sys +import os.path +import subprocess +import struct +import re +import hashlib + +version = "1.1" + +# +# Python 2.6 and earlier did not have OrderedDict use the backport +# from ordereddict package. If that is not available report error. +# +try: + from collections import OrderedDict +except ImportError: + try: + from ordereddict import OrderedDict + except ImportError: + print "error: this script requires the 'ordereddict' class." + print "Try 'pip install --user ordereddict'" + print "Or 'easy_install --user ordereddict'" + sys.exit(1) + +__all__ = [] + +KB = 1024 +MB = 1024 * KB + +def error(msg, ex=None): + """Print an error message and exit. + + msg -- string, the message to print + ex -- exception, the associate exception, if any + """ + + sys.stderr.write("pack: %s" % msg) + if ex != None: sys.stderr.write(": %s" % str(ex)) + sys.stderr.write("\n") + sys.exit(1) + +FlashInfo = namedtuple("FlashInfo", "type pagesize blocksize chipsize") +ImageInfo = namedtuple("ProgInfo", "name filename type") +PartInfo = namedtuple("PartInfo", "name offset length") + +def roundup(value, roundto): + """Return the next largest multiple of 'roundto'.""" + + return ((value + roundto - 1) // roundto) * roundto + +class GPT(object): + GPTheader = namedtuple("GPTheader", "signature revision header_size" + " crc32 current_lba backup_lba first_usable_lba" + " last_usable_lba disk_guid start_lba_part_entry" + " num_part_entry part_entry_size part_crc32") + GPT_SIGNATURE = 'EFI PART' + GPT_REVISION = '\x00\x00\x01\x00' + GPT_HEADER_SIZE = 0x5C + GPT_HEADER_FMT = "<8s4sLL4xQQQQ16sQLLL" + + GPTtable = namedtuple("GPTtable", "part_type unique_guid first_lba" + " last_lba attribute_flag part_name") + GPT_TABLE_FMT = "<16s16sQQQ72s" + + def __init__(self, filename, pagesize, blocksize, chipsize): + self.filename = filename + self.pagesize = pagesize + self.blocksize = blocksize + self.chipsize = chipsize + self.__partitions = OrderedDict() + + def __validate_and_read_parts(self, part_fp): + """Validate the GPT and read the partition""" + part_fp.seek(self.blocksize, os.SEEK_SET) + gptheader_str = part_fp.read(struct.calcsize(GPT.GPT_HEADER_FMT)) + gptheader = struct.unpack(GPT.GPT_HEADER_FMT, gptheader_str) + gptheader = GPT.GPTheader._make(gptheader) + + if gptheader.signature != GPT.GPT_SIGNATURE: + error("Invalid signature") + + if gptheader.revision != GPT.GPT_REVISION: + error("Unsupported GPT Revision") + + if gptheader.header_size != GPT.GPT_HEADER_SIZE: + error("Invalid Header size") + + # Adding GPT partition info. This has to be flashed first. + # GPT Header starts at LBA1 so (current_lba -1) will give the + # starting of primary GPT. + # blocksize will equal to gptheader.first_usuable_lba - current_lba + 1 + + name = "0:GPT" + block_start = gptheader.current_lba - 1 + block_count = gptheader.first_usable_lba - gptheader.current_lba + 1 + part_info = PartInfo(name, block_start, block_count) + self.__partitions[name] = part_info + + part_fp.seek(2 * self.blocksize, os.SEEK_SET) + + for i in range(gptheader.num_part_entry): + gpt_table_str = part_fp.read(struct.calcsize(GPT.GPT_TABLE_FMT)) + gpt_table = struct.unpack(GPT.GPT_TABLE_FMT, gpt_table_str) + gpt_table = GPT.GPTtable._make(gpt_table) + + block_start = gpt_table.first_lba + block_count = gpt_table.last_lba - gpt_table.first_lba + 1 + + part_name = gpt_table.part_name.strip(chr(0)) + name = part_name.replace('\0','') + part_info = PartInfo(name, block_start, block_count) + self.__partitions[name] = part_info + + # Adding the GPT Backup partition. + # GPT header backup_lba gives block number where the GPT backup header will be. + # GPT Backup header will start from offset of 32 blocks before + # the GPTheader.backup_lba. Backup GPT size is 33 blocks. + name = "0:GPTBACKUP" + block_start = gptheader.backup_lba - 32 + block_count = 33 + part_info = PartInfo(name, block_start, block_count) + self.__partitions[name] = part_info + + def get_parts(self): + """Returns a list of partitions present in the GPT.""" + + try: + with open(self.filename, "r") as part_fp: + self.__validate_and_read_parts(part_fp) + except IOError, e: + error("error opening %s" % self.filename, e) + + return self.__partitions + +class MIBIB(object): + Header = namedtuple("Header", "magic1 magic2 version age") + HEADER_FMT = " 0: + if yaffs: + self.append("nand write.yaffs $fileaddr 0x%08x 0x%08x" + % (offset, size)) + else: + size = roundup(size, self.pagesize) + self.append("nand write $fileaddr 0x%08x 0x%08x" % (offset, size)) + + def switch_layout(self, layout): + """Generate code, to switch between sbl/linux layouts.""" + + self.append("ipq_nand %s" % layout) + +class NorScript(FlashScript): + """Class for creating NAND flash scripts.""" + + def __init__(self, flinfo): + FlashScript.__init__(self, flinfo) + + def erase(self, offset, size): + """Generate code, to erase the specified partition.""" + + size = roundup(size, self.blocksize) + self.append("sf erase 0x%08x +0x%08x" % (offset, size)) + + def write(self, offset, size, yaffs): + """Generate code, to write to a partition.""" + + if size > 0: + self.append("sf write $fileaddr 0x%08x 0x%08x" % (offset, size)) + + def nand_write(self, offset, part_size, img_size): + """Handle the NOR + NAND case + All binaries upto HLOS will go to NOR and Root FS will go to NAND + Assumed all nand page sizes are less than are equal to 8KB + """ + self.append("nand device 0 && nand erase 0x%08x 0x%08x" % (offset, part_size)) + if img_size > 0: + self.append("nand write $fileaddr 0x%08x 0x%08x" % (offset, img_size)) + + def switch_layout(self, layout): + pass + +class EmmcScript(FlashScript): + """Class for creating EMMC scripts.""" + + def __init__(self, flinfo): + FlashScript.__init__(self, flinfo) + + def erase(self, offset, size): + """Generate code, to erase the specified partition.""" + + self.append("mmc erase 0x%08x %x" % (offset, size)) + + def write(self, offset, size, yaffs): + """Generate code, to write to a partition.""" + if size > 0: + size = roundup(size, self.blocksize) + blk_cnt = size / self.blocksize + self.append("mmc write $fileaddr 0x%08x %x" % (offset, blk_cnt)) + + def switch_layout(self, layout): + pass + +its_tmpl = Template(""" +/dts-v1/; + +/ { + description = "${desc}"; + images { +${images} + }; +}; +""") + +its_image_tmpl = Template(""" + ${name} { + description = "${desc}"; + data = /incbin/("./${fname}"); + type = "${imtype}"; + arch = "arm"; + compression = "none"; + hash@1 { algo = "crc32"; }; + }; +""") + + +def sha1(message): + """Returns SHA1 digest in hex format of the message.""" + + m = hashlib.sha1() + m.update(message) + return m.hexdigest() + + +class Pack(object): + """Class to create a flashable, multi-image blob. + + Combine multiple images present in a directory, and generate a + U-Boot script to flash the images. + """ + # The maximum rootfs size is 64MB + norplusnand_rootfs_img_size = (64 * 1024 * 1024) + + def __init__(self): + self.flinfo = None + self.images_dname = None + self.ipq_nand = None + self.partitions = {} + + self.fconf_fname = None + self.scr_fname = None + self.its_fname = None + self.img_fname = None + + def __get_yaffs(self, info, section): + """Get the yaffs flag for a section. + + info -- ConfigParser object, containing image flashing info + section -- section to check if yaffs flag is set + """ + try: + yaffs = info.get(section, "yaffs") + if yaffs.lower() in ["0", "no"]: + yaffs = False + elif yaffs.lower() in ["1", "yes"]: + yaffs = True + else: + error("invalid value for 'yaffs' in '%s'" % section) + except ConfigParserError, e: + yaffs = False + + if self.flinfo.type == "nor" and yaffs == True: + error("yaffs cannot be used with NOR flash type") + + return yaffs + + def __get_layout(self, info, section): + """Get the layout for a section. + + info -- ConfigParser object, containing image flashing info + section - section to retreive the layout from + """ + try: + layout = info.get(section, "layout") + except ConfigParserError, e: + layout = None + + if self.ipq_nand and layout == None: + error("layout not specified for IPQ device") + + if not self.ipq_nand and layout != None: + error("layout specified for a non IPQ device") + + if layout not in ("sbl", "linux", None): + error("invalid layout in '%s'" % section) + + return layout + + def __get_machid(self, info, section): + """Get the machid for a section. + + info -- ConfigParser object, containing image flashing info + section -- section to retreive the machid from + """ + try: + machid = info.get(section, "if_machid") + machid = int(machid, 0) + machid = "%x" % machid + except ConfigParserError, e: + machid = None + except ValueError, e: + error("invalid value for machid, should be integer") + + return machid + + def __get_img_size(self, filename): + """Get the size of the image to be flashed + + filaneme -- string, filename of the image to be flashed + """ + + if filename.lower() == "none": + return 0 + try: + return getsize(os.path.join(self.images_dname, filename)) + except OSError, e: + error("error getting image size '%s'" % filename, e) + + def __get_part_info(self, partition): + """Return partition info for the specified partition. + + partition -- string, partition name + """ + try: + return self.partitions[partition] + except KeyError, e: + return None + + def __gen_flash_script(self, info, script, flinfo): + """Generate the script to flash the images. + + info -- ConfigParser object, containing image flashing info + script -- Script object, to append commands to + """ + count = 0 + + for section in info.sections(): + try: + filename = info.get(section, "filename") + partition = info.get(section, "partition") + include = info.get(section, "include") + except ConfigParserError, e: + error("error getting image info in section '%s'" % section, e) + + if include.lower() in ["0", "no"]: + continue + + machid = self.__get_machid(info, section) + layout = self.__get_layout(info, section) + yaffs = self.__get_yaffs(info, section) + + img_size = self.__get_img_size(filename) + part_info = self.__get_part_info(partition) + + if self.flinfo.type == 'nand': + size = roundup(img_size, flinfo.pagesize) + tr = ' | tr \"\\000\" \"\\377\"' + + if self.flinfo.type == 'emmc': + size = roundup(img_size, flinfo.blocksize) + tr = '' + + if ((self.flinfo.type == 'nand' or self.flinfo.type == 'emmc') and (size != img_size)): + pad_size = size - img_size + filename_abs = os.path.join(self.images_dname, filename) + filename_abs_pad = filename_abs + ".padded" + cmd = 'cat %s > %s' % (filename_abs, filename_abs_pad) + ret = subprocess.call(cmd, shell=True) + if ret != 0: + error("failed to copy image") + cmd = 'dd if=/dev/zero count=1 bs=%s %s >> %s' % (pad_size, tr, filename_abs_pad) + cmd = '(' + cmd + ') 1>/dev/null 2>/dev/null' + ret = subprocess.call(cmd, shell=True) + if ret != 0: + error("failed to create padded image from script") + + if self.flinfo.type != "emmc": + if part_info == None: + if self.flinfo.type == 'norplusnand': + if count > 2: + error("More than 2 NAND images for NOR+NAND is not allowed") + elif img_size > part_info.length: + error("img size is larger than part. len in '%s'" % section) + else: + if part_info != None: + if (img_size > 0): + if img_size > (part_info.length * self.flinfo.blocksize): + error("img size is larger than part. len in '%s'" % section) + + if part_info == None and self.flinfo.type != 'norplusnand': + continue + + if machid: + script.start_if("machid", machid) + + script.start_activity("Flashing %s:" % section) + if self.ipq_nand: script.switch_layout(layout) + if img_size > 0: + if ((self.flinfo.type == 'nand' or self.flinfo.type == 'emmc') and (size != img_size)): + filename_pad = filename + ".padded" + script.imxtract(section + "-" + sha1(filename_pad)) + else: + script.imxtract(section + "-" + sha1(filename)) + + if part_info == None: + if self.flinfo.type == 'norplusnand': + offset = count * Pack.norplusnand_rootfs_img_size + part_size = Pack.norplusnand_rootfs_img_size + script.nand_write(offset, part_size, img_size) + count = count + 1 + else: + offset = part_info.offset + script.erase(offset, part_info.length) + script.write(offset, img_size, yaffs) + script.finish_activity() + + if machid: + script.end_if() + + if part_info == None and self.flinfo.type != 'norplusnand': + print "Flash type is norplusemmc" + else: + script.end() + + def __gen_script(self, script_fp, info_fp, script, images, flinfo): + """Generate the script to flash the multi-image blob. + + script_fp -- file object, to write script to + info_fp -- file object, to read flashing information from + script -- Script object, to append the commands to + images -- list of ImageInfo, appended to, based on images in config + """ + try: + info = ConfigParser({"include": "yes"}) + info.readfp(info_fp) + except ConfigParserError, e: + error("error parsing info file '%s'" % self.fconf_fname, e) + + self.__gen_flash_script(info, script, flinfo) + + for section in info.sections(): + if info.get(section, "include").lower() in ["0", "no"]: + continue + + partition = info.get(section, "partition") + part_info = self.__get_part_info(partition) + + if part_info == None and self.flinfo.type != 'norplusnand': + continue + + filename = info.get(section, "filename") + if self.flinfo.type == 'nand': + img_size = self.__get_img_size(filename) + size = roundup(img_size, flinfo.pagesize) + if ( size != img_size ): + filename = filename + ".padded" + if self.flinfo.type == 'emmc': + img_size = self.__get_img_size(filename) + size = roundup(img_size, flinfo.blocksize) + if ( size != img_size ): + filename = filename + ".padded" + image_info = ImageInfo(section + "-" + sha1(filename), + filename, "firmware") + if filename.lower() != "none": + if image_info not in images: + images.append(image_info) + + def __its_escape(self, string): + """Return string with ITS special characters escaped. + + string -- string to be escape. + + String in ITS files, consider 'slash' as special + character. Escape them by prefixing them with a slash. + """ + return string.replace("\\", "\\\\") + + def __mkimage(self, images): + """Create the multi-image blob. + + images -- list of ImageInfo, containing images to be part of the blob + """ + try: + its_fp = open(self.its_fname, "wb") + except IOError, e: + error("error opening its file '%s'" % self.its_fname, e) + + desc = "Flashing %s %x %x" + desc = desc % (self.flinfo.type, self.flinfo.pagesize, + self.flinfo.blocksize) + + image_data = [] + for (section, fname, imtype) in images: + fname = self.__its_escape(fname) + subs = dict(name=section, desc=fname, fname=fname, imtype=imtype) + image_data.append(its_image_tmpl.substitute(subs)) + + image_data = "".join(image_data) + its_data = its_tmpl.substitute(desc=desc, images=image_data) + + its_fp.write(its_data) + its_fp.close() + + try: + cmd = ["mkimage", "-f", self.its_fname, self.img_fname] + ret = subprocess.call(cmd) + if ret != 0: + error("failed to create u-boot image from script") + except OSError, e: + error("error executing mkimage", e) + + def __create_fnames(self): + """Populate the filenames.""" + + self.scr_fname = os.path.join(self.images_dname, "flash.scr") + self.its_fname = os.path.join(self.images_dname, "flash.its") + + def __gen_board_script(self, board_section, machid, flinfo, + part_fname, fconf_fname, images): + """Generate the flashing script for one board. + + board_section -- string, board section in board config file + machid -- string, board machine ID in hex format + flinfo -- FlashInfo object, contains board specific flash params + part_fname -- string, partition file specific to the board + fconf_fname -- string, flash config file specific to the board + images -- list of ImageInfo, append images used by the board here + """ + script_fp = open(self.scr_fname, "a") + + try: + fconf_fp = open(fconf_fname) + except IOError, e: + error("error opening flash config file '%s'" % fconf_fname, e) + + if flinfo.type != "emmc": + mibib = MIBIB(part_fname, flinfo.pagesize, flinfo.blocksize, + flinfo.chipsize) + self.partitions = mibib.get_parts() + else: + gpt = GPT(part_fname, flinfo.pagesize, flinfo.blocksize, flinfo.chipsize) + self.partitions = gpt.get_parts() + + self.flinfo = flinfo + if flinfo.type == "nand": + self.ipq_nand = True + script = NandScript(flinfo, self.ipq_nand) + elif flinfo.type == "nor" or flinfo.type == "norplusnand": + self.ipq_nand = False + script = NorScript(flinfo) + elif flinfo.type == "emmc": + self.ipq_nand = False + script = EmmcScript(flinfo) + else: + error("error, flash type unspecified.") + + script.start_if("machid", machid) + self.__gen_script(script_fp, fconf_fp, script, images, flinfo) + script.end_if() + + try: + script_fp.write(script.dumps()) + except IOError, e: + error("error writing to script '%s'" % script_fp.name, e) + + script_fp.close() + + def __process_board_flash_emmc(self, ftype, board_section, machid, images): + """Extract board info from config and generate the flash script. + + ftype -- string, flash type 'emmc' + board_section -- string, board section in config file + machid -- string, board machine ID in hex format + images -- list of ImageInfo, append images used by the board here + """ + + pagesize_param = "%s_pagesize" % ftype + blocksize_param = "%s_blocksize" % "emmc" + blocks_per_chip_param = "%s_total_blocks" % "emmc" + part_fname_param = "%s_partition_mbn" % ftype + fconf_fname_param = "%s_flash_conf" % ftype + + if ftype == "norplusemmc": + part_fname_param = "%s_gpt_bin" % ftype + + try: + pagesize = int(self.bconf.get(board_section, pagesize_param)) + blocksize = int(self.bconf.get(board_section, blocksize_param)) + chipsize = int(self.bconf.get(board_section, + blocks_per_chip_param)) + except ConfigParserError, e: + error("missing flash info in section '%s'" % board_section, e) + except ValueError, e: + error("invalid flash info in section '%s'" % board_section, e) + + if ftype == "norplusemmc": + ftype = "emmc" + + flinfo = FlashInfo(ftype, pagesize, blocksize, chipsize) + + try: + part_fname = self.bconf.get(board_section, part_fname_param) + if not os.path.isabs(part_fname): + part_fname = os.path.join(self.images_dname, part_fname) + except ConfigParserError, e: + error("missing partition file in section '%s'" % board_section, e) + + try: + fconf_fname = self.bconf.get(board_section, fconf_fname_param) + if not os.path.isabs(fconf_fname): + fconf_fname = os.path.join(self.images_dname, fconf_fname) + except ConfigParserError, e: + error("missing NAND config in section '%s'" % board_section, e) + + self.__gen_board_script(board_section, machid, flinfo, + part_fname, fconf_fname, images) + + def __process_board_flash(self, ftype, board_section, machid, images): + """Extract board info from config and generate the flash script. + + ftype -- string, flash type 'nand' or 'nor' or 'emmc' or 'norplusnand' + board_section -- string, board section in config file + machid -- string, board machine ID in hex format + images -- list of ImageInfo, append images used by the board here + """ + + pagesize_param = "%s_pagesize" % ftype + pages_per_block_param = "%s_pages_per_block" % ftype + blocks_per_chip_param = "%s_total_blocks" % ftype + part_fname_param = "%s_partition_mbn" % ftype + fconf_fname_param = "%s_flash_conf" % ftype + + if ftype == "norplusnand" or ftype == "norplusemmc": + pagesize_param = "%s_pagesize" % "nor" + pages_per_block_param = "%s_pages_per_block" % "nor" + blocks_per_chip_param = "%s_total_blocks" % "nor" + + try: + pagesize = int(self.bconf.get(board_section, pagesize_param)) + pages_per_block = int(self.bconf.get(board_section, + pages_per_block_param)) + blocks_per_chip = int(self.bconf.get(board_section, + blocks_per_chip_param)) + except ConfigParserError, e: + error("missing flash info in section '%s'" % board_section, e) + except ValueError, e: + error("invalid flash info in section '%s'" % board_section, e) + + blocksize = pages_per_block * pagesize + chipsize = blocks_per_chip * blocksize + if ftype == "norplusemmc": + ftype = "nor" + + flinfo = FlashInfo(ftype, pagesize, blocksize, chipsize) + + try: + part_fname = self.bconf.get(board_section, part_fname_param) + if not os.path.isabs(part_fname): + part_fname = os.path.join(self.images_dname, part_fname) + except ConfigParserError, e: + error("missing partition file in section '%s'" % board_section, e) + + try: + fconf_fname = self.bconf.get(board_section, fconf_fname_param) + if not os.path.isabs(fconf_fname): + fconf_fname = os.path.join(self.images_dname, fconf_fname) + except ConfigParserError, e: + error("missing NAND config in section '%s'" % board_section, e) + + self.__gen_board_script(board_section, machid, flinfo, + part_fname, fconf_fname, images) + + def __process_board(self, board_section, images): + try: + machid = int(self.bconf.get(board_section, "machid"), 0) + machid = "%x" % machid + except ConfigParserError, e: + error("missing machid in section '%s'" % board_section, e) + except ValueError, e: + error("invalid machid in section '%s'" % board_section, e) + + try: + available = self.bconf.get(board_section, "nand_available") + if available == "true" and self.flash_type == "nand": + self.__process_board_flash("nand", board_section, machid, images) + except ConfigParserError, e: + error("error getting board info in section '%s'" % board_section, e) + + try: + available = self.bconf.get(board_section, "nor_available") + if available == "true" and self.flash_type == "nor": + self.__process_board_flash("nor", board_section, machid, images) + except ConfigParserError, e: + error("error getting board info in section '%s'" % board_section, e) + + try: + available = self.bconf.get(board_section, "emmc_available") + if available == "true" and self.flash_type == "emmc": + self.__process_board_flash_emmc("emmc", board_section, machid, images) + except ConfigParserError, e: + error("error getting board info in section '%s'" % board_section, e) + + try: + available = self.bconf.get(board_section, "norplusnand_available") + if available == "true" and self.flash_type == "norplusnand": + self.__process_board_flash("norplusnand", board_section, machid, images) + except ConfigParserError, e: + error("error getting board info in section '%s'" % board_section, e) + + try: + available = self.bconf.get(board_section, "norplusemmc_available") + if available == "true" and self.flash_type == "norplusemmc": + self.__process_board_flash("norplusemmc", board_section, machid, images) + self.__process_board_flash_emmc("norplusemmc", board_section, machid, images) + except ConfigParserError, e: + error("error getting board info in section '%s'" % board_section, e) + + + + def main_bconf(self, flash_type, images_dname, out_fname, brdconfig): + """Start the packing process, using board config. + + flash_type -- string, indicates flash type, 'nand' or 'nor' or 'emmc' or 'norplusnand' + images_dname -- string, name of images directory + out_fname -- string, output file path + """ + self.flash_type = flash_type + self.images_dname = images_dname + self.img_fname = out_fname + + self.__create_fnames() + + try: + os.unlink(self.scr_fname) + except OSError, e: + pass + + try: + bconf_fname = os.path.join(images_dname, brdconfig) + bconf_fp = open(bconf_fname) + self.bconf = ConfigParser() + self.bconf.readfp(bconf_fp) + bconf_fp.close() + except IOError, e: + error("error reading board configuration file", e) + except ConfigParserError, e: + error("error parsing board configuration file", e) + + images = [] + for section in self.bconf.sections(): + self.__process_board(section, images) + + images.insert(0, ImageInfo("script", "flash.scr", "script")) + self.__mkimage(images) + + def main(self, flinfo, images_dname, out_fname, part_fname, fconf_fname, ipq_nand): + """Start the packing process. + + flinfo -- FlashInfo object, containing flash parameters + images_dname -- string, name of images directory + out_fname -- string, output file path + part_fname -- string, partition file path + fconf_fname -- string, flash confing file path + ipq_nand -- bool, indicates whether this is an IPQ device + """ + self.flinfo = flinfo + self.images_dname = images_dname + self.img_fname = out_fname + self.ipq_nand = ipq_nand + + self.__create_fnames() + + if self.flinfo.type == "nand": + script = NandScript(self.flinfo, self.ipq_nand) + elif self.flinfo.type == "nor" or self.flinfo.type == "norplusnand": + script = NorScript(self.flinfo) + elif self.flinfo.type == "emmc": + script = EmmcScript(self.flinfo) + else: + error("Invalid flash type specified. It should be 'nand' or 'nor' or 'norplusnand'") + + if not os.path.isabs(part_fname): + part_fname = os.path.join(self.images_dname, part_fname) + + if not os.path.isabs(fconf_fname): + self.fconf_fname = os.path.join(self.images_dname, fconf_fname) + + mibib = MIBIB(part_fname, self.flinfo.pagesize, self.flinfo.blocksize, + self.flinfo.chipsize) + self.partitions = mibib.get_parts() + + script.echo("", verbose=True) + + script.start_activity("Check environment:") + script.check_isset("imgaddr") + script.check_isset("machid") + script.finish_activity() + + try: + info_fp = open(self.fconf_fname) + except IOError, e: + error("error opening info file '%s'" % self.fconf_fname, e) + + try: + scr_fp = open(self.scr_fname, "wb") + except IOError, e: + error("error opening script file '%s'" % self.scr_fname, e) + + images = [] + self.__gen_script(scr_fp, info_fp, script, images) + try: + scr_fp.write(script.dumps()) + except IOError, e: + error("error writing to script '%s'" % script_fp.name, e) + scr_fp.close() # Flush out all written commands + + images.insert(0, ImageInfo("script", "flash.scr", "script")) + self.__mkimage(images) + +class UsageError(Exception): + """Indicates error in command arguments.""" + pass + +class ArgParser(object): + """Class to parse command-line arguments.""" + + DEFAULT_PAGESIZE = 4096 + DEFAULT_PAGES_PER_BLOCK = 64 + DEFAULT_BLOCKS_PER_CHIP = 1024 + DEFAULT_TYPE = "nand" + DEFAULT_PART_FNAME = "partition.mbn" + DEFAULT_FCONF_FNAME = "flash.conf" + + def __init__(self): + self.__pagesize = None + self.__pages_per_block = None + self.__blocksize = None + self.__chipsize = None + self.__flash_type = None + + self.flash_info = None + self.images_dname = None + self.ipq_nand = False + self.bconf = False + self.bconf_fname = "boardconfig" + self.part_fname = None + self.fconf_fname = None + self.genitb_fname = None + + def __init_pagesize(self, pagesize): + """Set the pagesize, from the command line argument. + + pagesize -- string, flash page size + + Raise UsageError, if pagesize is invalid + """ + if pagesize == None: + self.__pagesize = ArgParser.DEFAULT_PAGESIZE + else: + try: + self.__pagesize = int(pagesize) + except ValueError: + raise UsageError("invalid page size '%s'" % pagesize) + + def __init_blocksize(self, pages_per_block): + """Set the blocksize, from the command line argument. + + pages_per_block -- string, no. of pages in a flash block + + Raise UsageError, if pages_per_block is invalid + """ + if pages_per_block == None: + self.__blocksize = (self.__pagesize + * ArgParser.DEFAULT_PAGES_PER_BLOCK) + else: + try: + self.__blocksize = self.__pagesize * int(pages_per_block) + except ValueError: + raise UsageError("invalid block size '%s'" % self.__blocksize) + + def __init_chipsize(self, blocks_per_chip): + """Set the chipsize, from the command line argument. + + blocks_per_chip -- string, no. of blocks in a flash chip + + Raise UsageError, if chips_per_block is invalid + """ + if blocks_per_chip == None: + self.__chipsize = (self.__blocksize + * ArgParser.DEFAULT_BLOCKS_PER_CHIP) + else: + try: + self.__chipsize = self.__blocksize * int(blocks_per_chip) + except ValueError: + raise UsageError("invalid chip size '%s'" % self.__chipsize) + + def __init_flash_info(self): + """Set flash_info from the parsed flash paramaters.""" + + self.flash_info = FlashInfo(self.__flash_type, + self.__pagesize, + self.__blocksize, + self.__chipsize) + + def __init_flash_type(self, flash_type): + """Set the flash_type, from the command line argument. + + flash_type -- string, nand or nor + + Raise UsageError, if flash_type is invalid + """ + + if flash_type == None: + self.__flash_type = ArgParser.DEFAULT_TYPE + elif flash_type in [ "nand", "nor", "emmc", "norplusnand", "norplusemmc" ]: + self.__flash_type = flash_type + else: + raise UsageError("invalid flash type '%s'" % flash_type) + + def __init_part_fname(self, part_fname): + """Set the partition filename from command line argument + + part_fname -- string, the partition filename + """ + + if part_fname == None: + self.part_fname = ArgParser.DEFAULT_PART_FNAME + else: + self.part_fname = part_fname + + def __init_fconf_fname(self, fconf_fname): + """Set the flash configuration filename from command line argument + + fconf_fname -- string, the flash configuration filename + """ + + if fconf_fname == None: + self.fconf_fname = ArgParser.DEFAULT_FCONF_FNAME + else: + self.fconf_fname = fconf_fname + + def __init_out_fname(self, out_fname, images_dname, flash_type, + pagesize, pages_per_block, blocks_per_chip, + bconf): + """Set the out_fname from the command line argument. + + out_fname -- string, the output filename + images_dname -- string, the images dirname + flash_type -- string, the flash type + pagesize -- int, the flash page size in bytes + pages_per_block -- int, the flash pages per block + blocks_per_chip -- int, the flash blocks per chip + bconf -- bool, whether is board config mode + """ + + if out_fname == None: + images_dname_norm = os.path.abspath(images_dname) + if bconf: + fmt = "%s-%s%simg" + self.out_fname = fmt % (images_dname_norm, flash_type, + os.path.extsep) + else: + fmt = "%s-%s-%d-%d-%d%simg" + self.out_fname = fmt % (images_dname_norm, flash_type, + pagesize, pages_per_block, + blocks_per_chip, os.path.extsep) + else: + if os.path.isabs(out_fname): + self.out_fname = out_fname + else: + images_dname_parent = os.path.dirname(images_dname) + self.out_fname = os.path.join(images_dname_parent, out_fname) + + def __init_images_dname(self, args): + """Set the images_dname from the command line argument. + + args -- list of string, command line args after stripping options + """ + self.images_dname = args[0] + + def parse(self, argv): + """Start the parsing process, and populate members with parsed value. + + argv -- list of string, the command line arguments + """ + flash_type = None + pagesize = None + pages_per_block = None + blocks_per_chip = None + ipq_nand = False + out_fname = None + part_fname = None + fconf_fname = None + bconf = False + bconf_fname = None + genitb_fname = None + + try: + opts, args = getopt(argv[1:], "Bib:hp:t:o:c:m:f:F:M:") + except GetoptError, e: + raise UsageError(e.msg) + + for option, value in opts: + if option == "-t": + flash_type = value + elif option == "-i": + ipq_nand = True + elif option == "-p": + pagesize = value + elif option == "-b": + pages_per_block = value + elif option == '-c': + blocks_per_chip = value + elif option == "-o": + out_fname = value + elif option == "-m": + part_fname = value + elif option == "-f": + fconf_fname = value + elif option == "-B": + bconf = True + elif option == "-F": + bconf_fname = value + elif option == "-M": + genitb_fname= value + + if len(args) != 1: + raise UsageError("insufficient arguments") + + self.__init_flash_type(flash_type) + self.__init_pagesize(pagesize) + self.__init_blocksize(pages_per_block) + self.__init_chipsize(blocks_per_chip) + self.__init_flash_info() + self.__init_images_dname(args) + self.__init_out_fname(out_fname, self.images_dname, + self.__flash_type, self.__pagesize, + self.__blocksize / self.__pagesize, + self.__chipsize / self.__blocksize, + bconf) + self.__init_part_fname(part_fname) + self.__init_fconf_fname(fconf_fname) + + self.ipq_nand = ipq_nand + self.bconf = bconf + if bconf_fname != None: + self.bconf_fname = bconf_fname + + self.genitb_fname = genitb_fname + + def usage(self, msg): + """Print error message and command usage information. + + msg -- string, the error message + """ + print "pack: %s" % msg + print + print "Usage: pack [options] IDIR" + print + print "where IDIR is the path containing the images." + print + print " -t TYPE specifies partition type, 'nand' or 'nor'," + print " default is '%s'." % ArgParser.DEFAULT_TYPE + print " -p SIZE specifies the page size in bytes," + print " default is %d." % ArgParser.DEFAULT_PAGESIZE + print " -b COUNT specifies the pages per block," + print " default is %d." % ArgParser.DEFAULT_PAGES_PER_BLOCK + print " -c COUNT specifies the no. of blocks per chip" + print " default is %d." % ArgParser.DEFAULT_BLOCKS_PER_CHIP + print " -i specifies IPQ processor specific NAND layout" + print " switch, default disabled." + print " -m FILE specifies the partition filename" + print " default is '%s'." % ArgParser.DEFAULT_PART_FNAME + print " -f FILE specifies the flash configuration filename" + print " default is '%s'." % ArgParser.DEFAULT_FCONF_FNAME + print " -o FILE specifies the output filename" + print " default is IDIR-TYPE-SIZE-COUNT.img" + print " if the filename is relative, it is relative" + print " to the parent of IDIR." + print " -M specifies script name to build single ITB with multiple dtb's," + print " default disabled." + print + print "NOTE: The above invocation method of pack is deprecated." + print "The new pack invocation uses a board config file to retrieve" + print "the board specific parameters. The new invocation is provided" + print "below." + print + print "Usage: pack [options] IDIR" + print + print "where IDIR is the path containing the images." + print + print " -t TYPE specifies partition type, 'nand' or 'nor', or 'emmc'" + print " default is '%s'." % ArgParser.DEFAULT_TYPE + print " -B specifies board config should be used, for" + print " flash parameters." + print " -F specifies board config file name should be used, for" + print " flash parameters. Defaults to 'boardconfig'" + print " -o FILE specifies the output filename" + print " default is IDIR-TYPE.img" + print " if the filename is relative, it is relative" + print " to the parent of IDIR." + print + print "Pack Version: %s" % version + + +def main(): + """Main script entry point. + + Created to avoid polluting the global namespace. + """ + try: + parser = ArgParser() + parser.parse(sys.argv) + except UsageError, e: + parser.usage(e.args[0]) + sys.exit(1) + + if parser.genitb_fname: + prc = subprocess.Popen(['sh', parser.genitb_fname]) + prc.wait() + + if prc.returncode != 0: + print 'ERROR: unable to create ITB' + return prc.returncode + else: + print '...ITB binary created' + + + pack = Pack() + if parser.bconf: + pack.main_bconf(parser.flash_info.type, parser.images_dname, + parser.out_fname, parser.bconf_fname) + else: + pack.main(parser.flash_info, parser.images_dname, + parser.out_fname, parser.part_fname, + parser.fconf_fname, parser.ipq_nand) + +class ArgParserTestCase(TestCase): + def setUp(self): + self.parser = ArgParser() + + def test_defaults(self): + self.parser.parse(["pack.py", "itest"]) + self.assertEqual(self.parser.images_dname, "itest") + + fmt = "itest-%s-%d-%d-%d.img" + expected_fname = fmt % (ArgParser.DEFAULT_TYPE, + ArgParser.DEFAULT_PAGESIZE, + ArgParser.DEFAULT_PAGES_PER_BLOCK, + ArgParser.DEFAULT_BLOCKS_PER_CHIP) + self.assertEqual(self.parser.out_fname, expected_fname) + self.assertEqual(self.parser.ipq_nand, False) + self.assertEqual(self.parser.flash_info.type, + ArgParser.DEFAULT_TYPE) + self.assertEqual(self.parser.flash_info.pagesize, + ArgParser.DEFAULT_PAGESIZE) + self.assertEqual(self.parser.flash_info.blocksize, + ArgParser.DEFAULT_PAGES_PER_BLOCK + * ArgParser.DEFAULT_PAGESIZE) + self.assertEqual(self.parser.flash_info.chipsize, + ArgParser.DEFAULT_BLOCKS_PER_CHIP + * ArgParser.DEFAULT_PAGES_PER_BLOCK + * ArgParser.DEFAULT_PAGESIZE) + + def test_ipq_flag(self): + self.parser.parse(["pack.py", "-i", "itest"]) + self.assertEqual(self.parser.ipq_nand, True) + + def test_invalid_flag(self): + self.assertRaises(UsageError, self.parser.parse, + ["pack.py", "-x", "itest"]) + + def test_type_option(self): + self.parser.parse(["pack.py", "-t", "nor", "itest"]) + self.assertEqual(self.parser.flash_info.type, "nor") + + def test_invalid_type_option(self): + self.assertRaises(UsageError, self.parser.parse, + ["pack.py", "-t", "abcd", "itest"]) + + def test_pagesize_option(self): + self.parser.parse(["pack.py", "-p", "2048", "itest"]) + self.assertEqual(self.parser.flash_info.pagesize, 2048) + + def test_invalid_pagesize_option(self): + self.assertRaises(UsageError, self.parser.parse, + ["pack.py", "-p", "abcd", "itest"]) + + def test_pages_per_block_option(self): + self.parser.parse(["pack.py", "-b", "32", "itest"]) + self.assertEqual(self.parser.flash_info.blocksize, + ArgParser.DEFAULT_PAGESIZE * 32) + + def test_invalid_pages_per_block_option(self): + self.assertRaises(UsageError, self.parser.parse, + ["pack.py", "-b", "abcd", "itest"]) + + def test_blocks_per_chip_option(self): + self.parser.parse(["pack.py", "-c", "512", "itest"]) + self.assertEqual(self.parser.flash_info.chipsize, + ArgParser.DEFAULT_PAGESIZE + * ArgParser.DEFAULT_PAGES_PER_BLOCK + * 512) + + def test_out_fname_rel_option(self): + self.parser.parse(["pack.py", "-o", "abcd", "/tmp/test/itest"]) + self.assertEqual(self.parser.out_fname, "/tmp/test/abcd") + + def test_out_fname_abs_option(self): + self.parser.parse(["pack.py", "-o", "/tmp/abcd", "/tmp/test/itest"]) + self.assertEqual(self.parser.out_fname, "/tmp/abcd") + + def test_partition_option(self): + self.parser.parse(["pack.py", "-m", "abcd", "/tmp/test/itest"]) + self.assertEqual(self.parser.part_fname, "abcd") + + def test_flash_conf_option(self): + self.parser.parse(["pack.py", "-f", "abcd", "/tmp/test/itest"]) + self.assertEqual(self.parser.fconf_fname, "abcd") + +class PackTestCase(TestCase): + def setUp(self): + self.pack = Pack() + blocksize = (ArgParser.DEFAULT_PAGESIZE + * ArgParser.DEFAULT_PAGES_PER_BLOCK) + chipsize = blocksize * ArgParser.DEFAULT_BLOCKS_PER_CHIP + + self.flinfo = FlashInfo(ArgParser.DEFAULT_TYPE, + ArgParser.DEFAULT_PAGESIZE, + blocksize, chipsize) + self.img_dname = mkdtemp() + self.img_fname = self.img_dname + ".img" + self.part_fname = "partition.mbn" + self.fconf_fname = "flash.conf" + + sbl1_fp = open(os.path.join(self.img_dname, "sbl1.mbn"), "w") + sbl1_fp.write("#" * blocksize * 2) + sbl1_fp.close() + + self.__create_partition_mbn(blocksize, chipsize) + + def __create_partition_mbn(self, blocksize, chipsize): + part_fname = os.path.join(self.img_dname, self.part_fname) + + mibib = MIBIB(part_fname, ArgParser.DEFAULT_PAGESIZE, blocksize, + chipsize) + + offset = 0 + part_size = 2 * blocksize + mibib.add_part(PartInfo("0:SBL1", offset, part_size)) + + offset += part_size + part_size = 2 * blocksize + mibib.add_part(PartInfo("0:MIBIB", offset, part_size)) + + offset += part_size + part_size = 1 * blocksize + mibib.add_part(PartInfo("0:SBL2", offset, part_size)) + + offset += part_size + part_size = None + mibib.add_part(PartInfo("0:FS", offset, part_size)) + + mibib.write() + + def __mkconf(self, conf_str): + conf_fname = os.path.join(self.img_dname, self.fconf_fname) + conf_fp = open(conf_fname, "w") + conf_fp.write(conf_str) + conf_fp.close() + + def tearDown(self): + rmtree(self.img_dname) + try: + os.remove(self.img_fname) + except OSError: + pass + + def test_simple(self): + self.__mkconf(""" +[sbl1] +partition = 0:SBL1 +filename = sbl1.mbn +""") + + self.pack.main(self.flinfo, self.img_dname, self.img_fname, + self.part_fname, self.fconf_fname, ipq_nand=False) + self.assertEqual(os.path.exists(self.img_fname), True) + + def test_missing_conf(self): + self.assertRaises(SystemExit, + self.pack.main, + self.flinfo, + self.img_dname, + self.img_fname, + self.part_fname, + self.fconf_fname, + ipq_nand=False) + + def test_nand_layout(self): + self.__mkconf(""" +[sbl1] +partition = 0:SBL1 +filename = sbl1.mbn +layout = sbl +""") + self.pack.main(self.flinfo, self.img_dname, self.img_fname, + self.part_fname, self.fconf_fname, ipq_nand=True) + self.assertEqual(os.path.exists(self.img_fname), True) + + def test_invalid_layout(self): + self.__mkconf(""" +[sbl1] +partition = 0:SBL1 +filename = sbl1.mbn +layout = abcd +""") + self.assertRaises(SystemExit, + self.pack.main, + self.flinfo, + self.img_dname, + self.img_fname, + self.part_fname, + self.fconf_fname, + ipq_nand=True) + + def test_inconsistent_layout(self): + self.__mkconf(""" +[sbl1] +partition = 0:SBL1 +filename = sbl1.mbn +layout = sbl +""") + self.assertRaises(SystemExit, + self.pack.main, + self.flinfo, + self.img_dname, + self.img_fname, + self.part_fname, + self.fconf_fname, + ipq_nand=False) + + def test_invalid_filename(self): + self.__mkconf(""" +[sbl1] +partition = 0:SBL1 +filename = sbl10.mbn +""") + self.assertRaises(SystemExit, + self.pack.main, + self.flinfo, + self.img_dname, + self.img_fname, + self.part_fname, + self.fconf_fname, + ipq_nand=False) + + def test_special_chars_in_filename(self): + self.__mkconf(""" +[slash] +partition = 0:SBL1 +filename = sb\\l1.mbn +""") + + sbl1_fp = open(os.path.join(self.img_dname, "sb\\l1.mbn"), "w") + sbl1_fp.write("abcdef") + sbl1_fp.close() + + self.pack.main(self.flinfo, self.img_dname, self.img_fname, + self.part_fname, self.fconf_fname, ipq_nand=False) + self.assertEqual(os.path.exists(self.img_fname), True) + + def __get_images(self): + mkimage_output = subprocess.check_output(["mkimage", "-l", self.img_fname]) + return re.findall(r"Image \d+ \((.*)\)", mkimage_output) + + def test_multi_image(self): + self.__mkconf(""" +[sbl1] +partition = 0:SBL1 +filename = sbl1.mbn + +[sbl2] +partition = 0:MIBIB +filename = partition.mbn +""") + + self.pack.main(self.flinfo, self.img_dname, self.img_fname, + self.part_fname, self.fconf_fname, ipq_nand=False) + count = len(self.__get_images()) + self.assertEqual(count, 3) + + def test_include(self): + self.__mkconf(""" +[sbl1] +partition = 0:SBL1 +filename = sbl1.mbn +include = no + +[sbl2] +partition = 0:MIBIB +filename = partition.mbn +""") + + self.pack.main(self.flinfo, self.img_dname, self.img_fname, + self.part_fname, self.fconf_fname, ipq_nand=False) + images = self.__get_images() + print images + self.assertTrue("sbl2" in images) + self.assertTrue("sbl1" not in images) + + def test_yaffs_yes(self): + self.__mkconf(""" +[sbl1] +partition = 0:SBL1 +filename = sbl1.mbn +yaffs = yes +""") + self.pack.main(self.flinfo, self.img_dname, self.img_fname, + self.part_fname, self.fconf_fname, ipq_nand=False) + + def test_yaffs_no(self): + self.__mkconf(""" +[sbl1] +partition = 0:SBL1 +filename = sbl1.mbn +yaffs = no +""") + self.pack.main(self.flinfo, self.img_dname, self.img_fname, + self.part_fname, self.fconf_fname, ipq_nand=False) + + def test_yaffs_invalid(self): + self.__mkconf(""" +[sbl1] +partition = 0:SBL1 +filename = sbl1.mbn +yaffs = abcd +""") + self.assertRaises(SystemExit, + self.pack.main, + self.flinfo, + self.img_dname, + self.img_fname, + self.part_fname, + self.fconf_fname, + ipq_nand=False) + + def test_invalid_partition(self): + self.__mkconf(""" +[sbl1] +partition = 0:SBL5 +filename = sbl1.mbn +""") + self.assertRaises(SystemExit, + self.pack.main, + self.flinfo, + self.img_dname, + self.img_fname, + self.part_fname, + self.fconf_fname, + ipq_nand=False) + + def test_img_larger_than_partition(self): + self.__mkconf(""" +[sbl2] +partition = 0:SBL2 +filename = sbl1.mbn +""") + self.assertRaises(SystemExit, + self.pack.main, + self.flinfo, + self.img_dname, + self.img_fname, + self.part_fname, + self.fconf_fname, + ipq_nand=False) + + def test_machid_in_hex(self): + self.__mkconf(""" +[sbl1] +partition = 0:SBL1 +filename = sbl1.mbn +if_machid = 0x152 +""") + self.pack.main(self.flinfo, self.img_dname, self.img_fname, + self.part_fname, self.fconf_fname, ipq_nand=False) + self.assertEqual(os.path.exists(self.img_fname), True) + + def test_machid_in_dec(self): + self.__mkconf(""" +[sbl1] +partition = 0:SBL1 +filename = sbl1.mbn +if_machid = 256 +""") + self.pack.main(self.flinfo, self.img_dname, self.img_fname, + self.part_fname, self.fconf_fname, ipq_nand=False) + self.assertEqual(os.path.exists(self.img_fname), True) + + def test_machid_invalid(self): + self.__mkconf(""" +[sbl1] +partition = 0:SBL1 +filename = sbl1.mbn +if_machid = xyz +""") + self.assertRaises(SystemExit, + self.pack.main, + self.flinfo, + self.img_dname, + self.img_fname, + self.part_fname, + self.fconf_fname, + ipq_nand=False) + +if __name__ == "__main__": + main() diff --git a/root/package/utils/sysupgrade-helper/src/tools/patman/patman.py b/root/package/utils/sysupgrade-helper/src/tools/patman/patman.py new file mode 100644 index 00000000..cfe06d08 --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/tools/patman/patman.py @@ -0,0 +1,153 @@ +#!/usr/bin/python +# +# Copyright (c) 2011 The Chromium OS Authors. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +"""See README for more information""" + +from optparse import OptionParser +import os +import re +import sys +import unittest + +# Our modules +import checkpatch +import command +import gitutil +import patchstream +import terminal +import test + + +parser = OptionParser() +parser.add_option('-H', '--full-help', action='store_true', dest='full_help', + default=False, help='Display the README file') +parser.add_option('-c', '--count', dest='count', type='int', + default=-1, help='Automatically create patches from top n commits') +parser.add_option('-i', '--ignore-errors', action='store_true', + dest='ignore_errors', default=False, + help='Send patches email even if patch errors are found') +parser.add_option('-n', '--dry-run', action='store_true', dest='dry_run', + default=False, help="Do a try run (create but don't email patches)") +parser.add_option('-s', '--start', dest='start', type='int', + default=0, help='Commit to start creating patches from (0 = HEAD)') +parser.add_option('-t', '--test', action='store_true', dest='test', + default=False, help='run tests') +parser.add_option('-v', '--verbose', action='store_true', dest='verbose', + default=False, help='Verbose output of errors and warnings') +parser.add_option('--cc-cmd', dest='cc_cmd', type='string', action='store', + default=None, help='Output cc list for patch file (used by git)') +parser.add_option('--no-tags', action='store_false', dest='process_tags', + default=True, help="Don't process subject tags as aliaes") + +parser.usage = """patman [options] + +Create patches from commits in a branch, check them and email them as +specified by tags you place in the commits. Use -n to """ + +(options, args) = parser.parse_args() + +# Run our meagre tests +if options.test: + import doctest + + sys.argv = [sys.argv[0]] + suite = unittest.TestLoader().loadTestsFromTestCase(test.TestPatch) + result = unittest.TestResult() + suite.run(result) + + suite = doctest.DocTestSuite('gitutil') + suite.run(result) + + # TODO: Surely we can just 'print' result? + print result + for test, err in result.errors: + print err + for test, err in result.failures: + print err + +# Called from git with a patch filename as argument +# Printout a list of additional CC recipients for this patch +elif options.cc_cmd: + fd = open(options.cc_cmd, 'r') + re_line = re.compile('(\S*) (.*)') + for line in fd.readlines(): + match = re_line.match(line) + if match and match.group(1) == args[0]: + for cc in match.group(2).split(', '): + cc = cc.strip() + if cc: + print cc + fd.close() + +elif options.full_help: + pager = os.getenv('PAGER') + if not pager: + pager = 'more' + fname = os.path.join(os.path.dirname(sys.argv[0]), 'README') + command.Run(pager, fname) + +# Process commits, produce patches files, check them, email them +else: + gitutil.Setup() + + if options.count == -1: + # Work out how many patches to send if we can + options.count = gitutil.CountCommitsToBranch() - options.start + + col = terminal.Color() + if not options.count: + str = 'No commits found to process - please use -c flag' + print col.Color(col.RED, str) + sys.exit(1) + + # Read the metadata from the commits + if options.count: + series = patchstream.GetMetaData(options.start, options.count) + cover_fname, args = gitutil.CreatePatches(options.start, options.count, + series) + + # Fix up the patch files to our liking, and insert the cover letter + series = patchstream.FixPatches(series, args) + if series and cover_fname and series.get('cover'): + patchstream.InsertCoverLetter(cover_fname, series, options.count) + + # Do a few checks on the series + series.DoChecks() + + # Check the patches, and run them through 'git am' just to be sure + ok = checkpatch.CheckPatches(options.verbose, args) + if not gitutil.ApplyPatches(options.verbose, args, + options.count + options.start): + ok = False + + # Email the patches out (giving the user time to check / cancel) + cmd = '' + if ok or options.ignore_errors: + cc_file = series.MakeCcFile(options.process_tags) + cmd = gitutil.EmailPatches(series, cover_fname, args, + options.dry_run, cc_file) + os.remove(cc_file) + + # For a dry run, just show our actions as a sanity check + if options.dry_run: + series.ShowActions(args, cmd, options.process_tags) diff --git a/root/package/utils/sysupgrade-helper/src/tools/scripts/make-asm-offsets b/root/package/utils/sysupgrade-helper/src/tools/scripts/make-asm-offsets new file mode 100644 index 00000000..4c33756d --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/tools/scripts/make-asm-offsets @@ -0,0 +1,27 @@ +#!/bin/sh + +# Adapted from Linux kernel's "Kbuild": +# commit 1cdf25d704f7951d02a04064c97db547d6021872 +# Author: Christoph Lameter + +mkdir -p $(dirname $2) + +# Default sed regexp - multiline due to syntax constraints +SED_CMD="/^->/{s:->#\(.*\):/* \1 */:; \ + s:^->\([^ ]*\) [\$#]*\([-0-9]*\) \(.*\):#define \1 (\2) /* \3 */:; \ + s:^->\([^ ]*\) [\$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \ + s:->::; p;}" + +(set -e + echo "#ifndef __ASM_OFFSETS_H__" + echo "#define __ASM_OFFSETS_H__" + echo "/*" + echo " * DO NOT MODIFY." + echo " *" + echo " * This file was generated by $(basename $0)" + echo " *" + echo " */" + echo "" + sed -ne "${SED_CMD}" $1 + echo "" + echo "#endif" ) > $2 diff --git a/root/package/utils/sysupgrade-helper/src/tools/setlocalversion b/root/package/utils/sysupgrade-helper/src/tools/setlocalversion new file mode 100644 index 00000000..e4758f5e --- /dev/null +++ b/root/package/utils/sysupgrade-helper/src/tools/setlocalversion @@ -0,0 +1,177 @@ +#!/bin/sh +# +# This scripts adds local version information from the version +# control systems git, mercurial (hg) and subversion (svn). +# +# It was originally copied from the Linux kernel v3.2.0-rc4 and modified +# to support the U-Boot build-system. +# + +usage() { + echo "Usage: $0 [--save-scmversion] [srctree]" >&2 + exit 1 +} + +scm_only=false +srctree=. +if test "$1" = "--save-scmversion"; then + scm_only=true + shift +fi +if test $# -gt 0; then + srctree=$1 + shift +fi +if test $# -gt 0 -o ! -d "$srctree"; then + usage +fi + +scm_version() +{ + local short + short=false + + cd "$srctree" + if test -e .scmversion; then + cat .scmversion + return + fi + if test "$1" = "--short"; then + short=true + fi + + # Check for git and a git repo. + if test -e .git && head=`git rev-parse --verify --short HEAD 2>/dev/null`; then + + # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore + # it, because this version is defined in the top level Makefile. + if [ -z "`git describe --exact-match 2>/dev/null`" ]; then + + # If only the short version is requested, don't bother + # running further git commands + if $short; then + echo "+" + return + fi + # If we are past a tagged commit (like + # "v2.6.30-rc5-302-g72357d5"), we pretty print it. + if atag="`git describe 2>/dev/null`"; then + echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}' + + # If we don't have a tag at all we print -g{commitish}. + else + printf '%s%s' -g $head + fi + fi + + # Is this git on svn? + if git config --get svn-remote.svn.url >/dev/null; then + printf -- '-svn%s' "`git svn find-rev $head`" + fi + + # Update index only on r/w media + [ -w . ] && git update-index --refresh --unmerged > /dev/null + + # Check for uncommitted changes + if git diff-index --name-only HEAD | grep -v "^scripts/package" \ + | read dummy; then + printf '%s' -dirty + fi + + # All done with git + return + fi + + # Check for mercurial and a mercurial repo. + if test -d .hg && hgid=`hg id 2>/dev/null`; then + # Do we have an tagged version? If so, latesttagdistance == 1 + if [ "`hg log -r . --template '{latesttagdistance}'`" == "1" ]; then + id=`hg log -r . --template '{latesttag}'` + printf '%s%s' -hg "$id" + else + tag=`printf '%s' "$hgid" | cut -d' ' -f2` + if [ -z "$tag" -o "$tag" = tip ]; then + id=`printf '%s' "$hgid" | sed 's/[+ ].*//'` + printf '%s%s' -hg "$id" + fi + fi + + # Are there uncommitted changes? + # These are represented by + after the changeset id. + case "$hgid" in + *+|*+\ *) printf '%s' -dirty ;; + esac + + # All done with mercurial + return + fi + + # Check for svn and a svn repo. + if rev=`svn info 2>/dev/null | grep '^Last Changed Rev'`; then + rev=`echo $rev | awk '{print $NF}'` + printf -- '-svn%s' "$rev" + + # All done with svn + return + fi +} + +collect_files() +{ + local file res + + for file; do + case "$file" in + *\~*) + continue + ;; + esac + if test -e "$file"; then + res="$res$(cat "$file")" + fi + done + echo "$res" +} + +if $scm_only; then + if test ! -e .scmversion; then + res=$(scm_version) + echo "$res" >.scmversion + fi + exit +fi + +#if test -e include/config/auto.conf; then +# . include/config/auto.conf +#else +# echo "Error: kernelrelease not valid - run 'make prepare' to update it" +# exit 1 +#fi +CONFIG_LOCALVERSION= +CONFIG_LOCALVERSION_AUTO=y + +# localversion* files in the build and source directory +res="$(collect_files localversion*)" +if test ! "$srctree" -ef .; then + res="$res$(collect_files "$srctree"/localversion*)" +fi + +# CONFIG_LOCALVERSION and LOCALVERSION (if set) +res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}" + +# scm version string if not at a tagged commit +if test "$CONFIG_LOCALVERSION_AUTO" = "y"; then + # full scm version string + res="$res$(scm_version)" +else + # append a plus sign if the repository is not in a clean + # annotated or signed tagged state (as git describe only + # looks at signed or annotated tags - git tag -a/-s) and + # LOCALVERSION= is not specified + if test "${LOCALVERSION+set}" != "set"; then + scm=$(scm_version --short) + res="$res${scm:++}" + fi +fi + +echo "$res [${VERSION_CODE:-"local"},${REVISION:-"local"}]" diff --git a/root/target/linux/bcm27xx/patches-5.15/950-0785-ARM-dts-Add-bcm2711-rpi-cm4antrouter5g.dts.patch b/root/target/linux/bcm27xx/patches-5.15/950-0785-ARM-dts-Add-bcm2711-rpi-cm4antrouter5g.dts.patch new file mode 100644 index 00000000..6912d784 --- /dev/null +++ b/root/target/linux/bcm27xx/patches-5.15/950-0785-ARM-dts-Add-bcm2711-rpi-cm4antrouter5g.dts.patch @@ -0,0 +1,317 @@ +--- a/arch/arm/boot/dts/bcm2711-rpi-cm4.dts 2022-01-04 02:51:16.000000000 +0800 ++++ b/arch/arm/boot/dts/bcm2711-rpi-cm4.dts 2022-01-04 03:10:34.000000000 +0800 +@@ -7,7 +7,7 @@ + + / { + compatible = "raspberrypi,4-compute-module", "brcm,bcm2711"; +- model = "Raspberry Pi Compute Module 4"; ++ model = "openmptcprouter_5G_CM4"; + + chosen { + /* 8250 auxiliary UART instead of pl011 */ +@@ -91,19 +91,12 @@ + gpio-line-names = "BT_ON", + "WL_ON", + "PWR_LED_OFF", +- "ANT1", + "VDD_SD_IO_SEL", + "CAM_GPIO", + "SD_PWR_ON", + "ANT2"; + status = "okay"; + +- ant1: ant1 { +- gpio-hog; +- gpios = <3 GPIO_ACTIVE_HIGH>; +- output-high; +- }; +- + ant2: ant2 { + gpio-hog; + gpios = <7 GPIO_ACTIVE_HIGH>; +@@ -138,23 +131,10 @@ + "SPI_MISO", + "SPI_MOSI", + "SPI_SCLK", +- "GPIO12", +- "GPIO13", + /* Serial port */ + "TXD1", + "RXD1", +- "GPIO16", +- "GPIO17", +- "GPIO18", +- "GPIO19", +- "GPIO20", +- "GPIO21", +- "GPIO22", +- "GPIO23", +- "GPIO24", + "GPIO25", +- "GPIO26", +- "GPIO27", + "RGMII_MDIO", + "RGMIO_MDC", + /* Used by BT module */ +@@ -368,14 +348,9 @@ + mmc2 = &sdhost; + i2c3 = &i2c3; + i2c4 = &i2c4; +- i2c5 = &i2c5; +- i2c6 = &i2c6; + i2c20 = &ddc0; + i2c21 = &ddc1; +- spi3 = &spi3; + spi4 = &spi4; +- spi5 = &spi5; +- spi6 = &spi6; + /delete-property/ intc; + }; + +@@ -398,49 +373,7 @@ + pinctrl-0 = <&uart1_pins>; + }; + +-&spi0 { +- pinctrl-names = "default"; +- pinctrl-0 = <&spi0_pins &spi0_cs_pins>; +- cs-gpios = <&gpio 8 1>, <&gpio 7 1>; +- +- spidev0: spidev@0{ +- compatible = "spidev"; +- reg = <0>; /* CE0 */ +- #address-cells = <1>; +- #size-cells = <0>; +- spi-max-frequency = <125000000>; +- }; +- +- spidev1: spidev@1{ +- compatible = "spidev"; +- reg = <1>; /* CE1 */ +- #address-cells = <1>; +- #size-cells = <0>; +- spi-max-frequency = <125000000>; +- }; +-}; +- + &gpio { +- spi0_pins: spi0_pins { +- brcm,pins = <9 10 11>; +- brcm,function = ; +- }; +- +- spi0_cs_pins: spi0_cs_pins { +- brcm,pins = <8 7>; +- brcm,function = ; +- }; +- +- spi3_pins: spi3_pins { +- brcm,pins = <1 2 3>; +- brcm,function = ; +- }; +- +- spi3_cs_pins: spi3_cs_pins { +- brcm,pins = <0 24>; +- brcm,function = ; +- }; +- + spi4_pins: spi4_pins { + brcm,pins = <5 6 7>; + brcm,function = ; +@@ -451,38 +384,12 @@ + brcm,function = ; + }; + +- spi5_pins: spi5_pins { +- brcm,pins = <13 14 15>; +- brcm,function = ; +- }; +- +- spi5_cs_pins: spi5_cs_pins { +- brcm,pins = <12 26>; +- brcm,function = ; +- }; +- +- spi6_pins: spi6_pins { +- brcm,pins = <19 20 21>; +- brcm,function = ; +- }; +- +- spi6_cs_pins: spi6_cs_pins { +- brcm,pins = <18 27>; +- brcm,function = ; +- }; +- + i2c0_pins: i2c0 { + brcm,pins = <0 1>; + brcm,function = ; + brcm,pull = ; + }; + +- i2c1_pins: i2c1 { +- brcm,pins = <2 3>; +- brcm,function = ; +- brcm,pull = ; +- }; +- + i2c3_pins: i2c3 { + brcm,pins = <4 5>; + brcm,function = ; +@@ -495,23 +402,6 @@ + brcm,pull = ; + }; + +- i2c5_pins: i2c5 { +- brcm,pins = <12 13>; +- brcm,function = ; +- brcm,pull = ; +- }; +- +- i2c6_pins: i2c6 { +- brcm,pins = <22 23>; +- brcm,function = ; +- brcm,pull = ; +- }; +- +- i2s_pins: i2s { +- brcm,pins = <18 19 20 21>; +- brcm,function = ; +- }; +- + sdio_pins: sdio_pins { + brcm,pins = <34 35 36 37 38 39>; + brcm,function = ; // alt3 = SD1 +@@ -554,29 +444,12 @@ + brcm,function = ; + brcm,pull = <0 2>; + }; +- +- uart5_pins: uart5_pins { +- brcm,pins = <12 13>; +- brcm,function = ; +- brcm,pull = <0 2>; +- }; + }; + + &i2c0if { + clock-frequency = <100000>; + }; + +-&i2c1 { +- pinctrl-names = "default"; +- pinctrl-0 = <&i2c1_pins>; +- clock-frequency = <100000>; +-}; +- +-&i2s { +- pinctrl-names = "default"; +- pinctrl-0 = <&i2s_pins>; +-}; +- + // ============================================= + // Board specific stuff here + +@@ -611,6 +484,81 @@ + linux,default-trigger = "default-on"; + gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; + }; ++ ++ wlan2g { ++ label = "wlan2g"; ++ gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ wlan5g { ++ label = "wlan5g"; ++ gpios = <&gpio 3 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ wan { ++ label = "wan"; ++ gpios = <&gpio 27 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ 5g1 { ++ label = "5g1"; ++ gpios = <&gpio 21 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ 5g2 { ++ label = "5g2"; ++ gpios = <&gpio 20 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ 5g3 { ++ label = "5g3"; ++ gpios = <&gpio 16 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ 5g4 { ++ label = "5g4"; ++ gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ 5g5 { ++ label = "5g5"; ++ gpios = <&gpio 10 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ 5g6 { ++ label = "5g6"; ++ gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ 5gpwr1 { ++ label = "5gpwr1"; ++ gpios = <&gpio 26 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ 5gpwr2 { ++ label = "5gpwr2"; ++ gpios = <&gpio 19 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ 5gpwr3 { ++ label = "5gpwr3"; ++ gpios = <&gpio 13 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ 5gpwr4 { ++ label = "5gpwr4"; ++ gpios = <&gpio 24 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ 5gpwr5 { ++ label = "5gpwr5"; ++ gpios = <&gpio 23 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ 5gpwr6 { ++ label = "5gpwr6"; ++ gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; ++ }; + }; + + &pwm1 { +@@ -640,21 +588,6 @@ + eth_led0 = <&phy1>,"led-modes:0"; + eth_led1 = <&phy1>,"led-modes:4"; + +- ant1 = <&ant1>,"output-high?=on", +- <&ant1>, "output-low?=off", +- <&ant2>, "output-high?=off", +- <&ant2>, "output-low?=on"; +- ant2 = <&ant1>,"output-high?=off", +- <&ant1>, "output-low?=on", +- <&ant2>, "output-high?=on", +- <&ant2>, "output-low?=off"; +- noant = <&ant1>,"output-high?=off", +- <&ant1>, "output-low?=on", +- <&ant2>, "output-high?=off", +- <&ant2>, "output-low?=on"; +- + sd_poll_once = <&emmc2>, "non-removable?"; +- spi_dma4 = <&spi0>, "dmas:0=", <&dma40>, +- <&spi0>, "dmas:8=", <&dma40>; + }; + }; diff --git a/root/target/linux/generic/pending-5.4/690-net-add-support-for-threaded-NAPI-polling.patch b/root/target/linux/generic/pending-5.4/690-net-add-support-for-threaded-NAPI-polling.patch new file mode 100644 index 00000000..88c995f2 --- /dev/null +++ b/root/target/linux/generic/pending-5.4/690-net-add-support-for-threaded-NAPI-polling.patch @@ -0,0 +1,344 @@ +From: Felix Fietkau +Date: Sun, 26 Jul 2020 14:03:21 +0200 +Subject: [PATCH] net: add support for threaded NAPI polling + +For some drivers (especially 802.11 drivers), doing a lot of work in the NAPI +poll function does not perform well. Since NAPI poll is bound to the CPU it +was scheduled from, we can easily end up with a few very busy CPUs spending +most of their time in softirq/ksoftirqd and some idle ones. + +Introduce threaded NAPI for such drivers based on a workqueue. The API is the +same except for using netif_threaded_napi_add instead of netif_napi_add. + +In my tests with mt76 on MT7621 using threaded NAPI + a thread for tx scheduling +improves LAN->WLAN bridging throughput by 10-50%. Throughput without threaded +NAPI is wildly inconsistent, depending on the CPU that runs the tx scheduling +thread. + +With threaded NAPI it seems stable and consistent (and higher than the best +results I got without it). + +Based on a patch by Hillf Danton + +Cc: Hillf Danton +Signed-off-by: Felix Fietkau +--- + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -340,6 +340,7 @@ struct napi_struct { + struct list_head dev_list; + struct hlist_node napi_hash_node; + unsigned int napi_id; ++ struct work_struct work; + }; + + enum { +@@ -350,6 +351,7 @@ enum { + NAPI_STATE_HASHED, /* In NAPI hash (busy polling possible) */ + NAPI_STATE_NO_BUSY_POLL,/* Do not add in napi_hash, no busy polling */ + NAPI_STATE_IN_BUSY_POLL,/* sk_busy_loop() owns this NAPI */ ++ NAPI_STATE_THREADED, /* Use threaded NAPI */ + }; + + enum { +@@ -360,6 +362,7 @@ enum { + NAPIF_STATE_HASHED = BIT(NAPI_STATE_HASHED), + NAPIF_STATE_NO_BUSY_POLL = BIT(NAPI_STATE_NO_BUSY_POLL), + NAPIF_STATE_IN_BUSY_POLL = BIT(NAPI_STATE_IN_BUSY_POLL), ++ NAPIF_STATE_THREADED = BIT(NAPI_STATE_THREADED), + }; + + enum gro_result { +@@ -2101,6 +2104,7 @@ struct net_device { + struct lock_class_key addr_list_lock_key; + bool proto_down; + unsigned wol_enabled:1; ++ unsigned threaded:1; + }; + #define to_net_dev(d) container_of(d, struct net_device, dev) + +@@ -2281,6 +2285,26 @@ void netif_napi_add(struct net_device *d + int (*poll)(struct napi_struct *, int), int weight); + + /** ++ * netif_threaded_napi_add - initialize a NAPI context ++ * @dev: network device ++ * @napi: NAPI context ++ * @poll: polling function ++ * @weight: default weight ++ * ++ * This variant of netif_napi_add() should be used from drivers using NAPI ++ * with CPU intensive poll functions. ++ * This will schedule polling from a high priority workqueue ++ */ ++static inline void netif_threaded_napi_add(struct net_device *dev, ++ struct napi_struct *napi, ++ int (*poll)(struct napi_struct *, int), ++ int weight) ++{ ++ set_bit(NAPI_STATE_THREADED, &napi->state); ++ netif_napi_add(dev, napi, poll, weight); ++} ++ ++/** + * netif_tx_napi_add - initialize a NAPI context + * @dev: network device + * @napi: NAPI context +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -156,6 +156,7 @@ static DEFINE_SPINLOCK(offload_lock); + struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly; + struct list_head ptype_all __read_mostly; /* Taps */ + static struct list_head offload_base __read_mostly; ++static struct workqueue_struct *napi_workq __read_mostly; + + static int netif_rx_internal(struct sk_buff *skb); + static int call_netdevice_notifiers_info(unsigned long val, +@@ -5931,6 +5932,11 @@ void __napi_schedule(struct napi_struct + { + unsigned long flags; + ++ if (test_bit(NAPI_STATE_THREADED, &n->state)) { ++ queue_work(napi_workq, &n->work); ++ return; ++ } ++ + local_irq_save(flags); + ____napi_schedule(this_cpu_ptr(&softnet_data), n); + local_irq_restore(flags); +@@ -6246,9 +6256,89 @@ static void init_gro_hash(struct napi_st + napi->gro_bitmask = 0; + } + ++static int __napi_poll(struct napi_struct *n, bool *repoll) ++{ ++ int work, weight; ++ ++ weight = n->weight; ++ ++ /* This NAPI_STATE_SCHED test is for avoiding a race ++ * with netpoll's poll_napi(). Only the entity which ++ * obtains the lock and sees NAPI_STATE_SCHED set will ++ * actually make the ->poll() call. Therefore we avoid ++ * accidentally calling ->poll() when NAPI is not scheduled. ++ */ ++ work = 0; ++ if (test_bit(NAPI_STATE_SCHED, &n->state)) { ++ work = n->poll(n, weight); ++ trace_napi_poll(n, work, weight); ++ } ++ ++ WARN_ON_ONCE(work > weight); ++ ++ if (likely(work < weight)) ++ return work; ++ ++ /* Drivers must not modify the NAPI state if they ++ * consume the entire weight. In such cases this code ++ * still "owns" the NAPI instance and therefore can ++ * move the instance around on the list at-will. ++ */ ++ if (unlikely(napi_disable_pending(n))) { ++ napi_complete(n); ++ return work; ++ } ++ ++ if (n->gro_bitmask) { ++ /* flush too old packets ++ * If HZ < 1000, flush all packets. ++ */ ++ napi_gro_flush(n, HZ >= 1000); ++ } ++ ++ gro_normal_list(n); ++ ++ *repoll = true; ++ ++ return work; ++} ++ ++static void napi_workfn(struct work_struct *work) ++{ ++ struct napi_struct *n = container_of(work, struct napi_struct, work); ++ void *have; ++ ++ for (;;) { ++ bool repoll = false; ++ ++ local_bh_disable(); ++ ++ have = netpoll_poll_lock(n); ++ __napi_poll(n, &repoll); ++ netpoll_poll_unlock(have); ++ ++ local_bh_enable(); ++ ++ if (!repoll) ++ return; ++ ++ if (!need_resched()) ++ continue; ++ ++ /* ++ * have to pay for the latency of task switch even if ++ * napi is scheduled ++ */ ++ queue_work(napi_workq, work); ++ return; ++ } ++} ++ + void netif_napi_add(struct net_device *dev, struct napi_struct *napi, + int (*poll)(struct napi_struct *, int), int weight) + { ++ if (dev->threaded) ++ set_bit(NAPI_STATE_THREADED, &napi->state); + INIT_LIST_HEAD(&napi->poll_list); + hrtimer_init(&napi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); + napi->timer.function = napi_watchdog; +@@ -6265,6 +6355,7 @@ void netif_napi_add(struct net_device *d + #ifdef CONFIG_NETPOLL + napi->poll_owner = -1; + #endif ++ INIT_WORK(&napi->work, napi_workfn); + set_bit(NAPI_STATE_SCHED, &napi->state); + set_bit(NAPI_STATE_NPSVC, &napi->state); + list_add_rcu(&napi->dev_list, &dev->napi_list); +@@ -6305,6 +6396,7 @@ static void flush_gro_hash(struct napi_s + void netif_napi_del(struct napi_struct *napi) + { + might_sleep(); ++ cancel_work_sync(&napi->work); + if (napi_hash_del(napi)) + synchronize_net(); + list_del_init(&napi->dev_list); +@@ -6317,50 +6409,18 @@ EXPORT_SYMBOL(netif_napi_del); + + static int napi_poll(struct napi_struct *n, struct list_head *repoll) + { ++ bool do_repoll = false; + void *have; +- int work, weight; ++ int work; + + list_del_init(&n->poll_list); + + have = netpoll_poll_lock(n); + +- weight = n->weight; +- +- /* This NAPI_STATE_SCHED test is for avoiding a race +- * with netpoll's poll_napi(). Only the entity which +- * obtains the lock and sees NAPI_STATE_SCHED set will +- * actually make the ->poll() call. Therefore we avoid +- * accidentally calling ->poll() when NAPI is not scheduled. +- */ +- work = 0; +- if (test_bit(NAPI_STATE_SCHED, &n->state)) { +- work = n->poll(n, weight); +- trace_napi_poll(n, work, weight); +- } +- +- WARN_ON_ONCE(work > weight); ++ work = __napi_poll(n, &do_repoll); + +- if (likely(work < weight)) +- goto out_unlock; +- +- /* Drivers must not modify the NAPI state if they +- * consume the entire weight. In such cases this code +- * still "owns" the NAPI instance and therefore can +- * move the instance around on the list at-will. +- */ +- if (unlikely(napi_disable_pending(n))) { +- napi_complete(n); ++ if (!do_repoll) + goto out_unlock; +- } +- +- if (n->gro_bitmask) { +- /* flush too old packets +- * If HZ < 1000, flush all packets. +- */ +- napi_gro_flush(n, HZ >= 1000); +- } +- +- gro_normal_list(n); + + /* Some drivers may have called napi_schedule + * prior to exhausting their budget. +@@ -10340,6 +10400,10 @@ static int __init net_dev_init(void) + sd->backlog.weight = weight_p; + } + ++ napi_workq = alloc_workqueue("napi_workq", WQ_UNBOUND | WQ_HIGHPRI, ++ WQ_UNBOUND_MAX_ACTIVE | WQ_SYSFS); ++ BUG_ON(!napi_workq); ++ + dev_boot_phase = 0; + + /* The loopback device is special if any other network devices +--- a/net/core/net-sysfs.c ++++ b/net/core/net-sysfs.c +@@ -442,6 +442,52 @@ static ssize_t proto_down_store(struct d + } + NETDEVICE_SHOW_RW(proto_down, fmt_dec); + ++static int change_napi_threaded(struct net_device *dev, unsigned long val) ++{ ++ struct napi_struct *napi; ++ ++ if (list_empty(&dev->napi_list)) ++ return -EOPNOTSUPP; ++ ++ list_for_each_entry(napi, &dev->napi_list, dev_list) { ++ if (val) ++ set_bit(NAPI_STATE_THREADED, &napi->state); ++ else ++ clear_bit(NAPI_STATE_THREADED, &napi->state); ++ } ++ ++ return 0; ++} ++ ++static ssize_t napi_threaded_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ return netdev_store(dev, attr, buf, len, change_napi_threaded); ++} ++ ++static ssize_t napi_threaded_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct net_device *netdev = to_net_dev(dev); ++ struct napi_struct *napi; ++ bool enabled = false; ++ ++ if (!rtnl_trylock()) ++ return restart_syscall(); ++ ++ list_for_each_entry(napi, &netdev->napi_list, dev_list) { ++ if (test_bit(NAPI_STATE_THREADED, &napi->state)) ++ enabled = true; ++ } ++ ++ rtnl_unlock(); ++ ++ return sprintf(buf, fmt_dec, enabled); ++} ++static DEVICE_ATTR_RW(napi_threaded); ++ + static ssize_t phys_port_id_show(struct device *dev, + struct device_attribute *attr, char *buf) + { +@@ -532,6 +578,7 @@ static struct attribute *net_class_attrs + &dev_attr_flags.attr, + &dev_attr_tx_queue_len.attr, + &dev_attr_gro_flush_timeout.attr, ++ &dev_attr_napi_threaded.attr, + &dev_attr_phys_port_id.attr, + &dev_attr_phys_port_name.attr, + &dev_attr_phys_switch_id.attr, diff --git a/root/target/linux/ipq40xx/base-files/bin/board_detect b/root/target/linux/ipq40xx/base-files/bin/board_detect new file mode 100644 index 00000000..840bd017 --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/bin/board_detect @@ -0,0 +1,14 @@ +#!/bin/sh + +CFG=$1 + +[ -n "$CFG" ] || CFG=/etc/board.json + +[ -d "/etc/board.d/" -a ! -s "$CFG" ] && { + for a in $(ls /etc/board.d/*); do + [ -x $a ] || continue; + $(. $a) + done +} + +[ -s "$CFG" ] || return 1 diff --git a/root/target/linux/ipq40xx/base-files/bin/board_modem b/root/target/linux/ipq40xx/base-files/bin/board_modem new file mode 100644 index 00000000..7628fc86 --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/bin/board_modem @@ -0,0 +1,307 @@ +#!/bin/sh +# +# Copyright (c) 2015 The Linux Foundation. All rights reserved. +# Copyright (c) 2011-2015 OpenWrt.org +# + +. /lib/functions/uci-defaults.sh +. /lib/functions/system.sh + +CFG=/etc/board.json + +# do not run on preinit/early init +[ "$EARLY_INIT" ] && return + +strstr() { + [ "${1#*$2*}" = "$1" ] && return 1 + return 0 +} + +print_array() { + json_add_array $1 + case "$1" in + 4G) + for element in $2 + do + json_add_string "" "$(echo $element)" + done + ;; + 3G) + for element in $2 + do + json_add_string "" "wcdma_$(echo $element)" + done + ;; + 2G) + for element in $2 + do + json_add_string "" "$(echo $element)" + done + ;; + esac + json_close_array +} + +gather_band_capabilities() { + # Same logic as unhandler.c + ###################### EG06 ######################### + if strstr $revision_from_unhandler "EG06E"; then #EG06E + lte_bands="1 3 5 7 8 20 28 32 38 40 41" #B + trysg_bands="850 900 1800 2100" #MHz + dug_bands="" + elif strstr $revision_from_unhandler "EG06A"; then #EG06A + lte_bands="2 4 5 7 12 13 25 26 29 30 66" + trysg_bands="850 1700 1900" + dug_bands="" + ###################### EC25 ######################### + elif strstr $revision_from_unhandler "EC25EF"; then #EC25E + lte_bands="1 3 5 7 8 20 38 40 41" + trysg_bands="850 900 2100" + dug_bands="900 1800" #MHz + elif strstr $revision_from_unhandler "EC25EC"; then #EC25EC + lte_bands="1 3 7 8 20 28" + trysg_bands="900 2100" + dug_bands="900 1800" + elif strstr $revision_from_unhandler "EC25AUX"; then #EC25AUX + lte_bands="1 2 3 4 5 7 8 28 40" + trysg_bands="850 900 1700 1900 2100" + dug_bands="850 900 1800 1900" + elif strstr $revision_from_unhandler "EC25AFA"; then #EC25A + lte_bands="2 4 12" + trysg_bands="850 1700 1900" + dug_bands="" + elif strstr $revision_from_unhandler "EC25V"; then #EC25V + lte_bands="4 13" + trysg_bands="" + dug_bands="" + elif strstr $revision_from_unhandler "EC25AFX"; then #EC25AFX + lte_bands="2 4 5 12 13 14 66 71" + trysg_bands="850 1700 1900" + dug_bands="" + elif strstr $revision_from_unhandler "EC25AFF"; then #EC25AF + lte_bands="2 4 5 12 13 14 66 71" + trysg_bands="850 1700 1900" + dug_bands="" + elif strstr $revision_from_unhandler "EC25AUTF"; then #EC25AUT + lte_bands="1 3 5 7 28" + trysg_bands="850 2100" + dug_bands="" + elif strstr $revision_from_unhandler "EC25AUTL"; then #EC25AUTL + lte_bands="3 7 28" + trysg_bands="" + dug_bands="" + elif strstr $revision_from_unhandler "EC25AUF"; then #EC25AU + lte_bands="1 2 3 4 5 7 8 28 40" + trysg_bands="850 900 1900 2100" + dug_bands="850 900 1800 1900" + elif strstr $revision_from_unhandler "EC25J"; then #EC25J + lte_bands="1 3 8 18 19 26 41" + trysg_bands="800 900 2100" + dug_bands="" + elif strstr $revision_from_unhandler "EC25EUX"; then #EC25EUX + lte_bands="1 3 7 8 20 28 38 40 41" + trysg_bands="900 2100" + dug_bands="900 1800" + elif strstr $revision_from_unhandler "EC25EUF"; then #EC25EU + lte_bands="1 3 7 8 20 28 38 40 41" + trysg_bands="900 2100" + dug_bands="900 1800" + elif strstr $revision_from_unhandler "EC25EUG"; then #EC25EU + lte_bands="1 3 7 8 20 28 38 40 41" + trysg_bands="900 2100" + dug_bands="900 1800" + elif strstr $revision_from_unhandler "EC25MX"; then #EC25MX + lte_bands="2 4 5 7 28 66" + trysg_bands="850 1700 1900" + dug_bands="" + ###################### EC21 ######################### + elif strstr $revision_from_unhandler "EC21EUX"; then #EC21EUX + lte_bands="1 3 7 8 20 28" + trysg_bands="900 2100" + dug_bands="900 1800" + elif strstr $revision_from_unhandler "EC21EU"; then #EC21EU + lte_bands="1 3 7 8 20 28" + trysg_bands="900 2100" + dug_bands="900 1800" + elif strstr $revision_from_unhandler "EC21EC"; then #EC21EC + lte_bands="1 3 7 8 20 28" + trysg_bands="900 2100" + dug_bands="900 1800" + elif strstr $revision_from_unhandler "EC21E"; then #EC21E + lte_bands="1 3 5 7 8 20" + trysg_bands="850 900 2100" + dug_bands="900 1800" + elif strstr $revision_from_unhandler "EC21V"; then #EC21V + lte_bands="4 13" + trysg_bands="" + dug_bands="" + elif strstr $revision_from_unhandler "EC21KL"; then #EC21KL + lte_bands="1 3 5 7 8" + trysg_bands="" + dug_bands="" + elif strstr $revision_from_unhandler "EC21J"; then #EC21J + lte_bands="1 3 8 18 19 26" + trysg_bands="" + dug_bands="" + elif strstr $revision_from_unhandler "EC21AUX"; then #EC21AUX + lte_bands="1 2 3 4 5 7 8 28 40" + trysg_bands="850 900 1700 1900 2100" + dug_bands="850 900 1800 1900" + elif strstr $revision_from_unhandler "EC21AUT"; then #EC21AUT + lte_bands="1 3 5 7 28" + trysg_bands="850 2100" + dug_bands="" + elif strstr $revision_from_unhandler "EC21AU"; then #EC21AU + lte_bands="1 2 3 4 5 7 8 28 40" + trysg_bands="850 900 1900 2100" + dug_bands="850 900 1800 1900" + elif strstr $revision_from_unhandler "EC21A"; then #EC21A + lte_bands="2 4 12" + trysg_bands="850 1700 1900" + dug_bands="" + ###################### EG25 ######################### + elif strstr $revision_from_unhandler "EG25G"; then #EG25G + lte_bands="1 2 3 4 5 7 8 12 13 18 19 20 25 26 28 38 39 40 41" + trysg_bands="800 850 900 1700 1900 2100" + dug_bands="850 900 1800 1900" + elif strstr $revision_from_unhandler "EG12EA"; then #EG12EA + lte_bands="1 3 5 7 8 20 28 38 40 41" + trysg_bands="850 900 1800 2100" + dug_bands="" + elif strstr $revision_from_unhandler "EG12NA"; then #EG12NA + lte_bands="2 4 5 7 12 13 14 17 25 26 29 30 41 66 71" + trysg_bands="850 1700 1900" + dug_bands="" + elif strstr $revision_from_unhandler "BG96"; then #BG96M + lte_bands="1 2 3 4 5 8 12 13 18 19 20 26 28 39" + trysg_bands="" + dug_bands="850 900 1800 1900" + ##################### SLM750 ######################## + elif strstr $revision_from_unhandler "750VE"; then #SLM750VE + lte_bands="1 3 5 7 8 20 40" + trysg_bands="850 900 2100" + dug_bands="900 1800" + elif strstr $revision_from_unhandler "750VAU"; then #SLM750VAU + lte_bands="1 3 5 7 8 28 40" + trysg_bands="850 900 2100" + dug_bands="850 900 1800" + elif strstr $revision_from_unhandler "750VA"; then #SLM750VA + lte_bands="2 4 5 12 13 17 18 25 26 41" + trysg_bands="850 1700 1900" + dug_bands="850 1900" + elif strstr $revision_from_unhandler "750VJ"; then #SLM750VJ + lte_bands="1 3 8 18 19 26 41" + trysg_bands="800 900 2100" + dug_bands="" + elif strstr $revision_from_unhandler "750VSA"; then #SLM750VSA + lte_bands="2 4 5 7 8 28 40" + trysg_bands="850 900 1900" + dug_bands="850 900 1900" + ###################### UC20 ######################### + elif strstr $revision_from_unhandler "UC20E"; then #UC20E + lte_bands="" + trysg_bands="900 2100" + dug_bands="850 900 1800 1900" + elif strstr $revision_from_unhandler "UC20G"; then #UC20G + lte_bands="" + trysg_bands="800 850 900 1900 2100" + dug_bands="850 900 1800 1900" + elif strstr $revision_from_unhandler "UC20A"; then #UC20A + lte_bands="" + trysg_bands="850 1900" + dug_bands="" + else + lte_bands="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28" + trysg_bands="700 800 850 900 1500 1700 2600" + dug_bands="1700 1800 1900 2100" + fi +} + +validate_service_modes() { + json_get_keys service_modes service_modes + + found_modes="$(printf "$service_modes" | awk '!seen[$0]++'| wc -l)" + [ "$found_modes" -eq 0 ] && { + return 0 + } + + return 1 +} + +#~ Get model name for RUTX products +setup_modem() { + local key="$1" + local object_num="$2" + local id gps boudrate type desc control product vendor stop_bits + + json_select "$object_num" + json_get_vars id product + + if [ "$id" = "$id_from_unhandler" ]; then + + [ -z "$product" ] || \ + { + [ -f "/sys/bus/usb/devices/$id/idVendor" ] && [ -f "/sys/bus/usb/devices/$id/idProduct" ] || { + json_select .. + return 1 + } + + validate_service_modes && { + gather_band_capabilities + json_select_object service_modes + [ -z "$lte_bands" ] || print_array "4G" "$lte_bands" + [ -z "$trysg_bands" ] || print_array "3G" "$trysg_bands" + [ -z "$dug_bands" ] || print_array "2G" "$dug_bands" + json_select .. + } + json_select .. + return 1 + } + + vendor="$(cat "/sys/bus/usb/devices/$id/idVendor")" + product="$(cat "/sys/bus/usb/devices/$id/idProduct")" + + [ -f "/lib/network/wwan/$vendor:$product" ] && { + devicename="$id" + + gather_band_capabilities + + json_set_namespace defaults old_cb + json_load "$(cat /lib/network/wwan/$vendor:$product)" + json_get_vars gps boudrate type desc control stop_bits + json_set_namespace "$old_cb" + + [ "${devicename%%:*}" = "$devicename" ] && { + json_add_string vendor "$vendor" + json_add_string product "$product" + json_add_string gps "$gps" + json_add_string stop_bits "$stop_bits" + json_add_string boudrate "$boudrate" + json_add_string type "$type" + json_add_string desc "$desc" + json_add_string control "$control" + json_add_object service_modes + [ -z "$lte_bands" ] || print_array "4G" "$lte_bands" + [ -z "$trysg_bands" ] || print_array "3G" "$trysg_bands" + [ -z "$dug_bands" ] || print_array "2G" "$dug_bands" + json_close_object + } + } + fi + json_select .. +} + +[ -s "${CFG}" ] || exit 1 + +id_from_unhandler="$1" +revision_from_unhandler="$2" + +lock /var/run/board_modem.lock + +board_config_update +json_for_each_item setup_modem modems +board_config_flush + +lock -u /var/run/board_modem.lock + +exit 0 diff --git a/root/target/linux/ipq40xx/base-files/bin/board_track b/root/target/linux/ipq40xx/base-files/bin/board_track new file mode 100644 index 00000000..563b8768 --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/bin/board_track @@ -0,0 +1,47 @@ +#!/bin/sh + +. /lib/functions/uci-defaults.sh + +CFG=/etc/board.json +SLP=30 + +check_modem() { + json_select "$2" + json_get_vars id + + [ -z "$id" ] && { + json_select .. + return 0 + } + + #logger -t "board-track" "ls -d /sys/bus/usb/devices/$id/${id}*/tty?*" + ttys=$(ls -d /sys/bus/usb/devices/$id/${id}*/tty?*) + + [ -n "$ttys" ] || { #FAILED TO FIND MODEM + logger -t "board-track" "modem $id not detected" + for m in /sys/class/gpio/modem*_power; do + label="$(basename $m | awk -F_ '{print $1}')" + mctl -s -m ${label} + sleep 1 + mctl -p -m ${label} + done + sleep 5 + ip link set up dev wwan0 2>&1 >/dev/null + ip link set up dev wwan1 2>&1 >/dev/null + json_select .. + return 1 + } + + [ -n "$(ip link show dev wwan0 | grep DOWN)" ] && ip link set up dev wwan0 2>&1 >/dev/null + [ -n "$(ip link show dev wwan1 | grep DOWN)" ] && ip link set up dev wwan1 2>&1 >/dev/null + + #MODEM UP + json_select .. +} + +board_config_update +while true; do + json_for_each_item check_modem modems + sleep $SLP + [ $SLP -lt 300 ] && SLP=$((SLP+30)) +done diff --git a/root/target/linux/ipq40xx/base-files/bin/config_generate b/root/target/linux/ipq40xx/base-files/bin/config_generate new file mode 100644 index 00000000..b2542b14 --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/bin/config_generate @@ -0,0 +1,665 @@ +#!/bin/sh + +CFG=/etc/board.json + +. /usr/share/libubox/jshn.sh + +[ -s $CFG ] || /bin/board_detect || exit 1 + +[ -s /etc/config/network ] && \ +[ -s /etc/config/system ] && \ +[ -s /etc/config/hwinfo ] && \ +[ -s /etc/config/blesem ] && \ +exit 0 + +generate_static_network() { + uci -q batch <<-EOF + delete network.loopback + set network.loopback='interface' + set network.loopback.ifname='lo' + set network.loopback.proto='static' + set network.loopback.ipaddr='127.0.0.1' + set network.loopback.netmask='255.0.0.0' + EOF + [ -e /proc/sys/net/ipv6 ] && { + uci -q batch <<-EOF + delete network.globals + set network.globals='globals' + set network.globals.ula_prefix='auto' + EOF + } + + if json_is_a dsl object; then + json_select dsl + if json_is_a atmbridge object; then + json_select atmbridge + local vpi vci encaps payload nameprefix + json_get_vars vpi vci encaps payload nameprefix + uci -q batch <<-EOF + delete network.atm + set network.atm='atm-bridge' + set network.atm.vpi='$vpi' + set network.atm.vci='$vci' + set network.atm.encaps='$encaps' + set network.atm.payload='$payload' + set network.atm.nameprefix='$nameprefix' + EOF + json_select .. + fi + + if json_is_a modem object; then + json_select modem + local type annex firmware tone xfer_mode + json_get_vars type annex firmware tone xfer_mode + uci -q batch <<-EOF + delete network.dsl + set network.dsl='dsl' + set network.dsl.annex='$annex' + set network.dsl.firmware='$firmware' + set network.dsl.tone='$tone' + set network.dsl.xfer_mode='$xfer_mode' + EOF + json_select .. + fi + json_select .. + fi +} + +addr_offset=2 +generate_network() { + local keys var val ifname macaddr proto type ipaddr netmask + + uci -q batch <<-EOF + delete "network.$1" + set network.$1='interface' + EOF + + json_select network + json_select "$1" + json_get_keys keys + for var in $keys; do + json_get_var val "$var" + [ "${var#_*}" = "$var" ] && { + eval "$var=\"\$val\"" + uci -q set "network.$1.$var=$val" + } + done + json_select .. + json_select .. + + #~ [ -n "$ifname" ] || return + + # force bridge for multi-interface devices (and lan) + case "$1:$ifname" in + *\ * | lan:*) + type="bridge" + uci -q set "network.$1.type=$type" + ;; + esac + + if [ -n "$macaddr" ]; then + for name in $ifname; do + uci -q batch <<-EOF + delete network.$1_${name/./_}_dev + set network.$1_${name/./_}_dev='device' + set network.$1_${name/./_}_dev.name='$name' + set network.$1_${name/./_}_dev.macaddr='$macaddr' + EOF + done + fi + + case "$proto" in + static) + local ipad + case "$1" in + lan) + ipad=${ipaddr:-"192.168.100.1"} + ;; + *) ipad=${ipaddr:-"192.168.$((addr_offset++)).1"} ;; + esac + + netm=${netmask:-"255.255.255.0"} + + uci -q batch <<-EOF + set network.$1.proto='static' + set network.$1.ipaddr='$ipad' + set network.$1.netmask='$netm' + EOF + [ -e /proc/sys/net/ipv6 ] && uci set network.$1.ip6assign='60' + ;; + + dhcp) + # fixup IPv6 slave interface if parent is a bridge + [ "$type" = "bridge" ] && ifname="br-$1" + + uci set network.$1.proto='dhcp' + uci set network.$1.metric='1' + + #[ -e /proc/sys/net/ipv6 ] && { + # uci -q batch <<-EOF + # delete network.${1}6 + # set network.${1}6='interface' + # set network.${1}6.device='$ifname' + # set network.${1}6.proto='dhcpv6' + # set network.${1}6.metric='1' + # EOF + #} + ;; + + pppoe) + uci -q batch <<-EOF + set network.$1.proto='pppoe' + set network.$1.username='username' + set network.$1.password='password' + EOF + [ -e /proc/sys/net/ipv6 ] && { + uci -q batch <<-EOF + set network.$1.ipv6='1' + delete network.${1}6 + set network.${1}6='interface' + set network.${1}6.ifname='@${1}' + set network.${1}6.proto='dhcpv6' + EOF + } + ;; + esac +} + +add_modem_section() { + local id="$1" + local num="$2" + local simcount="$3" + local builtin="$4" + + for count in $(seq "$simcount"); do + interface="mob${num}s${count}a1" + local proto="wwan" + + # just like this for now + # probably we should merge connm with wwan + [ -e /dev/smd9 ] && { + proto="connm" + } + + uci -q batch <<-EOF + delete network.$interface + set network.$interface='interface' + set network.$interface.proto='$proto' + set network.$interface.modem='$id' + set network.$interface.metric='$((num+1))' + set network.$interface.sim='${count}' + set network.$interface.pdp='1' + EOF + + # just like this for now + # probably we should merge connm with wwan + [ -e /dev/smd9 ] && { + uci set network.$interface.ifname='rmnet0' + } + + update_firewall_zone "wan" "$interface" + create_multiwan_iface "$interface" "$num" + add_simcard_config "$id" "${count}" "${count}" "$builtin" + add_sim_switch_config "$id" "${count}" + add_quota_limit_config "$interface" + done + add_sms_storage_config "$id" +} + +generate_dynamic_lte() { +[ -f /lib/functions/modem.sh ] || return +. /lib/functions/modem.sh + + local interface num id simcount builtin + + #creating simcard sections from board.json file + if json_is_a modems array; then + json_get_keys modems modems + json_select modems + + num=1 + + for modem in $modems; do + json_select "$modem" + json_get_vars id simcount builtin + json_select .. + add_modem_section "$id" "$num" "$simcount" "$builtin" + num=$(( num + 1 )) + done + + json_select .. + else + ## because of RUTX8 have no default modem + # after this script runs out simcard config + # must not be empty due to external modems could appear to config + echo " " >> /etc/config/simcard + fi + + #creating simcard sections from conneted via USB + for a in `ls /sys/bus/usb/devices`; do + local vendor product + [ -f "/sys/bus/usb/devices/$a/idVendor" ] && [ -f "/sys/bus/usb/devices/$a/idProduct" ] || continue + vendor=$(cat "/sys/bus/usb/devices/$a/idVendor") + product=$(cat "/sys/bus/usb/devices/$a/idProduct") + [ -f "/lib/network/wwan/${vendor}:${product}" ] && { + add_simcard_config "$a" "1" "0" "" + } + done +} + +generate_switch_vlans_ports() { + local switch="$1" + local port ports role roles num attr val + + # + # autogenerate vlans + # + + if json_is_a roles array; then + json_get_keys roles roles + json_select roles + + for role in $roles; do + json_select "$role" + json_get_vars ports + json_select .. + + uci -q batch <<-EOF + add network switch_vlan + set network.@switch_vlan[-1].device='$switch' + set network.@switch_vlan[-1].vlan='$role' + set network.@switch_vlan[-1].ports='$ports' + EOF + done + + json_select .. + fi + + + # + # write port specific settings + # + + if json_is_a ports array; then + json_get_keys ports ports + json_select ports + + for port in $ports; do + json_select "$port" + json_get_vars num + + if json_is_a attr object; then + json_get_keys attr attr + json_select attr + uci -q batch <<-EOF + add network switch_port + set network.@switch_port[-1].device='$switch' + set network.@switch_port[-1].port=$num + EOF + + for attr in $attr; do + json_get_var val "$attr" + uci -q set network.@switch_port[-1].$attr="$val" + done + json_select .. + fi + json_select .. + done + + json_select .. + fi +} + +generate_switch() { + local key="$1" + local vlans + + json_select switch + json_select "$key" + json_get_vars enable reset blinkrate cpu_port \ + ar8xxx_mib_type ar8xxx_mib_poll_interval + + uci -q batch <<-EOF + add network switch + set network.@switch[-1].name='$key' + set network.@switch[-1].reset='$reset' + set network.@switch[-1].enable_vlan='$enable' + set network.@switch[-1].blinkrate='$blinkrate' + set network.@switch[-1].ar8xxx_mib_type='$ar8xxx_mib_type' + set network.@switch[-1].ar8xxx_mib_poll_interval='$ar8xxx_mib_poll_interval' + EOF + + generate_switch_vlans_ports "$1" + + json_select .. + json_select .. +} + + +generate_static_system() { + param=$(/sbin/mnf_info "--name") + hostname=${param:0:6} + uci -q batch <<-EOF + delete system.@system[0] + set system.system='system' + set system.@system[-1].hostname='OpenMPTCProuter' + set system.@system[-1].timezone='UTC' + set system.@system[-1].ttylogin='0' + set system.@system[-1].log_size='128' + set system.@system[-1].urandom_seed='0' + + delete system.ntp + set system.ntp='timeserver' + set system.ntp.enabled='0' + set system.ntp.enable_server='0' + add_list system.ntp.server='0.pool.ntp.org' + add_list system.ntp.server='1.pool.ntp.org' + add_list system.ntp.server='2.pool.ntp.org' + add_list system.ntp.server='3.pool.ntp.org' + + delete system.debug + set system.debug='debug' + set system.debug.sms_utils_debug_level='4' + EOF + + if json_is_a system object; then + json_select system + local hostname + #if json_get_var hostname hostname; then + # uci -q set "system.@system[-1].hostname=$hostname" + #fi + + if json_is_a ntpserver array; then + local keys key + json_get_keys keys ntpserver + json_select ntpserver + uci -q delete "system.ntp.server" + + for key in $keys; do + local server + if json_get_var server "$key"; then + uci -q add_list "system.ntp.server=$server" + fi + done + json_select .. + fi + json_select .. + fi +} + +generate_rssimon() { + local key="$1" + local cfg="rssid_$key" + local refresh threshold + + json_select rssimon + json_select "$key" + json_get_vars refresh threshold + json_select .. + json_select .. + + uci -q batch <<-EOF + delete system.$cfg + set system.$cfg='rssid' + set system.$cfg.dev='$key' + set system.$cfg.refresh='$refresh' + set system.$cfg.threshold='$threshold' + EOF +} + +generate_led() { + local key="$1" + local cfg="led_$key" + + json_select led + json_select "$key" + json_get_vars name sysfs type trigger default + + uci -q batch <<-EOF + delete system.$cfg + set system.$cfg='led' + set system.$cfg.name='$name' + set system.$cfg.sysfs='$sysfs' + set system.$cfg.trigger='$trigger' + set system.$cfg.default='$default' + EOF + + case "$type" in + gpio) + local gpio inverted + json_get_vars gpio inverted + uci -q batch <<-EOF + set system.$cfg.trigger='gpio' + set system.$cfg.gpio='$gpio' + set system.$cfg.inverted='$inverted' + EOF + ;; + + netdev) + local device mode + json_get_vars device mode + uci -q batch <<-EOF + set system.$cfg.trigger='netdev' + set system.$cfg.mode='$mode' + set system.$cfg.dev='$device' + EOF + ;; + + usb) + local device + json_get_vars device + uci -q batch <<-EOF + set system.$cfg.trigger='usbdev' + set system.$cfg.interval='50' + set system.$cfg.dev='$device' + EOF + ;; + + usbport) + local ports port + json_get_values ports ports + uci set system.$cfg.trigger='usbport' + for port in $ports; do + uci add_list system.$cfg.port=$port + done + ;; + + rssi) + local iface minq maxq offset factor + json_get_vars iface minq maxq offset factor + uci -q batch <<-EOF + set system.$cfg.trigger='rssi' + set system.$cfg.iface='rssid_$iface' + set system.$cfg.minq='$minq' + set system.$cfg.maxq='$maxq' + set system.$cfg.offset='$offset' + set system.$cfg.factor='$factor' + EOF + ;; + + switch) + local port_mask speed_mask mode + json_get_vars port_mask speed_mask mode + uci -q batch <<-EOF + set system.$cfg.port_mask='$port_mask' + set system.$cfg.speed_mask='$speed_mask' + set system.$cfg.mode='$mode' + EOF + ;; + + portstate) + local port_state + json_get_vars port_state + uci -q batch <<-EOF + set system.$cfg.port_state='$port_state' + EOF + ;; + + timer|oneshot) + local delayon delayoff + json_get_vars delayon delayoff + uci -q batch <<-EOF + set system.$cfg.trigger='$type' + set system.$cfg.delayon='$delayon' + set system.$cfg.delayoff='$delayoff' + EOF + ;; + esac + + json_select .. + json_select .. +} + +generate_gpioswitch() { + local cfg="$1" + + json_select gpioswitch + json_select "$cfg" + local name pin default + json_get_vars name pin default + uci -q batch <<-EOF + delete system.$cfg + set system.$cfg='gpio_switch' + set system.$cfg.name='$name' + set system.$cfg.gpio_pin='$pin' + set system.$cfg.value='$default' + EOF + json_select .. + json_select .. +} + +generate_hwinfo() { + local parameter="$1" + local temp + + json_select hwinfo + json_get_var temp "$parameter" + json_select .. + + uci -q batch <<-EOF + set hwinfo.hwinfo='hwinfo' + set hwinfo.hwinfo.$parameter='$temp' + EOF +} + +generate_bluetooth() { + uci -q batch <<-EOF + set blesem.general='section' + set blesem.general.enabled='0' + set blesem.settings='app' + set blesem.settings.refresh_time='30000' + EOF +} + +add_firewall_zone() { + local ifname + + json_select network + json_select "$1" + json_get_vars ifname + json_select .. + json_select .. + + fw3 -q network "$1" || fw3 -q device "$ifname" && return + + uci -q batch <<-EOF + add firewall zone + set firewall.@zone[-1].name='$1' + set firewall.@zone[-1].network='$1' + set firewall.@zone[-1].input='REJECT' + set firewall.@zone[-1].output='ACCEPT' + set firewall.@zone[-1].forward='REJECT' + + add firewall forwarding + set firewall.@forwarding[-1].src='$1' + set firewall.@forwarding[-1].dest='wan' + + add firewall rule + set firewall.@rule[-1].name='Allow-DNS-$1' + set firewall.@rule[-1].src='$1' + set firewall.@rule[-1].dest_port='53' + set firewall.@rule[-1].proto='tcp udp' + set firewall.@rule[-1].target='ACCEPT' + + add firewall rule + set firewall.@rule[-1].name='Allow-DHCP-$1' + set firewall.@rule[-1].src='$1' + set firewall.@rule[-1].dest_port='67' + set firewall.@rule[-1].proto='udp' + set firewall.@rule[-1].family='ipv4' + set firewall.@rule[-1].target='ACCEPT' + EOF +} + +add_dhcp() { + + json_select network + json_select "$1" + json_get_vars _dhcp + json_select .. + json_select .. + + [ "$_dhcp" = "1" ] || return + uci -q batch <<-EOF + set dhcp.$1='dhcp' + set dhcp.$1.interface='$1' + set dhcp.$1.start='100' + set dhcp.$1.limit='150' + set dhcp.$1.leasetime='1h' + EOF +} + +json_init +json_load "$(cat ${CFG})" + +umask 077 + +if [ ! -s /etc/config/network ]; then + touch /etc/config/network + generate_static_network + + json_get_keys keys network + for key in $keys; do + generate_network $key + add_firewall_zone "$key" + add_dhcp "$key" + done + + json_get_keys keys switch + for key in $keys; do generate_switch $key; done + + generate_dynamic_lte +fi + +if [ ! -s /etc/config/system ]; then + touch /etc/config/system + generate_static_system + + json_get_keys keys rssimon + for key in $keys; do generate_rssimon $key; done + + json_get_keys keys gpioswitch + for key in $keys; do generate_gpioswitch $key; done + + json_get_keys keys led + for key in $keys; do generate_led $key; done +fi + +if [ ! -s /etc/config/hwinfo ]; then + touch /etc/config/hwinfo + json_get_keys keys hwinfo + for key in $keys; do generate_hwinfo $key; done +fi + +if [ ! -s /etc/config/blesem ]; then + bluetooth="" + json_select hwinfo + json_get_vars bluetooth + [ "$bluetooth" -eq 1 ] && { + touch /etc/config/blesem + touch /etc/config/ble_devices + generate_bluetooth + } +fi + +uci commit diff --git a/root/target/linux/ipq40xx/base-files/bin/ipcalc.sh b/root/target/linux/ipq40xx/base-files/bin/ipcalc.sh new file mode 100644 index 00000000..5d5eac3e --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/bin/ipcalc.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +awk -f - $* <limit) end=limit + + print "IP="int2ip(ipaddr) + print "NETMASK="int2ip(netmask) + print "BROADCAST="int2ip(broadcast) + print "NETWORK="int2ip(network) + print "PREFIX="32-bitcount(compl32(netmask)) + + # range calculations: + # ipcalc + + if (ARGC > 3) { + print "START="int2ip(start) + print "END="int2ip(end) + } +} +EOF diff --git a/root/target/linux/ipq40xx/base-files/etc/board.d/1-board_json b/root/target/linux/ipq40xx/base-files/etc/board.d/1-board_json new file mode 100644 index 00000000..619e0062 --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/etc/board.d/1-board_json @@ -0,0 +1,207 @@ +#!/bin/sh +# +# Copyright (c) 2015 The Linux Foundation. All rights reserved. +# Copyright (c) 2011-2015 OpenWrt.org +# + +. /lib/functions/uci-defaults.sh +. /lib/functions/teltonika-defaults.sh +. /lib/functions/system.sh + +setup_json() { + local model="$1" + + case "$model" in + RUTX08*) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_switch "switch0" \ + "0u@eth0" "2:lan:1" "3:lan:2" "4:lan:3" "0u@eth1" "5:wan" + ucidef_set_hwinfo usb ethernet ios + ;; + RUTX09*) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_switch "switch0" \ + "0u@eth0" "2:lan:1" "3:lan:2" "4:lan:3" "0u@eth1" "5:wan" + ucidef_add_static_modem_info "$model" "3-1" "2" "gps_out" + ucidef_set_hwinfo dual_sim usb gps mobile ethernet ios + ;; + RUTX10*) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_switch "switch0" \ + "0u@eth0" "2:lan:1" "3:lan:2" "4:lan:3" "0u@eth1" "5:wan" + ucidef_set_hwinfo bluetooth usb wifi dual_band_ssid ethernet ios + ;; + RUTX11*) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_switch "switch0" \ + "0u@eth0" "2:lan:1" "3:lan:2" "4:lan:3" "0u@eth1" "5:wan" + ucidef_add_static_modem_info "$model" "3-1" "2" "gps_out" + ucidef_set_hwinfo dual_sim usb gps mobile wifi dual_band_ssid bluetooth ethernet ios + ;; + RUTXR1*) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_switch "switch0" \ + "0u@eth0" "1:lan" "2:lan" "3:lan" "4:lan" "0u@eth1" "5:wan" + ucidef_add_static_modem_info "$model" "3-1" "2" + ucidef_set_hwinfo dual_sim usb mobile wifi dual_band_ssid ethernet sfp_port + ucidef_set_release_version "2.3.1" + ;; + RUTX12*) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_switch "switch0" \ + "0u@eth0" "1:lan" "2:lan" "3:lan" "4:lan" "0u@eth1" "5:wan" + # builtin and primary should be first modem + ucidef_add_static_modem_info "$model" "3-1" "1" "primary" "gps_out" + ucidef_add_static_modem_info "$model" "1-1.2" "1" + ucidef_set_hwinfo usb gps mobile wifi dual_band_ssid bluetooth ethernet ios + ucidef_set_release_version "2.3.1" + ;; + RUTX14*) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_switch "switch0" \ + "0u@eth0" "1:lan" "2:lan" "3:lan" "4:lan" "0u@eth1" "5:wan" + ucidef_add_static_modem_info "$model" "1-1" "2" "gps_out" + ucidef_set_hwinfo usb gps dual_sim mobile wifi dual_band_ssid bluetooth ethernet ios at_sim + ucidef_set_release_version "2.6.1" + ;; + RUTX18*) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_switch "switch0" \ + "0u@eth0" "1:lan" "2:lan" "3:lan" "4:lan" "0u@eth1" "5:wan" + ucidef_add_static_modem_info "$model" "2-1" "2" "gps_out" + ucidef_set_hwinfo usb gps dual_sim mobile wifi dual_band_ssid bluetooth ethernet ios + ;; + TRB2*) + ucidef_set_led_switch "lan" "LAN" "eth_led" "switch0" "0x04" + ucidef_set_interface_lan "eth0" + ucidef_add_static_modem_info "$model" "1-1.4" "2" "gps_out" + ucidef_add_serial_capabilities "rs232 rs485" \ + "300 600 1200 2400 4800 9600 14400 19200 38400 56000 57600 115200 \ + 230400 460800 921600 1000000 3000000" \ + "7 8" + ucidef_set_hwinfo dual_sim mobile gps ethernet ios + ;; + RUT200* |\ + RUT241*) + ucidef_set_led_switch "lan" "LAN" "eth1_led" "switch0" "0x2" + ucidef_set_led_switch "wan" "WAN" "eth2_led" "switch0" "0x1" + ucidef_add_switch "switch0" "1:lan" "0:wan" "6@eth0" + ucidef_set_interface_macaddr "lan" "$(mtd_get_mac_binary config 0x0)" + ucidef_set_interface_macaddr "wan" "$(macaddr_add "$(mtd_get_mac_binary config 0x0)" 1)" + ucidef_add_static_modem_info "$model" "1-1" "1" + [ "${model:7:1}" = "1" ] && ucidef_set_hwinfo mobile wifi \ + ethernet || ucidef_set_hwinfo mobile wifi ethernet ios + ;; + RUT2*) + ucidef_set_led_switch "lan" "LAN" "lan_led" "switch0" "0x04" + ucidef_set_led_netdev "wan" "WAN" "wan_led" "eth1" + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_static_modem_info "$model" "1-1" "1" + [ "${model:6:1}" = "1" ] && ucidef_set_hwinfo mobile wifi \ + ethernet || ucidef_set_hwinfo mobile wifi ethernet ios + ;; + RUT300*) + ucidef_set_led_switch "lan1" "LAN1" "eth1_led" "switch0" "0x02" + ucidef_set_led_switch "lan2" "LAN2" "eth2_led" "switch0" "0x10" + ucidef_set_led_switch "lan3" "LAN3" "eth3_led" "switch0" "0x08" + ucidef_set_led_switch "lan4" "LAN4" "eth4_led" "switch0" "0x04" + ucidef_set_led_netdev "wan" "WAN" "wan_led" "eth1" + ucidef_set_interface_wan "eth1" + ucidef_add_switch "switch0" \ + "0@eth0" "1:lan:1" "2:lan:4" "3:lan:3" "4:lan:2" + ucidef_set_hwinfo usb ethernet ios + ;; + RUT360*) + ucidef_set_led_switch "lan" "LAN" "eth1_led" "switch0" "0x10" + ucidef_set_led_netdev "wan" "WAN" "eth2_led" "eth1" + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_add_static_modem_info "$model" "1-1" "1" + ucidef_set_hwinfo mobile wifi dual_band_ssid ethernet ios + ;; + RUT950*) + ucidef_set_led_switch "lan1" "LAN1" "eth1_led" "switch0" "0x10" + ucidef_set_led_switch "lan2" "LAN2" "eth2_led" "switch0" "0x08" + ucidef_set_led_switch "lan3" "LAN3" "eth3_led" "switch0" "0x04" + ucidef_set_led_netdev "wan" "WAN" "wan_led" "eth1" + ucidef_set_interface_wan "eth1" + ucidef_add_switch "switch0" "0@eth0" "2:lan:3" "3:lan:2" "4:lan:1" + ucidef_add_static_modem_info "$model" "1-1" "2" + [ "${model:7:2}" = "06" ] && ucidef_set_hwinfo dual_sim mobile \ + wifi ethernet || ucidef_set_hwinfo dual_sim mobile wifi ethernet ios + ;; + RUT955*) + ucidef_set_led_switch "lan1" "LAN1" "eth1_led" "switch0" "0x10" + ucidef_set_led_switch "lan2" "LAN2" "eth2_led" "switch0" "0x08" + ucidef_set_led_switch "lan3" "LAN3" "eth3_led" "switch0" "0x04" + ucidef_set_led_netdev "wan" "WAN" "wan_led" "eth1" + ucidef_set_interface_wan "eth1" + ucidef_add_switch "switch0" "0@eth0" "2:lan:3" "3:lan:2" "4:lan:1" + ucidef_add_static_modem_info "$model" "1-1.4" "2" "gps_out" + [ "${model:7:2}" = "06" ] && ucidef_set_hwinfo dual_sim usb gps \ + mobile wifi ethernet || ucidef_set_hwinfo dual_sim usb gps \ + mobile wifi ethernet ios + ucidef_add_serial_capabilities "rs232" \ + "200 300 600 1200 1800 2400 4800 9600 19200 38400 57600 115200 \ + 230400 460800 500000 576000" \ + "5 6 7 8" + ucidef_add_serial_capabilities "rs485" \ + "300 600 1200 1800 2400 4800 9600 19200 38400 57600 115200 230400 \ + 460800 500000 576000 921600 1000000 1152000 1500000 2000000 \ + 2500000 3000000" \ + "8" + ;; + TRB140*) + ucidef_set_interface_lan "eth0 rndis0" + ucidef_add_trb14x_lte_modem "$model" + ucidef_add_nand_info "$model" + [ "${model:7:1}" = "2" ] && ucidef_set_hwinfo mobile ethernet || \ + ucidef_set_hwinfo mobile ethernet ios + ;; + TRB141*) + ucidef_set_interface_lan "rndis0" + ucidef_add_trb14x_lte_modem "$model" + ucidef_add_nand_info "$model" + ucidef_set_hwinfo mobile ios + ;; + TRB142* |\ + TRB145*) + ucidef_set_interface_lan "rndis0" + ucidef_add_trb14x_lte_modem "$model" + ucidef_add_nand_info "$model" + [ "${model:7:1}" = "2" ] && ucidef_set_hwinfo mobile || \ + ucidef_set_hwinfo mobile ios + [ "${model:5:1}" = "2" ] && local rs="rs232" + ucidef_add_serial_capabilities "${rs:-rs485}" \ + "300 600 1200 2400 4800 9600 19200 38400 57600 115200 460800" \ + "5 6 7 8" + [ "${model:5:2}" = "23" -o "${model:5:2}" = "52" ] && \ + ucidef_set_release_version "7.1" + ;; + TCR100*) + ucidef_set_led_switch "lan" "LAN" "eth1_led" "switch0" "0x10" + ucidef_set_led_netdev "wan" "WAN" "eth2_led" "eth1" + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ucidef_set_interface guest proto static type bridge \ + guest 1 _wireless true _dhcp true + ucidef_add_static_modem_info "$model" "1-1" "1" + ucidef_set_hwinfo mobile wifi dual_band_ssid wps ethernet + ;; + *) + echo "Unsupported hardware. Network interfaces not intialized" + ;; + esac +} + +#~ Get model name for RUTX products +model="$(mnf_info --name)" 2>/dev/null + +platform="$(cat /proc/device-tree/platform)" 2>/dev/null + +board_config_update +setup_json "$model" + +ucidef_set_board_platform "$platform" + +board_config_flush + +exit 0 diff --git a/root/target/linux/ipq40xx/base-files/etc/init.d/boot b/root/target/linux/ipq40xx/base-files/etc/init.d/boot new file mode 100644 index 00000000..85549882 --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/etc/init.d/boot @@ -0,0 +1,70 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2006-2011 OpenWrt.org + +START=10 +STOP=90 + +uci_apply_defaults() { + . /lib/functions/system.sh + + cd /etc/uci-defaults || return 0 + files="$(find . -type f | sort)" + [ -z "$files" ] && return 0 + mkdir -p /tmp/.uci + for file in $files; do + ( . "./$file" ) && rm -f "$file" + done + uci commit +} + +boot() { + [ -f /proc/mounts ] || /sbin/mount_root + [ -f /proc/jffs2_bbc ] && echo "S" > /proc/jffs2_bbc + + mkdir -p /var/run + mkdir -p /var/log + mkdir -p /var/lock + mkdir -p /var/state + mkdir -p /var/tmp + mkdir -p /tmp/.uci + chmod 0700 /tmp/.uci + touch /var/log/wtmp + touch /var/log/lastlog + mkdir -p /tmp/resolv.conf.d + touch /tmp/resolv.conf.d/resolv.conf.auto + ln -sf /tmp/resolv.conf.d/resolv.conf.auto /tmp/resolv.conf + grep -q debugfs /proc/filesystems && /bin/mount -o noatime -t debugfs debugfs /sys/kernel/debug + grep -q bpf /proc/filesystems && /bin/mount -o nosuid,nodev,noexec,noatime,mode=0700 -t bpf bpffs /sys/fs/bpf + grep -q pstore /proc/filesystems && /bin/mount -o noatime -t pstore pstore /sys/fs/pstore + + # mount all entries in fstab + /bin/mount -a & + + # /log directory might be created on preinit + # symlink /storage to /log on TRB14X devices + [ -d /storage -a ! -h /log ] && { + rm -rf /log + ln -sf /storage /log + } + + # Wifi --- + param=$(/sbin/mnf_info "--name") + router_name=${param:0:6} + if [ $router_name == "RUTX08" ] || [ $router_name == "RUTX09" ]; then + rm /etc/modules.d/ath10k + fi + + /bin/board_detect + + /sbin/kmodloader + + /bin/config_generate + uci_apply_defaults + + [ -f "/etc/config/teltonika" ] && rm /etc/config/teltonika + + # temporary hack until configd exists + /sbin/reload_config + # leave finished boot script indication + touch /var/run/boot-done +} diff --git a/root/target/linux/ipq40xx/base-files/etc/init.d/done b/root/target/linux/ipq40xx/base-files/etc/init.d/done new file mode 100644 index 00000000..b64e6e4d --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/etc/init.d/done @@ -0,0 +1,13 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2006 OpenWrt.org + +START=95 +boot() { + mount_root done + rm -f /sysupgrade.tgz && sync + + # process user commands + [ -f /etc/rc.local ] && { + sh /etc/rc.local + } +} diff --git a/root/target/linux/ipq40xx/base-files/etc/init.d/gpio_switch b/root/target/linux/ipq40xx/base-files/etc/init.d/gpio_switch new file mode 100644 index 00000000..24d790b0 --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/etc/init.d/gpio_switch @@ -0,0 +1,66 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2015 OpenWrt.org + +START=94 +STOP=10 +USE_PROCD=1 + + +load_gpio_switch() +{ + local name + local gpio_pin + local value + + config_get gpio_pin "$1" gpio_pin + config_get name "$1" name + config_get value "$1" value 0 + + [ -z "$gpio_pin" ] && { + echo >&2 "Skipping gpio_switch '$name' due to missing gpio_pin" + return 1 + } + + local gpio_path + if [ -n "$(echo "$gpio_pin" | grep -E "^[0-9]+$")" ]; then + gpio_path="/sys/class/gpio/gpio${gpio_pin}" + + # export GPIO pin for access + [ -d "$gpio_path" ] || { + echo "$gpio_pin" >/sys/class/gpio/export + # we need to wait a bit until the GPIO appears + [ -d "$gpio_path" ] || sleep 1 + } + + # direction attribute only exists if the kernel supports changing the + # direction of a GPIO + if [ -e "${gpio_path}/direction" ]; then + # set the pin to output with high or low pin value + { [ "$value" = "0" ] && echo "low" || echo "high"; } \ + >"$gpio_path/direction" + else + { [ "$value" = "0" ] && echo "0" || echo "1"; } \ + >"$gpio_path/value" + fi + else + gpio_path="/sys/class/gpio/${gpio_pin}" + + [ -d "$gpio_path" ] && { + { [ "$value" = "0" ] && echo "0" || echo "1"; } \ + >"$gpio_path/value" + } + fi +} + +service_triggers() +{ + procd_add_reload_trigger "system" +} + +start_service() +{ + [ -e /sys/class/gpio/ ] && { + config_load system + config_foreach load_gpio_switch gpio_switch + } +} diff --git a/root/target/linux/ipq40xx/base-files/etc/init.d/led b/root/target/linux/ipq40xx/base-files/etc/init.d/led new file mode 100644 index 00000000..277fb4e7 --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/etc/init.d/led @@ -0,0 +1,140 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2008 OpenWrt.org + +START=96 + +load_led() { + local name + local sysfs + local trigger + local dev + local ports + local mode + local default + local delayon + local delayoff + local interval + + config_get sysfs $1 sysfs + config_get name $1 name "$sysfs" + config_get trigger $1 trigger "none" + config_get dev $1 dev + config_get ports $1 port + config_get mode $1 mode + config_get_bool default $1 default "0" + config_get delayon $1 delayon + config_get delayoff $1 delayoff + config_get interval $1 interval "50" + config_get port_state $1 port_state + config_get delay $1 delay "150" + config_get message $1 message "" + config_get gpio $1 gpio "0" + config_get inverted $1 inverted "0" + + if [ "$trigger" = "rssi" ]; then + # handled by rssileds userspace process + return + fi + + [ "$trigger" = "usbdev" ] && { + # Backward compatibility: translate to the new trigger + trigger="usbport" + # Translate port of root hub, e.g. 4-1 -> usb4-port1 + ports=$(echo "$dev" | sed -n 's/^\([0-9]*\)-\([0-9]*\)$/usb\1-port\2/p') + # Translate port of extra hub, e.g. 2-2.4 -> 2-2-port4 + [ -z "$ports" ] && ports=$(echo "$dev" | sed -n 's/\./-port/p') + } + + [ -e /sys/class/leds/${sysfs}/brightness ] && { + echo "setting up led ${name}" + + printf "%s %s %d\n" \ + "$sysfs" \ + "$(sed -ne 's/^.*\[\(.*\)\].*$/\1/p' /sys/class/leds/${sysfs}/trigger)" \ + "$(cat /sys/class/leds/${sysfs}/brightness)" \ + >> /var/run/led.state + + [ "$default" = 0 ] && + echo 0 >/sys/class/leds/${sysfs}/brightness + + echo $trigger > /sys/class/leds/${sysfs}/trigger 2> /dev/null + ret="$?" + + [ $default = 1 ] && + cat /sys/class/leds/${sysfs}/max_brightness > /sys/class/leds/${sysfs}/brightness + + [ $ret = 0 ] || { + echo >&2 "Skipping trigger '$trigger' for led '$name' due to missing kernel module" + return 1 + } + case "$trigger" in + "netdev") + [ -n "$dev" ] && { + echo $dev > /sys/class/leds/${sysfs}/device_name + for m in $mode; do + [ -e "/sys/class/leds/${sysfs}/$m" ] && \ + echo 1 > /sys/class/leds/${sysfs}/$m + done + echo $interval > /sys/class/leds/${sysfs}/interval + } + ;; + + "timer"|"oneshot") + [ -n "$delayon" ] && \ + echo $delayon > /sys/class/leds/${sysfs}/delay_on + [ -n "$delayoff" ] && \ + echo $delayoff > /sys/class/leds/${sysfs}/delay_off + ;; + + "usbport") + local p + + for p in $ports; do + echo 1 > /sys/class/leds/${sysfs}/ports/$p + done + ;; + + "port_state") + [ -n "$port_state" ] && \ + echo $port_state > /sys/class/leds/${sysfs}/port_state + ;; + + "gpio") + echo $gpio > /sys/class/leds/${sysfs}/gpio + echo $inverted > /sys/class/leds/${sysfs}/inverted + ;; + + switch[0-9]*) + local port_mask speed_mask + + config_get port_mask $1 port_mask + [ -n "$port_mask" ] && \ + echo $port_mask > /sys/class/leds/${sysfs}/port_mask + config_get speed_mask $1 speed_mask + [ -n "$speed_mask" ] && \ + echo $speed_mask > /sys/class/leds/${sysfs}/speed_mask + [ -n "$mode" ] && \ + echo "$mode" > /sys/class/leds/${sysfs}/mode + ;; + esac + } +} + +start() { + [ -e /sys/class/leds/ ] && { + [ -s /var/run/led.state ] && { + local led trigger brightness + while read led trigger brightness; do + [ -e "/sys/class/leds/$led/trigger" ] && \ + echo "$trigger" > "/sys/class/leds/$led/trigger" + + [ -e "/sys/class/leds/$led/brightness" ] && \ + echo "$brightness" > "/sys/class/leds/$led/brightness" + done < /var/run/led.state + rm /var/run/led.state + } + + config_load system + config_foreach load_led led + } +} diff --git a/root/target/linux/ipq40xx/base-files/etc/init.d/modem_tracker b/root/target/linux/ipq40xx/base-files/etc/init.d/modem_tracker new file mode 100644 index 00000000..46202b76 --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/etc/init.d/modem_tracker @@ -0,0 +1,37 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2021 Teltonika Networks +# Copyright (C) 2022 Ycarus (Yannick Chabanois) + +START=2 + +USE_PROCD=1 + +PROG=/bin/board_track +NAME=board_track +PIDCOUNT=1 + +start_service() { + . /lib/functions + + [ "$(board_name)" != "teltonika,rutx" ] && return 0 + local pid_file="/var/run/${NAME}.${PIDCOUNT}.pid" + + procd_open_instance + procd_set_param command "$PROG" + procd_set_param file /etc/config/system + + procd_set_param respawn + + procd_set_param stdout 1 + procd_set_param pidfile $pid_file + procd_close_instance +} + +reload_service() { + stop + start +} + +service_triggers() { + procd_add_reload_trigger "system" +} diff --git a/root/target/linux/ipq40xx/base-files/etc/init.d/ntpserver b/root/target/linux/ipq40xx/base-files/etc/init.d/ntpserver new file mode 100644 index 00000000..78095bd4 --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/etc/init.d/ntpserver @@ -0,0 +1,28 @@ +#!/bin/sh /etc/rc.common + +# Copyright (C) 2021 Teltonika + +START=50 +STOP=51 +USE_PROCD=1 + +service_triggers() +{ + procd_add_reload_trigger "ntpserver" +} + +start_service() { + . /lib/functions.sh + local enabled + + config_load ntpserver + config_get enabled general enabled "0" + + [ "$enabled" -gt 0 ] || return + + logger -t "ntpd" "Starting NTP server" + procd_open_instance + procd_set_param respawn 0 + procd_set_param command "ntpd" -ln + procd_close_instance +} diff --git a/root/target/linux/ipq40xx/base-files/etc/init.d/powerctl b/root/target/linux/ipq40xx/base-files/etc/init.d/powerctl new file mode 100644 index 00000000..7b346fc5 --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/etc/init.d/powerctl @@ -0,0 +1,32 @@ +#!/bin/sh /etc/rc.common + +START=98 + +ipq40xx_power_auto() { + # change scaling governor as ondemand to enable clock scaling based on system load + echo "performance" > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor + + # set scaling min freq as 200 MHz + echo "716000" > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq + + # Change sampling rate for frequency scaling decisions to 1s, from 10 ms + #echo "1000000" > /sys/devices/system/cpu/cpufreq/ondemand/sampling_rate + + # Change sampling rate for frequency down scaling decision to 10s + #echo 10 > /sys/devices/system/cpu/cpufreq/ondemand/sampling_down_factor + + # Change the CPU load threshold above which frequency is up-scaled to + # turbo frequency,to 50% + #echo 50 > /sys/devices/system/cpu/cpufreq/ondemand/up_threshold +} + +start() { + . /lib/functions.sh + + local board=$(board_name) + case "$board" in + teltonika,rutx | ap-dk01.1-c1 | ap-dk01.1-c2 | ap-dk04.1-c1 | ap-dk04.1-c2 | ap-dk04.1-c3 | \ + ap-dk04.1-c4 | ap-dk04.1-c5 | ap-dk05.1-c1 | ap-dk06.1-c1 | ap-dk07.1-c1 | ap-dk07.1-c2 | ap-dk07.1-c3) + ipq40xx_power_auto ;; + esac +} diff --git a/root/target/linux/ipq40xx/base-files/etc/init.d/set-irq-affinity b/root/target/linux/ipq40xx/base-files/etc/init.d/set-irq-affinity new file mode 100644 index 00000000..910f661b --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/etc/init.d/set-irq-affinity @@ -0,0 +1,22 @@ +#!/bin/sh /etc/rc.common + +START=99 + +start() { + mask=4 + for rps in /sys/class/net/eth0/queues/rx-* + do + echo "$mask" > "$rps/rps_cpus" + done + for irq in $(grep -F "ath10k_ahb" /proc/interrupts | cut -d: -f1 | sed 's, *,,') + do + echo "$mask" > "/proc/irq/$irq/smp_affinity" + mask=8 + done + + mask=2 + for irq in $(grep -F "edma_eth_rx" /proc/interrupts | cut -d: -f1 | sed 's, *,,') + do + echo "$mask" > "/proc/irq/$irq/smp_affinity" + done +} \ No newline at end of file diff --git a/root/target/linux/ipq40xx/base-files/etc/init.d/sysctl b/root/target/linux/ipq40xx/base-files/etc/init.d/sysctl new file mode 100644 index 00000000..01416a5c --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/etc/init.d/sysctl @@ -0,0 +1,46 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2006 OpenWrt.org + +START=11 + +apply_defaults() { + local mem="$(awk '/^MemTotal:/ {print $2}' /proc/meminfo)" + local min_free frag_low_thresh frag_high_thresh + + if [ "$mem" -gt 65536 ]; then # 128M + min_free=16384 + elif [ "$mem" -gt 32768 ]; then # 64M + #Too high for RUT3 device, lets make 2048 + #min_free=8192 + min_free=2048 + else + min_free=1024 + frag_low_thresh=393216 + frag_high_thresh=524288 + fi + + sysctl -qw vm.min_free_kbytes="$min_free" + + [ "$frag_low_thresh" ] && sysctl -qw \ + net.ipv4.ipfrag_low_thresh="$frag_low_thresh" \ + net.ipv4.ipfrag_high_thresh="$frag_high_thresh" \ + net.ipv6.ip6frag_low_thresh="$frag_low_thresh" \ + net.ipv6.ip6frag_high_thresh="$frag_high_thresh" \ + net.netfilter.nf_conntrack_frag6_low_thresh="$frag_low_thresh" \ + net.netfilter.nf_conntrack_frag6_high_thresh="$frag_high_thresh" + + # first set default, then all interfaces to avoid races with appearing interfaces + if [ -d /proc/sys/net/ipv6/conf ]; then + echo 0 > /proc/sys/net/ipv6/conf/default/accept_ra + for iface in /proc/sys/net/ipv6/conf/*/accept_ra; do + echo 0 > "$iface" + done + fi +} + +start() { + apply_defaults + for CONF in /etc/sysctl.d/*.conf /etc/sysctl.conf; do + [ -f "$CONF" ] && sysctl -e -p "$CONF" >&- + done +} diff --git a/root/target/linux/ipq40xx/base-files/etc/init.d/sysfixtime b/root/target/linux/ipq40xx/base-files/etc/init.d/sysfixtime new file mode 100644 index 00000000..47d7af61 --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/etc/init.d/sysfixtime @@ -0,0 +1,34 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2013-2014 OpenWrt.org + +START=00 +STOP=90 + +RTC_DEV=/dev/rtc0 +HWCLOCK=/sbin/hwclock + +boot() { +# start && exit 0 + + local maxtime="$(maxtime)" + local curtime="$(date +%s)" + [ $curtime -lt $maxtime ] && date -s @$maxtime +} + +start() { + boot +} + +stop() { + [ -e "$RTC_DEV" ] && [ -e "$HWCLOCK" ] && $HWCLOCK -w -u -f $RTC_DEV && \ + logger -t sysfixtime "saved '$(date)' to $RTC_DEV" +} + +maxtime() { + local file newest + + for file in $( find /etc -type f ) ; do + [ -z "$newest" -o "$newest" -ot "$file" ] && newest=$file + done + [ "$newest" ] && date -r "$newest" +%s +} diff --git a/root/target/linux/ipq40xx/base-files/etc/init.d/system b/root/target/linux/ipq40xx/base-files/etc/init.d/system new file mode 100644 index 00000000..0e467091 --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/etc/init.d/system @@ -0,0 +1,45 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2014 OpenWrt.org + +START=10 +USE_PROCD=1 + +validate_system_section() { + uci_load_validate system system "$1" "$2" \ + 'hostname:string:%%NAME%%' \ + 'conloglevel:uinteger' \ + 'buffersize:uinteger' \ + 'timezone:string:UTC' \ + 'zonename:string' +} + +system_config() { + [ "$2" = 0 ] || { + echo "validation failed" + return 1 + } + + echo "$hostname" > /proc/sys/kernel/hostname + [ -z "$conloglevel" -a -z "$buffersize" ] || dmesg ${conloglevel:+-n $conloglevel} ${buffersize:+-s $buffersize} + echo "$timezone" > /tmp/TZ + [ -n "$zonename" ] && [ -f "/usr/share/zoneinfo/${zonename// /_}" ] \ + && ln -sf "/usr/share/zoneinfo/${zonename// /_}" /tmp/localtime \ + && rm -f /tmp/TZ + + # apply timezone to kernel + hwclock -u --systz +} + +reload_service() { + config_load system + config_foreach validate_system_section system system_config +} + +service_triggers() { + procd_add_reload_trigger "system" + procd_add_validation validate_system_section +} + +start_service() { + reload_service +} diff --git a/root/target/linux/ipq40xx/base-files/etc/init.d/umount b/root/target/linux/ipq40xx/base-files/etc/init.d/umount new file mode 100644 index 00000000..b764ae15 --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/etc/init.d/umount @@ -0,0 +1,13 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2006 OpenWrt.org + +STOP=90 + +restart() { + : +} + +stop() { + sync + /bin/umount -a -d -r +} diff --git a/root/target/linux/ipq40xx/base-files/lib/functions/teltonika-defaults.sh b/root/target/linux/ipq40xx/base-files/lib/functions/teltonika-defaults.sh new file mode 100644 index 00000000..5cb17a99 --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/lib/functions/teltonika-defaults.sh @@ -0,0 +1,284 @@ +#!/bin/ash + +. /lib/functions.sh +. /usr/share/libubox/jshn.sh + +ucidef_add_nand_info() { + local model="$1" + + model=${model:0:7} + + json_select_object nand + + case "$model" in + TRB1412) + json_add_int blocksize 128 + json_add_int pagesize 2048 + json_add_int subpagesize 2048 + ;; + TRB1422 |\ + TRB1423 |\ + TRB1452) + json_add_int blocksize 256 + json_add_int pagesize 4096 + json_add_int subpagesize 4096 + ;; + TRB14*0) + json_add_int blocksize 128 + json_add_int pagesize 2048 + json_add_int subpagesize 2048 + ;; + TRB14*1) + json_add_int blocksize 256 + json_add_int pagesize 4096 + json_add_int subpagesize 4096 + ;; + esac + + json_select .. +} + +ucidef_add_static_modem_info() { + #Parameters: model usb_id sim_count other_params + local model usb_id count + local modem_counter=0 + local sim_count=1 + + model="$1" + usb_id="$2" + + [ -n "$3" ] && sim_count="$3" + + json_get_keys count modems + [ -n "$count" ] && modem_counter="$(echo "$count" | wc -w)" + + json_select_array "modems" + json_add_object + json_add_string id "$usb_id" + json_add_string num "$((modem_counter + 1))" + json_add_boolean builtin 1 + json_add_int simcount "$sim_count" + + for i in "$@"; do + case "$i" in + primary) + json_add_boolean primary 1 + ;; + gps_out) + json_add_boolean gps_out 1 + ;; + esac + done + + json_close_object + json_select .. +} + +ucidef_add_trb14x_lte_modem() { + print_array() { + json_add_array $1 + for element in $2 + do + json_add_string "" "$(echo $element)" + done + json_close_array + } + #Parameters: model primary + local model vendor product boudrate gps type desc control region modem_counter + modem_counter=1 + json_select_array "modems" + + model="$1" + + model=${model:0:7} + + case "$model" in + TRB1422) + vendor=05c6 + product=9215 + ;; + TRB1412 |\ + TRB1423 |\ + TRB1452 |\ + TRB140*) + vendor=2c7c + product=0125 + ;; + TRB14*) + vendor=2c7c + product=0121 + ;; + esac + + case "$model" in + TRB1412 |\ + TRB14*0) + region="EU" + [ "$product" = "0121" ] && { + lte_bands="1 3 7 8 20 28" + trysg_bands="wcdma_2100 wcdma_900" + dug_bands="gsm_1800 gsm_900" + } + [ "$product" = "0125" ] && { + lte_bands="1 3 7 8 20 28 38 40 41" + trysg_bands="wcdma_2100 wcdma_900" + dug_bands="gsm_1800 gsm_900" + } + ;; + TRB1422) + region="CE" + lte_bands="1 3 5 8 34 38 39 40 41" + trysg_bands="bc-0-a-system bc-0-b-system wcdma_2100 wcdma_900" + dug_bands="gsm_1800 gsm_900" + ;; + TRB1423 |\ + TRB1452 |\ + TRB14*1) + region="AU" + [ "$product" = "0121" ] && { + lte_bands="1 2 3 4 5 7 8 28 40" + trysg_bands="wcdma_2100 wcdma_1900 wcdma_900 wcdma_850" + dug_bands="gsm_1800 gsm_900 gsm_850 gsm_1900" + } + [ "$product" = "0125" ] && { + lte_bands="1 2 3 4 5 7 8 28 40" + trysg_bands="wcdma_2100 wcdma_1900 wcdma_900 wcdma_850" + dug_bands="gsm_1800 gsm_900 gsm_850 gsm_1900" + } + ;; + esac + + [ -f "/lib/network/wwan/$vendor:$product" ] && { + devicename="3-1" + json_set_namespace defaults old_cb + json_load "$(cat /lib/network/wwan/$vendor:$product)" + json_get_vars gps boudrate type desc control stop_bits + json_set_namespace $old_cb + + [ "${devicename%%:*}" = "$devicename" ] && { + json_add_object + json_add_string id "$devicename" + json_add_string num "$modem_counter" + json_add_string vendor "$vendor" + json_add_string product "$product" + json_add_string stop_bits "$stop_bits" + json_add_string gps "$gps" + json_add_string boudrate "$boudrate" + json_add_string type "$type" + json_add_string desc "$desc" + json_add_string region "$region" + json_add_string control "$control" + json_add_int simcount 1 + json_add_boolean builtin 1 + [ -n "$2" ] && json_add_boolean primary 1 + json_add_object service_modes + [ -z "$lte_bands" ] || print_array "4G" "$lte_bands" + [ -z "$trysg_bands" ] || print_array "3G" "$trysg_bands" + [ -z "$dug_bands" ] || print_array "2G" "$dug_bands" + json_close_object + json_close_object + } + } + json_select .. +} + +ucidef_add_serial_capabilities() { + json_select_array serial + json_add_object + [ -n "$1" ] && { + json_select_array devices + for d in $1; do + json_add_string "" $d + done + json_select .. + } + + json_select_array bauds + for b in $2; do + json_add_string "" $b + done + json_select .. + + json_select_array data_bits + for n in $3; do + json_add_string "" $n + done + json_select .. + json_close_object + json_select .. +} + +ucidef_set_hwinfo() { + local function + local dual_sim=0 + local wifi=0 + local dual_band_ssid=0 + local wps=0 + local mobile=0 + local gps=0 + local usb=0 + local bluetooth=0 + local ethernet=0 + local sfp_port=0 + local ios=0 + + for function in "$@"; do + case "$function" in + dual_sim) + dual_sim=1 + ;; + wifi) + wifi=1 + ;; + dual_band_ssid) + dual_band_ssid=1 + ;; + wps) + wps=1 + ;; + mobile) + mobile=1 + ;; + gps) + gps=1 + ;; + usb) + usb=1 + ;; + bluetooth) + bluetooth=1 + ;; + ethernet) + ethernet=1 + ;; + sfp_port) + sfp_port=1 + ;; + ios) + ios=1 + ;; + at_sim) + at_sim=1 + ;; + esac + done + + json_select_object hwinfo + json_add_boolean dual_sim "$dual_sim" + json_add_boolean usb "$usb" + json_add_boolean bluetooth "$bluetooth" + json_add_boolean wifi "$wifi" + json_add_boolean dual_band_ssid "$dual_band_ssid" + json_add_boolean wps "$wps" + json_add_boolean mobile "$mobile" + json_add_boolean gps "$gps" + json_add_boolean ethernet "$ethernet" + json_add_boolean sfp_port "$sfp_port" + json_add_boolean ios "$ios" + json_add_boolean at_sim "$at_sim" + json_select .. +} + +ucidef_set_release_version() { + json_add_string release_version "$1" +} diff --git a/root/target/linux/ipq40xx/base-files/lib/functions/teltonika-functions.sh b/root/target/linux/ipq40xx/base-files/lib/functions/teltonika-functions.sh new file mode 100644 index 00000000..5381f81f --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/lib/functions/teltonika-functions.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +. /usr/share/libubox/jshn.sh + +is_ios_enabled() { + local ios + json_load_file "/etc/board.json" && \ + json_select hwinfo && \ + json_get_var ios ios && [ "$ios" = "1" ] +} diff --git a/root/target/linux/ipq40xx/base-files/lib/upgrade/stage2 b/root/target/linux/ipq40xx/base-files/lib/upgrade/stage2 new file mode 100644 index 00000000..93792413 --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/lib/upgrade/stage2 @@ -0,0 +1,138 @@ +#!/bin/sh + +. /lib/functions.sh +. /lib/functions/system.sh + +export IMAGE="$1" +COMMAND="$2" + +export INTERACTIVE=0 +export VERBOSE=1 +export CONFFILES=/tmp/sysupgrade.conffiles + +RAMFS_COPY_BIN= # extra programs for temporary ramfs root +RAMFS_COPY_DATA= # extra data files + +include /lib/upgrade + + +supivot() { # + /bin/mount | grep "on $1 type" 2>&- 1>&- || /bin/mount -o bind $1 $1 + mkdir -p $1$2 $1/proc $1/sys $1/dev $1/tmp $1/overlay && \ + /bin/mount -o noatime,move /proc $1/proc && \ + pivot_root $1 $1$2 || { + /bin/umount -l $1 $1 + return 1 + } + + /bin/mount -o noatime,move $2/sys /sys + /bin/mount -o noatime,move $2/dev /dev + /bin/mount -o noatime,move $2/tmp /tmp + /bin/mount -o noatime,move $2/overlay /overlay 2>&- + return 0 +} + +switch_to_ramfs() { + for binary in \ + /bin/busybox /bin/ash /bin/sh /bin/mount /bin/umount \ + pivot_root mount_root reboot sync kill sleep \ + md5sum hexdump cat zcat bzcat dd tar \ + ls basename find cp mv rm mkdir rmdir mknod touch chmod \ + '[' printf wc grep awk sed cut \ + mtd partx losetup mkfs.ext4 nandwrite flash_erase \ + ubiupdatevol ubiattach ubiblock ubiformat \ + ubidetach ubirsvol ubirmvol ubimkvol \ + snapshot snapshot_tool date \ + dumpimage $RAMFS_COPY_BIN + do + local file="$(command -v "$binary" 2>/dev/null)" + [ -n "$file" ] && install_bin "$file" + done + install_file /etc/resolv.conf /lib/*.sh /lib/functions/*.sh /lib/upgrade/*.sh /lib/upgrade/do_stage2 /usr/share/libubox/jshn.sh $RAMFS_COPY_DATA + + [ -L "/lib64" ] && ln -s /lib $RAM_ROOT/lib64 + + supivot $RAM_ROOT /mnt || { + v "Failed to switch over to ramfs. Please reboot." + exit 1 + } + + /bin/mount -o remount,ro /mnt + /bin/umount -l /mnt + + grep /overlay /proc/mounts > /dev/null && { + /bin/mount -o noatime,remount,ro /overlay + /bin/umount -l /overlay + } +} + +kill_remaining() { # [ [ ] ] + local loop_limit=10 + + local sig="${1:-TERM}" + local loop="${2:-0}" + local run=true + local stat + local proc_ppid=$(cut -d' ' -f4 /proc/$$/stat) + + vn "Sending $sig to remaining processes ..." + + while $run; do + run=false + for stat in /proc/[0-9]*/stat; do + [ -f "$stat" ] || continue + + local pid name state ppid rest + read pid name state ppid rest < $stat + name="${name#(}"; name="${name%)}" + + # Skip PID1, our parent, ourself and our children + [ $pid -ne 1 -a $pid -ne $proc_ppid -a $pid -ne $$ -a $ppid -ne $$ ] || continue + + local cmdline + read cmdline < /proc/$pid/cmdline + + # Skip kernel threads + [ -n "$cmdline" ] || continue + + _vn " $name" + kill -$sig $pid 2>/dev/null + + [ $loop -eq 1 ] && run=true + done + + let loop_limit-- + [ $loop_limit -eq 0 ] && { + _v + v "Failed to kill all processes." + exit 1 + } + done + _v +} + +indicate_upgrade + +killall -9 telnetd +killall -9 dropbear +killall -9 ash + +kill_remaining TERM +sleep 3 +kill_remaining KILL 1 + +sleep 1 + +echo 3 > /proc/sys/vm/drop_caches + +if [ -n "$IMAGE" ] && type 'platform_pre_upgrade' >/dev/null 2>/dev/null; then + platform_pre_upgrade "$IMAGE" +fi + +if [ -n "$(rootfs_type)" ]; then + v "Switching to ramdisk..." + switch_to_ramfs +fi + +# Exec new shell from ramfs +exec /bin/busybox ash -c "$COMMAND" diff --git a/root/target/linux/ipq40xx/base-files/sbin/mctl b/root/target/linux/ipq40xx/base-files/sbin/mctl new file mode 100644 index 00000000..f501cc2e --- /dev/null +++ b/root/target/linux/ipq40xx/base-files/sbin/mctl @@ -0,0 +1,120 @@ +#!/bin/sh + +. /usr/share/libubox/jshn.sh + +PS_ON=1 +PS_OFF=2 + +MPS=0 +MLBL="modem" + +modem_reset() { + local label="$1" + + [ -e "/sys/class/gpio/${label}_reset/value" ] || return + + echo 1 > "/sys/class/gpio/${label}_reset/value" + sleep 1 + echo 0 > "/sys/class/gpio/${label}_reset/value" +} + +modem_off() { + local label="$1" + + [ -e "/sys/class/gpio/${label}_reset/value" ] || return + + echo 1 > "/sys/class/gpio/${label}_reset/value" +} + +modem_power() { + local label="$1" + + [ -e "/sys/class/gpio/${label}_power/value" ] || return + + # simulate power press + echo 1 > "/sys/class/gpio/${label}_power/value" + sleep 1 + echo 0 > "/sys/class/gpio/${label}_power/value" +} + +modem_list() { + local list="modem" + local label + + [ "$(modem_fetch_primary)" -eq 0 ] && { + echo "${list}" + return + } + + for m in /sys/class/gpio/modem*_power; do + label="$(basename $m | awk -F_ '{print $1}')" + [ "${label}" != "modem" ] && list="${list},${label}" + done + + echo "${list}" +} + +modem_fetch_primary() { + local modem modems primary + + json_init + json_load_file "/etc/board.json" + + json_get_keys modems modems + json_select modems + + for modem in $modems; do + json_select "$modem" + json_get_vars primary + + [ -n "$primary" ] && { + echo 1 + return + } + + json_select .. + done + echo 0 +} + +modem_is_available() { + local label="$1" + [ -e "/sys/class/gpio/${label}_power/value" ] +} + +usage() { + cat < +Control modem power state. + +Options: + -p, --power-on power on modem + -s, --shutdown shutdown modem + -r, --reboot reboot modem + -m, --modem