diff --git a/platform/broadcom/rules.mk b/platform/broadcom/rules.mk index 582af46b86..c7fa0f7aa8 100755 --- a/platform/broadcom/rules.mk +++ b/platform/broadcom/rules.mk @@ -1,4 +1,4 @@ -include $(PLATFORM_PATH)/sdk.mk +include $(PLATFORM_PATH)/sai-modules.mk include $(PLATFORM_PATH)/sai.mk include $(PLATFORM_PATH)/platform-modules-s6000.mk include $(PLATFORM_PATH)/platform-modules-dell.mk diff --git a/platform/broadcom/sai-modules.mk b/platform/broadcom/sai-modules.mk new file mode 100644 index 0000000000..31cd5996ef --- /dev/null +++ b/platform/broadcom/sai-modules.mk @@ -0,0 +1,11 @@ +# Broadcom SAI modules + +KVERSION = 4.9.0-5-amd64 +BRCM_OPENNSL_KERNEL_VERSION = 3.4.1.11-1 + +BRCM_OPENNSL_KERNEL = opennsl-modules-$(KVERSION)_$(BRCM_OPENNSL_KERNEL_VERSION)_amd64.deb +$(BRCM_OPENNSL_KERNEL)_SRC_PATH = $(PLATFORM_PATH)/saibcm-modules +$(BRCM_OPENNSL_KERNEL)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) +SONIC_DPKG_DEBS += $(BRCM_OPENNSL_KERNEL) + +SONIC_STRETCH_DEBS += $(BRCM_OPENNSL_KERNEL) diff --git a/platform/broadcom/saibcm-modules/.gitignore b/platform/broadcom/saibcm-modules/.gitignore new file mode 100644 index 0000000000..338005f50c --- /dev/null +++ b/platform/broadcom/saibcm-modules/.gitignore @@ -0,0 +1,4 @@ +*.debhelper.log +*.debhelper +*.substvars +*.ko diff --git a/platform/broadcom/saibcm-modules/debian/changelog b/platform/broadcom/saibcm-modules/debian/changelog new file mode 100644 index 0000000000..5ea7b289ee --- /dev/null +++ b/platform/broadcom/saibcm-modules/debian/changelog @@ -0,0 +1,48 @@ +opennsl (3.4.1.11-1) unstable; urgency=medium + + * Port Broadcom SAI 3.4.1.11 + * Cherry-pick change from master branch, 3.4.1.11-1 + + -- Ying Xie Fri, 05 Jan 2018 23:21:47 +0000 + +opennsl (3.4.1.10-1) unstable; urgency=medium + + * Upgrade to 3.4.1.10-1 + + -- Ying Xie Tue, 19 Dec 2017 21:33:48 +0000 + +opennsl (3.4.1.9-1) unstable; urgency=medium + + * Upgrade to 3.4.1.9-1 + + -- Ying Xie Thu, 14 Dec 2017 22:04:11 +0000 + +opennsl (3.4.1.7-2) unstable; urgency=medium + + * Add Arista 7260cx3 Rev2 hardware support + + -- Ying Xie Mon, 27 Nov 2017 18:13:50 +0000 + +opennsl (3.4.1.7-1) unstable; urgency=medium + + * Importing opennsl 3.4.1.7 + + -- Ying Xie Mon, 23 Oct 2017 23:47:25 +0000 + +opennsl (3.4.1.5-2) unstable; urgency=medium + + * Importing TD2 changes from opennsl 3.2.2.2 + + -- Ying Xie Tue, 26 Sep 2017 01:28:44 +0000 + +opennsl (3.4.1.5-1) unstable; urgency=medium + + * Importing opennsl 3.4.1.5 + + -- Ying Xie Wed, 20 Sep 2017 16:42:12 +0000 + +opennsl (3.4.1.3-1) unstable; urgency=low + + * Initial release + + -- Guohan Lu Fri, 17 Jul 2015 04:46:01 -0700 diff --git a/platform/broadcom/saibcm-modules/debian/compat b/platform/broadcom/saibcm-modules/debian/compat new file mode 100644 index 0000000000..45a4fb75db --- /dev/null +++ b/platform/broadcom/saibcm-modules/debian/compat @@ -0,0 +1 @@ +8 diff --git a/platform/broadcom/saibcm-modules/debian/control b/platform/broadcom/saibcm-modules/debian/control new file mode 100644 index 0000000000..e84d6de9fd --- /dev/null +++ b/platform/broadcom/saibcm-modules/debian/control @@ -0,0 +1,14 @@ +Source: opennsl +Section: main +Priority: extra +Maintainer: Guohan Lu +Build-Depends: debhelper (>= 8.0.0), bzip2 +Standards-Version: 3.9.3 +#Vcs-Git: git://git.debian.org/collab-maint/bcmsdk.git +#Vcs-Browser: http://git.debian.org/?p=collab-maint/bcmsdk.git;a=summary + +Package: opennsl-modules-4.9.0-5-amd64 +Architecture: amd64 +Section: main +Depends: linux-image-4.9.0-5-amd64 +Description: kernel modules for broadcom SAI diff --git a/platform/broadcom/saibcm-modules/debian/opennsl-modules-4.9.0-5-amd64.dirs b/platform/broadcom/saibcm-modules/debian/opennsl-modules-4.9.0-5-amd64.dirs new file mode 100644 index 0000000000..30ebf9851e --- /dev/null +++ b/platform/broadcom/saibcm-modules/debian/opennsl-modules-4.9.0-5-amd64.dirs @@ -0,0 +1 @@ +lib/modules/4.9.0-5-amd64/extra diff --git a/platform/broadcom/saibcm-modules/debian/opennsl-modules-4.9.0-5-amd64.init b/platform/broadcom/saibcm-modules/debian/opennsl-modules-4.9.0-5-amd64.init new file mode 100755 index 0000000000..07a6f83475 --- /dev/null +++ b/platform/broadcom/saibcm-modules/debian/opennsl-modules-4.9.0-5-amd64.init @@ -0,0 +1,47 @@ +#!/bin/bash +# This script load/unload opennsl kernel modules + +### BEGIN INIT INFO +# Provides: load-opennsl-modules +# Required-Start: +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: S +# Default-Stop: 0 6 +# Short-Description: Load OpenNSL kernel modules +### END INIT INFO + +case "$1" in +start) + echo -n "Load OpenNSL kernel modules... " + + modprobe linux-kernel-bde dmasize=32M maxpayload=128 + modprobe linux-user-bde + modprobe linux-bcm-knet use_rx_skb=1 rx_buffer_size=9238 + + echo "done." + ;; + +stop) + echo -n "Unload OpenNSL kernel modules... " + + rmmod linux-bcm-knet + rmmod linux-user-bde + rmmod linux-kernel-bde + + echo "done." + ;; + +force-reload|restart) + echo "Not supported" + ;; + +*) + echo "Usage: /etc/init.d/opennsl-modules-4.9.0-5-amd64.init {start|stop}" + exit 1 + ;; +esac + +exit 0 + diff --git a/platform/broadcom/saibcm-modules/debian/opennsl-modules-4.9.0-5-amd64.install b/platform/broadcom/saibcm-modules/debian/opennsl-modules-4.9.0-5-amd64.install new file mode 100644 index 0000000000..d79178a4a5 --- /dev/null +++ b/platform/broadcom/saibcm-modules/debian/opennsl-modules-4.9.0-5-amd64.install @@ -0,0 +1,4 @@ +systems/linux/user/x86-smp_generic_64-2_6/linux-bcm-knet.ko lib/modules/4.9.0-5-amd64/extra +systems/linux/user/x86-smp_generic_64-2_6/linux-kernel-bde.ko lib/modules/4.9.0-5-amd64/extra +systems/linux/user/x86-smp_generic_64-2_6/linux-user-bde.ko lib/modules/4.9.0-5-amd64/extra +systemd/opennsl-modules-4.9.0-5-amd64.service lib/systemd/system diff --git a/platform/broadcom/saibcm-modules/debian/rules b/platform/broadcom/saibcm-modules/debian/rules new file mode 100755 index 0000000000..231c52aa8c --- /dev/null +++ b/platform/broadcom/saibcm-modules/debian/rules @@ -0,0 +1,183 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. +# +# This version is for a hypothetical package that can build a kernel modules +# architecture-dependant package via make-kpkg, as well as an +# architecture-independent module source package, and other packages +# either dep/indep for things like common files or userspace components +# needed for the kernel modules. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + + + + +# some default definitions, important! +# +# Name of the source package +psource:=opennsl-source + +# The short upstream name, used for the module source directory +sname:=opennsl + +### KERNEL SETUP +### Setup the stuff needed for making kernel module packages +### taken from /usr/share/kernel-package/sample.module.rules + +# prefix of the target package name +PACKAGE=opennsl-modules +# modifieable for experiments or debugging m-a +MA_DIR ?= /usr/share/modass +# load generic variable handling +-include $(MA_DIR)/include/generic.make +# load default rules, including kdist, kdist_image, ... +-include $(MA_DIR)/include/common-rules.make + + + +# module assistant calculates all needed things for us and sets +# following variables: +# KSRC (kernel source directory), KVERS (kernel version string), KDREV +# (revision of the Debian kernel-image package), CC (the correct +# compiler), VERSION (the final package version string), PKGNAME (full +# package name with KVERS included), DEB_DESTDIR (path to store DEBs) + +# The kdist_config target is called by make-kpkg modules_config and +# by kdist* rules by dependency. It should configure the module so it is +# ready for compilation (mostly useful for calling configure). +# prep-deb-files from module-assistant creates the neccessary debian/ files +kdist_config: prep-deb-files + +# the kdist_clean target is called by make-kpkg modules_clean and from +# kdist* rules. It is responsible for cleaning up any changes that have +# been made by the other kdist_commands (except for the .deb files created) +kdist_clean: clean + dh_testdir + dh_clean + SDK=$(realpath .) LINUX_UAPI_SPLIT=1 DEBIAN_LINUX_HEADER=1 KERNDIR=/usr/src/linux-headers-4.9.0-5-amd64 KERNEL_SRC=/usr/src/linux-headers-4.9.0-5-amd64 $(MAKE) -C systems/linux/user/x86-smp_generic_64-2_6 clean +# rm -f driver/*.o driver/*.ko +# +### end KERNEL SETUP + +configure: configure-stamp +configure-stamp: + dh_testdir + # Add here commands to configure the package. + + touch configure-stamp + + +build-arch: configure-stamp build-arch-stamp +build-arch-stamp: + dh_testdir + + # Add here command to compile/build the package. + SDK=$(realpath .) LINUX_UAPI_SPLIT=1 DEBIAN_LINUX_HEADER=1 KERNDIR=/usr/src/linux-headers-4.9.0-5-amd64 KERNEL_SRC=/usr/src/linux-headers-4.9.0-5-amd64 $(MAKE) -C systems/linux/user/x86-smp_generic_64-2_6 + + touch $@ + +#k = $(shell echo $(KVERS) | grep -q ^2.6 && echo k) + +build-indep: configure-stamp build-indep-stamp +build-indep-stamp: + dh_testdir + + # Add here command to compile/build the arch indep package. + # It's ok not to do anything here, if you don't need to build + # anything for this package. + #docbook-to-man debian/opennsl.sgml > opennsl.1 + + touch $@ + +build: build-arch + +clean: + dh_testdir + #dh_testroot + rm -f build-arch-stamp build-indep-stamp configure-stamp + + # Add here commands to clean up after the build process. + SDK=$(realpath .) LINUX_UAPI_SPLIT=1 DEBIAN_LINUX_HEADER=1 KERNDIR=/usr/src/linux-headers-4.9.0-5-amd64 KERNEL_SRC=/usr/src/linux-headers-4.9.0-5-amd64 $(MAKE) -C systems/linux/user/x86-smp_generic_64-2_6 clean + + dh_clean + +install: DH_OPTIONS= +install: build + dh_testdir + dh_testroot + dh_prep + dh_installdirs + dh_install + +# Build architecture-independent files here. +# Pass -i to all debhelper commands in this target to reduce clutter. +binary-indep: build install + dh_testdir -i + dh_testroot -i + dh_installchangelogs -i + dh_installdocs -i + dh_installexamples -i +# dh_install -i +# dh_installmenu -i +# dh_installdebconf -i +# dh_installlogrotate -i +# dh_installemacsen -i +# dh_installpam -i +# dh_installmime -i +# dh_installinit -i +# dh_installcron -i +# dh_installinfo -i + dh_installman -i + dh_link -i + dh_compress -i + dh_fixperms -i + dh_installdeb -i +# dh_perl -i +# dh_makeshlibs -i + dh_installdeb -i + dh_shlibdeps -i + dh_gencontrol -i + dh_md5sums -i + dh_builddeb -i + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir -s + dh_testroot -s +# dh_installdebconf -s + + dh_installdocs -s + dh_installexamples -s + dh_installmenu -s +# dh_installlogrotate -s +# dh_installemacsen -s +# dh_installpam -s +# dh_installmime -s + dh_installmodules -s + dh_systemd_enable -s + dh_installinit -s + dh_systemd_start -s + dh_installcron -s +# dh_installman -s + dh_installinfo -s + dh_installchangelogs -s + dh_strip -s + dh_link -s + dh_compress -s + dh_fixperms -s + dh_makeshlibs -s + dh_installdeb -s +# dh_perl -s + dh_shlibdeps -s + dh_gencontrol -s + dh_md5sums -s + dh_builddeb -s + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure binary-modules kdist kdist_configure kdist_image kdist_clean diff --git a/platform/broadcom/saibcm-modules/include/ibde.h b/platform/broadcom/saibcm-modules/include/ibde.h new file mode 100644 index 0000000000..c022e0b95a --- /dev/null +++ b/platform/broadcom/saibcm-modules/include/ibde.h @@ -0,0 +1,158 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: ibde.h,v 1.27 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ + +#ifndef __IBDE_H__ +#define __IBDE_H__ + +#include + +/* + * Represents a collection of devices + */ + +typedef struct ibde_dev_s { + uint16 device; + uint8 rev; + sal_vaddr_t base_address; + sal_vaddr_t base_address1; + sal_vaddr_t base_address2; +} ibde_dev_t; + + +typedef struct ibde_s { + + const char *(*name)(void); + + /* Returns the number of devices available */ + /* Each device is is accessed through a handle */ + /* Handles are assumed to index the array of devices */ + + /* Support SWITCH or ETHERNET or CPU devices */ + int (*num_devices)(int type); +#define BDE_ALL_DEVICES 0 +#define BDE_SWITCH_DEVICES 1 +#define BDE_ETHER_DEVICES 2 +#define BDE_CPU_DEVICES 3 + + const ibde_dev_t *(*get_dev)(int d); + + /* + * Get types of underlaying devices. + * A combination of bus type and functional type is returned. + * In case of bus type, support PCI and SPI device types. + * In case of functional type, specify if underlaying device is + * a switching or ethernet device. + */ + uint32 (*get_dev_type)(int d); +#define BDE_PCI_DEV_TYPE SAL_PCI_DEV_TYPE /* PCI device */ +#define BDE_SPI_DEV_TYPE SAL_SPI_DEV_TYPE /* SPI device */ +#define BDE_EB_DEV_TYPE SAL_EB_DEV_TYPE /* EB device */ +#define BDE_ICS_DEV_TYPE SAL_ICS_DEV_TYPE /* ICS device */ +#define BDE_MII_DEV_TYPE SAL_MII_DEV_TYPE /* MII device */ +#define BDE_I2C_DEV_TYPE SAL_I2C_DEV_TYPE /* I2C device */ +#define BDE_AXI_DEV_TYPE SAL_AXI_DEV_TYPE /* AXI device */ +#define BDE_EMMI_DEV_TYPE SAL_EMMI_DEV_TYPE /* EMMI device */ +#define BDE_DEV_BUS_ALT SAL_DEV_BUS_ALT /* Alternate Access */ +#define BDE_DEV_BUS_MSI SAL_DEV_BUS_MSI /* Message-signaled interrupts */ + +#define BDE_DEV_BUS_TYPE_MASK SAL_DEV_BUS_TYPE_MASK + +#define BDE_SWITCH_DEV_TYPE SAL_SWITCH_DEV_TYPE /* Switch device */ +#define BDE_ETHER_DEV_TYPE SAL_ETHER_DEV_TYPE /* Ethernet device */ +#define BDE_CPU_DEV_TYPE SAL_CPU_DEV_TYPE /* CPU device */ + +#define BDE_BYTE_SWAP 0x01000000 /* SW byte swap */ +#define BDE_NO_IPROC 0x02000000 /* Device uses two BARs, but is not iProc */ + +#define BDE_256K_REG_SPACE 0x20000000 /* Map 256K (v 64K) */ +#define BDE_128K_REG_SPACE 0x40000000 /* Map 128K (v 64K) */ +#define BDE_320K_REG_SPACE 0x80000000 /* Map 256K+64K */ + +/* Bus supports only 16bit reads */ +#define BDE_DEV_BUS_RD_16BIT SAL_DEV_BUS_RD_16BIT + +/* Bus supports only 16bit writes */ +#define BDE_DEV_BUS_WR_16BIT SAL_DEV_BUS_WR_16BIT + +/* Backward compatibility */ +#define BDE_ET_DEV_TYPE BDE_MII_DEV_TYPE + +#define BDE_DEV_MEM_MAPPED(_d) \ + ((_d) & (BDE_PCI_DEV_TYPE | BDE_ICS_DEV_TYPE | BDE_EB_DEV_TYPE |\ + BDE_EMMI_DEV_TYPE | BDE_AXI_DEV_TYPE)) + + /* + * PCI Bus Access + */ + uint32 (*pci_conf_read)(int d, uint32 addr); + int (*pci_conf_write)(int d, uint32 addr, uint32 data); + void (*pci_bus_features)(int d, int *be_pio, int *be_packet, + int *be_other); + + uint32 (*read)(int d, uint32 addr); + int (*write)(int d, uint32 addr, uint32 data); + + uint32* (*salloc)(int d, int size, const char *name); + void (*sfree)(int d, void *ptr); + int (*sflush)(int d, void *addr, int length); + int (*sinval)(int d, void *addr, int length); + + int (*interrupt_connect)(int d, void (*)(void*), void *data); + int (*interrupt_disconnect)(int d); + + sal_paddr_t (*l2p)(int d, void *laddr); + void* (*p2l)(int d, sal_paddr_t paddr); + + /* + * SPI Access via SMP + */ + int (*spi_read)(int d, uint32 addr, uint8 *buf, int len); + int (*spi_write)(int d, uint32 addr, uint8 *buf, int len); + /* Special SPI access addresses */ +#define BDE_DEV_OP_EMMI_INIT SAL_DEV_OP_EMMI_INIT + + /* + * iProc register access + */ + uint32 (*iproc_read)(int d, uint32 addr); + int (*iproc_write)(int d, uint32 addr, uint32 data); + + /* + * Shared memory access + */ + uint32 (*shmem_read)(int dev, uint32 addr, uint8 *buf, uint32 len); + void (*shmem_write)(int dev, uint32 addr, uint8 *buf, uint32 len); + sal_vaddr_t (*shmem_map)(int dev, uint32 addr, uint32 size); + + /* + * cmic + */ + int (*get_cmic_ver)(int d, uint32 *ver); + +} ibde_t; + + +/* System BDE */ +extern ibde_t *bde; + + +#endif /* __IBDE_H__ */ diff --git a/platform/broadcom/saibcm-modules/include/kcom.h b/platform/broadcom/saibcm-modules/include/kcom.h new file mode 100644 index 0000000000..5755df250f --- /dev/null +++ b/platform/broadcom/saibcm-modules/include/kcom.h @@ -0,0 +1,541 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: kcom.h,v 1.9 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + * + * File: kcom.h + * Purpose: User/Kernel message definitions + */ + +#ifndef _KCOM_H +#define _KCOM_H + +#include + +#define KCOM_CHAN_KNET "KCOM_KNET" + +/* + * Message types + */ +#define KCOM_MSG_TYPE_CMD 1 /* Command */ +#define KCOM_MSG_TYPE_RSP 2 /* Command response */ +#define KCOM_MSG_TYPE_EVT 3 /* Unsolicited event */ + + +/* + * Message opcodes + */ +#define KCOM_M_NONE 0 /* Should not be used */ +#define KCOM_M_VERSION 1 /* Protocol version */ +#define KCOM_M_STRING 2 /* For debug messages */ +#define KCOM_M_HW_RESET 3 /* H/W not ready */ +#define KCOM_M_HW_INIT 4 /* H/W initialized */ +#define KCOM_M_ETH_HW_CONFIG 5 /* ETH HW config*/ +#define KCOM_M_DETACH 6 /* Detach kernel module */ +#define KCOM_M_NETIF_CREATE 11 /* Create network interface */ +#define KCOM_M_NETIF_DESTROY 12 /* Destroy network interface */ +#define KCOM_M_NETIF_LIST 13 /* Get list of network interface IDs */ +#define KCOM_M_NETIF_GET 14 /* Get network interface info */ +#define KCOM_M_FILTER_CREATE 21 /* Create Rx filter */ +#define KCOM_M_FILTER_DESTROY 22 /* Destroy Rx filter */ +#define KCOM_M_FILTER_LIST 23 /* Get list of Rx filter IDs */ +#define KCOM_M_FILTER_GET 24 /* Get Rx filter info */ +#define KCOM_M_DMA_INFO 31 /* Tx/Rx DMA info */ +#define KCOM_M_DBGPKT_SET 41 /* Enbale debug packet function */ +#define KCOM_M_DBGPKT_GET 42 /* Get debug packet function info */ + +#define KCOM_VERSION 8 /* Protocol version */ + +/* + * Message status codes + */ +#define KCOM_E_NONE 0 /* No errors */ +#define KCOM_E_PARAM 1 /* Invalid/unsupported parameter */ +#define KCOM_E_RESOURCE 2 /* Out of memory or other resource */ +#define KCOM_E_NOT_FOUND 3 /* Requested object not found */ + +typedef struct kcom_msg_hdr_s { + uint8 type; + uint8 opcode; + uint8 seqno; + uint8 status; + uint8 unit; + uint8 reserved; + uint16 id; +} kcom_msg_hdr_t; + + +/* + * Object types + */ + +/* + * System network interface + * + * Network interface types: + * + * KCOM_NETIF_T_VLAN + * Transmits to this interface will go to ingress PIPE of switch + * CPU port using specified VLAN ID. Packet will be switched. + * + * KCOM_NETIF_T_PORT + * Transmits to this interface will go to unmodified to specified + * physical switch port. All switching logic is bypassed. + * + * KCOM_NETIF_T_META + * Transmits to this interface will be done using raw meta data + * as DMA descriptors. Currently used for RCPU mode only. + * + * Network interface flags: + * + * KCOM_NETIF_F_ADD_TAG + * Add VLAN tag to packets sent directly to physical port. + * + * KCOM_NETIF_F_RCPU_ENCAP + * Use RCPU encapsulation for packets that enter and exit this + * interface. + */ +#define KCOM_NETIF_T_VLAN 0 +#define KCOM_NETIF_T_PORT 1 +#define KCOM_NETIF_T_META 2 + +#define KCOM_NETIF_F_ADD_TAG (1U << 0) +#define KCOM_NETIF_F_RCPU_ENCAP (1U << 1) +/* If a netif has this flag, the packet sent to the netif can't be stripped tag or added tag */ +#define KCOM_NETIF_F_KEEP_RX_TAG (1U << 2) + +#define KCOM_NETIF_NAME_MAX 16 + +typedef struct kcom_netif_s { + uint16 id; + uint8 type; + uint8 flags; + uint32 cb_user_data; + uint8 port; + uint8 reserved; + uint16 vlan; + uint16 qnum; + uint8 macaddr[6]; + uint8 ptch[2]; + uint8 itmh[4]; + char name[KCOM_NETIF_NAME_MAX]; +} kcom_netif_t; + +/* + * Packet filters + * + * Filters work like software TCAMs where a mask is applied to the + * source data, and the result is then compared to the filter data. + * + * Filters are checked in priority order with the lowest priority + * values being checked first (i.e. 0 is the highest priority). + * + * Filter types: + * + * KCOM_FILTER_T_RX_PKT + * Filter data and mask are applied to the Rx DMA control block + * as well as to the Rx packet contents. + * + * Destination types: + * + * KCOM_DEST_T_NULL + * Packet is dropped. + * + * KCOM_DEST_T_NETIF + * Packet is sent to network interface with ID . + * + * KCOM_DEST_T_API + * Packet is sent to Rx API through queue . + * + * KCOM_DEST_T_CB + * Packet destination is obtained from kernel call-back function. + * + * Filter flags: + * + * KCOM_FILTER_F_ANY_DATA + * When this flags is set the filter will match any packet on + * the associated unit. + * + * KCOM_FILTER_F_STRIP_TAG + * Strip VLAN tag before packet is sent to destination. + * This flag only applies to KCOM_DEST_T_NETIF. + * + */ +#define KCOM_FILTER_BYTES_MAX 256 +#define KCOM_FILTER_WORDS_MAX BYTES2WORDS(KCOM_FILTER_BYTES_MAX) + +#define KCOM_FILTER_T_RX_PKT 1 + +#define KCOM_DEST_T_NULL 0 +#define KCOM_DEST_T_NETIF 1 +#define KCOM_DEST_T_API 2 +#define KCOM_DEST_T_CB 3 + +#define KCOM_FILTER_F_ANY_DATA (1U << 0) +#define KCOM_FILTER_F_STRIP_TAG (1U << 1) + +#define KCOM_FILTER_DESC_MAX 32 + +typedef struct kcom_filter_s { + uint16 id; + uint8 type; + uint8 priority; + char desc[KCOM_FILTER_DESC_MAX]; + uint32 flags; + uint32 cb_user_data; + uint16 dest_type; + uint16 dest_id; + uint16 dest_proto; + uint16 mirror_type; + uint16 mirror_id; + uint16 mirror_proto; + uint16 oob_data_offset; + uint16 oob_data_size; + uint16 pkt_data_offset; + uint16 pkt_data_size; + union { + uint8 b[KCOM_FILTER_BYTES_MAX]; + uint32 w[KCOM_FILTER_WORDS_MAX]; + } data; + union { + uint8 b[KCOM_FILTER_BYTES_MAX]; + uint32 w[KCOM_FILTER_WORDS_MAX]; + } mask; +} kcom_filter_t; + +/* + * DMA buffer information + * + * Cookie field is reserved use by application (32/64-bit pointer). + * + * For Tx operation the application will submit the start address of + * the Tx DCB chain which is queued for transfer by the kernel module. + * Once DMA is done a DMA event is returned to the application with an + * optional sequence number. + * + * For Rx operation the application will submit the start address of + * the Rx DCB chain which should be use for packet reception by the + * kernel module. Once DMA is done a DMA event is returned to the + * application with an optional sequence number. + * + * Cookie field is reserved use by application (32/64-bit pointer). + * + * Packet info types: + * + * KCOM_DMA_INFO_T_TX_DCB + * Data is physical start address of Tx DCB chain. + * + * KCOM_DMA_INFO_T_RX_DCB + * Data is physical start address of Rx DCB chain. + * + * Packet info flags: + * + * KCOM_DMA_INFO_F_TX_DONE + * This flag is set by the kernel module and means that one or more + * packets have been sent. + * + * KCOM_DMA_INFO_F_RX_DONE + * This flag is set by the kernel module and means that one or more + * Rx buffers contain valid packet data. + */ +#define KCOM_DMA_INFO_T_TX_DCB 1 +#define KCOM_DMA_INFO_T_RX_DCB 2 + +#define KCOM_DMA_INFO_F_TX_DONE (1U << 0) +#define KCOM_DMA_INFO_F_RX_DONE (1U << 1) + +typedef struct kcom_dma_info_s { + uint8 type; + uint8 cnt; + uint16 size; + uint16 chan; + uint16 flags; + union { + void *p; + uint8 b[8]; + } cookie; + union { + uint32 dcb_start; + struct { + uint32 tx; + uint32 rx; + } seqno; + } data; + } kcom_dma_info_t; + +/* Default channel configuration */ +#define KCOM_DMA_TX_CHAN 0 +#define KCOM_DMA_RX_CHAN 1 + + +#define KCOM_ETH_HW_T_RESET 1 +#define KCOM_ETH_HW_T_INIT 2 +#define KCOM_ETH_HW_T_OTHER 3 + +#define KCOM_ETH_HW_C_ALL 0xff + +#define KCOM_ETH_HW_RESET_F_TX (1U << 0) +#define KCOM_ETH_HW_RESET_F_RX (1U << 1) +#define KCOM_ETH_HW_RESET_F_TX_RECLAIM (1U << 2) +#define KCOM_ETH_HW_RESET_F_RX_RECLAIM (1U << 3) + +#define KCOM_ETH_HW_INIT_F_TX (1U << 0) +#define KCOM_ETH_HW_INIT_F_RX (1U << 1) +#define KCOM_ETH_HW_INIT_F_RX_FILL (1U << 2) + + +#define KCOM_ETH_HW_OTHER_F_FIFO_LOOPBACK (1U << 0) +#define KCOM_ETH_HW_OTHER_F_INTERRUPT (1U << 1) + + + + +typedef struct kcom_eth_hw_config_s { + uint8 type; + uint8 chan; + uint32 flags; + uint32 value; + } kcom_eth_hw_config_t; + +/* + * Message types + */ + +/* + * Request KCOM interface version of kernel module. + */ +typedef struct kcom_msg_version_s { + kcom_msg_hdr_t hdr; + uint32 version; + uint32 netif_max; + uint32 filter_max; +} kcom_msg_version_t; + +/* + * Send literal string to/from kernel module. + * Mainly for debugging purposes. + */ +#define KCOM_MSG_STRING_MAX 128 + +typedef struct kcom_msg_string_s { + kcom_msg_hdr_t hdr; + uint32 len; + char val[KCOM_MSG_STRING_MAX]; +} kcom_msg_string_t; + + +/* + * Indicate that eth hardware is about to be reset. Active + * DMA operations should be aborted and DMA and interrupts + * should be disabled. + */ +/* + * Indicate that eth hardware has been properly initialized + * for DMA operation to commence. + */ +typedef struct kcom_msg_eth_hw_config_s { + kcom_msg_hdr_t hdr; + kcom_eth_hw_config_t config; +} kcom_msg_eth_hw_config_t; + + +/* + * Indicate that switch hardware is about to be reset. Active + * DMA operations should be aborted and DMA and interrupts + * should be disabled. + */ +typedef struct kcom_msg_hw_reset_s { + kcom_msg_hdr_t hdr; + uint32 channels; +} kcom_msg_hw_reset_t; + +/* + * Indicate that switch hardware has been properly initialized + * for DMA operation to commence. + */ +typedef struct kcom_msg_hw_init_s { + kcom_msg_hdr_t hdr; + uint16 dcb_size; + uint16 dcb_type; + uint32 cdma_channels; +} kcom_msg_hw_init_t; + +/* + * Release blocked IOCTL threads and clean up as necessary. + */ +typedef struct kcom_msg_detach_s { + kcom_msg_hdr_t hdr; + uint32 flags; +} kcom_msg_detach_t; + +/* + * Enable/Disable debugging packet function. + */ +typedef struct kcom_msg_dbg_pkt_set_s { + kcom_msg_hdr_t hdr; + int enable; +} kcom_msg_dbg_pkt_set_t; + +/* + * Get debugging packet function info. + */ +typedef struct kcom_msg_dbg_pkt_get_s { + kcom_msg_hdr_t hdr; + int value; +} kcom_msg_dbg_pkt_get_t; + +/* + * Create new system network interface. The network interface will + * be associated with the specified switch unit number. + * The interface id and name will be assigned by the kernel module. + */ +typedef struct kcom_msg_netif_create_s { + kcom_msg_hdr_t hdr; + kcom_netif_t netif; +} kcom_msg_netif_create_t; + +/* + * Destroy system network interface. + */ +typedef struct kcom_msg_netif_destroy_s { + kcom_msg_hdr_t hdr; +} kcom_msg_netif_destroy_t; + +/* + * Get list of currently defined system network interfaces. + */ +#ifndef KCOM_NETIF_MAX +#define KCOM_NETIF_MAX 128 +#endif + +typedef struct kcom_msg_netif_list_s { + kcom_msg_hdr_t hdr; + uint32 ifcnt; + uint16 id[KCOM_NETIF_MAX]; +} kcom_msg_netif_list_t; + +/* + * Get detailed network interface information. + */ +typedef struct kcom_msg_netif_get_s { + kcom_msg_hdr_t hdr; + kcom_netif_t netif; +} kcom_msg_netif_get_t; + +/* + * Create new packet filter. + * The filter id will be assigned by the kernel module. + */ +typedef struct kcom_msg_filter_create_s { + kcom_msg_hdr_t hdr; + kcom_filter_t filter; +} kcom_msg_filter_create_t; + +/* + * Destroy packet filter. + */ +typedef struct kcom_msg_filter_destroy_s { + kcom_msg_hdr_t hdr; +} kcom_msg_filter_destroy_t; + +/* + * Get list of currently defined packet filters. + */ +#ifndef KCOM_FILTER_MAX +/* OPENNSL_FIXUP - Increased the filters to 1024 from 128 */ +#define KCOM_FILTER_MAX 1024 +#endif + +typedef struct kcom_msg_filter_list_s { + kcom_msg_hdr_t hdr; + uint32 fcnt; + uint16 id[KCOM_FILTER_MAX]; +} kcom_msg_filter_list_t; + +/* + * Get detailed packet filter information. + */ +typedef struct kcom_msg_filter_get_s { + kcom_msg_hdr_t hdr; + kcom_filter_t filter; +} kcom_msg_filter_get_t; + +/* + * DMA info + */ +typedef struct kcom_msg_dma_info_s { + kcom_msg_hdr_t hdr; + kcom_dma_info_t dma_info; +} kcom_msg_dma_info_t; + + +/* + * All messages (e.g. for generic receive) + */ + +typedef union kcom_msg_s { + kcom_msg_hdr_t hdr; + kcom_msg_version_t version; + kcom_msg_string_t string; + kcom_msg_hw_reset_t hw_reset; + kcom_msg_hw_init_t hw_init; + kcom_msg_eth_hw_config_t eth_hw_config; + kcom_msg_detach_t detach; + kcom_msg_netif_create_t netif_create; + kcom_msg_netif_destroy_t netif_destroy; + kcom_msg_netif_list_t netif_list; + kcom_msg_netif_get_t netif_get; + kcom_msg_filter_create_t filter_create; + kcom_msg_filter_destroy_t filter_destroy; + kcom_msg_filter_list_t filter_list; + kcom_msg_filter_get_t filter_get; + kcom_msg_dma_info_t dma_info; + kcom_msg_dbg_pkt_set_t dbg_pkt_set; + kcom_msg_dbg_pkt_get_t dbg_pkt_get; +} kcom_msg_t; + + +/* + * KCOM communication channel vectors + * + * open + * Open KCOM channel. + * + * close + * Close KCOM channel. + * + * send + * Send KCOM message. If bufsz is non-zero, a synchronous send will be + * performed (if supported) and the function will return the number of + * bytes in the response. + * + * recv + * Receive KCOM message. This function is used t oreceive unsolicited + * messages from the kernel. If synchronous send is not supported, this + * function is also used to retrieve responses to command messages. + */ + +typedef struct kcom_chan_s { + void *(*open)(char *name); + int (*close)(void *handle); + int (*send)(void *handle, void *msg, unsigned int len, unsigned int bufsz); + int (*recv)(void *handle, void *msg, unsigned int bufsz); +} kcom_chan_t; + +#endif /* _KCOM_H */ diff --git a/platform/broadcom/saibcm-modules/include/sal/core/sync.h b/platform/broadcom/saibcm-modules/include/sal/core/sync.h new file mode 100644 index 0000000000..edac848b50 --- /dev/null +++ b/platform/broadcom/saibcm-modules/include/sal/core/sync.h @@ -0,0 +1,39 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: sync.h,v 1.1 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ + +#ifndef _SAL_SYNC_H +#define _SAL_SYNC_H + +typedef struct sal_sem_s{ + char sal_opaque_type; +} *sal_sem_t; + +#define sal_sem_FOREVER (-1) +#define sal_sem_BINARY 1 +#define sal_sem_COUNTING 0 + +sal_sem_t sal_sem_create(char *desc, int binary, int initial_count); +void sal_sem_destroy(sal_sem_t b); +int sal_sem_take(sal_sem_t b, int usec); +int sal_sem_give(sal_sem_t b); + +#endif /* !_SAL_SYNC_H */ diff --git a/platform/broadcom/saibcm-modules/include/sal/core/thread.h b/platform/broadcom/saibcm-modules/include/sal/core/thread.h new file mode 100644 index 0000000000..1bccb1aaa3 --- /dev/null +++ b/platform/broadcom/saibcm-modules/include/sal/core/thread.h @@ -0,0 +1,31 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: thread.h,v 1.1 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ + +#ifndef _SAL_THREAD_H +#define _SAL_THREAD_H + +#include + +void sal_usleep(uint32 usec); +void sal_udelay(uint32 usec); + +#endif /* !_SAL_THREAD_H */ diff --git a/platform/broadcom/saibcm-modules/include/sal/types.h b/platform/broadcom/saibcm-modules/include/sal/types.h new file mode 100644 index 0000000000..29e6fc6522 --- /dev/null +++ b/platform/broadcom/saibcm-modules/include/sal/types.h @@ -0,0 +1,156 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: types.h,v 1.3 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + * + * File: types.h + * Purpose: SAL type definitions + */ + +#ifndef _SAL_TYPES_H +#define _SAL_TYPES_H + +/* + * Define platform-independent types + */ + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef DONT_CARE +#define DONT_CARE 0 +#endif + +#define VOL volatile + +/* + * 64-bit type + */ + +#ifdef LONGS_ARE_64BITS + +#define COMPILER_64BIT +#define COMPILER_UINT64 unsigned long +#define u64_H(v) (((uint32 *) &(v))[u64_MSW]) +#define u64_L(v) (((uint32 *) &(v))[u64_LSW]) + +#else /* !LONGS_ARE_64BITS */ + +#define COMPILER_64BIT +#define COMPILER_UINT64 unsigned long long +#define u64_H(v) (((uint32 *) &(v))[u64_MSW]) +#define u64_L(v) (((uint32 *) &(v))[u64_LSW]) + +#endif /* LONGS_ARE_64BITS */ + +/* + * Define unsigned and signed integers with guaranteed sizes. + * Adjust if your compiler uses different sizes for short or int. + */ + +typedef unsigned char uint8; /* 8-bit quantity */ +typedef unsigned short uint16; /* 16-bit quantity */ +typedef unsigned int uint32; /* 32-bit quantity */ +typedef COMPILER_UINT64 uint64; /* 64-bit quantity */ + +typedef signed char int8; /* 8-bit quantity */ +typedef signed short int16; /* 16-bit quantity */ +typedef signed int int32; /* 32-bit quantity */ + +#define BITS2BYTES(x) (((x) + 7) / 8) +#define BITS2WORDS(x) (((x) + 31) / 32) + +#define BYTES2BITS(x) ((x) * 8) +#define BYTES2WORDS(x) (((x) + 3) / 4) + +#define WORDS2BITS(x) ((x) * 32) +#define WORDS2BYTES(x) ((x) * 4) + +#define COUNTOF(ary) ((int) (sizeof (ary) / sizeof ((ary)[0]))) + +typedef uint32 sal_paddr_t; /* Physical address (PCI address) */ + +#ifdef PTRS_ARE_64BITS +typedef uint64 sal_vaddr_t; /* Virtual address (Host address) */ +#define PTR_TO_INT(x) ((uint32)(((sal_vaddr_t)(x))&0xFFFFFFFF)) +#else +typedef uint32 sal_vaddr_t; /* Virtual address (Host address) */ +#define PTR_TO_INT(x) ((uint32)(x)) +#endif + +#define INT_TO_PTR(x) ((void *)((sal_vaddr_t)(x))) + +#define PTR_TO_UINTPTR(x) ((sal_vaddr_t)(x)) +#define UINTPTR_TO_PTR(x) ((void *)(x)) + +typedef union +{ + uint8 u8; + uint16 u16; + uint32 u32; + uint64 u64; + sal_paddr_t paddr; + sal_vaddr_t vaddr; + void *ptr; +} any_t; + +/* Device bus types */ +#define SAL_PCI_DEV_TYPE 0x00001 /* PCI device */ +#define SAL_SPI_DEV_TYPE 0x00002 /* SPI device */ +#define SAL_EB_DEV_TYPE 0x00004 /* EB device */ +#define SAL_ICS_DEV_TYPE 0x00008 /* ICS device */ +#define SAL_MII_DEV_TYPE 0x00010 /* MII device */ +#define SAL_RCPU_DEV_TYPE 0x00020 /* RCPU device */ +#define SAL_I2C_DEV_TYPE 0x00040 /* I2C device */ +#define SAL_AXI_DEV_TYPE 0x00080 /* AXI device */ +#define SAL_EMMI_DEV_TYPE 0x10000 /* EMMI device */ +#define SAL_DEV_BUS_TYPE_MASK 0xf00ff /* Odd for historical reasons */ + +/* Device types */ +#define SAL_SWITCH_DEV_TYPE 0x00100 /* Switch device */ +#define SAL_ETHER_DEV_TYPE 0x00200 /* Ethernet device */ +#define SAL_CPU_DEV_TYPE 0x00400 /* CPU device */ +#define SAL_DEV_TYPE_MASK 0x00f00 + +/* Access types */ +#define SAL_DEV_BUS_RD_16BIT 0x01000 /* 16 bit reads on bus */ +#define SAL_DEV_BUS_WR_16BIT 0x02000 /* 16 bit writes on bus */ +#define SAL_DEV_BUS_ALT 0x04000 /* Alternate access */ +#define SAL_DEV_BUS_MSI 0x08000 /* Message-signaled interrupts */ +#define SAL_DEV_FLAG_MASK 0x0f000 + +/* BDE reserved mask (cannot be used by SAL) */ +#define SAL_DEV_BDE_MASK 0xff000000 + +/* Backward compatibility */ +#define SAL_ET_DEV_TYPE SAL_MII_DEV_TYPE + +/* Special access addresses */ +#define SAL_DEV_OP_EMMI_INIT 0x0fff1000 + +#endif /* !_SAL_TYPES_H */ diff --git a/platform/broadcom/saibcm-modules/include/sdk_config.h b/platform/broadcom/saibcm-modules/include/sdk_config.h new file mode 100644 index 0000000000..5a1bcaddfc --- /dev/null +++ b/platform/broadcom/saibcm-modules/include/sdk_config.h @@ -0,0 +1,46 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: sdk_config.h,v 1.5 Broadcom SDK $ + * $Copyright: (c) 2006 Broadcom Corp. + * All Rights Reserved.$ + * + * + */ + +#ifndef __SDK_CONFIG_H__ +#define __SDK_CONFIG_H__ + +/* + * Include custom overrides + */ +#ifdef SDK_INCLUDE_CUSTOM_CONFIG +#include +#endif + + +/* + * Memory Barrier operation if required. + * Defaults to nothing. + */ +#ifndef SDK_CONFIG_MEMORY_BARRIER +#define SDK_CONFIG_MEMORY_BARRIER +#endif + + + +#endif /* __SDK_CONFIG_H__ */ diff --git a/platform/broadcom/saibcm-modules/include/soc/cmic.h b/platform/broadcom/saibcm-modules/include/soc/cmic.h new file mode 100644 index 0000000000..c6cfc25c75 --- /dev/null +++ b/platform/broadcom/saibcm-modules/include/soc/cmic.h @@ -0,0 +1,38 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: cmic.h,v 1.1 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + * + * File: cmic.h + * Purpose: Maps out structures used for CMIC operations and + * exports routines and constants. + */ + +#ifndef _SOC_CMIC_H +#define _SOC_CMIC_H + +/* IRQ Register (RO) */ +#define CMIC_IRQ_STAT 0x00000144 + +/* IRQ Mask Registers (R/W) */ +#define CMIC_IRQ_MASK 0x00000148 +#define CMIC_IRQ_MASK_1 0x0000006C +#define CMIC_IRQ_MASK_2 0x00000070 + +#endif /* !_SOC_CMIC_H */ diff --git a/platform/broadcom/saibcm-modules/include/soc/devids.h b/platform/broadcom/saibcm-modules/include/soc/devids.h new file mode 100644 index 0000000000..69fba7777c --- /dev/null +++ b/platform/broadcom/saibcm-modules/include/soc/devids.h @@ -0,0 +1,1948 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * Copyright: (c) 2017 Broadcom Corp. + * All Rights Reserved. + */ + +#ifndef _SOC_DEVIDS_H +#define _SOC_DEVIDS_H + + +#define BROADCOM_VENDOR_ID 0x14e4 + +#define BCM5690_DEVICE_ID 0x5690 +#define BCM5690_A0_REV_ID 1 +#define BCM5690_A1_REV_ID 2 +#define BCM5690_A2_REV_ID 3 + +#define BCM5691_DEVICE_ID 0x5691 +#define BCM5691_A0_REV_ID 1 +#define BCM5691_A1_REV_ID 2 +#define BCM5691_A2_REV_ID 3 + +#define BCM5692_DEVICE_ID 0x5692 +#define BCM5692_A0_REV_ID 1 +#define BCM5692_A1_REV_ID 2 +#define BCM5692_A2_REV_ID 3 + +#define BCM5693_DEVICE_ID 0x5693 +#define BCM5693_A0_REV_ID 1 +#define BCM5693_A1_REV_ID 2 +#define BCM5693_A2_REV_ID 3 + +#define BCM5695_DEVICE_ID 0x5695 +#define BCM5695_A0_REV_ID 1 +#define BCM5695_A1_REV_ID 2 +#define BCM5695_B0_REV_ID 0x11 + +#define BCM5696_DEVICE_ID 0x5696 +#define BCM5696_A0_REV_ID 1 +#define BCM5696_A1_REV_ID 2 +#define BCM5696_B0_REV_ID 0x11 + +#define BCM5697_DEVICE_ID 0x5697 +#define BCM5697_A0_REV_ID 1 +#define BCM5697_A1_REV_ID 2 +#define BCM5697_B0_REV_ID 0x11 + +#define BCM5698_DEVICE_ID 0x5698 +#define BCM5698_A0_REV_ID 1 +#define BCM5698_A1_REV_ID 2 +#define BCM5698_B0_REV_ID 0x11 + +#define BCM5670_DEVICE_ID 0x5670 +#define BCM5670_A0_REV_ID 1 +#define BCM5670_A1_REV_ID 2 + +#define BCM5671_DEVICE_ID 0x5671 +#define BCM5671_A0_REV_ID 1 +#define BCM5671_A1_REV_ID 2 +#define BCM5671_A2_REV_ID 3 + +#define BCM5675_DEVICE_ID 0x5675 +#define BCM5675_A0_REV_ID 1 +#define BCM5675_A1_REV_ID 2 + +#define BCM5676_DEVICE_ID 0x5676 +#define BCM5676_A0_REV_ID 1 +#define BCM5676_A1_REV_ID 2 + +#define BCM5673_DEVICE_ID 0x5673 +#define BCM5673_A0_REV_ID 1 +#define BCM5673_A1_REV_ID 2 +#define BCM5673_A2_REV_ID 3 + +#define BCM5674_DEVICE_ID 0x5674 +#define BCM5674_A0_REV_ID 1 + +#define BCM56100_DEVICE_ID 0xb100 +#define BCM56100_A0_REV_ID 1 +#define BCM56100_A1_REV_ID 2 +#define BCM56101_DEVICE_ID 0xb101 +#define BCM56101_A0_REV_ID 1 +#define BCM56101_A1_REV_ID 2 +#define BCM56102_DEVICE_ID 0xb102 +#define BCM56102_A0_REV_ID 1 +#define BCM56102_A1_REV_ID 2 +#define BCM56105_DEVICE_ID 0xb105 +#define BCM56105_A0_REV_ID 1 +#define BCM56105_A1_REV_ID 2 +#define BCM56106_DEVICE_ID 0xb106 +#define BCM56106_A0_REV_ID 1 +#define BCM56106_A1_REV_ID 2 +#define BCM56107_DEVICE_ID 0xb107 +#define BCM56107_A0_REV_ID 1 +#define BCM56107_A1_REV_ID 2 + +#define BCM56110_DEVICE_ID 0xb110 +#define BCM56110_A0_REV_ID 1 +#define BCM56111_DEVICE_ID 0xb111 +#define BCM56111_A0_REV_ID 1 +#define BCM56112_DEVICE_ID 0xb112 +#define BCM56112_A0_REV_ID 1 +#define BCM56115_DEVICE_ID 0xb115 +#define BCM56115_A0_REV_ID 1 +#define BCM56116_DEVICE_ID 0xb116 +#define BCM56116_A0_REV_ID 1 +#define BCM56117_DEVICE_ID 0xb117 +#define BCM56117_A0_REV_ID 1 + +#define BCM56300_DEVICE_ID 0xb300 +#define BCM56300_A0_REV_ID 1 +#define BCM56300_A1_REV_ID 2 +#define BCM56300_B0_REV_ID 0x11 +#define BCM56300_B1_REV_ID 0x12 +#define BCM56301_DEVICE_ID 0xb301 +#define BCM56301_A0_REV_ID 1 +#define BCM56301_A1_REV_ID 2 +#define BCM56301_B0_REV_ID 0x11 +#define BCM56301_B1_REV_ID 0x12 +#define BCM56302_DEVICE_ID 0xb302 +#define BCM56302_A0_REV_ID 1 +#define BCM56302_A1_REV_ID 2 +#define BCM56302_B0_REV_ID 0x11 +#define BCM56302_B1_REV_ID 0x12 +#define BCM56303_DEVICE_ID 0xb303 +#define BCM56303_A1_REV_ID 2 +#define BCM56303_A0_REV_ID 1 +#define BCM56303_B0_REV_ID 0x11 +#define BCM56303_B1_REV_ID 0x12 +#define BCM56304_DEVICE_ID 0xb304 +#define BCM56304_A0_REV_ID 1 +#define BCM56304_A1_REV_ID 2 +#define BCM56304_B0_REV_ID 0x11 +#define BCM56304_B1_REV_ID 0x12 +#define BCM56404_DEVICE_ID 0xb404 +#define BCM56404_A0_REV_ID 1 +#define BCM56404_A1_REV_ID 2 +#define BCM56305_DEVICE_ID 0xb305 +#define BCM56305_A0_REV_ID 1 +#define BCM56305_A1_REV_ID 2 +#define BCM56305_B0_REV_ID 0x11 +#define BCM56305_B1_REV_ID 0x12 +#define BCM56306_DEVICE_ID 0xb306 +#define BCM56306_A0_REV_ID 1 +#define BCM56306_A1_REV_ID 2 +#define BCM56306_B0_REV_ID 0x11 +#define BCM56306_B1_REV_ID 0x12 +#define BCM56307_DEVICE_ID 0xb307 +#define BCM56307_A0_REV_ID 1 +#define BCM56307_A1_REV_ID 2 +#define BCM56307_B0_REV_ID 0x11 +#define BCM56307_B1_REV_ID 0x12 +#define BCM56308_DEVICE_ID 0xb308 +#define BCM56308_A0_REV_ID 1 +#define BCM56308_A1_REV_ID 2 +#define BCM56308_B0_REV_ID 0x11 +#define BCM56308_B1_REV_ID 0x12 +#define BCM56309_DEVICE_ID 0xb309 +#define BCM56309_A0_REV_ID 1 +#define BCM56309_A1_REV_ID 2 +#define BCM56309_B0_REV_ID 0x11 +#define BCM56309_B1_REV_ID 0x12 + +#define BCM56310_DEVICE_ID 0xb310 +#define BCM56310_A0_REV_ID 1 +#define BCM56311_DEVICE_ID 0xb311 +#define BCM56311_A0_REV_ID 1 +#define BCM56312_DEVICE_ID 0xb312 +#define BCM56312_A0_REV_ID 1 +#define BCM56313_DEVICE_ID 0xb313 +#define BCM56313_A0_REV_ID 1 +#define BCM56314_DEVICE_ID 0xb314 +#define BCM56314_A0_REV_ID 1 +#define BCM56315_DEVICE_ID 0xb315 +#define BCM56315_A0_REV_ID 1 +#define BCM56316_DEVICE_ID 0xb316 +#define BCM56316_A0_REV_ID 1 +#define BCM56317_DEVICE_ID 0xb317 +#define BCM56317_A0_REV_ID 1 +#define BCM56318_DEVICE_ID 0xb318 +#define BCM56318_A0_REV_ID 1 +#define BCM56319_DEVICE_ID 0xb319 +#define BCM56319_A0_REV_ID 1 + +#ifndef EXCLUDE_BCM56324 +#define BCM56322_DEVICE_ID 0xb322 +#define BCM56322_A0_REV_ID 1 +#define BCM56324_DEVICE_ID 0xb324 +#define BCM56324_A0_REV_ID 1 +#endif + +#define BCM53300_DEVICE_ID 0xb006 +#define BCM53300_A0_REV_ID 0x11 +#define BCM53300_A1_REV_ID 0x12 +#define BCM53301_DEVICE_ID 0xb206 +#define BCM53301_A0_REV_ID 0x11 +#define BCM53301_A1_REV_ID 0x12 +#define BCM53302_DEVICE_ID 0xb008 +#define BCM53302_A0_REV_ID 0x11 +#define BCM53302_A1_REV_ID 0x12 + +#define BCM56500_DEVICE_ID 0xb500 +#define BCM56500_A0_REV_ID 1 +#define BCM56500_A1_REV_ID 2 +#define BCM56500_B0_REV_ID 0x11 +#define BCM56500_B1_REV_ID 0x12 +#define BCM56500_B2_REV_ID 0x13 +#define BCM56501_DEVICE_ID 0xb501 +#define BCM56501_A0_REV_ID 1 +#define BCM56501_A1_REV_ID 2 +#define BCM56501_B0_REV_ID 0x11 +#define BCM56501_B1_REV_ID 0x12 +#define BCM56501_B2_REV_ID 0x13 +#define BCM56502_DEVICE_ID 0xb502 +#define BCM56502_A0_REV_ID 1 +#define BCM56502_A1_REV_ID 2 +#define BCM56502_B0_REV_ID 0x11 +#define BCM56502_B1_REV_ID 0x12 +#define BCM56502_B2_REV_ID 0x13 +#define BCM56503_DEVICE_ID 0xb503 +#define BCM56503_A0_REV_ID 1 +#define BCM56503_A1_REV_ID 2 +#define BCM56503_B0_REV_ID 0x11 +#define BCM56503_B1_REV_ID 0x12 +#define BCM56503_B2_REV_ID 0x13 +#define BCM56504_DEVICE_ID 0xb504 +#define BCM56504_A0_REV_ID 1 +#define BCM56504_A1_REV_ID 2 +#define BCM56504_B0_REV_ID 0x11 +#define BCM56504_B1_REV_ID 0x12 +#define BCM56504_B2_REV_ID 0x13 +#define BCM56505_DEVICE_ID 0xb505 +#define BCM56505_A0_REV_ID 1 +#define BCM56505_A1_REV_ID 2 +#define BCM56505_B0_REV_ID 0x11 +#define BCM56505_B1_REV_ID 0x12 +#define BCM56505_B2_REV_ID 0x13 +#define BCM56506_DEVICE_ID 0xb506 +#define BCM56506_A0_REV_ID 1 +#define BCM56506_A1_REV_ID 2 +#define BCM56506_B0_REV_ID 0x11 +#define BCM56506_B1_REV_ID 0x12 +#define BCM56506_B2_REV_ID 0x13 +#define BCM56507_DEVICE_ID 0xb507 +#define BCM56507_A0_REV_ID 1 +#define BCM56507_A1_REV_ID 2 +#define BCM56507_B0_REV_ID 0x11 +#define BCM56507_B1_REV_ID 0x12 +#define BCM56507_B2_REV_ID 0x13 +#define BCM56508_DEVICE_ID 0xb508 +#define BCM56508_A0_REV_ID 1 +#define BCM56508_A1_REV_ID 2 +#define BCM56508_B0_REV_ID 0x11 +#define BCM56508_B1_REV_ID 0x12 +#define BCM56508_B2_REV_ID 0x13 +#define BCM56509_DEVICE_ID 0xb509 +#define BCM56509_A0_REV_ID 1 +#define BCM56509_A1_REV_ID 2 +#define BCM56509_B0_REV_ID 0x11 +#define BCM56509_B1_REV_ID 0x12 +#define BCM56509_B2_REV_ID 0x13 + +#define BCM56600_DEVICE_ID 0xb600 +#define BCM56600_A0_REV_ID 1 +#define BCM56600_B0_REV_ID 0x11 +#define BCM56600_C0_REV_ID 0x21 +#define BCM56601_DEVICE_ID 0xb601 +#define BCM56601_A0_REV_ID 1 +#define BCM56601_B0_REV_ID 0x11 +#define BCM56601_C0_REV_ID 0x21 +#define BCM56602_DEVICE_ID 0xb602 +#define BCM56602_A0_REV_ID 1 +#define BCM56602_B0_REV_ID 0x11 +#define BCM56602_C0_REV_ID 0x21 +#define BCM56603_DEVICE_ID 0xb603 +#define BCM56603_A0_REV_ID 1 +#define BCM56603_B0_REV_ID 0x11 +#define BCM56603_C0_REV_ID 0x21 +#define BCM56605_DEVICE_ID 0xb605 +#define BCM56605_A0_REV_ID 1 +#define BCM56605_B0_REV_ID 0x11 +#define BCM56605_C0_REV_ID 0x21 +#define BCM56606_DEVICE_ID 0xb606 +#define BCM56606_A0_REV_ID 1 +#define BCM56606_B0_REV_ID 0x11 +#define BCM56606_C0_REV_ID 0x21 +#define BCM56607_DEVICE_ID 0xb607 +#define BCM56607_A0_REV_ID 1 +#define BCM56607_B0_REV_ID 0x11 +#define BCM56607_C0_REV_ID 0x21 +#define BCM56608_DEVICE_ID 0xb608 +#define BCM56608_A0_REV_ID 1 +#define BCM56608_B0_REV_ID 0x11 +#define BCM56608_C0_REV_ID 0x21 + +#define BCM56580_DEVICE_ID 0xb580 +#define BCM56580_A0_REV_ID 1 + +#define BCM56700_DEVICE_ID 0xb700 +#define BCM56700_A0_REV_ID 1 +#define BCM56701_DEVICE_ID 0xb701 +#define BCM56701_A0_REV_ID 1 + +#define BCM56800_DEVICE_ID 0xb800 +#define BCM56800_A0_REV_ID 1 +#define BCM56801_DEVICE_ID 0xb801 +#define BCM56801_A0_REV_ID 1 +#define BCM56802_DEVICE_ID 0xb802 +#define BCM56802_A0_REV_ID 1 +#define BCM56803_DEVICE_ID 0xb803 +#define BCM56803_A0_REV_ID 1 + +#define BCM56224_DEVICE_ID 0xb224 +#define BCM56224_A0_REV_ID 1 +#define BCM56224_B0_REV_ID 0x11 +#define BCM56225_DEVICE_ID 0xb225 +#define BCM56225_A0_REV_ID 1 +#define BCM56225_B0_REV_ID 0x11 +#define BCM56226_DEVICE_ID 0xb226 +#define BCM56226_A0_REV_ID 1 +#define BCM56226_B0_REV_ID 0x11 +#define BCM56227_DEVICE_ID 0xb227 +#define BCM56227_A0_REV_ID 1 +#define BCM56227_B0_REV_ID 0x11 +#define BCM56228_DEVICE_ID 0xb228 +#define BCM56228_A0_REV_ID 1 +#define BCM56228_B0_REV_ID 0x11 +#define BCM56229_DEVICE_ID 0xb229 +#define BCM56229_A0_REV_ID 1 +#define BCM56229_B0_REV_ID 0x11 +#define BCM56024_DEVICE_ID 0xb024 +#define BCM56024_A0_REV_ID 1 +#define BCM56024_B0_REV_ID 0x11 +#define BCM56025_DEVICE_ID 0xb025 +#define BCM56025_A0_REV_ID 1 +#define BCM56025_B0_REV_ID 0x11 +#define BCM53724_DEVICE_ID 0xc724 +#define BCM53724_A0_REV_ID 1 +#define BCM53724_B0_REV_ID 0x11 +#define BCM53726_DEVICE_ID 0xc726 +#define BCM53726_A0_REV_ID 1 +#define BCM53726_B0_REV_ID 0x11 + +#define BCM53312_DEVICE_ID 0xc312 +#define BCM53312_A0_REV_ID 1 +#define BCM53312_B0_REV_ID 0x11 +#define BCM53313_DEVICE_ID 0xc313 +#define BCM53313_A0_REV_ID 1 +#define BCM53313_B0_REV_ID 0x11 +#define BCM53314_DEVICE_ID 0xc314 +#define BCM53314_A0_REV_ID 1 +#define BCM53314_B0_REV_ID 0x11 + +#define BCM53322_DEVICE_ID 0xc322 +#define BCM53322_A0_REV_ID 1 +#define BCM53323_DEVICE_ID 0xc323 +#define BCM53323_A0_REV_ID 1 +#define BCM53324_DEVICE_ID 0xc324 +#define BCM53324_A0_REV_ID 1 + + +#define BCM56218_DEVICE_ID 0xB218 +#define BCM56218_A0_REV_ID 1 +#define BCM56218_A1_REV_ID 2 +#define BCM56218_A2_REV_ID 3 +#define BCM56218X_DEVICE_ID 0xc710 +#define BCM56218X_A0_REV_ID 1 +#define BCM56218X_A1_REV_ID 2 +#define BCM56218X_A2_REV_ID 3 +#define BCM56219_DEVICE_ID 0xB219 +#define BCM56219_A0_REV_ID 1 +#define BCM56219_A1_REV_ID 2 +#define BCM56219_A2_REV_ID 3 +#define BCM56218R_DEVICE_ID 0xB21A +#define BCM56218R_A0_REV_ID 1 +#define BCM56218R_A1_REV_ID 2 +#define BCM56218R_A2_REV_ID 3 +#define BCM56219R_DEVICE_ID 0xB21B +#define BCM56219R_A0_REV_ID 1 +#define BCM56219R_A1_REV_ID 2 +#define BCM56219R_A2_REV_ID 3 +#define BCM56214_DEVICE_ID 0xB214 +#define BCM56214_A0_REV_ID 1 +#define BCM56214_A1_REV_ID 2 +#define BCM56214_A2_REV_ID 3 +#define BCM56215_DEVICE_ID 0xB215 +#define BCM56215_A0_REV_ID 1 +#define BCM56215_A1_REV_ID 2 +#define BCM56215_A2_REV_ID 3 +#define BCM56214R_DEVICE_ID 0xB21C +#define BCM56214R_A0_REV_ID 1 +#define BCM56214R_A1_REV_ID 2 +#define BCM56214R_A2_REV_ID 3 +#define BCM56215R_DEVICE_ID 0xB21D +#define BCM56215R_A0_REV_ID 1 +#define BCM56215R_A1_REV_ID 2 +#define BCM56215R_A2_REV_ID 3 +#define BCM56216_DEVICE_ID 0xB216 +#define BCM56216_A0_REV_ID 1 +#define BCM56216_A1_REV_ID 2 +#define BCM56216_A2_REV_ID 3 +#define BCM56217_DEVICE_ID 0xB217 +#define BCM56217_A0_REV_ID 1 +#define BCM56217_A1_REV_ID 2 +#define BCM56217_A2_REV_ID 3 +#define BCM56212_DEVICE_ID 0xB212 +#define BCM56212_A0_REV_ID 1 +#define BCM56212_A1_REV_ID 2 +#define BCM56212_A2_REV_ID 3 +#define BCM56213_DEVICE_ID 0xB213 +#define BCM56213_A0_REV_ID 1 +#define BCM56213_A1_REV_ID 2 +#define BCM56213_A2_REV_ID 3 +#define BCM53718_DEVICE_ID 0xC71A +#define BCM53718_A0_REV_ID 1 +#define BCM53718_A1_REV_ID 2 +#define BCM53718_A2_REV_ID 3 +#define BCM53714_DEVICE_ID 0xC71B +#define BCM53714_A0_REV_ID 1 +#define BCM53714_A1_REV_ID 2 +#define BCM53714_A2_REV_ID 3 +#define BCM53716_DEVICE_ID 0xC716 +#define BCM53716_A0_REV_ID 1 +#define BCM53716_A1_REV_ID 2 +#define BCM53716_A2_REV_ID 3 +#define BCM56018_DEVICE_ID 0xB018 +#define BCM56018_A0_REV_ID 1 +#define BCM56018_A1_REV_ID 2 +#define BCM56018_A2_REV_ID 3 +#define BCM56014_DEVICE_ID 0xB014 +#define BCM56014_A0_REV_ID 1 +#define BCM56014_A1_REV_ID 2 +#define BCM56014_A2_REV_ID 3 + +#define BCM56510_DEVICE_ID 0xb510 +#define BCM56510_A0_REV_ID 1 +#define BCM56511_DEVICE_ID 0xb511 +#define BCM56511_A0_REV_ID 1 +#define BCM56512_DEVICE_ID 0xb512 +#define BCM56512_A0_REV_ID 1 +#define BCM56513_DEVICE_ID 0xb513 +#define BCM56513_A0_REV_ID 1 +#define BCM56514_DEVICE_ID 0xb514 +#define BCM56514_A0_REV_ID 1 +#define BCM56516_DEVICE_ID 0xb516 +#define BCM56516_A0_REV_ID 1 +#define BCM56517_DEVICE_ID 0xb517 +#define BCM56517_A0_REV_ID 1 +#define BCM56518_DEVICE_ID 0xb518 +#define BCM56518_A0_REV_ID 1 +#define BCM56519_DEVICE_ID 0xb519 +#define BCM56519_A0_REV_ID 1 + +#define BCM56620_DEVICE_ID 0xb620 +#define BCM56620_A0_REV_ID 1 +#define BCM56620_A1_REV_ID 2 +#define BCM56620_B0_REV_ID 0x11 +#define BCM56620_B1_REV_ID 0x12 +#define BCM56620_B2_REV_ID 0x13 +#define BCM56624_DEVICE_ID 0xb624 +#define BCM56624_A0_REV_ID 1 +#define BCM56624_A1_REV_ID 2 +#define BCM56624_B0_REV_ID 0x11 +#define BCM56624_B1_REV_ID 0x12 +#define BCM56624_B2_REV_ID 0x13 +#define BCM56626_DEVICE_ID 0xb626 +#define BCM56626_A0_REV_ID 1 +#define BCM56626_A1_REV_ID 2 +#define BCM56626_B0_REV_ID 0x11 +#define BCM56626_B1_REV_ID 0x12 +#define BCM56626_B2_REV_ID 0x13 +#define BCM56628_DEVICE_ID 0xb628 +#define BCM56628_A0_REV_ID 1 +#define BCM56628_A1_REV_ID 2 +#define BCM56628_B0_REV_ID 0x11 +#define BCM56628_B1_REV_ID 0x12 +#define BCM56628_B2_REV_ID 0x13 +#define BCM56629_DEVICE_ID 0xb629 +#define BCM56629_A0_REV_ID 1 +#define BCM56629_A1_REV_ID 2 +#define BCM56629_B0_REV_ID 0x11 +#define BCM56629_B1_REV_ID 0x12 +#define BCM56629_B2_REV_ID 0x13 + +#define BCM56680_DEVICE_ID 0xb680 +#define BCM56680_A0_REV_ID 1 +#define BCM56680_A1_REV_ID 2 +#define BCM56680_B0_REV_ID 0x11 +#define BCM56680_B1_REV_ID 0x12 +#define BCM56680_B2_REV_ID 0x13 +#define BCM56684_DEVICE_ID 0xb684 +#define BCM56684_A0_REV_ID 1 +#define BCM56684_A1_REV_ID 2 +#define BCM56684_B0_REV_ID 0x11 +#define BCM56684_B1_REV_ID 0x12 +#define BCM56684_B2_REV_ID 0x13 +#define BCM56686_DEVICE_ID 0xb686 +#define BCM56686_B0_REV_ID 0x11 +#define BCM56686_B1_REV_ID 0x12 +#define BCM56686_B2_REV_ID 0x13 + +#define BCM56820_DEVICE_ID 0xb820 +#define BCM56820_A0_REV_ID 1 +#define BCM56820_B0_REV_ID 0x11 +#define BCM56821_DEVICE_ID 0xb821 +#define BCM56821_A0_REV_ID 1 +#define BCM56821_B0_REV_ID 0x11 +#define BCM56822_DEVICE_ID 0xb822 +#define BCM56822_A0_REV_ID 1 +#define BCM56822_B0_REV_ID 0x11 +#define BCM56823_DEVICE_ID 0xb823 +#define BCM56823_A0_REV_ID 1 +#define BCM56823_B0_REV_ID 0x11 +#define BCM56825_DEVICE_ID 0xb825 +#define BCM56825_B0_REV_ID 0x11 + +#define BCM56720_DEVICE_ID 0xb720 +#define BCM56720_A0_REV_ID 1 +#define BCM56720_B0_REV_ID 0x11 +#define BCM56721_DEVICE_ID 0xb721 +#define BCM56721_A0_REV_ID 1 +#define BCM56721_B0_REV_ID 0x11 + +#define BCM56725_DEVICE_ID 0xb725 +#define BCM56725_A0_REV_ID 1 +#define BCM56725_B0_REV_ID 0x11 + +#define BCM56630_DEVICE_ID 0xb630 +#define BCM56630_A0_REV_ID 1 +#define BCM56630_B0_REV_ID 0x11 +#define BCM56634_DEVICE_ID 0xb634 +#define BCM56634_A0_REV_ID 1 +#define BCM56634_B0_REV_ID 0x11 +#define BCM56636_DEVICE_ID 0xb636 +#define BCM56636_A0_REV_ID 1 +#define BCM56636_B0_REV_ID 0x11 +#define BCM56638_DEVICE_ID 0xb638 +#define BCM56638_A0_REV_ID 1 +#define BCM56638_B0_REV_ID 0x11 +#define BCM56639_DEVICE_ID 0xb639 +#define BCM56639_A0_REV_ID 1 +#define BCM56639_B0_REV_ID 0x11 + +#define BCM56685_DEVICE_ID 0xb685 +#define BCM56685_A0_REV_ID 1 +#define BCM56685_B0_REV_ID 0x11 +#define BCM56689_DEVICE_ID 0xb689 +#define BCM56689_A0_REV_ID 1 +#define BCM56689_B0_REV_ID 0x11 + +#define BCM56520_DEVICE_ID 0xb520 +#define BCM56520_A0_REV_ID 1 +#define BCM56520_B0_REV_ID 0x11 +#define BCM56521_DEVICE_ID 0xb521 +#define BCM56521_A0_REV_ID 1 +#define BCM56521_B0_REV_ID 0x11 +#define BCM56522_DEVICE_ID 0xb522 +#define BCM56522_A0_REV_ID 1 +#define BCM56522_B0_REV_ID 0x11 +#define BCM56524_DEVICE_ID 0xb524 +#define BCM56524_A0_REV_ID 1 +#define BCM56524_B0_REV_ID 0x11 +#define BCM56526_DEVICE_ID 0xb526 +#define BCM56526_A0_REV_ID 1 +#define BCM56526_B0_REV_ID 0x11 + +#define BCM56534_DEVICE_ID 0xb534 +#define BCM56534_B0_REV_ID 0x11 +#define BCM56538_DEVICE_ID 0xb538 +#define BCM56538_B0_REV_ID 0x11 + +#define BCM56331_DEVICE_ID 0xb331 +#define BCM56331_A0_REV_ID 1 +#define BCM56331_B0_REV_ID 0x11 +#define BCM56331_B1_REV_ID 0x12 +#define BCM56333_DEVICE_ID 0xb333 +#define BCM56333_A0_REV_ID 1 +#define BCM56333_B0_REV_ID 0x11 +#define BCM56333_B1_REV_ID 0x12 +#define BCM56334_DEVICE_ID 0xb334 +#define BCM56334_A0_REV_ID 1 +#define BCM56334_B0_REV_ID 0x11 +#define BCM56334_B1_REV_ID 0x12 +#define BCM56338_DEVICE_ID 0xb338 +#define BCM56338_A0_REV_ID 1 +#define BCM56338_B0_REV_ID 0x11 +#define BCM56338_B1_REV_ID 0x12 + +#define BCM56320_DEVICE_ID 0xb320 +#define BCM56320_A0_REV_ID 1 +#define BCM56320_B0_REV_ID 0x11 +#define BCM56320_B1_REV_ID 0x12 +#define BCM56321_DEVICE_ID 0xb321 +#define BCM56321_A0_REV_ID 1 +#define BCM56321_B0_REV_ID 0x11 +#define BCM56321_B1_REV_ID 0x12 + + +#define BCM56548H_DEVICE_ID 0xB54A +#define BCM56548H_A0_REV_ID 1 +#define BCM56548_DEVICE_ID 0xb548 +#define BCM56548_A0_REV_ID 1 +#define BCM56547_DEVICE_ID 0xb547 +#define BCM56547_A0_REV_ID 1 + +#define BCM56346_DEVICE_ID 0xb346 +#define BCM56346_A0_REV_ID 1 +#define BCM56345_DEVICE_ID 0xb345 +#define BCM56345_A0_REV_ID 1 +#define BCM56344_DEVICE_ID 0xb344 +#define BCM56344_A0_REV_ID 1 +#define BCM56342_DEVICE_ID 0xb342 +#define BCM56342_A0_REV_ID 1 +#define BCM56340_DEVICE_ID 0xb340 +#define BCM56340_A0_REV_ID 1 + +#define BCM56049_DEVICE_ID 0xb049 +#define BCM56049_A0_REV_ID 1 +#define BCM56048_DEVICE_ID 0xb048 +#define BCM56048_A0_REV_ID 1 +#define BCM56047_DEVICE_ID 0xb047 +#define BCM56047_A0_REV_ID 1 + +#define BCM56042_DEVICE_ID 0xb042 +#define BCM56042_A0_REV_ID 1 +#define BCM56041_DEVICE_ID 0xb041 +#define BCM56041_A0_REV_ID 1 +#define BCM56040_DEVICE_ID 0xb040 +#define BCM56040_A0_REV_ID 1 + +#define BCM56132_DEVICE_ID 0xb132 +#define BCM56132_A0_REV_ID 1 +#define BCM56132_B0_REV_ID 0x11 +#define BCM56132_B1_REV_ID 0x12 +#define BCM56134_DEVICE_ID 0xb134 +#define BCM56134_A0_REV_ID 1 +#define BCM56134_B0_REV_ID 0x11 +#define BCM56134_B1_REV_ID 0x12 + +#define BCM56230_DEVICE_ID 0xb230 +#define BCM56230_B1_REV_ID 0x12 +#define BCM56231_DEVICE_ID 0xb231 +#define BCM56231_B1_REV_ID 0x12 + +#define BCM56140_DEVICE_ID 0xb140 +#define BCM56140_A0_REV_ID 1 +#define BCM56142_DEVICE_ID 0xb142 +#define BCM56142_A0_REV_ID 1 +#define BCM56143_DEVICE_ID 0xb143 +#define BCM56143_A0_REV_ID 1 +#define BCM56144_DEVICE_ID 0xb144 +#define BCM56144_A0_REV_ID 1 +#define BCM56146_DEVICE_ID 0xb146 +#define BCM56146_A0_REV_ID 1 +#define BCM56147_DEVICE_ID 0xb147 +#define BCM56147_A0_REV_ID 1 +#define BCM56149_DEVICE_ID 0xb149 +#define BCM56149_A0_REV_ID 1 + +#define BCM56840_DEVICE_ID 0xb840 +#define BCM56840_A0_REV_ID 1 +#define BCM56840_A1_REV_ID 2 +#define BCM56840_A2_REV_ID 3 +#define BCM56840_A3_REV_ID 4 +#define BCM56840_A4_REV_ID 5 +#define BCM56840_B0_REV_ID 0x11 +#define BCM56840_B1_REV_ID 0x12 +#define BCM56841_DEVICE_ID 0xb841 +#define BCM56841_A0_REV_ID 1 +#define BCM56841_A1_REV_ID 2 +#define BCM56841_A2_REV_ID 3 +#define BCM56841_A3_REV_ID 4 +#define BCM56841_A4_REV_ID 5 +#define BCM56841_B0_REV_ID 0x11 +#define BCM56841_B1_REV_ID 0x12 +#define BCM56843_DEVICE_ID 0xb843 +#define BCM56843_A0_REV_ID 1 +#define BCM56843_A1_REV_ID 2 +#define BCM56843_A2_REV_ID 3 +#define BCM56843_A3_REV_ID 4 +#define BCM56843_A4_REV_ID 5 +#define BCM56843_B0_REV_ID 0x11 +#define BCM56843_B1_REV_ID 0x12 +#define BCM56845_DEVICE_ID 0xb845 +#define BCM56845_A0_REV_ID 1 +#define BCM56845_A1_REV_ID 2 +#define BCM56845_A2_REV_ID 3 +#define BCM56845_A3_REV_ID 4 +#define BCM56845_A4_REV_ID 5 +#define BCM56845_B0_REV_ID 0x11 +#define BCM56845_B1_REV_ID 0x12 + +#define BCM56743_DEVICE_ID 0xb743 +#define BCM56743_A0_REV_ID 1 +#define BCM56743_A1_REV_ID 2 +#define BCM56743_A2_REV_ID 3 +#define BCM56743_A3_REV_ID 4 +#define BCM56743_A4_REV_ID 5 +#define BCM56743_B0_REV_ID 0x11 +#define BCM56743_B1_REV_ID 0x12 +#define BCM56745_DEVICE_ID 0xb745 +#define BCM56745_A0_REV_ID 1 +#define BCM56745_A1_REV_ID 2 +#define BCM56745_A2_REV_ID 3 +#define BCM56745_A3_REV_ID 4 +#define BCM56745_A4_REV_ID 5 +#define BCM56745_B0_REV_ID 0x11 +#define BCM56745_B1_REV_ID 0x12 + +#define BCM56260_DEVICE_ID 0xb260 +#define BCM56260_A0_REV_ID 1 +#define BCM56260_B0_REV_ID 0x11 +#define BCM56261_DEVICE_ID 0xb261 +#define BCM56261_A0_REV_ID 1 +#define BCM56261_B0_REV_ID 0x11 +#define BCM56262_DEVICE_ID 0xb262 +#define BCM56262_A0_REV_ID 1 +#define BCM56262_B0_REV_ID 0x11 +#define BCM56263_DEVICE_ID 0xb263 +#define BCM56263_A0_REV_ID 1 +#define BCM56263_B0_REV_ID 0x11 + +#define BCM56265_DEVICE_ID 0xb265 +#define BCM56265_A0_REV_ID 1 +#define BCM56265_B0_REV_ID 0x11 +#define BCM56266_DEVICE_ID 0xb266 +#define BCM56266_A0_REV_ID 1 +#define BCM56266_B0_REV_ID 0x11 +#define BCM56267_DEVICE_ID 0xb267 +#define BCM56267_A0_REV_ID 1 +#define BCM56267_B0_REV_ID 0x11 +#define BCM56268_DEVICE_ID 0xb268 +#define BCM56268_A0_REV_ID 1 +#define BCM56268_B0_REV_ID 0x11 + +#define BCM56233_DEVICE_ID 0xb233 +#define BCM56233_B0_REV_ID 0x11 + +#define BCM56460_DEVICE_ID 0xb460 +#define BCM56460_A0_REV_ID 1 +#define BCM56460_B0_REV_ID 0x11 +#define BCM56461_DEVICE_ID 0xb461 +#define BCM56461_A0_REV_ID 1 +#define BCM56461_B0_REV_ID 0x11 +#define BCM56462_DEVICE_ID 0xb462 +#define BCM56462_A0_REV_ID 1 +#define BCM56462_B0_REV_ID 0x11 +#define BCM56463_DEVICE_ID 0xb463 +#define BCM56463_A0_REV_ID 1 +#define BCM56463_B0_REV_ID 0x11 + +#define BCM56465_DEVICE_ID 0xb465 +#define BCM56465_A0_REV_ID 1 +#define BCM56465_B0_REV_ID 0x11 +#define BCM56466_DEVICE_ID 0xb466 +#define BCM56466_A0_REV_ID 1 +#define BCM56466_B0_REV_ID 0x11 +#define BCM56467_DEVICE_ID 0xb467 +#define BCM56467_A0_REV_ID 1 +#define BCM56467_B0_REV_ID 0x11 +#define BCM56468_DEVICE_ID 0xb468 +#define BCM56468_A0_REV_ID 1 +#define BCM56468_B0_REV_ID 0x11 + +#define BCM56270_DEVICE_ID 0xb270 +#define BCM56270_A0_REV_ID 1 +#define BCM56271_DEVICE_ID 0xb271 +#define BCM56271_A0_REV_ID 1 +#define BCM56272_DEVICE_ID 0xb272 +#define BCM56272_A0_REV_ID 1 + +#define BCM53460_DEVICE_ID 0x8460 +#define BCM53460_A0_REV_ID 1 +#define BCM53461_DEVICE_ID 0x8461 +#define BCM53461_A0_REV_ID 1 + +#define BCM56842_DEVICE_ID 0xb842 +#define BCM56842_A0_REV_ID 1 +#define BCM56842_A1_REV_ID 2 +#define BCM56844_DEVICE_ID 0xb844 +#define BCM56844_A0_REV_ID 1 +#define BCM56844_A1_REV_ID 2 +#define BCM56846_DEVICE_ID 0xb846 +#define BCM56846_A0_REV_ID 1 +#define BCM56846_A1_REV_ID 2 +#define BCM56549_DEVICE_ID 0xb549 +#define BCM56549_A0_REV_ID 1 +#define BCM56549_A1_REV_ID 2 +#define BCM56053_DEVICE_ID 0xb053 +#define BCM56053_A0_REV_ID 1 +#define BCM56053_A1_REV_ID 2 +#define BCM56831_DEVICE_ID 0xb831 +#define BCM56831_A0_REV_ID 1 +#define BCM56831_A1_REV_ID 2 +#define BCM56835_DEVICE_ID 0xb835 +#define BCM56835_A0_REV_ID 1 +#define BCM56835_A1_REV_ID 2 +#define BCM56838_DEVICE_ID 0xb838 +#define BCM56838_A0_REV_ID 1 +#define BCM56838_A1_REV_ID 2 +#define BCM56847_DEVICE_ID 0xb847 +#define BCM56847_A0_REV_ID 1 +#define BCM56847_A1_REV_ID 2 +#define BCM56847_A2_REV_ID 3 +#define BCM56847_A3_REV_ID 4 +#define BCM56847_A4_REV_ID 5 +#define BCM56847_B0_REV_ID 0x11 +#define BCM56847_B1_REV_ID 0x12 +#define BCM56849_DEVICE_ID 0xb849 +#define BCM56849_A0_REV_ID 1 +#define BCM56849_A1_REV_ID 2 + +#define BCM56742_DEVICE_ID 0xb742 +#define BCM56742_A0_REV_ID 1 +#define BCM56742_A1_REV_ID 2 +#define BCM56742_A2_REV_ID 3 +#define BCM56744_DEVICE_ID 0xb744 +#define BCM56744_A0_REV_ID 1 +#define BCM56744_A1_REV_ID 2 +#define BCM56746_DEVICE_ID 0xb746 +#define BCM56746_A0_REV_ID 1 +#define BCM56746_A1_REV_ID 2 + +#define BCM88230_DEVICE_ID 0x0230 +#define BCM88230_A0_REV_ID 1 +#define BCM88230_B0_REV_ID 0x11 +#define BCM88230_C0_REV_ID 0x21 +#define BCM88231_DEVICE_ID 0x0231 +#define BCM88231_A0_REV_ID 1 +#define BCM88231_B0_REV_ID 0x11 +#define BCM88231_C0_REV_ID 0x21 +#define BCM88235_DEVICE_ID 0x0235 +#define BCM88235_A0_REV_ID 1 +#define BCM88235_B0_REV_ID 0x11 +#define BCM88235_C0_REV_ID 0x21 +#define BCM88236_DEVICE_ID 0x0236 +#define BCM88236_A0_REV_ID 1 +#define BCM88236_B0_REV_ID 0x11 +#define BCM88236_C0_REV_ID 0x21 +#define BCM88239_DEVICE_ID 0x0239 +#define BCM88239_A0_REV_ID 1 +#define BCM88239_B0_REV_ID 0x11 +#define BCM88239_C0_REV_ID 0x21 +#define BCM56613_DEVICE_ID 0xb613 +#define BCM56613_A0_REV_ID 1 +#define BCM56613_B0_REV_ID 0x11 +#define BCM56613_C0_REV_ID 0x21 + +#define BCM88732_DEVICE_ID 0x0732 +#define BCM88732_A0_REV_ID 1 +#define BCM88732_A1_REV_ID 2 +#define BCM88732_A2_REV_ID 4 +#define BCM88732_B0_REV_ID 0x11 +#define BCM88732_B1_REV_ID 0x12 +#define BCM88732_B2_REV_ID 0x13 + +#define BCM56640_DEVICE_ID 0xb640 +#define BCM56640_A0_REV_ID 1 +#define BCM56640_A1_REV_ID 2 +#define BCM56640_B0_REV_ID 0x11 +#define BCM56643_DEVICE_ID 0xb643 +#define BCM56643_A0_REV_ID 1 +#define BCM56643_A1_REV_ID 2 +#define BCM56643_B0_REV_ID 0x11 +#define BCM56644_DEVICE_ID 0xb644 +#define BCM56644_A0_REV_ID 1 +#define BCM56644_A1_REV_ID 2 +#define BCM56644_B0_REV_ID 0x11 +#define BCM56648_DEVICE_ID 0xb648 +#define BCM56648_A0_REV_ID 1 +#define BCM56648_A1_REV_ID 2 +#define BCM56648_B0_REV_ID 0x11 +#define BCM56649_DEVICE_ID 0xb649 +#define BCM56649_A0_REV_ID 1 +#define BCM56649_A1_REV_ID 2 +#define BCM56649_B0_REV_ID 0x11 + +#define BCM56540_DEVICE_ID 0xb540 +#define BCM56540_A0_REV_ID 1 +#define BCM56540_A1_REV_ID 2 +#define BCM56540_B0_REV_ID 0x11 +#define BCM56541_DEVICE_ID 0xb541 +#define BCM56541_A0_REV_ID 1 +#define BCM56541_A1_REV_ID 2 +#define BCM56541_B0_REV_ID 0x11 +#define BCM56542_DEVICE_ID 0xb542 +#define BCM56542_A0_REV_ID 1 +#define BCM56542_A1_REV_ID 2 +#define BCM56542_B0_REV_ID 0x11 +#define BCM56543_DEVICE_ID 0xb543 +#define BCM56543_A0_REV_ID 1 +#define BCM56543_A1_REV_ID 2 +#define BCM56543_B0_REV_ID 0x11 +#define BCM56544_DEVICE_ID 0xb544 +#define BCM56544_A0_REV_ID 1 +#define BCM56544_A1_REV_ID 2 +#define BCM56544_B0_REV_ID 0x11 + +#define BCM56545_DEVICE_ID 0xb545 +#define BCM56545_A0_REV_ID 1 +#define BCM56545_A1_REV_ID 2 +#define BCM56545_B0_REV_ID 0x11 +#define BCM56546_DEVICE_ID 0xb546 +#define BCM56546_A0_REV_ID 1 +#define BCM56546_A1_REV_ID 2 +#define BCM56546_B0_REV_ID 0x11 + +#define BCM56044_DEVICE_ID 0xb044 +#define BCM56044_B0_REV_ID 0x11 +#define BCM56045_DEVICE_ID 0xb045 +#define BCM56045_A0_REV_ID 1 +#define BCM56045_A1_REV_ID 2 +#define BCM56045_B0_REV_ID 0x11 +#define BCM56046_DEVICE_ID 0xb046 +#define BCM56046_A0_REV_ID 1 +#define BCM56046_A1_REV_ID 2 +#define BCM56046_B0_REV_ID 0x11 + + +#define BCM56440_DEVICE_ID 0xb440 +#define BCM56440_A0_REV_ID 1 +#define BCM56440_B0_REV_ID 0x11 +#define BCM56441_DEVICE_ID 0xb441 +#define BCM56441_A0_REV_ID 1 +#define BCM56441_B0_REV_ID 0x11 +#define BCM56442_DEVICE_ID 0xb442 +#define BCM56442_A0_REV_ID 1 +#define BCM56442_B0_REV_ID 0x11 +#define BCM56443_DEVICE_ID 0xb443 +#define BCM56443_A0_REV_ID 1 +#define BCM56443_B0_REV_ID 0x11 +#define BCM56445_DEVICE_ID 0xb445 +#define BCM56445_A0_REV_ID 1 +#define BCM56445_B0_REV_ID 0x11 +#define BCM56446_DEVICE_ID 0xb446 +#define BCM56446_A0_REV_ID 1 +#define BCM56446_B0_REV_ID 0x11 +#define BCM56447_DEVICE_ID 0xb447 +#define BCM56447_A0_REV_ID 1 +#define BCM56447_B0_REV_ID 0x11 +#define BCM56448_DEVICE_ID 0xb448 +#define BCM56448_A0_REV_ID 1 +#define BCM56448_B0_REV_ID 0x11 +#define BCM56449_DEVICE_ID 0xb449 +#define BCM56449_A0_REV_ID 1 +#define BCM56449_B0_REV_ID 0x11 +#define BCM56240_DEVICE_ID 0xb240 +#define BCM56240_A0_REV_ID 1 +#define BCM56240_B0_REV_ID 0x11 +#define BCM56241_DEVICE_ID 0xb241 +#define BCM56241_A0_REV_ID 1 +#define BCM56241_B0_REV_ID 0x11 +#define BCM56242_DEVICE_ID 0xb242 +#define BCM56242_A0_REV_ID 1 +#define BCM56242_B0_REV_ID 0x11 +#define BCM56243_DEVICE_ID 0xb243 +#define BCM56243_A0_REV_ID 1 +#define BCM56243_B0_REV_ID 0x11 +#define BCM56245_DEVICE_ID 0xb245 +#define BCM56245_A0_REV_ID 1 +#define BCM56245_B0_REV_ID 0x11 +#define BCM56246_DEVICE_ID 0xb246 +#define BCM56246_A0_REV_ID 1 +#define BCM56246_B0_REV_ID 0x11 +#define BCM55440_DEVICE_ID 0xa440 +#define BCM55440_A0_REV_ID 1 +#define BCM55440_B0_REV_ID 0x11 +#define BCM55441_DEVICE_ID 0xa441 +#define BCM55441_A0_REV_ID 1 +#define BCM55441_B0_REV_ID 0x11 + +#define BCM55450_DEVICE_ID 0xa450 +#define BCM55450_A0_REV_ID 1 +#define BCM55450_B0_REV_ID 0x11 +#define BCM55450_B1_REV_ID 0x12 + +#define BCM55455_DEVICE_ID 0xa455 +#define BCM55455_A0_REV_ID 1 +#define BCM55455_B0_REV_ID 0x11 +#define BCM55455_B1_REV_ID 0x12 + +#define BCM56248_DEVICE_ID 0xb248 +#define BCM56248_A0_REV_ID 1 +#define BCM56248_B0_REV_ID 0x11 +#define BCM56248_B1_REV_ID 0x12 + +#define BCM56450_DEVICE_ID 0xb450 +#define BCM56450_A0_REV_ID 1 +#define BCM56450_B0_REV_ID 0x11 +#define BCM56450_B1_REV_ID 0x12 + +#define BCM56452_DEVICE_ID 0xb452 +#define BCM56452_A0_REV_ID 1 +#define BCM56452_B0_REV_ID 0x11 +#define BCM56452_B1_REV_ID 0x12 + +#define BCM56454_DEVICE_ID 0xb454 +#define BCM56454_A0_REV_ID 1 +#define BCM56454_B0_REV_ID 0x11 +#define BCM56454_B1_REV_ID 0x12 + +#define BCM56455_DEVICE_ID 0xb455 +#define BCM56455_A0_REV_ID 1 +#define BCM56455_B0_REV_ID 0x11 +#define BCM56455_B1_REV_ID 0x12 + +#define BCM56456_DEVICE_ID 0xb456 +#define BCM56456_A0_REV_ID 1 +#define BCM56456_B0_REV_ID 0x11 +#define BCM56456_B1_REV_ID 0x12 + +#define BCM56457_DEVICE_ID 0xb457 +#define BCM56457_A0_REV_ID 1 +#define BCM56457_B0_REV_ID 0x11 +#define BCM56457_B1_REV_ID 0x12 + +#define BCM56458_DEVICE_ID 0xb458 +#define BCM56458_A0_REV_ID 1 +#define BCM56458_B0_REV_ID 0x11 +#define BCM56458_B1_REV_ID 0x12 + +#define BCM56850_DEVICE_ID 0xb850 +#define BCM56850_A0_REV_ID 1 +#define BCM56850_A1_REV_ID 2 +#define BCM56850_A2_REV_ID 3 +#define BCM56851_DEVICE_ID 0xb851 +#define BCM56851_A0_REV_ID 1 +#define BCM56851_A1_REV_ID 2 +#define BCM56851_A2_REV_ID 3 +#define BCM56852_DEVICE_ID 0xb852 +#define BCM56852_A0_REV_ID 1 +#define BCM56852_A1_REV_ID 2 +#define BCM56852_A2_REV_ID 3 +#define BCM56853_DEVICE_ID 0xb853 +#define BCM56853_A0_REV_ID 1 +#define BCM56853_A1_REV_ID 2 +#define BCM56853_A2_REV_ID 3 +#define BCM56854_DEVICE_ID 0xb854 +#define BCM56854_A0_REV_ID 1 +#define BCM56854_A1_REV_ID 2 +#define BCM56854_A2_REV_ID 3 +#define BCM56855_DEVICE_ID 0xb855 +#define BCM56855_A0_REV_ID 1 +#define BCM56855_A1_REV_ID 2 +#define BCM56855_A2_REV_ID 3 +#define BCM56834_DEVICE_ID 0xb834 +#define BCM56834_A0_REV_ID 1 +#define BCM56834_A1_REV_ID 2 +#define BCM56834_A2_REV_ID 3 + +#define BCM56860_DEVICE_ID 0xb860 +#define BCM56860_A0_REV_ID 1 +#define BCM56860_A1_REV_ID 2 +#define BCM56861_DEVICE_ID 0xb861 +#define BCM56861_A0_REV_ID 1 +#define BCM56861_A1_REV_ID 2 +#define BCM56862_DEVICE_ID 0xb862 +#define BCM56862_A0_REV_ID 1 +#define BCM56862_A1_REV_ID 2 +#define BCM56864_DEVICE_ID 0xb864 +#define BCM56864_A0_REV_ID 1 +#define BCM56864_A1_REV_ID 2 +#define BCM56865_DEVICE_ID 0xb865 +#define BCM56865_A0_REV_ID 1 +#define BCM56865_A1_REV_ID 2 +#define BCM56866_DEVICE_ID 0xb866 +#define BCM56866_A0_REV_ID 1 +#define BCM56866_A1_REV_ID 2 +#define BCM56867_DEVICE_ID 0xb867 +#define BCM56867_A0_REV_ID 1 +#define BCM56867_A1_REV_ID 2 +#define BCM56868_DEVICE_ID 0xb868 +#define BCM56868_A0_REV_ID 1 +#define BCM56868_A1_REV_ID 2 +#define BCM56832_DEVICE_ID 0xb832 +#define BCM56832_A0_REV_ID 1 +#define BCM56832_A1_REV_ID 2 +#define BCM56833_DEVICE_ID 0xb833 +#define BCM56833_A0_REV_ID 1 +#define BCM56833_A1_REV_ID 2 +#define BCM56836_DEVICE_ID 0xb836 +#define BCM56836_A0_REV_ID 1 +#define BCM56836_A1_REV_ID 2 + + +#define BCM56750_DEVICE_ID 0xb750 +#define BCM56750_A0_REV_ID 1 +#define BCM56750_A1_REV_ID 2 +#define BCM56750_A2_REV_ID 3 + +#define BCM56830_DEVICE_ID 0xb830 +#define BCM56830_A0_REV_ID 1 +#define BCM56830_A1_REV_ID 2 +#define BCM56830_A2_REV_ID 3 + +#define BCM56150_DEVICE_ID 0xb150 +#define BCM56150_A0_REV_ID 1 +#define BCM56151_DEVICE_ID 0xb151 +#define BCM56151_A0_REV_ID 1 +#define BCM56152_DEVICE_ID 0xb152 +#define BCM56152_A0_REV_ID 1 + +#define BCM53342_DEVICE_ID 0x8342 +#define BCM53342_A0_REV_ID 1 +#define BCM53343_DEVICE_ID 0x8343 +#define BCM53343_A0_REV_ID 1 +#define BCM53344_DEVICE_ID 0x8344 +#define BCM53344_A0_REV_ID 1 +#define BCM53346_DEVICE_ID 0x8346 +#define BCM53346_A0_REV_ID 1 +#define BCM53347_DEVICE_ID 0x8347 +#define BCM53347_A0_REV_ID 1 + +#define BCM53333_DEVICE_ID 0x8333 +#define BCM53333_A0_REV_ID 1 +#define BCM53334_DEVICE_ID 0x8334 +#define BCM53334_A0_REV_ID 1 + +#define BCM53393_DEVICE_ID 0x8393 +#define BCM53393_A0_REV_ID 1 +#define BCM53394_DEVICE_ID 0x8394 +#define BCM53394_A0_REV_ID 1 + +#define BCM53400_DEVICE_ID 0x8400 +#define BCM53400_A0_REV_ID 1 +#define BCM56060_DEVICE_ID 0xb060 +#define BCM56060_A0_REV_ID 1 +#define BCM56062_DEVICE_ID 0xb062 +#define BCM56062_A0_REV_ID 1 +#define BCM56063_DEVICE_ID 0xb063 +#define BCM56063_A0_REV_ID 1 +#define BCM56064_DEVICE_ID 0xb064 +#define BCM56064_A0_REV_ID 1 +#define BCM56065_DEVICE_ID 0xb065 +#define BCM56065_A0_REV_ID 1 +#define BCM56066_DEVICE_ID 0xb066 +#define BCM56066_A0_REV_ID 1 +#define BCM53401_DEVICE_ID 0x8401 +#define BCM53411_DEVICE_ID 0x8411 +#define BCM53401_A0_REV_ID 1 +#define BCM53402_DEVICE_ID 0x8402 +#define BCM53412_DEVICE_ID 0x8412 +#define BCM53402_A0_REV_ID 1 +#define BCM53403_DEVICE_ID 0x8403 +#define BCM53413_DEVICE_ID 0x8413 +#define BCM53403_A0_REV_ID 1 +#define BCM53404_DEVICE_ID 0x8404 +#define BCM53414_DEVICE_ID 0x8414 +#define BCM53404_A0_REV_ID 1 +#define BCM53405_DEVICE_ID 0x8405 +#define BCM53415_DEVICE_ID 0x8415 +#define BCM53405_A0_REV_ID 1 +#define BCM53406_DEVICE_ID 0x8406 +#define BCM53416_DEVICE_ID 0x8416 +#define BCM53406_A0_REV_ID 1 +#define BCM53408_DEVICE_ID 0x8408 +#define BCM53418_DEVICE_ID 0x8418 +#define BCM53408_A0_REV_ID 1 +#define BCM53365_DEVICE_ID 0x8365 +#define BCM53365_A0_REV_ID 1 +#define BCM53369_DEVICE_ID 0x8369 +#define BCM53369_A0_REV_ID 1 + +#define BCM53454_DEVICE_ID 0x8454 +#define BCM53455_DEVICE_ID 0x8455 +#define BCM53454_A0_REV_ID 1 +#define BCM53456_DEVICE_ID 0x8456 +#define BCM53457_DEVICE_ID 0x8457 +#define BCM53456_A0_REV_ID 1 + +#define BCM53422_DEVICE_ID 0x8422 +#define BCM53422_A0_REV_ID 1 +#define BCM53424_DEVICE_ID 0x8424 +#define BCM53424_A0_REV_ID 1 +#define BCM53426_DEVICE_ID 0x8426 +#define BCM53426_A0_REV_ID 1 + +#define BCM56960_DEVICE_ID 0xb960 +#define BCM56960_A0_REV_ID 1 +#define BCM56960_B0_REV_ID 0x11 +#define BCM56960_B1_REV_ID 0x12 +#define BCM56961_DEVICE_ID 0xb961 +#define BCM56961_A0_REV_ID 1 +#define BCM56961_B0_REV_ID 0x11 +#define BCM56961_B1_REV_ID 0x12 +#define BCM56962_DEVICE_ID 0xb962 +#define BCM56962_A0_REV_ID 1 +#define BCM56962_B0_REV_ID 0x11 +#define BCM56962_B1_REV_ID 0x12 +#define BCM56963_DEVICE_ID 0xb963 +#define BCM56963_A0_REV_ID 1 +#define BCM56963_B0_REV_ID 0x11 +#define BCM56963_B1_REV_ID 0x12 +#define BCM56930_DEVICE_ID 0xb930 +#define BCM56930_A0_REV_ID 1 +#define BCM56930_B0_REV_ID 0x11 +#define BCM56930_B1_REV_ID 0x12 +#define BCM56930_C0_REV_ID 0x21 +#define BCM56931_DEVICE_ID 0xb931 +#define BCM56931_A0_REV_ID 1 +#define BCM56931_B0_REV_ID 0x11 +#define BCM56931_C0_REV_ID 0x21 +#define BCM56935_DEVICE_ID 0xb935 +#define BCM56935_A0_REV_ID 1 +#define BCM56935_B0_REV_ID 0x11 +#define BCM56935_C0_REV_ID 0x21 +#define BCM56936_DEVICE_ID 0xb936 +#define BCM56936_A0_REV_ID 1 +#define BCM56936_B0_REV_ID 0x11 +#define BCM56936_C0_REV_ID 0x21 +#define BCM56939_DEVICE_ID 0xb939 +#define BCM56939_A0_REV_ID 1 +#define BCM56939_B0_REV_ID 0x11 +#define BCM56939_C0_REV_ID 0x21 + +#define BCM56168_DEVICE_ID 0xb168 +#define BCM56168_A0_REV_ID 1 +#define BCM56168_B0_REV_ID 0x11 +#define BCM56168_B1_REV_ID 0x12 +#define BCM56169_DEVICE_ID 0xb169 +#define BCM56169_A0_REV_ID 1 +#define BCM56169_B0_REV_ID 0x11 +#define BCM56169_B1_REV_ID 0x12 + +#define BCM56968_DEVICE_ID 0xb968 +#define BCM56968_A0_REV_ID 1 +#define BCM56968_B0_REV_ID 0x11 +#define BCM56968_B1_REV_ID 0x12 + +#define BCM56160_DEVICE_ID 0xb160 +#define BCM56160_A0_REV_ID 1 +#define BCM56160_B0_REV_ID 0x11 +#define BCM56162_DEVICE_ID 0xb162 +#define BCM56162_A0_REV_ID 1 +#define BCM56162_B0_REV_ID 0x11 + +#define BCM56163_DEVICE_ID 0xb163 +#define BCM56163_A0_REV_ID 1 +#define BCM56163_B0_REV_ID 0x11 +#define BCM56164_DEVICE_ID 0xb164 +#define BCM56164_A0_REV_ID 1 +#define BCM56164_B0_REV_ID 0x11 +#define BCM56166_DEVICE_ID 0xb166 +#define BCM56166_A0_REV_ID 1 +#define BCM56166_B0_REV_ID 0x11 + +#define BCM53440_DEVICE_ID 0x8440 +#define BCM53440_A0_REV_ID 1 +#define BCM53440_B0_REV_ID 0x11 +#define BCM53442_DEVICE_ID 0x8442 +#define BCM53442_A0_REV_ID 1 +#define BCM53442_B0_REV_ID 0x11 +#define BCM53443_DEVICE_ID 0x8443 +#define BCM53443_A0_REV_ID 1 +#define BCM53443_B0_REV_ID 0x11 + +#define BCM53434_DEVICE_ID 0x8434 +#define BCM53434_A0_REV_ID 1 +#define BCM53434_B0_REV_ID 0x11 + +#define BCM56560_DEVICE_ID 0xb560 +#define BCM56560_A0_REV_ID 1 +#define BCM56560_B0_REV_ID 0x11 +#define BCM56560_B1_REV_ID 0x12 + +#define BCM56561_DEVICE_ID 0xb561 +#define BCM56561_A0_REV_ID 1 +#define BCM56561_B0_REV_ID 0x11 +#define BCM56561_B1_REV_ID 0x12 + +#define BCM56562_DEVICE_ID 0xb562 +#define BCM56562_A0_REV_ID 1 +#define BCM56562_B0_REV_ID 0x11 +#define BCM56562_B1_REV_ID 0x12 + +#define BCM56565_DEVICE_ID 0xb565 +#define BCM56565_A0_REV_ID 1 +#define BCM56565_B0_REV_ID 0x11 +#define BCM56565_B1_REV_ID 0x12 + +#define BCM56566_DEVICE_ID 0xb566 +#define BCM56566_A0_REV_ID 1 +#define BCM56566_B0_REV_ID 0x11 +#define BCM56566_B1_REV_ID 0x12 + +#define BCM56567_DEVICE_ID 0xb567 +#define BCM56567_A0_REV_ID 1 +#define BCM56567_B0_REV_ID 0x11 +#define BCM56567_B1_REV_ID 0x12 + +#define BCM56568_DEVICE_ID 0xb568 +#define BCM56568_A0_REV_ID 1 +#define BCM56568_B0_REV_ID 0x11 +#define BCM56568_B1_REV_ID 0x12 + +#define BCM56760_DEVICE_ID 0xb760 +#define BCM56760_A0_REV_ID 1 +#define BCM56760_A1_REV_ID 2 +#define BCM56760_B0_REV_ID 0x11 +#define BCM56760_B1_REV_ID 0x12 + +#define BCM56762_DEVICE_ID 0xb762 +#define BCM56762_A0_REV_ID 1 +#define BCM56762_B0_REV_ID 0x11 +#define BCM56762_B1_REV_ID 0x12 + +#define BCM56764_DEVICE_ID 0xb764 +#define BCM56764_A0_REV_ID 1 +#define BCM56764_B0_REV_ID 0x11 +#define BCM56764_B1_REV_ID 0x12 + +#define BCM56765_DEVICE_ID 0xb765 +#define BCM56765_A0_REV_ID 1 +#define BCM56765_B0_REV_ID 0x11 +#define BCM56765_B1_REV_ID 0x12 + +#define BCM56766_DEVICE_ID 0xb766 +#define BCM56766_A0_REV_ID 1 +#define BCM56766_B0_REV_ID 0x11 +#define BCM56766_B1_REV_ID 0x12 + +#define BCM56768_DEVICE_ID 0xb768 +#define BCM56768_A0_REV_ID 1 +#define BCM56768_B0_REV_ID 0x11 +#define BCM56768_B1_REV_ID 0x12 + +#define BCM56068_DEVICE_ID 0xb068 +#define BCM56068_A0_REV_ID 1 +#define BCM56068_B0_REV_ID 0x11 +#define BCM56068_B1_REV_ID 0x12 + +#define BCM56069_DEVICE_ID 0xb069 +#define BCM56069_A0_REV_ID 1 +#define BCM56069_B0_REV_ID 0x11 +#define BCM56069_B1_REV_ID 0x12 + +#define BCM56170_DEVICE_ID 0xb170 +#define BCM56170_A0_REV_ID 1 +#define BCM56172_DEVICE_ID 0xb172 +#define BCM56172_A0_REV_ID 1 +#define BCM56174_DEVICE_ID 0xb174 +#define BCM56174_A0_REV_ID 1 + +#define BCM53570_DEVICE_ID 0x8570 +#define BCM53570_A0_REV_ID 1 +#define BCM53575_DEVICE_ID 0x8575 +#define BCM53575_A0_REV_ID 1 + + +#define BCM56965_DEVICE_ID 0xb965 +#define BCM56965_A0_REV_ID 1 +#define BCM56965_A1_REV_ID 2 +#define BCM56969_DEVICE_ID 0xb969 +#define BCM56969_A0_REV_ID 1 +#define BCM56966_DEVICE_ID 0xb966 +#define BCM56966_A0_REV_ID 1 +#define BCM56967_DEVICE_ID 0xb967 +#define BCM56967_A0_REV_ID 1 + +#define BCM56970_DEVICE_ID 0xb970 +#define BCM56970_A0_REV_ID 1 +#define BCM56970_B0_REV_ID 0x11 +#define BCM56971_DEVICE_ID 0xb971 +#define BCM56971_A0_REV_ID 1 +#define BCM56971_B0_REV_ID 0x11 +#define BCM56972_DEVICE_ID 0xb972 +#define BCM56972_A0_REV_ID 1 +#define BCM56972_B0_REV_ID 0x11 +#define BCM56974_DEVICE_ID 0xb974 +#define BCM56974_A0_REV_ID 1 +#define BCM56974_B0_REV_ID 0x11 + + +#define BCM56870_DEVICE_ID 0xb870 +#define BCM56870_A0_REV_ID 1 +#define BCM56873_DEVICE_ID 0xb873 +#define BCM56873_A0_REV_ID 1 + +#define BCM5665_DEVICE_ID 0x5665 +#define BCM5665_A0_REV_ID 1 +#define BCM5665_B0_REV_ID 0x11 + + +#define BCM5655_DEVICE_ID 0x5655 +#define BCM5655_A0_REV_ID 1 +#define BCM5655_B0_REV_ID 0x11 + + +#define BCM5650_DEVICE_ID 0x5650 +#define BCM5650_A0_REV_ID 1 +#define BCM5650_B0_REV_ID 0x11 +#define BCM5650_C0_REV_ID 0x21 + +#define BROADCOM_PHYID_HIGH 0x0040 + +#define BCM5338_PHYID_LOW 0x62b0 +#define BCM5338_A0_REV_ID 0 +#define BCM5338_A1_REV_ID 1 +#define BCM5338_B0_REV_ID 3 + +#define BCM5324_PHYID_LOW 0xbc20 +#define BCM5324_PHYID_HIGH 0x143 +#define BCM5324_A1_PHYID_HIGH 0x153 +#define BCM5324_DEVICE_ID 0xbc20 +#define BCM5324_A0_REV_ID 0 +#define BCM5324_A1_REV_ID 1 +#define BCM5324_A2_REV_ID 2 + +#define BCM5380_PHYID_LOW 0x6250 +#define BCM5380_A0_REV_ID 0 + +#define BCM5388_PHYID_LOW 0x6288 +#define BCM5388_A0_REV_ID 0 + +#define BCM5396_PHYID_LOW 0xbd70 +#define BCM5396_PHYID_HIGH 0x143 +#define BCM5396_DEVICE_ID 0x96 +#define BCM5396_A0_REV_ID 0 + +#define BCM5389_PHYID_LOW 0xbd70 +#define BCM5389_PHYID_HIGH 0x143 +#define BCM5389_DEVICE_ID 0x89 +#define BCM5389_A0_REV_ID 0 +#define BCM5389_A1_DEVICE_ID 0x86 +#define BCM5389_A1_REV_ID 1 + +#define BCM5398_PHYID_LOW 0xbcd0 +#define BCM5398_PHYID_HIGH 0x0143 +#define BCM5398_DEVICE_ID 0x98 +#define BCM5398_A0_REV_ID 0 + +#define BCM5325_PHYID_LOW 0xbc30 +#define BCM5325_PHYID_HIGH 0x143 +#define BCM5325_DEVICE_ID 0xbc30 +#define BCM5325_A0_REV_ID 0 +#define BCM5325_A1_REV_ID 1 + +#define BCM5348_PHYID_LOW 0xbe40 +#define BCM5348_PHYID_HIGH 0x0143 +#define BCM5348_DEVICE_ID 0x48 +#define BCM5348_A0_REV_ID 0 +#define BCM5348_A1_REV_ID 1 + +#define BCM5397_PHYID_LOW 0xbcd0 +#define BCM5397_PHYID_HIGH 0x0143 +#define BCM5397_DEVICE_ID 0x97 +#define BCM5397_A0_REV_ID 0 + +#define BCM5347_PHYID_LOW 0xbe40 +#define BCM5347_PHYID_HIGH 0x0143 +#define BCM5347_DEVICE_ID 0x47 +#define BCM5347_A0_REV_ID 0 + +#define BCM5395_PHYID_LOW 0xbcf0 +#define BCM5395_PHYID_HIGH 0x0143 +#define BCM5395_DEVICE_ID 0xbcf0 +#define BCM5395_A0_REV_ID 0 + +#define BCM53242_PHYID_LOW 0xbf10 +#define BCM53242_PHYID_HIGH 0x0143 +#define BCM53242_DEVICE_ID 0xbf10 +#define BCM53242_A0_REV_ID 0 +#define BCM53242_B0_REV_ID 4 +#define BCM53242_B1_REV_ID 5 + +#define BCM53262_PHYID_LOW 0xbf20 +#define BCM53262_PHYID_HIGH 0x0143 +#define BCM53262_DEVICE_ID 0xbf20 +#define BCM53262_A0_REV_ID 0 +#define BCM53262_B0_REV_ID 4 +#define BCM53262_B1_REV_ID 5 + +#define BCM53115_PHYID_LOW 0xbf80 +#define BCM53115_PHYID_HIGH 0x0143 +#define BCM53115_DEVICE_ID 0xbf80 +#define BCM53115_A0_REV_ID 0 +#define BCM53115_A1_REV_ID 1 +#define BCM53115_B0_REV_ID 2 +#define BCM53115_B1_REV_ID 3 +#define BCM53115_C0_REV_ID 8 + +#define BCM53118_PHYID_LOW 0xbfe0 +#define BCM53118_PHYID_HIGH 0x0143 +#define BCM53118_DEVICE_ID 0xbfe0 +#define BCM53118_A0_REV_ID 0 + +#define BCM53118_B0_REV_ID 4 +#define BCM53118_B1_REV_ID 5 + +#define BCM53280_PHYID_LOW 0x5e90 +#define BCM53280_PHYID_HIGH 0x0362 +#define BCM53280_DEVICE_ID (0x4 | BCM53280_PHYID_LOW) +#define BCM53280_A0_REV_ID 0 +#define BCM53280_B0_REV_ID 0x4 +#define BCM53280_B1_REV_ID 0x5 +#define BCM53280_B2_REV_ID 0x6 +#define BCM53286_DEVICE_ID (0x4 | BCM53280_PHYID_LOW) +#define BCM53288_DEVICE_ID (0xc | BCM53280_PHYID_LOW) +#define BCM53284_DEVICE_ID (0x7 | BCM53280_PHYID_LOW) +#define BCM53283_DEVICE_ID (0x6 | BCM53280_PHYID_LOW) +#define BCM53282_DEVICE_ID (0x5 | BCM53280_PHYID_LOW) +#define BCM53101_PHYID_LOW 0x5ed0 +#define BCM53101_PHYID_HIGH 0x0362 +#define BCM53101_DEVICE_ID 0x5ed0 +#define BCM53101_A0_REV_ID 0 +#define BCM53101_B0_REV_ID 4 + +#define BCM53125_PHYID_LOW 0x5f20 +#define BCM53125_PHYID_HIGH 0x0362 +#define BCM53125_DEVICE_ID 0x5f20 +#define BCM53125_A0_REV_ID 0 +#define BCM53125_B0_REV_ID 0x4 +#define BCM53125_MODEL_ID 0x53125 + +#define BCM53134_PHYID_LOW 0x5350 +#define BCM53134_PHYID_HIGH 0xAE02 +#define BCM53134_DEVICE_ID 0x5350 +#define BCM53134_A0_REV_ID 0x0 +#define BCM53134_B0_REV_ID 0x1 +#define BCM53134_B1_REV_ID 0x2 +#define BCM53134_A0_MODEL_ID 0x5035 +#define BCM53134_B0_MODEL_ID 0x5075 + +#define BCM53128_PHYID_LOW 0x5e10 +#define BCM53128_PHYID_HIGH 0x0362 +#define BCM53128_DEVICE_ID 0x5e10 +#define BCM53128_A0_REV_ID 0 +#define BCM53128_B0_REV_ID 0x4 +#define BCM53128_MODEL_ID 0x53128 + +#define BCM53600_PHYID_LOW 0x5f40 +#define BCM53600_PHYID_HIGH 0x0362 +#define BCM53600_DEVICE_ID (0x3 | BCM53600_PHYID_LOW) +#define BCM53600_A0_REV_ID 0 +#define BCM53602_DEVICE_ID (0x1 | BCM53600_PHYID_LOW) +#define BCM53603_DEVICE_ID (0x2 | BCM53600_PHYID_LOW) +#define BCM53604_DEVICE_ID (0x3 | BCM53600_PHYID_LOW) +#define BCM53606_DEVICE_ID (0x7 | BCM53600_PHYID_LOW) + +#define BCM89500_PHYID_LOW 0x5d30 +#define BCM89500_PHYID_HIGH 0x0362 +#define BCM89500_DEVICE_ID 0x9500 +#define BCM89501_DEVICE_ID 0x9501 +#define BCM89200_DEVICE_ID 0x9200 +#define BCM89500_A0_REV_ID 0 +#define BCM89500_B0_REV_ID 0x4 +#define BCM89500_MODEL_ID 0x89500 + +#define BCM53010_PHYID_LOW 0x8760 +#define BCM53010_PHYID_HIGH 0x600d +#define BCM53010_DEVICE_ID 0x3010 +#define BCM53011_DEVICE_ID 0x3011 +#define BCM53012_DEVICE_ID 0x3012 +#define BCM53010_A0_REV_ID 0 +#define BCM53010_A2_REV_ID 0x2 +#define BCM53010_MODEL_ID 0x53010 + +#define BCM53018_PHYID_LOW 0x87c0 +#define BCM53018_PHYID_HIGH 0x600d +#define BCM53017_DEVICE_ID 0x3016 +#define BCM53018_DEVICE_ID 0x3018 +#define BCM53019_DEVICE_ID 0x3019 +#define BCM53018_A0_REV_ID 0 +#define BCM53018_MODEL_ID 0x53016 + +#define BCM53020_PHYID_LOW 0x87f0 +#define BCM53020_PHYID_HIGH 0x600d +#define BCM53020_DEVICE_ID 0x8022 +#define BCM53022_DEVICE_ID 0x8022 +#define BCM53023_DEVICE_ID 0x8023 +#define BCM53025_DEVICE_ID 0x8025 +#define BCM58625_DEVICE_ID 0x8625 +#define BCM58622_DEVICE_ID 0x8622 +#define BCM58623_DEVICE_ID 0x8623 +#define BCM58525_DEVICE_ID 0x8525 +#define BCM58522_DEVICE_ID 0x8522 +#define BCM53020_A0_REV_ID 0 +#define BCM53020_MODEL_ID 0x3025 + +#define BCM4713_DEVICE_ID 0x4713 +#define BCM4713_A0_REV_ID 0 +#define BCM4713_A9_REV_ID 9 + +#define BCM53000_GMAC_DEVICE_ID 0x4715 +#define BCM53000_A0_REV_ID 0 + +#define BCM53010_GMAC_DEVICE_ID 0x4715 + +#define BCM53000PCIE_DEVICE_ID 0x5300 + +#define SANDBURST_VENDOR_ID 0x17ba +#define BME3200_DEVICE_ID 0x0280 +#define BME3200_A0_REV_ID 0x0000 +#define BME3200_B0_REV_ID 0x0001 +#define BM9600_DEVICE_ID 0x0480 +#define BM9600_A0_REV_ID 0x0000 +#define BM9600_B0_REV_ID 0x0010 +#define QE2000_DEVICE_ID 0x0300 +#define QE2000_A1_REV_ID 0x0001 +#define QE2000_A2_REV_ID 0x0002 +#define QE2000_A3_REV_ID 0x0003 +#define QE2000_A4_REV_ID 0x0004 +#define BCM88020_DEVICE_ID 0x0380 +#define BCM88020_A0_REV_ID 0x0000 +#define BCM88020_A1_REV_ID 0x0001 +#define BCM88020_A2_REV_ID 0x0002 +#define BCM88025_DEVICE_ID 0x0580 +#define BCM88025_A0_REV_ID 0x0000 +#define BCM88030_DEVICE_ID 0x0038 +#define BCM88030_A0_REV_ID 0x0001 +#define BCM88030_A1_REV_ID 0x0002 +#define BCM88030_B0_REV_ID 0x0011 +#define BCM88030_B1_REV_ID 0x0012 +#define BCM88034_DEVICE_ID 0x0034 +#define BCM88034_A0_REV_ID (BCM88030_A0_REV_ID) +#define BCM88034_A1_REV_ID (BCM88030_A1_REV_ID) +#define BCM88034_B0_REV_ID (BCM88030_B0_REV_ID) +#define BCM88034_B1_REV_ID (BCM88030_B1_REV_ID) +#define BCM88039_DEVICE_ID 0x0039 +#define BCM88039_A0_REV_ID (BCM88030_A0_REV_ID) +#define BCM88039_A1_REV_ID (BCM88030_A1_REV_ID) +#define BCM88039_B0_REV_ID (BCM88030_B0_REV_ID) +#define BCM88039_B1_REV_ID (BCM88030_B1_REV_ID) +#define BCM88130_DEVICE_ID 0x0480 +#define BCM88130_A0_REV_ID 0x0000 +#define BCM88130_A1_REV_ID 0x0001 +#define BCM88130_B0_REV_ID 0x0010 +#define PLX_VENDOR_ID 0x10b5 +#define PLX9656_DEVICE_ID 0x9656 +#define PLX9656_REV_ID 0x0000 +#define PLX9056_DEVICE_ID 0x9056 +#define PLX9056_REV_ID 0x0000 + +#define TK371X_DEVICE_ID 0x8600 +#define TK371X_A0_REV_ID 0x0 + +#define GEDI_DEVICE_ID 0xa100 +#define GEDI_REV_ID 0x0001 +#define ARAD_DEVICE_ID 0x8650 +#define ARAD_A0_REV_ID 0x0000 +#define ARAD_B0_REV_ID 0x0011 +#define ARAD_B1_REV_ID 0x0012 +#define BCM88650_DEVICE_ID ARAD_DEVICE_ID +#define BCM88650_A0_REV_ID ARAD_A0_REV_ID +#define BCM88650_B0_REV_ID ARAD_B0_REV_ID +#define BCM88650_B1_REV_ID ARAD_B1_REV_ID +#define BCM88750_DEVICE_ID 0x8750 +#define BCM88750_A0_REV_ID 0x0000 +#define BCM88750_B0_REV_ID 0x0011 +#define BCM88753_DEVICE_ID 0x8753 +#define BCM88753_A0_REV_ID 0x0000 +#define BCM88753_B0_REV_ID 0x0011 +#define BCM88754_DEVICE_ID 0x8754 +#define BCM88754_A0_REV_ID 0x0000 +#define BCM88754_ORIGINAL_VENDOR_ID 0x16FC +#define BCM88754_ORIGINAL_DEVICE_ID 0x020F +#define BCM88754_A0_ORIGINAL_REV_ID 0x0001 +#define BCM88755_DEVICE_ID 0x8755 +#define BCM88755_B0_REV_ID 0x0011 +#define BCM88770_DEVICE_ID 0x8770 +#define BCM88770_A1_REV_ID 0x0002 +#define BCM88773_DEVICE_ID 0x8773 +#define BCM88773_A1_REV_ID 0x0002 +#define BCM88774_DEVICE_ID 0x8774 +#define BCM88774_A1_REV_ID 0x0002 +#define BCM88775_DEVICE_ID 0x8775 +#define BCM88775_A1_REV_ID 0x0002 +#define BCM88776_DEVICE_ID 0x8776 +#define BCM88776_A1_REV_ID 0x0002 +#define BCM88777_DEVICE_ID 0x8777 +#define BCM88777_A1_REV_ID 0x0002 +#define BCM88950_DEVICE_ID 0x8950 +#define BCM88950_A0_REV_ID 0x0001 +#define BCM88950_A1_REV_ID 0x0002 +#define BCM88953_DEVICE_ID 0x8953 +#define BCM88953_A1_REV_ID 0x0002 +#define BCM88954_DEVICE_ID 0x8954 +#define BCM88954_A1_REV_ID 0x0002 +#define BCM88955_DEVICE_ID 0x8955 +#define BCM88955_A1_REV_ID 0x0002 +#define BCM88956_DEVICE_ID 0x8956 +#define BCM88956_A1_REV_ID 0x0002 +#define BCM88790_DEVICE_ID 0x8790 +#define BCM88790_A0_REV_ID 0x0001 +#define ARADPLUS_DEVICE_ID 0x8660 +#define ARADPLUS_A0_REV_ID 0x0001 +#define BCM88660_DEVICE_ID ARADPLUS_DEVICE_ID +#define BCM88660_A0_REV_ID ARADPLUS_A0_REV_ID +#define JERICHO_DEVICE_ID 0x8675 +#define JERICHO_A0_REV_ID 0x0001 +#define JERICHO_B0_REV_ID 0x0011 +#define JERICHO_A1_REV_ID 0x0002 +#define BCM88670_DEVICE_ID 0x8670 +#define BCM88670_A0_REV_ID JERICHO_A0_REV_ID +#define BCM88670_A1_REV_ID JERICHO_A1_REV_ID +#define BCM88671_DEVICE_ID 0x8671 +#define BCM88671_A0_REV_ID JERICHO_A0_REV_ID +#define BCM88671_A1_REV_ID JERICHO_A1_REV_ID +#define BCM88671M_DEVICE_ID 0x867A +#define BCM88671M_A0_REV_ID JERICHO_A0_REV_ID +#define BCM88671M_A1_REV_ID JERICHO_A1_REV_ID + +#define BCM88670_B0_REV_ID JERICHO_B0_REV_ID +#define BCM88671_B0_REV_ID JERICHO_B0_REV_ID +#define BCM88671M_B0_REV_ID JERICHO_B0_REV_ID + +#define BCM88672_DEVICE_ID 0x8672 +#define BCM88672_A0_REV_ID JERICHO_A0_REV_ID +#define BCM88672_A1_REV_ID JERICHO_A1_REV_ID + +#define BCM88672_B0_REV_ID JERICHO_B0_REV_ID + +#define BCM88673_DEVICE_ID 0x8673 +#define BCM88673_A0_REV_ID JERICHO_A0_REV_ID +#define BCM88673_A1_REV_ID JERICHO_A1_REV_ID +#define BCM88674_DEVICE_ID 0x8674 +#define BCM88674_A0_REV_ID JERICHO_A0_REV_ID +#define BCM88674_A1_REV_ID JERICHO_A1_REV_ID +#define BCM88675_DEVICE_ID JERICHO_DEVICE_ID +#define BCM88675_A0_REV_ID JERICHO_A0_REV_ID +#define BCM88675_A1_REV_ID JERICHO_A1_REV_ID +#define BCM88675M_DEVICE_ID 0x867B +#define BCM88675M_A0_REV_ID JERICHO_A0_REV_ID +#define BCM88675M_A1_REV_ID JERICHO_A1_REV_ID +#define BCM88676_DEVICE_ID 0x8676 +#define BCM88676_A0_REV_ID JERICHO_A0_REV_ID +#define BCM88676_A1_REV_ID JERICHO_A1_REV_ID +#define BCM88676M_DEVICE_ID 0x867C +#define BCM88676M_A0_REV_ID JERICHO_A0_REV_ID +#define BCM88676M_A1_REV_ID JERICHO_A1_REV_ID +#define BCM88677_DEVICE_ID 0x8677 +#define BCM88677_A0_REV_ID JERICHO_A0_REV_ID +#define BCM88677_A1_REV_ID JERICHO_A1_REV_ID +#define BCM88678_DEVICE_ID 0x8678 +#define BCM88678_A0_REV_ID JERICHO_A0_REV_ID +#define BCM88678_A1_REV_ID JERICHO_A1_REV_ID +#define BCM88679_DEVICE_ID 0x8679 +#define BCM88679_A0_REV_ID JERICHO_A0_REV_ID +#define BCM88679_A1_REV_ID JERICHO_A1_REV_ID + +#define BCM88673_B0_REV_ID JERICHO_B0_REV_ID +#define BCM88674_B0_REV_ID JERICHO_B0_REV_ID +#define BCM88675_B0_REV_ID JERICHO_B0_REV_ID +#define BCM88675M_B0_REV_ID JERICHO_B0_REV_ID +#define BCM88676_B0_REV_ID JERICHO_B0_REV_ID +#define BCM88676M_B0_REV_ID JERICHO_B0_REV_ID +#define BCM88677_B0_REV_ID JERICHO_B0_REV_ID +#define BCM88678_B0_REV_ID JERICHO_B0_REV_ID +#define BCM88679_B0_REV_ID JERICHO_B0_REV_ID +#define QMX_DEVICE_ID 0x8375 +#define QMX_A0_REV_ID 0x0001 +#define QMX_B0_REV_ID 0x0011 +#define QMX_A1_REV_ID 0x0002 +#define BCM88370_DEVICE_ID 0x8370 +#define BCM88370_A0_REV_ID QMX_A0_REV_ID +#define BCM88370_A1_REV_ID QMX_A1_REV_ID +#define BCM88371_DEVICE_ID 0x8371 +#define BCM88371_A0_REV_ID QMX_A0_REV_ID +#define BCM88371_A1_REV_ID QMX_A1_REV_ID +#define BCM88371M_DEVICE_ID 0x837A +#define BCM88371M_A0_REV_ID QMX_A0_REV_ID +#define BCM88371M_A1_REV_ID QMX_A1_REV_ID +#define BCM88375_DEVICE_ID QMX_DEVICE_ID +#define BCM88375_A0_REV_ID QMX_A0_REV_ID +#define BCM88375_A1_REV_ID QMX_A1_REV_ID +#define BCM88376_DEVICE_ID 0x8376 +#define BCM88376_A0_REV_ID QMX_A0_REV_ID +#define BCM88376_A1_REV_ID QMX_A1_REV_ID +#define BCM88376M_DEVICE_ID 0x837B +#define BCM88376M_A0_REV_ID QMX_A0_REV_ID +#define BCM88376M_A1_REV_ID QMX_A1_REV_ID +#define BCM88377_DEVICE_ID 0x8377 +#define BCM88377_A0_REV_ID QMX_A0_REV_ID +#define BCM88377_A1_REV_ID QMX_A1_REV_ID +#define BCM88378_DEVICE_ID 0x8378 +#define BCM88378_A0_REV_ID QMX_A0_REV_ID +#define BCM88378_A1_REV_ID QMX_A1_REV_ID +#define BCM88379_DEVICE_ID 0x8379 +#define BCM88379_A0_REV_ID QMX_A0_REV_ID +#define BCM88379_A1_REV_ID QMX_A1_REV_ID + +#define BCM88370_B0_REV_ID QMX_B0_REV_ID +#define BCM88371_B0_REV_ID QMX_B0_REV_ID +#define BCM88371M_B0_REV_ID QMX_B0_REV_ID +#define BCM88375_B0_REV_ID QMX_B0_REV_ID +#define BCM88376_B0_REV_ID QMX_B0_REV_ID +#define BCM88376M_B0_REV_ID QMX_B0_REV_ID +#define BCM88377_B0_REV_ID QMX_B0_REV_ID +#define BCM88378_B0_REV_ID QMX_B0_REV_ID +#define BCM88379_B0_REV_ID QMX_B0_REV_ID + + +#define JERICHO_PLUS_DEVICE_ID 0x8680 +#define JERICHO_PLUS_A0_REV_ID 0x0001 +#define BCM88680_DEVICE_ID JERICHO_PLUS_DEVICE_ID +#define BCM88680_A0_REV_ID JERICHO_PLUS_A0_REV_ID +#define BCM88680_A1_REV_ID 0x0002 + + +#define BCM88681_DEVICE_ID 0x8681 +#define BCM88681_A0_REV_ID JERICHO_PLUS_A0_REV_ID + +#define BCM88682_DEVICE_ID 0x8682 +#define BCM88682_A0_REV_ID JERICHO_PLUS_A0_REV_ID + +#define BCM88683_DEVICE_ID 0x8683 +#define BCM88683_A0_REV_ID JERICHO_PLUS_A0_REV_ID + +#define BCM88684_DEVICE_ID 0x8684 +#define BCM88684_A0_REV_ID JERICHO_PLUS_A0_REV_ID + +#define BCM88685_DEVICE_ID 0x8685 +#define BCM88685_A0_REV_ID JERICHO_PLUS_A0_REV_ID + +#define BCM88380_DEVICE_ID 0x8380 +#define BCM88380_A0_REV_ID JERICHO_PLUS_A0_REV_ID +#define BCM88381_DEVICE_ID 0x8381 +#define BCM88381_A0_REV_ID JERICHO_PLUS_A0_REV_ID + +#define JERICHO_2_DEVICE_ID 0x8690 +#define JERICHO_2_A0_REV_ID 0x0001 +#define BCM88690_DEVICE_ID JERICHO_2_DEVICE_ID +#define BCM88690_A0_REV_ID JERICHO_2_A0_REV_ID + +#define QAX_DEVICE_ID 0x8470 +#define QAX_A0_REV_ID 0x0001 +#define QAX_B0_REV_ID 0x0011 +#define BCM88470_DEVICE_ID QAX_DEVICE_ID +#define BCM88470_B0_REV_ID QAX_B0_REV_ID +#define BCM88470P_DEVICE_ID 0x847C +#define BCM88471_DEVICE_ID 0x8471 +#define BCM88473_DEVICE_ID 0x8473 +#define BCM88474_DEVICE_ID 0x8474 +#define BCM88474H_DEVICE_ID 0x847B +#define BCM88476_DEVICE_ID 0x8476 +#define BCM88477_DEVICE_ID 0x8477 + + + + +#define BCM88470_A0_REV_ID QAX_A0_REV_ID + +#define QUX_DEVICE_ID 0x8270 +#define QUX_A0_REV_ID 0x0001 +#define QUX_A1_REV_ID 0x0002 +#define QUX_B0_REV_ID 0x0011 +#define BCM88270_DEVICE_ID QUX_DEVICE_ID +#define BCM88270_A0_REV_ID QUX_A0_REV_ID +#define BCM88270_A1_REV_ID QUX_A1_REV_ID +#define BCM88272_DEVICE_ID 0x8272 +#define BCM88273_DEVICE_ID 0x8273 +#define BCM88278_DEVICE_ID 0x8278 + +#define FLAIR_DEVICE_ID 0xF000 +#define FLAIR_A0_REV_ID 0x0001 +#define BCM8206_DEVICE_ID FLAIR_DEVICE_ID +#define BCM8206_A0_REV_ID FLAIR_A0_REV_ID + +#define ARDON_DEVICE_ID 0x8202 +#define ARDON_A0_REV_ID 0x0000 +#define BCM88202_DEVICE_ID ARDON_DEVICE_ID +#define BCM88202_A0_REV_ID ARDON_A0_REV_ID +#define ARDON_A1_REV_ID 0x0001 +#define BCM88202_A1_REV_ID ARDON_A1_REV_ID +#define ARDON_A2_REV_ID 0x0002 +#define BCM88202_A2_REV_ID ARDON_A2_REV_ID +#define BCM2801PM_DEVICE_ID 0x2801 +#define BCM2801PM_A0_REV_ID 0x0000 +#define BCM88360_DEVICE_ID 0x8360 +#define BCM88360_A0_REV_ID ARADPLUS_A0_REV_ID +#define BCM88361_DEVICE_ID 0x8361 +#define BCM88361_A0_REV_ID ARADPLUS_A0_REV_ID +#define BCM88363_DEVICE_ID 0x8363 +#define BCM88363_A0_REV_ID ARADPLUS_A0_REV_ID +#define BCM88460_DEVICE_ID 0x8460 +#define BCM88460_A0_REV_ID ARADPLUS_A0_REV_ID +#define BCM88461_DEVICE_ID 0x8461 +#define BCM88461_A0_REV_ID ARADPLUS_A0_REV_ID +#define BCM88560_DEVICE_ID 0x8560 +#define BCM88560_A0_REV_ID ARADPLUS_A0_REV_ID +#define BCM88561_DEVICE_ID 0x8561 +#define BCM88561_A0_REV_ID ARADPLUS_A0_REV_ID +#define BCM88562_DEVICE_ID 0x8562 +#define BCM88562_A0_REV_ID ARADPLUS_A0_REV_ID +#define BCM88661_DEVICE_ID 0x8661 +#define BCM88661_A0_REV_ID ARADPLUS_A0_REV_ID +#define BCM88664_DEVICE_ID 0x8664 +#define BCM88664_A0_REV_ID ARADPLUS_A0_REV_ID + + +#define BCM88350_DEVICE_ID 0x8350 +#define BCM88350_B1_REV_ID ARAD_B1_REV_ID +#define BCM88351_DEVICE_ID 0x8351 +#define BCM88351_B1_REV_ID ARAD_B1_REV_ID +#define BCM88450_DEVICE_ID 0x8450 +#define BCM88450_B1_REV_ID ARAD_B1_REV_ID +#define BCM88451_DEVICE_ID 0x8451 +#define BCM88451_B1_REV_ID ARAD_B1_REV_ID +#define BCM88550_DEVICE_ID 0x8550 +#define BCM88550_B1_REV_ID ARAD_B0_REV_ID +#define BCM88551_DEVICE_ID 0x8551 +#define BCM88551_B1_REV_ID ARAD_B1_REV_ID +#define BCM88552_DEVICE_ID 0x8552 +#define BCM88552_B1_REV_ID ARAD_B1_REV_ID +#define BCM88651_DEVICE_ID 0x8651 +#define BCM88651_B1_REV_ID ARAD_B1_REV_ID +#define BCM88654_DEVICE_ID 0x8654 +#define BCM88654_B1_REV_ID ARAD_B1_REV_ID + +#define BCM88772_DEVICE_ID 0x8772 +#define BCM88952_DEVICE_ID 0x8952 +#define BCM88772_A1_REV_ID 0x0002 +#define BCM88952_A0_REV_ID 0x0001 +#define BCM88952_A1_REV_ID 0x0002 + +#define BCM88752_DEVICE_ID 0x8752 +#define BCM88752_A0_REV_ID 0x0000 +#define BCM88752_B0_REV_ID 0x0011 + + +#define BCM83207_DEVICE_ID 0x3207 +#define BCM83208_DEVICE_ID 0x3208 +#define BCM83207_A0_REV_ID 0x0001 +#define BCM83208_A0_REV_ID 1 + +#define PCP_PCI_VENDOR_ID 0x1172 +#define PCP_PCI_DEVICE_ID 0x4 + +#define ACP_PCI_VENDOR_ID 0x10ee +#define ACP_PCI_DEVICE_ID 0x7011 +#define ACP_PCI_REV_ID 0x0001 +#endif + diff --git a/platform/broadcom/saibcm-modules/make/Make.config b/platform/broadcom/saibcm-modules/make/Make.config new file mode 100644 index 0000000000..d3f83c24c3 --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Make.config @@ -0,0 +1,364 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Make.config,v 1.3 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ +# + +ifneq ($(strip $(override-target)),) +override TARGET=$(override-target) +endif + +export TARGET + +# +# Set up the target name, and the target base variables. +# +# target = The full name of the target such as vxworks-bmw +# targetbase = 1st part of target (e.g. vxworks) +# targetplat = 2nd part of target (e.g. x86) if any; otherwise same as 1st +# +target = ${TARGET} +targetsplt = $(subst -, , ${target}) # change hyphens to spaces +targetbase = $(word 1,${targetsplt}) +targetplat = $(subst ${targetbase}-,,${TARGET}) + +# +# Common configuration for all platforms +# (Additional platform-dependent configurations are in Makefile.xxx) +# + +# +# THIS FILE SHOULD NOT BE MODIFIED LOCALLY, to override, add a file +# $SDK/make/Make.local that sets your local settings, and/or provide +# a path to your settings using the MAKE_LOCAL variable. If +# either of these files exists, their values will override those in this makefile. +# +ifdef MAKE_LOCAL +-include ${MAKE_LOCAL} +endif + +-include ${SDK}/make/Make.local + +ifdef ALL_CHIPS + ROBO_CHIPS = 1 + ESW_CHIPS = 1 +else + ifndef ROBO_CHIPS + ESW_CHIPS = 1 + endif +endif # ALL_CHIPS + +# +# By default, turn off the "changing directory" message. +# +MAKEFLAGS += --no-print-directory + +# +# Use gmake by default +# + +include ${SDK}/make/Make.tools +include ${SDK}/make/Makefile.${target} + +# use QUIET=1 to control printing of compilation lines +ifdef QUIET +Q:=@ +else +Q:= +endif + +# +# Suffix to add to the "target" files to allow local builds with different +# flags. Set "target_suffix" to XXX to cause the build to put built objects +# in ${target}${target_suffix}. This allows things like building a debug +# version with different flags. This may also be set in another Makefile. +# + +#target_suffix := + +# +# Optional suffix to add to the build directory and output binary files +# to allow multiple builds to co-exist for various reasons. +# +#chip_suffix := -$(shell echo $(CHIP) | tr A-Z a-z) + +# +# Combined suffixes +# +all_suffix = ${chip_suffix}${target_suffix} + +# +# Default location to place binaries and make depend files for building +# purposes. +# +ifeq "$(HOSTTYPE)" "Windows2000PC" +BLDROOTWITHDRIVE = ${SDK}/build/${target}${all_suffix}${bldroot_suffix} +BLDROOT = ${SDK_NO_DRIVE_NAME}/build/${target}${all_suffix}${bldroot_suffix} +else # ifeq "$(HOSTTYPE)" "Windows2000PC" + +ifndef SDKBUILD +SDKBUILD :=build +endif + +BLDROOT = ${SDK}/${SDKBUILD}/$(if ${BLDCONFIG},${BLDCONFIG}/)${target}${all_suffix}${bldroot_suffix} + +endif # ifeq "$(HOSTTYPE)" "Windows2000PC" + +# This is needed because we cannot include Make.vxworks before Make.config +ifndef DEST_DIR_SUFFIX +export DEST_DIR_SUFFIX :=$(subst $(realpath $(SDK))/systems,,$(realpath $(CURDIR)/$(dir ($(firstword $(MAKEFILE_LIST)))))) +ifeq ($(MAKELEVEL),0) +endif +endif + +ifeq ($(DEST_DIR),) +export DEST_DIR :=${SDK}/${SDKBUILD}$(if ${BLDCONFIG},/${BLDCONFIG})$(DEST_DIR_SUFFIX) +endif + +ifdef LOCALDIR +BLDDIR = ${BLDROOT}/${LOCALDIR} +ifeq "$(HOSTTYPE)" "Windows2000PC" +BLDDIRWITHDRIVE = ${BLDROOTWITHDRIVE}/${LOCALDIR} +endif +else # ifdef LOCALDIR +BLDDIR = ${BLDROOT} +ifeq "$(HOSTTYPE)" "Windows2000PC" +BLDDIRWITHDRIVE = ${BLDROOTWITHDRIVE} +endif +endif # ifdef LOCALDIR + +LIBDIR = ${BLDROOT} + +# +# Export directory, where build objects used by the outside world are +# placed (exported header files, libs, bins) +# +EXPDIR = ${SDK}/export/${target}${all_suffix} + +# +# Standard include paths +# +INCDIR = ${SDK}/include + +# +# Compilation Flags +# +# Flags may be added to (see below) +# + +INCFLAGS = -I${INCDIR} -I${SDK}/systems + +CFLAGS += ${INCFLAGS} +CXXFLAGS += ${INCFLAGS} +CPPFLAGS += ${INCFLAGS} + +# +# Debug #ifdef control +# +# Compiling out #ifdef DEBUG code saves about 1.3% on executable size. +# It is recommended to leave debug enabled when developing applications. +# +ifndef DEBUG_IFDEFS +DEBUG_IFDEFS=TRUE +endif + +ifeq ($(DEBUG_IFDEFS),TRUE) +CFLAGS += -DBROADCOM_DEBUG +CXXFLAGS += -DBROADCOM_DEBUG +CPPFLAGS += -DBROADCOM_DEBUG +endif + +# +# Debug symbol information control +# +ifndef DEBUG_SYMBOLS +DEBUG_SYMBOLS=TRUE +endif + +ifeq ($(DEBUG_SYMBOLS),TRUE) +CFLAGS += -g +CXXFLAGS += -g +CPPFLAGS += -g +endif + +# +# If DEBUG_CFLAGS is set, add its contents to CFLAGS. +# May be useful for setting on the command line or adding to Make.local. +# Example: gmake DEBUG_CFLAGS=-save-temps system.c +# + +ifneq ($(DEBUG_CFLAGS),) +CFLAGS += $(DEBUG_CFLAGS) +CXXFLAGS += $(DEBUG_CFLAGS) +CPPFLAGS += $(DEBUG_CFLAGS) +endif + +# +# Optimization level +# +# Set DEBUG_OPTIMIZE to TRUE (default) to use a normal optimization +# determined by OPTFLAGS_DEFAULT in the platform Makefile. +# Set DEBUG_OPTIMIZE to FALSE to use no optimization, +# strongly recommended when using any debugger. +# Set DEBUG_OPTIMIZE to any other option string to request specific +# optimization flags (for example -O2). +# +ifndef DEBUG_OPTIMIZE +DEBUG_OPTIMIZE=TRUE +endif + +ifeq ($(DEBUG_OPTIMIZE),TRUE) +OPTFLAGS += $(OPTFLAGS_DEFAULT) +else +ifneq ($(DEBUG_OPTIMIZE),FALSE) +OPTFLAGS += $(DEBUG_OPTIMIZE) +endif +endif + +# +# Debug assertion control. +# +# Compiling out assert() saves about 1.1% on executable size, +# however doing so is VERY MUCH discouraged. +# +ifndef DEBUG_ASSERTS +DEBUG_ASSERTS=TRUE +endif + +ifeq ($(DEBUG_ASSERTS),FALSE) +CFLAGS += -DNDEBUG +CXXFLAGS += -DNDEBUG +CPPFLAGS += -DNDEBUG +endif + +# +# GCC pedantic mode. +# +ifeq ($(DEBUG_PEDANTIC),TRUE) +CFGFLAGS += -D__PEDANTIC__ +CFLAGS += --pedantic +CXXFLAGS += --pedantic +endif + +# +# In each directory, build a list of local sources, objects, and headers +# +LSRCS = $(wildcard *.c *.cpp *.s *.cc *.C) +LOBJS = $(addsuffix .o, $(basename ${LSRCS})) +BOBJS = $(addprefix ${BLDDIR}/,${LOBJS}) +LHDRS = $(wildcard *.h *.H) +LDOTIS = $(wildcard *.i) + + +# +# Rule to create object file (build) directory +# + +.PHONY: all install clean distclean + +.PRECIOUS: ${BLDDIR}/.tree + +%/.tree: + @$(ECHO) 'Creating build directory $(dir $@)' + @$(MKDIR) $(dir $@) + @$(ECHO) "Build Directory for ${LOCALDIR} Created" > $@ + +# Rule allowing build through CPP only, creates .E file from .c file. + +%.E: %.c + $Q${CC} -E ${CFLAGS} $< | sed -e '/^ *$$/d' -e p -e d > $@ + +# Rule allowing build through source only, creates .s file from .c file. + +%.s: %.c + $Q${CC} -S ${CFLAGS} $< + +# +# Default Build rules for .c --> .o, leaving the binary in BLDDIR/X.o, +# even if file not built from directory of source. +# +ifeq ($(FAST),1) +${BLDDIR}/%.o: %.c +else +ifdef GENERATE_C_FILES +${BLDDIR}/%.o: %.c +else +${BLDDIR}/%.o: %.c +endif +endif +ifdef QUIET + @${ECHO} Compiling ${LOCALDIR}/$< +endif +ifdef LOCAL_D_FILE + $Q$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -o $@ -c $< --write-user-dependencies + -@/bin/cp $*.d $(BLDDIR)/$*.d + -@/bin/rm -f $*.d +else + $Q$(CC) -MD -MF $(BLDDIR)/$*.d $(CFLAGS) $(EXTRA_CFLAGS) -o $@ -c $< +endif + @/bin/cp $(BLDDIR)/$*.d $(BLDDIR)/$*.tmp;\ + /bin/sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' \ + < $(BLDDIR)/$*.d >> $(BLDDIR)/$*.tmp; \ + /bin/sed \ + -e 's| \([0-9a-zA-Z]\)| '$(SDK)/$(LOCALDIR)'\/\1|g' \ + -e 's|^\([0-9a-zA-Z]\)|'$(SDK)/$(LOCALDIR)'/\1|g' \ + -e 's| \(\.\.\/\)| '$(SDK)/$(LOCALDIR)'\/\1|g' \ + -e 's|'$(SDK)'|'$$\{SDK\}'|g' \ + -e 's/\w*\/\.\.\/*//g' \ + -e 's/\w*\/\.\.\/*//g' \ + -e 's/\w*\/\.\.\/*//g' \ + < $(BLDDIR)/$*.tmp > $(BLDDIR)/$*.P; \ + /bin/rm -f $(BLDDIR)/$*.d $(BLDDIR)/$*.tmp + +${BLDDIR}/%.o: %.s +ifdef QUIET + @${ECHO} Assembling ${LOCALDIR}/$< +endif + $Q${CC} ${CFLAGS} ${EXTRA_CFLAGS} -c $< -o $@ + +${BLDDIR}/%.o: %.cpp +ifdef QUIET + @${ECHO} Compiling ${LOCALDIR}/$< +endif + $Q${CXX} -c ${CXXFLAGS} -c $< -o $@ + +${BLDDIR}/%.o: %.cc ${BLDDIR}/.tree +ifdef QUIET + @${ECHO} Compiling ${LOCALDIR}/$< +endif + $Q${CXX} -c ${CXXFLAGS} -c $< -o $@ + +# +# Cause "make foo.o" in any subdirectory to put the object in the build +# directory instead of the local directory. +# +%.o: ${BLDDIR}/%.o + @ + +# +# List of directories where built objects live. +# (we are not making the export directories for now) +# +#DIRS = ${BLDDIR} ${EXPDIR}/lib ${EXPDIR}/bin ${EXPDIR}/include +DIRS = ${BLDDIR} + +ifeq (C_COMPILER,$(MAKECMDGOALS)) +C_COMPILER: + @echo $(CC) +endif diff --git a/platform/broadcom/saibcm-modules/make/Make.depend b/platform/broadcom/saibcm-modules/make/Make.depend new file mode 100644 index 0000000000..3d8b8c59d9 --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Make.depend @@ -0,0 +1,109 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Make.depend,v 1.14 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ +# +# Default rule to build dependencies. This builds a x.d file for each +# x.c file that describes the dependencies. We then conditionally include +# the generated .d files. +# + +# +# If making 'clean', do not include any .d files. If they are included, +# gmake intrinsically tries to remake them all. +# +ifeq (,$(findstring clean,$(MAKECMDGOALS))) + +ZFS :=$(wildcard *.zf) +ZFC := $(ZFS:.zf=.c) + +ifdef GENERATE_C_FILES +ifndef GEN_INCS +$(error "GEN_INCS was not defined") +endif + +ZF_GEN = ${SDK}/tools/zFrameCodeGen.pl + +# 1=.zf +define ZFS_RULE +$(1:.zf=Console.c) : $(1:.zf=.c) + @echo updated $$@ from $$? + +$(1:.zf=.c) : $(1) $(ZF_GEN) + @$(PERL) $(ZF_GEN) -s -z . -p . -g $1 -t c + @echo generated ${LOCALDIR}/$$@ from $(1) + @mv $$(*F).cx $$@ + @if [ -e $$(*F)Console.cx ] ; then \ + mv $$(*F)Console.cx $$(*F)Console.c; \ + echo Created $$(*F)Console.c ;\ + fi + @if [ -e $$(*F)Console.hx ] ; then \ + echo Created $(GEN_INCS)/$$(*F)Console.hx ;\ + mv $$(*F)Console.hx $(GEN_INCS)/ ; \ + fi + @mv $$(*F).hx $(GEN_INCS)/ +endef + +$(foreach zf,$(ZFS),$(eval $(call ZFS_RULE,$(zf)))) + +${BLDDIR}/%.P : ${BLDDIR}/.tree %.c + +.PHONY: GENFILES +GENFILES: $(ZFC) + +$(BOBJS) : $(ZFC) + +else +# +# Attempt to build the depend files. If it fails, the depend file is +# removed so that it is not included in later builds. +# +${BLDDIR}/%.P : %.c ${BLDDIR}/.tree + @$(ECHO) Dependencies for ${LOCALDIR}/$< + +${BLDDIR}/%.P : %.cc ${BLDDIR}/.tree + @$(ECHO) Dependencies for ${LOCALDIR}/$< + +endif + +# +# If there are C or C++ files in this directory, include the +# depend files for them. +# + +ifeq ($(findstring _COMPILER,$(MAKECMDGOALS))$(findstring variable,$(MAKECMDGOALS)),) +ifneq ($(strip ${LSRCS}),) +ifneq (,$(findstring .o,$(MAKECMDGOALS))) +-include $(addprefix ${BLDDIR}/,$(MAKECMDGOALS:.o=.P)) $(addprefix ${BLDDIR}/,$(MAKECMDGOALS:.o=.sig)) +else +-include $(addprefix ${BLDDIR}/,$(addsuffix .P,$(basename $(LSRCS)))) $(addprefix ${BLDDIR}/,$(addsuffix .sig,$(basename $(LSRCS)))) +endif +endif +endif + +endif # !CLEANING + +clean_d:: +ifdef QUIET + @$(ECHO) Cleaning dependencies for ${LOCALDIR} +endif +ifdef GENERATE_C_FILES + $Q$(RM) $(ZFC:%=$(SDK)/$(LOCALDIR)/%) $(ZFC:%.c=$(SDK)/$(LOCALDIR)/%Console.c) +endif + +clean:: clean_d diff --git a/platform/broadcom/saibcm-modules/make/Make.kernlib b/platform/broadcom/saibcm-modules/make/Make.kernlib new file mode 100644 index 0000000000..612b7e3479 --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Make.kernlib @@ -0,0 +1,70 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Make.kernlib,v 1.7 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ +# +# Make rules/targets for handling libraries + +.SECONDARY:: ${BOBJS} + +targetlibsoname = ${lib}.so.${SHAREDLIBVER} +targetlibrealname = ${targetlibsoname} +targetlibso = ${LIBDIR}/${targetlibrealname} + +ifeq ($(TOOLS),Borland) + +LIBSUFFIX=lib + +${LIBDIR}/%.lib: ${BORLAND_BOBJS} + $(RM) $@ + $(FOREACH) -subdir "$(LIBDIR)" \ + "tlib $@ $(foreach obj, $(BORLAND_LOBJS), +-$(obj))" + +else # !Borland + +LIBSUFFIX=a + +${LIBDIR}/%.a: ${BOBJS} +ifdef QUIET + @$(ECHO) Building library $(notdir $@) +endif + $Q$(RM) $@ + $Q$(AR) ${ARFLAGS} $@ $(sort ${BOBJS}) +ifeq ($(LINUX_MAKE_SHARED_LIB),1) +ifeq ($(targetbase),unix) + $(CC) -shared -Wl,-soname,${targetlibsoname} -o ${targetlibso} ${BOBJS} -lc +endif +endif # LINUX_MAKE_SHARED_LIB # +endif # !Borland + +targetlib = ${LIBDIR}/${lib}.${LIBSUFFIX} + +all:: ${BLDDIR}/.tree ${targetlib} + +install:: all + +clean:: +ifdef QUIET + @$(ECHO) Cleaning objects for ${LOCALDIR} and ${lib} +endif + $Q$(RM) ${BOBJS} + $Q$(RM) ${targetlib} + $Q$(RM) ${targetlibso} + +distclean:: clean + diff --git a/platform/broadcom/saibcm-modules/make/Make.lib b/platform/broadcom/saibcm-modules/make/Make.lib new file mode 100644 index 0000000000..992a24e695 --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Make.lib @@ -0,0 +1,81 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Make.lib,v 1.14 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ +# +# Make rules/targets for handling libraries + +.SECONDARY:: ${BOBJS} + +BOBJS_FAST = ${BOBJS} +BOBJS_MAKE_CMD = + +ifeq ($(FAST),1) + ifneq ($(strip $(BOBJS)),) + BOBJS_FAST = + BOBJS_ARGS = -j9 + BOBJS_MAKE_CMD = pwd && make LSRUN=$(SDK)/tools/lsrun.pl $(BOBJS_ARGS) ${BOBJS} + endif +endif + +ifeq ($(TOOLS),Borland) + +LIBSUFFIX=lib + +${LIBDIR}/%.lib: ${BORLAND_BOBJS} + $(RM) $@ + $(FOREACH) -subdir "$(LIBDIR)" \ + "tlib $@ $(foreach obj, $(BORLAND_LOBJS), +-$(obj))" + +else # !Borland + +ifeq ($(LINUX_MAKE_SHARED_LIB),1) +LIBSUFFIX=so.${SHAREDLIBVER} +else +LIBSUFFIX=a +endif + +targetlib = ${LIBDIR}/${lib}.${LIBSUFFIX} + +all:: ${BLDDIR}/.tree ${targetlib} + +${LIBDIR}/%.${LIBSUFFIX}: ${BOBJS_FAST} + $(BOBJS_MAKE_CMD) +ifdef QUIET + @$(ECHO) Building library $(notdir $@) +endif + $Q$(RM) $@ +ifeq ($(LINUX_MAKE_SHARED_LIB),1) + $(CC) -shared -Wl,-soname,${lib}.${LIBSUFFIX}${EXTRA_LIB_LDFLAGS} -o ${targetlib} ${BOBJS} -lc +else + ${Q}cd $(dir $(word 1,${BOBJS}));$(AR) ${ARFLAGS} $@ $(sort $(notdir ${BOBJS})) +endif + +endif # !Borland + + +install:: all + +clean:: +ifdef QUIET + @$(ECHO) Cleaning objects for ${LOCALDIR} and ${lib} +endif + $Q$(RM) ${BOBJS} + $Q$(RM) ${targetlib} + +distclean:: clean diff --git a/platform/broadcom/saibcm-modules/make/Make.linux b/platform/broadcom/saibcm-modules/make/Make.linux new file mode 100644 index 0000000000..18a6547bc6 --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Make.linux @@ -0,0 +1,98 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# +# $Id: Make.linux,v 1.18 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ +# +# Common make targets for Linux user and kernel builds included by top +# level Linux makefiles +# +# Variables referenced: +# +# LINUX_MAKE_FLAGS +# Additional flags passed to Make +# +# LINUX_MAKE_USER +# Defined: user build +# Undefined: kernel build +# +# LINUX_MAKE_DIR +# Common makefile location, if it is not ../common +# +# + +export DEST_DIR_SUFFIX :=$(subst $(realpath $(SDK))/systems,,$(realpath $(CURDIR)/$(dir ($(firstword $(MAKEFILE_LIST)))))) + +ifeq (,$(kernel_version)) +kernel_version=2_4 +endif + +ifndef LINUX_MAKE_SHARED_LIB +LINUX_MAKE_SHARED_LIB=0 +endif + +ifeq (,$(SHAREDLIBVER)) +SHAREDLIBVER=1 +endif + +ifndef LINUX_MAKE_DIR +ifdef LINUX_MAKE_USER +LINUX_MAKE_DIR := $(SDK)/systems/linux/user/common +else +LINUX_MAKE_DIR := $(SDK)/systems/linux/kernel/common +endif +endif + +ifdef LINUX_MAKE_USER + CMD = $(LINUX_MAKE_FLAGS) -C $(LINUX_MAKE_DIR) \ + platform=$(platform) bldroot_suffix=/$(platform) kernel_version=$(kernel_version) \ + LINUX_MAKE_SHARED_LIB=$(LINUX_MAKE_SHARED_LIB) SHAREDLIBVER=$(SHAREDLIBVER) +else + export LINUX_MAKE_KERNEL := 1 + CMD = $(LINUX_MAKE_FLAGS) -C $(LINUX_MAKE_DIR) \ + platform=$(platform) kernel_version=$(kernel_version) +endif + +ifneq (,$(MIPS_TOOLS_DIR)) + CMD += MIPS_TOOLS_DIR=$(MIPS_TOOLS_DIR) +endif + +ifneq (,$(MIPS_CROSS_COMPILE)) + CMD += MIPS_CROSS_COMPILE=$(MIPS_CROSS_COMPILE) +endif + +ifneq (,$(LINUX_INCLUDE)) + CMD += LINUX_INCLUDE=$(LINUX_INCLUDE) +endif + +# gmake does not understand $(CMD) to be a submake +# options are to +$(CMD) or $(MAKE) $(CMD) +# trying the latter +build: + $(MAKE) $(CMD) + +DELIVER clean C_COMPILER CXX_COMPILER variable mod bcm user: + $(MAKE) $(CMD) $@ + +clean_d: clean + +distclean: + $(MAKE) $(CMD) $@ + +.PHONY: build clean distclean clean_d DELIVER variable mod bcm user + diff --git a/platform/broadcom/saibcm-modules/make/Make.local b/platform/broadcom/saibcm-modules/make/Make.local new file mode 100644 index 0000000000..be0603fad7 --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Make.local @@ -0,0 +1,2 @@ +#Changing value of this Knet filter +CFGFLAGS += -UKCOM_FILTER_MAX -DKCOM_FILTER_MAX=256 diff --git a/platform/broadcom/saibcm-modules/make/Make.subdirs b/platform/broadcom/saibcm-modules/make/Make.subdirs new file mode 100644 index 0000000000..69363da2ff --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Make.subdirs @@ -0,0 +1,45 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Make.subdirs,v 1.8 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ +# +# Make rules/targets for handling subdirectories + +.PHONY: ${subdirs} + +all:: ${subdirs} +ifdef QUIET + @$(ECHO) Subdirectory build for ${subdirs} +endif + +${subdirs}:: + $Q$(MAKE) -C $@ kernel_version=$(kernel_version) LINUX_MAKE_SHARED_LIB=${LINUX_MAKE_SHARED_LIB} SHAREDLIBVER=${SHAREDLIBVER} + +ifeq "$(HOSTTYPE)" "Windows2000PC" +clean clean_d install distclean:: +ifdef QUIET + @$(ECHO) Subdirectory $@ for ${subdirs} +endif + $Q$(FOREACH) "$(subdirs)" "${MAKE} -C ## $@" +else +clean clean_d install distclean:: +ifdef QUIET + @$(ECHO) Subdirectory $@ for ${subdirs} +endif + @(for name in $(subdirs); do $(MAKE) -C $$name $@; done) +endif diff --git a/platform/broadcom/saibcm-modules/make/Make.tools b/platform/broadcom/saibcm-modules/make/Make.tools new file mode 100644 index 0000000000..c53d9d4276 --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Make.tools @@ -0,0 +1,39 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Make.tools,v 1.2 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ + +SYSNAME := $(shell uname -s) +HCC ?=/usr/bin/gcc +SED = /bin/sed +COMPRESS = /usr/bin/compress +PERL = /usr/bin/perl +LN = /bin/ln +HOSTTYPE= i386-linux + +# +# Platform Independent +# +MKTOOL = $(PERL) ${SDK}/tools/mktool.pl +RM = $(MKTOOL) -rm +MKDIR = $(MKTOOL) -md +FOREACH = $(MKTOOL) -foreach +CP = $(MKTOOL) -cp +MAKEDEP = $(MKTOOL) -dep +ECHO = $(MKTOOL) -echo +MKBEEP = ${MKTOOL} -beep diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-gto b/platform/broadcom/saibcm-modules/make/Makefile.linux-gto new file mode 100644 index 0000000000..ee45fc26a5 --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-gto @@ -0,0 +1,115 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Makefile.linux-gto-4_4,v 1.42 Broadcom SDK $ +# $Copyright: (c) 2015 Broadcom Corp. +# All Rights Reserved.$ + +# User must select one platform from below. +ifeq (,$(BUILD_PLATFORM)) +BUILD_PLATFORM=POWERPC_LINUX +endif + +# TOOLCHAIN_BASE_DIR Toolchain base directory for GTO devices +# TARGET_ARCHITECTURE Compiler for target architecture +# KERNDIR Kernel directory for iPROC-CMICd devices +TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/gto +TARGET_ARCHITECTURE := powerpc-broadcom-linux-gnuspe +KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/current + + +ifeq (,$(CROSS_COMPILE)) +CROSS_COMPILE := $(TARGET_ARCHITECTURE)- +endif + + +# GTO toolchain +TOOLCHAIN_BIN_DIR := $(TOOLCHAIN_BASE_DIR)/toolchain/host/usr/bin +override PATH := $(TOOLCHAIN_BIN_DIR)/../$(TARGET_ARCHITECTURE)/bin:$(TOOLCHAIN_BIN_DIR):$(PATH) +export TOOLCHAIN_BIN_DIR + + +# Default Linux include directory +ifeq (,$(LINUX_INCLUDE)) +LINUX_INCLUDE := $(KERNDIR)/include +endif + +CFGFLAGS += -DSYS_BE_PIO=1 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=1 +ENDIAN = BE_HOST=1 +CFGFLAGS += -D$(ENDIAN) +CFGFLAGS += -DBCM_PLATFORM_STRING=\"GTO_MPC8548\" +CFGFLAGS += -DSAL_BDE_DMA_MEM_DEFAULT=32 + +# Extra variables. +EXTRA_CFLAGS = -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) + +ARCH = powerpc +KBUILD_VERBOSE = 1 + +export ARCH KBUILD_VERBOSE + + +# From linux/arch/ppc/Makefile +comma = , +basetarget = $(basename $(notdir $@)) +modname = $(basetarget) + +name-fix = $(subst $(comma),_,$(subst -,_,$1)) +basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))" +modname_flags = $(if $(filter 1,$(words $(modname))),\ + -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))") + +KFLAG_INCLD = $(TOOLCHAIN_BIN_DIR)/../lib/gcc/$(TARGET_ARCHITECTURE)/4.6.4/include + +ifdef BROADCOM_SVK +ifdef BCM_BME3200_B0 +PLX_PCI2LBUS=1 +endif +ifdef BCM_BM9600_B0 +PLX_PCI2LBUS=1 +endif +ifeq ($PLX_PCI2LBUS, 1) +CFLAGS += -DBCM_PLX9656_LOCAL_BUS -DBDE_LINUX_NON_INTERRUPTIBLE +endif +endif + +ifdef DPP_CHIPS +CFLAGS += -DDUNE_BCM -D__DUNE_GTO_BCM_CPU__ -D__DUNE_LINUX_BCM_CPU_PCIE__ -D__DUNE_LINUX_BCM_CPU_PCP_DMA__ +CFGFLAGS += -DSOC_CM_FUNCTION +endif + +ifdef DFE_CHIPS +CFLAGS += -DDUNE_BCM -D__DUNE_GTO_BCM_CPU__ -D__DUNE_LINUX_BCM_CPU_PCIE__ +CFGFLAGS += -DSOC_CM_FUNCTION +endif + +ifdef SHADOW_PLX +CFLAGS += -DBCM_PLX9656_LOCAL_BUS -DBDE_LINUX_NON_INTERRUPTIBLE -DSHADOW_SVK +endif + +ifeq (,$(KFLAGS)) +KFLAGS := -D__KERNEL__ -m32 -nostdinc -isystem $(KFLAG_INCLD) -I$(LINUX_INCLUDE) -include $(LINUX_INCLUDE)/generated/uapi/linux/version.h -include $(LINUX_INCLUDE)/generated/autoconf.h -I$(KERNDIR)/arch/powerpc -I$(KERNDIR)/arch/powerpc/include -I$(KERNDIR)/include/asm-powerpc -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -msoft-float -pipe -ffixed-r2 -mmultiple -mno-altivec -funit-at-a-time -Wa,-me500 -fomit-frame-pointer -Wdeclaration-after-statement -Wno-pointer-sign +endif + +ifneq (,$(findstring TCL,$(FEATURE_LIST))) +#LINK_STATIC = 0 +#export LINK_STATIC +endif + +ifneq ($(targetplat),user) +include ${SDK}/make/Makefile.linux-kernel-4_4 +endif + diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-gto-2_6 b/platform/broadcom/saibcm-modules/make/Makefile.linux-gto-2_6 new file mode 100644 index 0000000000..0ca62fc01f --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-gto-2_6 @@ -0,0 +1,271 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Makefile.linux-gto-2_6,v 1.42 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ + +# User must select one platform from below.By default WR_LINUX is selected. . +ifeq (,$(BUILD_PLATFORM)) +#BUILD_PLATFORM=ELDK +BUILD_PLATFORM=WR_LINUX +endif + +# Specify the ELDK version you want to use for building SDK. +ifeq (,$(ELDK_VERSION)) +ifeq (ELDK,$(BUILD_PLATFORM)) +ELDK_VERSION=4.0 +endif +endif + +# Specify the KERNEL VERSION you want to use for building SDK. +ifeq (,$(KERN_VER)) +ifeq (ELDK,$(BUILD_PLATFORM)) +KERN_VER=2.6.21.7 +endif +endif + + +# Specify the Windriver Linux version here.For example '2.0' as shown below. +ifeq (WR_LINUX,$(BUILD_PLATFORM)) +ifeq (,$(WRS_LINUX_VERSION)) +WRS_LINUX_VERSION=2.0 +endif +endif + + +#glibc_small and glibc_std have their own cross-compilation tools and and path for these tools are different as implemented below. To enable glibc_small build, line given below should be uncommented. + +#WRL_GLIBC_SMALL=TRUE + +ifeq (2.0,$(WRS_LINUX_VERSION)) +ifeq ($(WRL_GLIBC_SMALL),TRUE) + +ifeq (,$(CROSS_COMPILE)) +CROSS_COMPILE := powerpc-wrs-linux-gnu-ppc_e500v2-glibc_small- +endif + +KERNDIR ?=/projects/ntsw-tools/linux/wrslinux_2.0/gto/glibc_small/build/linux-2.6.21-standard + +else + +ifeq (,$(CROSS_COMPILE)) +CROSS_COMPILE := powerpc-wrs-linux-gnu-ppc_e500v2-glibc_std- +endif + +KERNDIR ?= /projects/ntsw-tools/linux/wrslinux_2.0/gto/glibc_std/build/linux-2.6.21-standard + +endif + +export WRL_GLIBC_SMALL + +# After this point glibc_std and glibc_small share these flags + +WRLINUX_BASE ?=/tools/windriver/linux_ed/2.0_GA/Linux +TOOLCHAIN_EXEC_PREFIX=$(WRLINUX_BASE)/gnu/4.1-wrlinux-2.0/x86-linux2 +TOOLCHAIN_BIN_DIR=$(TOOLCHAIN_EXEC_PREFIX) +WIND_LIC_PROXY=$(WRLINUX_BASE)/setup/x86-linux2/bin +WRLINUX_GNU_PATH = $(WRLINUX_BASE)/gnu/4.1-wrlinux-2.0/x86-linux2/bin +override PATH := $(TOOLCHAIN_EXEC_PREFIX):$(KERNDIR)/../../host-cross/bin:$(KERNDIR)/../../host-cross/powerpc-wrs-linux-gnu/bin:$(WRLINUX_GNU_PATH):$(PATH) +export TOOLCHAIN_EXEC_PREFIX TOOLCHAIN_BIN_DIR WIND_LIC_PROXY +endif + + +ifeq (3.0,$(WRS_LINUX_VERSION)) +ifeq ($(WRL_GLIBC_SMALL),TRUE) + +ifeq (,$(CROSS_COMPILE)) +CROSS_COMPILE := powerpc-wrs-linux-gnu-ppc_e500v2-glibc_small- +endif + +KERNDIR ?=/projects/ntsw-tools/linux/wrslinux_3.0/gto/bcm98548xmc_30_glibc_small/build/linux-broadcom_bcm98548xmc-standard-build +KERNDIR_STD ?=/projects/ntsw-tools/linux/wrslinux_3.0/gto/bcm98548xmc_30_glibc_small/build/linux + +else + +ifeq (,$(CROSS_COMPILE)) +CROSS_COMPILE := powerpc-wrs-linux-gnu-ppc_e500v2-glibc_std- +endif + +KERNDIR ?=/projects/ntsw-tools/linux/wrslinux_3.0/gto/bcm98548xmc_30_glibc_std_debug/build/linux-broadcom_bcm98548xmc-standard-build +KERNDIR_STD ?=/projects/ntsw-tools/linux/wrslinux_3.0/gto/bcm98548xmc_30_glibc_std_debug/build/linux + +endif + +export WRL_GLIBC_SMALL + +# After this point glibc_std and glibc_small share these flags + +WRLINUX_BASE ?=/tools/windriver/linux_ed/3.0/Linux +TOOLCHAIN_EXEC_PREFIX=$(WRLINUX_BASE)/wrlinux-3.0/layers/wrll-toolchain-4.3-85/powerpc/toolchain/x86-linux2 +TOOLCHAIN_BIN_DIR=$(TOOLCHAIN_EXEC_PREFIX) +WIND_LIC_PROXY=$(WRLINUX_BASE)/setup/x86-linux2/bin +WRLINUX_GNU_PATH = $(WRLINUX_BASE)/wrlinux-3.0/layers/wrll-toolchain-4.3-85/powerpc/toolchain/x86-linux2/bin +override PATH := $(TOOLCHAIN_EXEC_PREFIX):$(KERNDIR_STD)/../../host-cross/bin:$(KERNDIR_STD)/../../host-cross/powerpc-wrs-linux-gnu/bin:$(WRLINUX_GNU_PATH):$(PATH) +export TOOLCHAIN_EXEC_PREFIX TOOLCHAIN_BIN_DIR WIND_LIC_PROXY + +LINUX_INCLUDE_STD := $(KERNDIR_STD)/include + +endif + +ifeq (ELDK,$(BUILD_PLATFORM)) +ifeq (2.6.21.7, $(KERN_VER)) + +ifeq (,$(CROSS_COMPILE)) +CROSS_COMPILE := ppc_85xx- +endif + +ifeq (4.0, $(ELDK_VERSION)) +override PATH := /tools/eldk/4.0/usr/bin:$(PATH) +else +override PATH := /tools/eldk/4.1/usr/bin:$(PATH) +endif +KERNDIR ?= /projects/ntsw-tools/linux/eldk/gto_eldk/linux-2.6.21.7 +endif +endif + +ifeq (ELDK,$(BUILD_PLATFORM)) +ifeq (2.6.24.4, $(KERN_VER)) + +ifeq (,$(CROSS_COMPILE)) +CROSS_COMPILE := ppc_85xx- +endif + +ifeq (4.0, $(ELDK_VERSION)) +override PATH := /tools/eldk/4.0/usr/bin:$(PATH) +else +override PATH := /tools/eldk/4.1/usr/bin:$(PATH) +endif +KERNDIR ?= /projects/ntsw-tools/linux/eldk/gto_eldk/linux-2.6.24.4 +endif +endif + + +ifeq (ELDK,$(BUILD_PLATFORM)) +ifeq (2.6.25, $(KERN_VER)) + +ifeq (,$(CROSS_COMPILE)) +CROSS_COMPILE := ppc_85xx- +endif + +ifeq (4.0, $(ELDK_VERSION)) +override PATH := /tools/eldk/4.0/usr/bin:$(PATH) +else +override PATH := /tools/eldk/4.1/usr/bin:$(PATH) +endif +KERNDIR ?= /projects/ntsw-tools/linux/eldk/gto_eldk/linux-2.6.25 +endif +endif + + +# Default Linux include directory +ifeq (,$(LINUX_INCLUDE)) +LINUX_INCLUDE := $(KERNDIR)/include +endif + +CFGFLAGS += -DSYS_BE_PIO=1 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=1 +ENDIAN = BE_HOST=1 +CFGFLAGS += -D$(ENDIAN) +CFGFLAGS += -DBCM_PLATFORM_STRING=\"GTO_MPC8548\" +CFGFLAGS += -DSAL_BDE_DMA_MEM_DEFAULT=32 + +# Extra variables. +EXTRA_CFLAGS = -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) + +ARCH = powerpc +KBUILD_VERBOSE = 1 + +export ARCH KBUILD_VERBOSE + + +# From linux/arch/ppc/Makefile +comma = , +basetarget = $(basename $(notdir $@)) +modname = $(basetarget) + +name-fix = $(subst $(comma),_,$(subst -,_,$1)) +basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))" +modname_flags = $(if $(filter 1,$(words $(modname))),\ + -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))") + + +ifeq (,$(KFLAG_INCLD)) +ifeq (4.0,$(ELDK_VERSION)) +ifeq (ELDK,$(BUILD_PLATFORM)) +KFLAG_INCLD = /tools/eldk/4.0/usr/lib/gcc/powerpc-linux/4.0.0/include +endif +endif + +ifeq (4.1,$(ELDK_VERSION)) +ifeq (ELDK,$(BUILD_PLATFORM)) +KFLAG_INCLD = /tools/eldk/4.1/usr/lib/gcc/powerpc-linux/4.0.0/include +endif +endif + +ifeq (2.0,$(WRS_LINUX_VERSION)) +KFLAG_INCLD = $(WRLINUX_GNU_PATH)/../lib/gcc/powerpc-wrs-linux-gnu/4.1.2/include +endif + +ifeq (3.0,$(WRS_LINUX_VERSION)) +KFLAG_INCLD = $(WRLINUX_GNU_PATH)/../lib/gcc/powerpc-wrs-linux-gnu/4.3.2/include +endif +endif + +ifdef BROADCOM_SVK +ifdef BCM_BME3200_B0 +PLX_PCI2LBUS=1 +endif +ifdef BCM_BM9600_B0 +PLX_PCI2LBUS=1 +endif +ifeq ($PLX_PCI2LBUS, 1) +CFLAGS += -DBCM_PLX9656_LOCAL_BUS -DBDE_LINUX_NON_INTERRUPTIBLE +endif +endif + +ifdef DPP_CHIPS +CFLAGS += -DDUNE_BCM -D__DUNE_LINUX_BCM_CPU_PCP_DMA__ +CFGFLAGS += -DSOC_CM_FUNCTION +endif + +ifdef DFE_CHIPS +CFLAGS += -DDUNE_BCM +CFGFLAGS += -DSOC_CM_FUNCTION +endif + +ifdef SAND_CHIPS +CFLAGS += -D__DUNE_GTO_BCM_CPU__ -D__DUNE_LINUX_BCM_CPU_PCIE__ +endif + +ifdef SHADOW_PLX +CFLAGS += -DBCM_PLX9656_LOCAL_BUS -DBDE_LINUX_NON_INTERRUPTIBLE -DSHADOW_SVK +endif + +ifeq (,$(KFLAGS)) +KFLAGS := -D__KERNEL__ -m32 -nostdinc -isystem $(KFLAG_INCLD) -I$(LINUX_INCLUDE) -include $(LINUX_INCLUDE)/linux/version.h -include $(LINUX_INCLUDE)/generated/autoconf.h -I$(KERNDIR)/arch/powerpc -I$(KERNDIR)/arch/powerpc -I$(KERNDIR)/arch/powerpc/include -I$(KERNDIR)/include/asm-powerpc -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -msoft-float -pipe -ffixed-r2 -mmultiple -mno-altivec -funit-at-a-time -Wa,-me500 -fomit-frame-pointer -Wdeclaration-after-statement -Wno-pointer-sign +endif + +#Wind river Linux 3.0 needs addtional flags +ifeq (3.0,$(WRS_LINUX_VERSION)) + +# Use MSI interrupts if kernel is compiled with MSI support. +#CFLAGS += -DBDE_LINUX_USE_MSI_INTERRUPT +KFLAGS += -I$(LINUX_INCLUDE_STD) -I$(KERNDIR_STD)/arch/powerpc -I$(KERNDIR_STD)/arch/powerpc/include -I$(KERNDIR_STD)/include.asm-powerpc -mno-spe +endif + +ifneq ($(targetplat),user) +include ${SDK}/make/Makefile.linux-kernel-2_6 +endif diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc b/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc new file mode 100644 index 0000000000..272ad93ef8 --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc @@ -0,0 +1,93 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Makefile.linux-iproc Exp $ +# $Copyright: (c) 2007 Broadcom Corp. +# All Rights Reserved.$ +# Makefile for iproc-CMICd + +# User must select one platform from below.By default ARM_LINUX is selected. . +ifeq (,$(BUILD_PLATFORM)) +BUILD_PLATFORM=ARM_LINUX +endif + +# TOOLCHAIN_BASE_DIR Toolchain base directory for iPROC-CMICd devices +# TARGET_ARCHITECTURE Compiler for target architecture +# KERNDIR Kernel directory for iPROC-CMICd devices +ifeq (BE,$(ENDIAN_MODE)) +TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/iproc-be/XLDK +TARGET_ARCHITECTURE:=armeb-broadcom-linux-uclibcgnueabi +KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux +else +TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/iproc/XLDK +TARGET_ARCHITECTURE:= arm-broadcom-linux-uclibcgnueabi +KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux +endif + +ifeq (,$(CROSS_COMPILE)) +CROSS_COMPILE:= $(TARGET_ARCHITECTURE)- +endif + +# arm9tools +TOOLCHAIN_BIN_DIR=$(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/bin +override PATH:=$(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/$(TARGET_ARCHITECTURE)/bin:$(TOOLCHAIN_BIN_DIR):$(PATH) +LD_LIBRARY_PATH=$(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/lib + +export TOOLCHAIN_BIN_DIR LD_LIBRARY_PATH + +# Default Linux include directory +ifeq (,$(LINUX_INCLUDE)) +LINUX_INCLUDE := $(KERNDIR)/include +endif + +ifeq (BE,$(ENDIAN_MODE)) +CFGFLAGS += -DSYS_BE_PIO=1 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=1 +ENDIAN = BE_HOST=1 +else +CFGFLAGS += -DSYS_BE_PIO=0 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=0 +ENDIAN = LE_HOST=1 +endif + +CFGFLAGS += -D$(ENDIAN) -DIPROC_CMICD +CFGFLAGS += -DBCM_PLATFORM_STRING=\"IPROC_CMICD\" + +ARCH = arm +KBUILD_VERBOSE = 1 + +export ARCH KBUILD_VERBOSE + +comma = , +basetarget = $(basename $(notdir $@)) +modname = $(basetarget) + +# Extra variables. +EXTRA_CFLAGS = -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) + +name-fix = $(subst $(comma),_,$(subst -,_,$1)) +basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))" +modname_flags = $(if $(filter 1,$(words $(modname))),\ + -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))") + +KFLAG_INCLD ?= $(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/lib/gcc/$(TARGET_ARCHITECTURE)/4.9.3/include + +ifeq (,$(KFLAGS)) +KFLAGS := -D__LINUX_ARM_ARCH__=7 -D__KERNEL__ -nostdinc -isystem $(KFLAG_INCLD) -I$(LINUX_INCLUDE) -include $(LINUX_INCLUDE)/generated/autoconf.h -I$(KERNDIR)/arch/arm/include -I$(KERNDIR)/arch/arm/include/generated -I$(KERNDIR)/arch/arm/mach-iproc/include -Wall -Wstrict-prototypes -Wno-trigraphs -Os -fno-strict-aliasing -fno-common -marm -mabi=aapcs-linux -fno-pic -pipe -msoft-float -ffreestanding -march=armv7-a -mfpu=vfp -mfloat-abi=softfp -fomit-frame-pointer -g -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign -mlong-calls +KFLAGS += -I$(LINUX_INCLUDE)/uapi -I$(LINUX_INCLUDE)/generated/uapi -I$(KERNDIR)/arch/arm/include/uapi -I$(KERNDIR)/arch/arm/include/generated/uapi +endif + +ifneq ($(targetplat),user) +include ${SDK}/make/Makefile.linux-kernel-3_6 +endif diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc-3_14 b/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc-3_14 new file mode 100644 index 0000000000..e8a17b1847 --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc-3_14 @@ -0,0 +1,104 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Makefile.linux-iproc-3_6,v 1.1 Broadcom SDK $ +# $Copyright: (c) 2007 Broadcom Corp. +# All Rights Reserved.$ +# Makefile for iproc-CMICd + +# User must select one platform from below.By default ARM_LINUX is selected. . +ifeq (,$(BUILD_PLATFORM)) +BUILD_PLATFORM=ARM_LINUX +endif + +# TOOLCHAIN_BASE_DIR Toolchain base directory for iPROC-CMICd devices +# TARGET_ARCHITECTURE Compiler for target architecture +# KERNDIR Kernel directory for iPROC-CMICd devices +ifeq (BE,$(ENDIAN_MODE)) +TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk37-be/buildroot-2013.11-gcc48-opt-broadcom +TARGET_ARCHITECTURE:=armeb-buildroot-linux-gnueabi +KERNDIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk37-be/XLDK/kernel/linux +else +TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk37/XLDK +TARGET_ARCHITECTURE:= arm-broadcom-linux-uclibcgnueabi +KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux +endif + + +ifeq (,$(CROSS_COMPILE)) +CROSS_COMPILE:= $(TARGET_ARCHITECTURE)- +endif + +# arm9tools +ifeq (BE,$(ENDIAN_MODE)) +TOOLCHAIN_BIN_DIR=$(TOOLCHAIN_BASE_DIR)/host/usr/bin +override PATH:=$(TOOLCHAIN_BASE_DIR)/host/usr/$(TARGET_ARCHITECTURE)/bin:$(TOOLCHAIN_BIN_DIR):$(PATH) +LD_LIBRARY_PATH=$(TOOLCHAIN_BASE_DIR)/host/usr/lib +else +TOOLCHAIN_BIN_DIR=$(TOOLCHAIN_BASE_DIR)/buildroot/usr/bin +override PATH:=$(TOOLCHAIN_BASE_DIR)/buildroot/usr/$(TARGET_ARCHITECTURE)/bin:$(TOOLCHAIN_BIN_DIR):$(PATH) +LD_LIBRARY_PATH=$(TOOLCHAIN_BASE_DIR)/buildroot/usr/lib +endif + +export TOOLCHAIN_BIN_DIR LD_LIBRARY_PATH + +# Default Linux include directory +ifeq (,$(LINUX_INCLUDE)) +LINUX_INCLUDE := $(KERNDIR)/include +endif + +ifeq (BE,$(ENDIAN_MODE)) +CFGFLAGS += -DSYS_BE_PIO=1 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=1 +ENDIAN = BE_HOST=1 +else +CFGFLAGS += -DSYS_BE_PIO=0 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=0 +ENDIAN = LE_HOST=1 +endif + +CFGFLAGS += -D$(ENDIAN) -DIPROC_CMICD +CFGFLAGS += -DBCM_PLATFORM_STRING=\"IPROC_CMICD\" + +ARCH = arm +KBUILD_VERBOSE = 1 + +export ARCH KBUILD_VERBOSE + +comma = , +basetarget = $(basename $(notdir $@)) +modname = $(basetarget) + +# Extra variables. +EXTRA_CFLAGS = -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) + +name-fix = $(subst $(comma),_,$(subst -,_,$1)) +basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))" +modname_flags = $(if $(filter 1,$(words $(modname))),\ + -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))") + +ifeq (BE,$(ENDIAN_MODE)) +KFLAG_INCLD ?= $(TOOLCHAIN_BASE_DIR)/host/usr/lib/gcc/$(TARGET_ARCHITECTURE)/4.8.2/include +else +KFLAG_INCLD ?= $(TOOLCHAIN_BASE_DIR)/buildroot/usr/lib/gcc/$(TARGET_ARCHITECTURE)/4.7.2/include +endif + +ifeq (,$(KFLAGS)) +KFLAGS := -D__LINUX_ARM_ARCH__=7 -D__KERNEL__ -nostdinc -isystem $(KFLAG_INCLD) -I$(LINUX_INCLUDE) -include $(LINUX_INCLUDE)/generated/autoconf.h -I$(KERNDIR)/arch/arm/include -I$(KERNDIR)/arch/arm/include/generated -I$(KERNDIR)/arch/arm/mach-northstar/include -I$(KERNDIR)/arch/arm/plat-iproc/include -Wall -Wstrict-prototypes -Wno-trigraphs -Os -fno-strict-aliasing -fno-common -marm -mabi=aapcs-linux -fno-pic -pipe -msoft-float -ffreestanding -march=armv7-a -mfpu=vfp -mfloat-abi=softfp -fomit-frame-pointer -g -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign -mlong-calls +KFLAGS += -I$(LINUX_INCLUDE)/uapi -I$(LINUX_INCLUDE)/generated/uapi -I$(KERNDIR)/arch/arm/include/uapi -I$(KERNDIR)/arch/arm/include/generated/uapi +endif + +ifneq ($(targetplat),user) +include ${SDK}/make/Makefile.linux-kernel-3_6 +endif diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel b/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel new file mode 100644 index 0000000000..2b8c36d6d4 --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel @@ -0,0 +1,113 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Makefile.linux-kernel,v 1.27 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ + +# Configuration Flags + +# Filter out features that cannot or should not be supported in kernel mode +_FEATURE_EXCLUDE_LIST += EDITLINE TCL OOB_RCPU CINT APIMODE DUNE_UI C_UNIT +FEATURE_EXCLUDE_LIST = $(sort $(_FEATURE_EXCLUDE_LIST)) +# Tools + +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +LD = $(CROSS_COMPILE)ld +AR = $(CROSS_COMPILE)ar +ARFLAGS = -rc +STRIP = $(CROSS_COMPILE)strip +RANLIB = $(CROSS_COMPILE)ranlib +OBJCOPY = $(CROSS_COMPILE)objcopy + +# Handle differences between gcc 2.x and gcc 3.x +gcc-tune-flag = $(shell if ${CC} -dumpspecs | grep mcpu >/dev/null; then echo cpu; else echo tune; fi) + +# Configuration Variables + +# OSType Defines: This defines the type of RTOS or microkernel which you +# are compiling the SAL (and its associated driver) for. New platforms +# can be created by porting the routines (system.c) to your platform and +# adding the define in this Makefile. + +OSTYPE = LINUX + +# +# ORIGIN is used to Optionally select different CFLAGS. It is used to import +# source from other vendors. If SOURCE=Broadcom, then the BCM_ flags are added +# to those passed to the compiler. If SOURCE != Broadcom, BCM_ flags are NOT +# added. +# +# Default specifies Broadcom +# +ifndef ORIGIN + ORIGIN = Broadcom +endif + +# +# STD_{C|CPP|CXX}FLAGS - Standard flags used by ALL compilations +# BCM_{C|CPP|CXX}FLAGS - Flags used for Broadcom source files +# OPT_{C|CPP|CXX}FLAGS - Defined in local make files BEFORE inclusion of +# this Makefile, to define local "Extra" flags. +# + +CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \ + -I$(SDK)/systems/bde/linux/include \ + -I$(LINUX_INCLUDE) + +CFGFLAGS += -DNO_FILEIO -DNO_CTRL_C -DNO_MEMTUNE + +CFGFLAGS += -D$(OSTYPE) + +# No user sal for the linux kernel +# NO_SAL_APPL=1 + +STD_CFLAGS = $(KFLAGS) $(CFGFLAGS) + + +STD_CPPFLAGS = ${STD_CFLAGS} +STD_CXXFLAGS = ${STD_CFLAGS} + +BCM_CFLAGS = -Wall -Werror +BCM_CPPFLAGS = ${BCM_CFLAGS} +BCM_CXXFLAGS = ${BCM_CFLAGS} + +ifeq (${ORIGIN}, Broadcom) + CFLAGS += ${STD_CFLAGS} ${BCM_CFLAGS} ${OPT_CFLAGS} + CPPFLAGS += ${STD_CPPFLAGS} ${BCM_CPPFLAGS} ${OPT_CPPFLAGS} + CXXFLAGS += ${STD_CXXFLAGS} ${BCM_CXXFLAGS} ${OPT_CXXFLAGS} +else + CFLAGS += ${STD_CFLAGS} ${OPT_CFLAGS} + CPPFLAGS += ${STD_CPPFLAGS} ${OPT_CPPFLAGS} + CXXFLAGS += ${STD_CXXFLAGS} ${OPT_CXXFLAGS} +endif + +# +# Ignore pedantic flag for kernel modules +# +ifdef DEBUG_PEDANTIC +DEBUG_PEDANTIC = FALSE +endif + +# +# DEPEND is used as a command to generate the list of dependencies. +# The format of the output must be +# "file.o : file.c a/b/c.h d/e/f.h ...", +# if it is on multiple lines, each line must end in a backslash. +# The output MUST be on standard out. +# +DEPEND = ${CC} -M $(CFLAGS) $< diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-2_6 b/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-2_6 new file mode 100644 index 0000000000..52660bc64f --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-2_6 @@ -0,0 +1,149 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Makefile.linux-kernel-2_6,v 1.40 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ + +# Configuration Flags + +# Filter out features that cannot or should not be supported in kernel mode + +_FEATURE_EXCLUDE_LIST += EDITLINE TCL OOB_RCPU CINT APIMODE DUNE_UI C_UNIT +FEATURE_EXCLUDE_LIST = $(sort $(_FEATURE_EXCLUDE_LIST)) + +# Tools + +# Conditionally Replaces DEFAULT var +ifeq ($(origin CC),default) +CC = $(LSRUN) $(CROSS_COMPILE)gcc +endif + +ifeq ($(origin CXX),default) +CXX = $(CROSS_COMPILE)g++ +endif + +ifeq ($(origin LD),default) +LD = $(CROSS_COMPILE)ld +endif + +ifeq ($(origin AR),default) +AR = $(CROSS_COMPILE)ar +endif + +ifeq ($(origin AS),default) +AS = $(CROSS_COMPILE)as +endif + +ifeq ($(origin ARFLAGS),default) + ARFLAGS = -rc +endif + +STRIP = $(CROSS_COMPILE)strip +RANLIB = $(CROSS_COMPILE)ranlib +OBJCOPY = $(CROSS_COMPILE)objcopy +NM = $(CROSS_COMPILE)nm + +# Handle differences between gcc 2.x and gcc 3.x +gcc-tune-flag = $(shell if ${CC} -dumpspecs | grep mcpu >/dev/null; then echo cpu; else echo tune; fi) + +# Configuration Variables + +# OSType Defines: This defines the type of RTOS or microkernel which you +# are compiling the SAL (and its associated driver) for. New platforms +# can be created by porting the routines (system.c) to your platform and +# adding the define in this Makefile. + +OSTYPE = LINUX + +# +# ORIGIN is used to Optionally select different CFLAGS. It is used to import +# source from other vendors. If SOURCE=Broadcom, then the BCM_ flags are added +# to those passed to the compiler. If SOURCE != Broadcom, BCM_ flags are NOT +# added. +# +# Default specifies Broadcom +# +ifndef ORIGIN + ORIGIN = Broadcom +endif + +# +# STD_{C|CPP|CXX}FLAGS - Standard flags used by ALL compilations +# BCM_{C|CPP|CXX}FLAGS - Flags used for Broadcom source files +# OPT_{C|CPP|CXX}FLAGS - Defined in local make files BEFORE inclusion of +# this Makefile, to define local "Extra" flags. +# + +ifdef IPROC_BUILD +CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \ + -I$(SDK)/systems/bde/linux/include \ + -I$(LINUX_INCLUDE) \ + -I$(KERNDIR)/arch/$(ARCH) +else +CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \ + -I$(SDK)/systems/bde/linux/include \ + -I$(LINUX_INCLUDE) \ + -I$(LINUX_INCLUDE)/asm/gcc \ + -I$(LINUX_INCLUDE)/asm/mach-generic \ + -I$(KERNDIR)/arch/$(ARCH) +endif + +CFGFLAGS += -DNO_FILEIO -DNO_CTRL_C -DNO_MEMTUNE + +CFGFLAGS += -D$(OSTYPE) + +# No user sal for the linux kernel +# NO_SAL_APPL=1 + +STD_CFLAGS = $(KFLAGS) $(CFGFLAGS) + + +STD_CPPFLAGS = ${STD_CFLAGS} +STD_CXXFLAGS = ${STD_CFLAGS} + +ifndef BCM_CFLAGS +BCM_CFLAGS = -Wall -Werror +endif + +BCM_CPPFLAGS = ${BCM_CFLAGS} +BCM_CXXFLAGS = ${BCM_CFLAGS} + +ifeq (${ORIGIN}, Broadcom) + CFLAGS += ${STD_CFLAGS} ${BCM_CFLAGS} ${OPT_CFLAGS} + CPPFLAGS += ${STD_CPPFLAGS} ${BCM_CPPFLAGS} ${OPT_CPPFLAGS} + CXXFLAGS += ${STD_CXXFLAGS} ${BCM_CXXFLAGS} ${OPT_CXXFLAGS} +else + CFLAGS += ${STD_CFLAGS} ${OPT_CFLAGS} + CPPFLAGS += ${STD_CPPFLAGS} ${OPT_CPPFLAGS} + CXXFLAGS += ${STD_CXXFLAGS} ${OPT_CXXFLAGS} +endif + +# +# Ignore pedantic flag for kernel modules +# +ifdef DEBUG_PEDANTIC +DEBUG_PEDANTIC = FALSE +endif + +# +# DEPEND is used as a command to generate the list of dependencies. +# The format of the output must be +# "file.o : file.c a/b/c.h d/e/f.h ...", +# if it is on multiple lines, each line must end in a backslash. +# The output MUST be on standard out. +# +DEPEND = ${CC} -M $(CFLAGS) $< diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-3_6 b/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-3_6 new file mode 100644 index 0000000000..50f32816c6 --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-3_6 @@ -0,0 +1,149 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Makefile.linux-kernel-3_6,v 1.2 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ + +# Configuration Flags + +# Filter out features that cannot or should not be supported in kernel mode + +_FEATURE_EXCLUDE_LIST += EDITLINE TCL OOB_RCPU CINT APIMODE DUNE_UI +FEATURE_EXCLUDE_LIST = $(sort $(_FEATURE_EXCLUDE_LIST)) + +# Tools + +# Conditionally Replaces DEFAULT var +ifeq ($(origin CC),default) +CC = $(LSRUN) $(CROSS_COMPILE)gcc +endif + +ifeq ($(origin CXX),default) +CXX = $(CROSS_COMPILE)g++ +endif + +ifeq ($(origin LD),default) +LD = $(CROSS_COMPILE)ld +endif + +ifeq ($(origin AR),default) +AR = $(CROSS_COMPILE)ar +endif + +ifeq ($(origin AS),default) +AS = $(CROSS_COMPILE)as +endif + +ifeq ($(origin ARFLAGS),default) + ARFLAGS = -rc +endif + +STRIP = $(CROSS_COMPILE)strip +RANLIB = $(CROSS_COMPILE)ranlib +OBJCOPY = $(CROSS_COMPILE)objcopy +NM = $(CROSS_COMPILE)nm + +# Handle differences between gcc 2.x and gcc 3.x +gcc-tune-flag = $(shell if ${CC} -dumpspecs | grep mcpu >/dev/null; then echo cpu; else echo tune; fi) + +# Configuration Variables + +# OSType Defines: This defines the type of RTOS or microkernel which you +# are compiling the SAL (and its associated driver) for. New platforms +# can be created by porting the routines (system.c) to your platform and +# adding the define in this Makefile. + +OSTYPE = LINUX + +# +# ORIGIN is used to Optionally select different CFLAGS. It is used to import +# source from other vendors. If SOURCE=Broadcom, then the BCM_ flags are added +# to those passed to the compiler. If SOURCE != Broadcom, BCM_ flags are NOT +# added. +# +# Default specifies Broadcom +# +ifndef ORIGIN + ORIGIN = Broadcom +endif + +# +# STD_{C|CPP|CXX}FLAGS - Standard flags used by ALL compilations +# BCM_{C|CPP|CXX}FLAGS - Flags used for Broadcom source files +# OPT_{C|CPP|CXX}FLAGS - Defined in local make files BEFORE inclusion of +# this Makefile, to define local "Extra" flags. +# + +ifdef IPROC_BUILD +CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \ + -I$(SDK)/systems/bde/linux/include \ + -I$(LINUX_INCLUDE) \ + -I$(KERNDIR)/arch/$(ARCH) +else +CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \ + -I$(SDK)/systems/bde/linux/include \ + -I$(LINUX_INCLUDE) \ + -I$(LINUX_INCLUDE)/asm/gcc \ + -I$(LINUX_INCLUDE)/asm/mach-generic \ + -I$(KERNDIR)/arch/$(ARCH) +endif + +CFGFLAGS += -DNO_FILEIO -DNO_CTRL_C -DNO_MEMTUNE + +CFGFLAGS += -D$(OSTYPE) + +# No user sal for the linux kernel +# NO_SAL_APPL=1 + +STD_CFLAGS = $(KFLAGS) $(CFGFLAGS) + + +STD_CPPFLAGS = ${STD_CFLAGS} +STD_CXXFLAGS = ${STD_CFLAGS} + +ifndef BCM_CFLAGS +BCM_CFLAGS = -Wall -Werror +endif + +BCM_CPPFLAGS = ${BCM_CFLAGS} +BCM_CXXFLAGS = ${BCM_CFLAGS} + +ifeq (${ORIGIN}, Broadcom) + CFLAGS += ${STD_CFLAGS} ${BCM_CFLAGS} ${OPT_CFLAGS} + CPPFLAGS += ${STD_CPPFLAGS} ${BCM_CPPFLAGS} ${OPT_CPPFLAGS} + CXXFLAGS += ${STD_CXXFLAGS} ${BCM_CXXFLAGS} ${OPT_CXXFLAGS} +else + CFLAGS += ${STD_CFLAGS} ${OPT_CFLAGS} + CPPFLAGS += ${STD_CPPFLAGS} ${OPT_CPPFLAGS} + CXXFLAGS += ${STD_CXXFLAGS} ${OPT_CXXFLAGS} +endif + +# +# Ignore pedantic flag for kernel modules +# +ifdef DEBUG_PEDANTIC +DEBUG_PEDANTIC = FALSE +endif + +# +# DEPEND is used as a command to generate the list of dependencies. +# The format of the output must be +# "file.o : file.c a/b/c.h d/e/f.h ...", +# if it is on multiple lines, each line must end in a backslash. +# The output MUST be on standard out. +# +DEPEND = ${CC} -M $(CFLAGS) $< diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-4_4 b/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-4_4 new file mode 100644 index 0000000000..d662b04334 --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-4_4 @@ -0,0 +1,158 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Makefile.linux-kernel-2_6,v 1.40 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ + +# Configuration Flags + +# Filter out features that cannot or should not be supported in kernel mode + +_FEATURE_EXCLUDE_LIST += EDITLINE TCL OOB_RCPU CINT APIMODE DUNE_UI C_UNIT +FEATURE_EXCLUDE_LIST = $(sort $(_FEATURE_EXCLUDE_LIST)) + +# Tools + +# Conditionally Replaces DEFAULT var +ifeq ($(origin CC),default) +CC = $(LSRUN) $(CROSS_COMPILE)gcc +endif + +ifeq ($(origin CXX),default) +CXX = $(CROSS_COMPILE)g++ +endif + +ifeq ($(origin LD),default) +LD = $(CROSS_COMPILE)ld +endif + +ifeq ($(origin AR),default) +AR = $(CROSS_COMPILE)ar +endif + +ifeq ($(origin AS),default) +AS = $(CROSS_COMPILE)as +endif + +ifeq ($(origin ARFLAGS),default) + ARFLAGS = -rc +endif + +STRIP = $(CROSS_COMPILE)strip +RANLIB = $(CROSS_COMPILE)ranlib +OBJCOPY = $(CROSS_COMPILE)objcopy +NM = $(CROSS_COMPILE)nm + +# Handle differences between gcc 2.x and gcc 3.x +gcc-tune-flag = $(shell if ${CC} -dumpspecs | grep mcpu >/dev/null; then echo cpu; else echo tune; fi) + +# Configuration Variables + +# OSType Defines: This defines the type of RTOS or microkernel which you +# are compiling the SAL (and its associated driver) for. New platforms +# can be created by porting the routines (system.c) to your platform and +# adding the define in this Makefile. +OSTYPE = LINUX + +# +# ORIGIN is used to Optionally select different CFLAGS. It is used to import +# source from other vendors. If SOURCE=Broadcom, then the BCM_ flags are added +# to those passed to the compiler. If SOURCE != Broadcom, BCM_ flags are NOT +# added. +# +# Default specifies Broadcom +# +ifndef ORIGIN + ORIGIN = Broadcom +endif + +# +# STD_{C|CPP|CXX}FLAGS - Standard flags used by ALL compilations +# BCM_{C|CPP|CXX}FLAGS - Flags used for Broadcom source files +# OPT_{C|CPP|CXX}FLAGS - Defined in local make files BEFORE inclusion of +# this Makefile, to define local "Extra" flags. +# +ifdef IPROC_BUILD +CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \ + -I$(SDK)/systems/bde/linux/include \ + -I$(LINUX_INCLUDE) \ + -I$(LINUX_INCLUDE)/uapi \ + -I$(LINUX_INCLUDE)/generated/uapi \ + -I$(KERNDIR)/arch/$(ARCH) \ + -I$(KERNDIR)/arch/$(ARCH)/include/uapi \ + -I$(KERNDIR)/arch/$(ARCH)/include/generated \ + -I$(KERNDIR)/arch/$(ARCH)/include/generated/uapi +else +CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \ + -I$(SDK)/systems/bde/linux/include \ + -I$(LINUX_INCLUDE) \ + -I$(LINUX_INCLUDE)/asm/gcc \ + -I$(LINUX_INCLUDE)/asm/mach-generic \ + -I$(LINUX_INCLUDE)/uapi \ + -I$(LINUX_INCLUDE)/generated/uapi \ + -I$(KERNDIR)/arch/$(ARCH) \ + -I$(KERNDIR)/arch/$(ARCH)/include/uapi \ + -I$(KERNDIR)/arch/$(ARCH)/include/generated \ + -I$(KERNDIR)/arch/$(ARCH)/include/generated/uapi +endif + +CFGFLAGS += -DNO_FILEIO -DNO_CTRL_C -DNO_MEMTUNE + +CFGFLAGS += -D$(OSTYPE) + +# No user sal for the linux kernel +# NO_SAL_APPL=1 + +STD_CFLAGS = $(KFLAGS) $(CFGFLAGS) + + +STD_CPPFLAGS = ${STD_CFLAGS} +STD_CXXFLAGS = ${STD_CFLAGS} + +ifndef BCM_CFLAGS +BCM_CFLAGS = -Wall -Werror +endif + +BCM_CPPFLAGS = ${BCM_CFLAGS} +BCM_CXXFLAGS = ${BCM_CFLAGS} + +ifeq (${ORIGIN}, Broadcom) + CFLAGS += ${STD_CFLAGS} ${BCM_CFLAGS} ${OPT_CFLAGS} + CPPFLAGS += ${STD_CPPFLAGS} ${BCM_CPPFLAGS} ${OPT_CPPFLAGS} + CXXFLAGS += ${STD_CXXFLAGS} ${BCM_CXXFLAGS} ${OPT_CXXFLAGS} +else + CFLAGS += ${STD_CFLAGS} ${OPT_CFLAGS} + CPPFLAGS += ${STD_CPPFLAGS} ${OPT_CPPFLAGS} + CXXFLAGS += ${STD_CXXFLAGS} ${OPT_CXXFLAGS} +endif + +# +# Ignore pedantic flag for kernel modules +# +ifdef DEBUG_PEDANTIC +DEBUG_PEDANTIC = FALSE +endif + +# +# DEPEND is used as a command to generate the list of dependencies. +# The format of the output must be +# "file.o : file.c a/b/c.h d/e/f.h ...", +# if it is on multiple lines, each line must end in a backslash. +# The output MUST be on standard out. +# +DEPEND = ${CC} -M $(CFLAGS) $< + diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-kmodule b/platform/broadcom/saibcm-modules/make/Makefile.linux-kmodule new file mode 100644 index 0000000000..a49919c615 --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-kmodule @@ -0,0 +1,82 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Makefile.linux-kmodule-3_6,v 1.2 Broadcom SDK $ +# $Copyright: (c) 2006 Broadcom Corp. +# All Rights Reserved.$ + +# Due to the extensive use of driver libraries, the SDK usually builds +# kernel modules from a precompiled object. To avoid various warnings +# and conflicts, the pre-compiled object must be named differently +# from the target module, and the object file itself should be +# appended with "_shipped". + +# If a module exports any symbols, then the exporting source file must +# be compiled within the kernel source tree for correct generation of +# module symbol versions. The symbol source file should be passed to +# this Makefile via the MODULE_SYM variable. + +MODULE := $(MOD_NAME).o +KMODULE := $(MOD_NAME).ko +PRE_COMPILED_OBJ := obj_$(MOD_NAME).o + +obj-m := $(MODULE) +$(MOD_NAME)-y := $(MODULE_SYM) $(PRE_COMPILED_OBJ) + + +ifeq (,$(CROSS_COMPILE)) + +export CROSS_COMPILE + +endif + +SAVE_CFLAGS := ${CFLAGS} + +include $(SDK)/make/Make.config + +PWD := $(shell pwd) + +ifneq ($(ARCH),) +# ELDK does not seem to `automatically' define ARCH where other gccs may +A := ARCH=$(ARCH) +export ARCH +endif + +# Provide an option in case kernel was built in separate directory +KERNBLDDIR ?= $(KERNDIR) + +# Standard SDK include path for building source files that export +# kernel symbols. + +override EXTRA_CFLAGS = -I${SDK}/include -I${SDK}/systems/linux/kernel/modules/include -I${SDK}/systems/bde/linux/include + +# The precopiled object needs a dummy command file to avoid warnings +# from the Kbuild scripts (modpost stage). +# Kernels before 2.6.17 do not support external module symbols files, +# so we create a dummy to prevent build failures. + +$(KMODULE): + rm -f *.o *.ko .*.cmd + rm -fr .tmp_versions + ln -s $(LIBDIR)/$(MODULE) $(PRE_COMPILED_OBJ)_shipped + echo "suppress warning" > .$(PRE_COMPILED_OBJ).cmd + $(MAKE) -C $(KERNBLDDIR) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) modules + if [ ! -f Module.symvers ]; then echo "old kernel (pre-2.6.17)" > Module.symvers; fi + cp -f $(KMODULE) $(LIBDIR) + rm -f $(PRE_COMPILED_OBJ)_shipped + +EXTRA_CFLAGS = $(CFLAGS) +CFLAGS := ${SAVE_CFLAGS} diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-common-2_6 b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-common-2_6 new file mode 100644 index 0000000000..29fb4cddd6 --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-common-2_6 @@ -0,0 +1,45 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Makefile.linux-x86-common-2_6,v 1.13 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ + +CFGFLAGS += -DSYS_BE_PIO=0 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=0 +ENDIAN = LE_HOST=1 +CFGFLAGS += -D$(ENDIAN) +CFGFLAGS += -DBCM_PLATFORM_STRING=\"X86\" +ifeq (,$(findstring -DSAL_BDE_DMA_MEM_DEFAULT,$(CFGFLAGS))) +CFGFLAGS += -DSAL_BDE_DMA_MEM_DEFAULT=16 +endif + +# Extra variables. +EXTRA_CFLAGS = -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) + +comma = , +basetarget = $(basename $(notdir $@)) +modname = $(basetarget) + +name-fix = $(subst $(comma),_,$(subst -,_,$1)) +basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))" +modname_flags = $(if $(filter 1,$(words $(modname))),\ +-D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))") + +ifneq ($(targetplat),user) +# By default we exclude -Werror from x86 kernel builds +BCM_CFLAGS = -Wall +include ${SDK}/make/Makefile.linux-kernel-2_6 +endif diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-generic-common-2_6 b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-generic-common-2_6 new file mode 100644 index 0000000000..5e01f2843b --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-generic-common-2_6 @@ -0,0 +1,52 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Makefile.linux-x86-generic-common-2_6,v 1.2 Broadcom SDK $ +# $Copyright: (c) 2008 Broadcom Corp. +# All Rights Reserved.$ + +# Default kernel source directory +ifeq (,$(KERNDIR)) +KERNDIR := /lib/modules/$(shell uname -r)/build +export KERNDIR +endif + +# Default architecture +ifeq (,$(ARCH)) +ARCH = $(shell uname -p) +ifneq (x86_64,$(ARCH)) +ARCH = i386 +endif +endif + +# Noisy kernel build +KBUILD_VERBOSE = 1 + +export ARCH KBUILD_VERBOSE KERNDIR + +# Default Linux include directory +ifeq (,$(LINUX_INCLUDE)) +LINUX_INCLUDE := $(KERNDIR)/include +endif + +# autoconf.h was moved in later kernels +AUTOCONF = $(KERNDIR)/include/generated/autoconf.h +ifeq (,$(shell ls $(AUTOCONF) 2>/dev/null)) +AUTOCONF = $(KERNDIR)/include/linux/autoconf.h +endif + +# gcc system include path +SYSINC = $(shell gcc -print-search-dirs | grep install | cut -c 10-)include diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-smp_generic_64-2_6 b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-smp_generic_64-2_6 new file mode 100644 index 0000000000..2c0242f984 --- /dev/null +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-smp_generic_64-2_6 @@ -0,0 +1,45 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# $Id: Makefile.linux-x86-smp_generic_64-2_6,v 1.5 Broadcom SDK $ +# $Copyright: (c) 2008 Broadcom Corp. +# All Rights Reserved.$ + +CFGFLAGS += -DLONGS_ARE_64BITS +CFGFLAGS += -DPTRS_ARE_64BITS +CFGFLAGS += -DPHYS_ADDRS_ARE_64BITS +CFGFLAGS += -DSAL_SPL_LOCK_ON_IRQ + +include ${SDK}/make/Makefile.linux-x86-generic-common-2_6 + +ifeq (,$(KFLAGS)) +KFLAGS := -nostdinc -isystem $(SYSINC) -I$(KERNDIR)/include -I$(KERNDIR)/arch/x86/include -include $(AUTOCONF) -D__KERNEL__ -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -fno-delete-null-pointer-checks -Os -m64 -mtune=generic -mno-red-zone -mcmodel=kernel -funit-at-a-time -maccumulate-outgoing-args -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -fno-stack-protector -fomit-frame-pointer -g -Wdeclaration-after-statement -Wno-pointer-sign +endif + +KFLAGS += -I$(LINUX_INCLUDE)/uapi -I$(LINUX_INCLUDE)/generated/uapi -I$(KERNDIR)/arch/x86/include/generated -I$(KERNDIR)/arch/x86/include/uapi -I$(KERNDIR)/arch/x86/include/generated/uapi + +ifeq ($(LINUX_MAKE_SHARED_LIB),1) +KFLAGS += -fPIC -mcmodel=small +else +KFLAGS += -mcmodel=kernel -fno-pie +endif + +ifeq (1,$(DEBIAN_LINUX_HEADER)) +KERNDIR_COMMON := $(subst amd64,common,$(KERNDIR)) +KFLAGS += -I$(KERNDIR_COMMON)/include -I$(KERNDIR_COMMON)/include/uapi -I$(KERNDIR_COMMON)/arch/x86/include -I$(KERNDIR_COMMON)/arch/x86/include/uapi +endif + +include ${SDK}/make/Makefile.linux-x86-common-2_6 diff --git a/platform/broadcom/saibcm-modules/systemd/opennsl-modules-4.9.0-5-amd64.service b/platform/broadcom/saibcm-modules/systemd/opennsl-modules-4.9.0-5-amd64.service new file mode 100644 index 0000000000..4da3f97619 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systemd/opennsl-modules-4.9.0-5-amd64.service @@ -0,0 +1,13 @@ +[Unit] +Description=Opennsl kernel modules init +After=local-fs.target +Before=syncd.service + +[Service] +Type=oneshot +ExecStart=-/etc/init.d/opennsl-modules-4.9.0-5-amd64 start +ExecStop=-/etc/init.d/opennsl-modules-4.9.0-5-amd64 stop +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux-bde.h b/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux-bde.h new file mode 100644 index 0000000000..e0c23f7305 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux-bde.h @@ -0,0 +1,275 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/*********************************************************************** + * + * $Id: linux-bde.h,v 1.24 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + * + * Linux Broadcom Device Enumerators + * + * + * There are two Linux BDEs: + * + * 1. Linux Kernel BDE + * + * This is a kernel module implementing a BDE + * for the driver running as part of the kernel. + * + * It manages the devices through the linux PCI interfaces, + * and manages a chunk of contiguous, boot-time allocated + * DMA memory. This is all that is needed if the BCM driver + * is run as part of the kernel (in another module). + * + * 2. Linux User BDE + * + * This is a kernel module and userland library which implement + * a complete BDE for applications running in userland. + * + * The kernel module relies upon the real kernel bde, + * and allows a user space application (through the user library) + * to talk directly to the devices. It also virtualized the device + * interrupts, so the entire driver can be run as a userspace + * application. + * + * While this causes a significant degradation in performance, + * because the system runs as a user application, the development + * and debugging process is about a gillion times easier. + * After the core logic is debugged, it can be retargeted using + * only the kernel bde and run in the kernel. + * + * + **********************************************************************/ + +#ifndef __LINUX_BDE_H__ +#define __LINUX_BDE_H__ + +#include + +#include + + +/* + * Device Major Numbers + * + * The kernel and user bdes need unique major numbers + * on systems that do not use devfs. + * + * They are defined here, along with the module names, + * to document them if you need to mknod them (or open) them, + * and to keep them unique. + * + */ + +#include + +#ifdef __KERNEL__ +#include +/* Key stone and Raptor has 2.6.21 but don't have definition */ +#if defined(KEYSTONE) || defined(RAPTOR) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)) + #ifdef PHYS_ADDRS_ARE_64BITS + typedef u64 phys_addr_t; + #else + typedef u32 phys_addr_t; + #endif + #endif +#endif +#endif + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) +#define LINUX_BDE_DMA_DEVICE_SUPPORT +#endif + +#define LINUX_KERNEL_BDE_NAME "linux-kernel-bde" +#define LINUX_KERNEL_BDE_MAJOR 127 + +#define LINUX_USER_BDE_NAME "linux-user-bde" +#define LINUX_USER_BDE_MAJOR 126 + + +/* Max devices */ +/* 16 switch chips + 2 out-of-band Ethernet + 2 CPUs */ +#define LINUX_BDE_MAX_SWITCH_DEVICES 16 +#define LINUX_BDE_MAX_ETHER_DEVICES 2 +#define LINUX_BDE_MAX_CPU_DEVICES 2 +#define LINUX_BDE_MAX_DEVICES (LINUX_BDE_MAX_SWITCH_DEVICES + \ + LINUX_BDE_MAX_ETHER_DEVICES + \ + LINUX_BDE_MAX_CPU_DEVICES) + +/* + * PCI devices will be initialized by the Linux Kernel, + * regardless of architecture. + * + * You need only provide bus endian settings. + */ + +typedef struct linux_bde_bus_s { + int be_pio; + int be_packet; + int be_other; +} linux_bde_bus_t; + + + +/* Device state used for PCI hot swap case. */ +/* + * BDE_DEV_STATE_NORMAL : A device is probed normally. Or when the device + * resource has been updated after "CHANGED", the state will move back to + * "NORMAL". + */ +#define BDE_DEV_STATE_NORMAL (0) +/* + * BDE_DEV_STATE_REMOVED : A previous probed device was removed. + * We will avoid any device access while the device is in this state. + * The state will be moved to "CHANGED" if the device is re-inserted + * and re-probed. + */ +#define BDE_DEV_STATE_REMOVED (1) +/* + * BDE_DEV_STATE_CHANGED : The device is re-probed after having been removed. + * The resouces assigned to the device might have been changed after + * re-probing, so we need to re-initialize our resource database accordingly. + * The state will change to "NORMAL" when the resource have been updated. + */ +#define BDE_DEV_STATE_CHANGED (2) + +extern int linux_bde_create(linux_bde_bus_t* bus, ibde_t** bde); +extern int linux_bde_destroy(ibde_t* bde); +#ifdef BCM_INSTANCE_SUPPORT +extern int linux_bde_instance_attach(unsigned int dev_mask,unsigned int dma_size); +#endif + +#ifdef __KERNEL__ + +/* + * Backdoors provided by the kernel bde + * + */ + +/* + * The user bde needs to get cpu physical address for + * the userland code to mmap. + * And the second address is bus address, it is either + * identical to cpu physical address or another address + * (IOVA) translated by IOMMU. + */ +extern int lkbde_get_dma_info(phys_addr_t *cpu_pbase, phys_addr_t *dma_pbase, ssize_t *size); +extern uint32 lkbde_get_dev_phys(int d); +extern uint32 lkbde_get_dev_phys_hi(int d); + +/* + * Virtual device address needed by kernel space + * interrupt handler. + */ +extern void *lkbde_get_dev_virt(int d); + +/* + * The user bde needs to get some physical addresses for + * the userland code to mmap. The following functions + * supports multiple resources for a single device. + */ +extern int lkbde_get_dev_resource(int d, int rsrc, uint32 *flags, + uint32 *phys_lo, uint32 *phys_hi); + +/* + * Backdoor to retrieve OS device structure to be used for + * DMA operations. + */ +extern void *lkbde_get_dma_dev(int d); + +/* + * Backdoor to retrieve original hardware/OS device. + */ +extern void *lkbde_get_hw_dev(int d); + +/* + * Retrive the device state from Kernel BDE. + * Used for KNET and User BDE for pci hot swap case. + */ +extern int lkbde_dev_state_get(int d, uint32 *state); +extern int lkbde_dev_state_set(int d, uint32 state); + +/* + * Retrive the mapping between emulated HW device and instance id + */ +extern int lkbde_dev_instid_get(int d, uint32 *instid); +extern int lkbde_dev_instid_set(int d, uint32 instid); + +/* + * Functions that allow an interrupt handler in user mode to + * coexist with interrupt handler in kernel module. + */ +extern int lkbde_irq_mask_set(int d, uint32 addr, uint32 mask, uint32 fmask); +extern int lkbde_irq_mask_get(int d, uint32 *mask, uint32 *fmask); + +#if (defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT)) +extern int lkbde_cpu_write(int d, uint32 addr, uint32 *buf); +extern int lkbde_cpu_read(int d, uint32 addr, uint32 *buf); +extern int lkbde_cpu_pci_register(int d); +#endif + +/* + * This flag must be OR'ed onto the device number when calling + * interrupt_connect/disconnect and irq_mask_set functions from + * a secondary device driver. + */ +#define LKBDE_ISR2_DEV 0x8000 + +#if defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) +#include +#if defined(__DUNE_LINUX_BCM_CPU_PCIE__) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +#ifndef _SIMPLE_MEMORY_ALLOCATION_ +#define _SIMPLE_MEMORY_ALLOCATION_ 1 +#endif +#ifndef USE_LINUX_BDE_MMAP +#define USE_LINUX_BDE_MMAP 1 +#endif +#endif +#endif + +#if defined(IPROC_CMICD) && defined(CONFIG_CMA) +#ifndef _SIMPLE_MEMORY_ALLOCATION_ +#define _SIMPLE_MEMORY_ALLOCATION_ 1 +#endif +#endif + +/* Don't use _SIMPLE_MEMORY_ALLOCATION_ method for newer kernel than 3.10.0 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) +#ifndef _SIMPLE_MEMORY_ALLOCATION_ +#define _SIMPLE_MEMORY_ALLOCATION_ 0 +#endif +#endif + +/* Allocation via dma_alloc_coherent is turned off by default */ +#ifndef _SIMPLE_MEMORY_ALLOCATION_ +#define _SIMPLE_MEMORY_ALLOCATION_ 9 /* compile in the allocation method, but do not use it by default */ +#endif + +/* By default we use our private mmap only if /dev/mem mmap has restrictions */ +#ifndef USE_LINUX_BDE_MMAP +#ifdef CONFIG_STRICT_DEVMEM +#define USE_LINUX_BDE_MMAP 1 +#else +#define USE_LINUX_BDE_MMAP 0 +#endif +#endif + +#endif /* __KERNEL__ */ + +#endif /* __LINUX_BDE_H__ */ diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux_dma.h b/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux_dma.h new file mode 100644 index 0000000000..f2621a982c --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux_dma.h @@ -0,0 +1,76 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/*********************************************************************** + * + * $Id: linux_dma.h,v 1.24 Broadcom SDK $ + * $Copyright: (c) 2016 Broadcom Corp. + * All Rights Reserved.$ + * + **********************************************************************/ + +#ifndef __LINUX_DMA_H__ +#define __LINUX_DMA_H__ + +#include + +#ifdef __KERNEL__ + +#ifdef SAL_BDE_XLP +#define KMALLOC(size, flags) __kmalloc(size, flags) +#else +#define KMALLOC(size, flags) kmalloc(size, flags) +#endif + +#if defined(CONFIG_IDT_79EB334) || defined(CONFIG_BCM4702) +/* ioremap is broken in kernel */ +#define IOREMAP(addr, size) ((void *)KSEG1ADDR(addr)) +#else +#define IOREMAP(addr, size) ioremap_nocache(addr, size) +#endif + +#if defined (__mips__) +#if defined(CONFIG_NONCOHERENT_IO) || defined(CONFIG_DMA_NONCOHERENT) +/* Use flush/invalidate for cached memory */ +#define NONCOHERENT_DMA_MEMORY +/* Remap virtual DMA addresses to non-cached segment */ +#define REMAP_DMA_NONCACHED +#endif /* CONFIG_NONCOHERENT_IO || CONFIG_DMA_NONCOHERENT */ +#endif /* __mips__ */ + +#if defined(BCM958525) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,5)) +#define REMAP_DMA_NONCACHED +#endif + +#ifndef DMA_BIT_MASK +#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) +#endif + +extern void _dma_init(int robo_switch); +extern int _dma_cleanup(void); +extern void _dma_pprint(void); +extern uint32_t *_salloc(int d, int size, const char *name); +extern void _sfree(int d, void *ptr); +extern int _sinval(int d, void *ptr, int length); +extern int _sflush(int d, void *ptr, int length); +extern sal_paddr_t _l2p(int d, void *vaddr); +extern void *_p2l(int d, sal_paddr_t paddr); +extern int _dma_pool_allocated(void); +extern int _dma_range_valid(unsigned long phys_addr, unsigned long size); + +#endif /* __KERNEL__ */ + +#endif /* __LINUX_DMA_H__ */ diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/include/mpool.h b/platform/broadcom/saibcm-modules/systems/bde/linux/include/mpool.h new file mode 100644 index 0000000000..001743d719 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/include/mpool.h @@ -0,0 +1,37 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: mpool.h,v 1.2 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ + +#ifndef __MPOOL_H__ +#define __MPOOL_H__ + +struct mpool_mem_s; +typedef struct mpool_mem_s* mpool_handle_t; + +extern int mpool_init(void); +extern mpool_handle_t mpool_create(void* base_address, int size); +extern void* mpool_alloc(mpool_handle_t pool, int size); +extern void mpool_free(mpool_handle_t pool, void* ptr); +extern int mpool_destroy(mpool_handle_t pool); + +extern int mpool_usage(mpool_handle_t pool); + +#endif /* __MPOOL_H__ */ diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/Makefile b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/Makefile new file mode 100644 index 0000000000..0d126c9a23 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/Makefile @@ -0,0 +1,115 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# -*- Makefile -*- +# $Id: Makefile,v 1.18 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ +# +# Makefile for Linux kernel BDE +# +LOCALDIR = systems/bde/linux/kernel + +# Make sure we build for the kernel if this is a user-mode build +ifneq ($(platform), ) +override-target=linux-$(platform) +endif + +include $(SDK)/make/Make.config + +LIBS = $(LIBDIR)/libkern.a + +BDE = linux-kernel-bde.o + +ifdef ROBO_CHIPS +CFLAGS += -I$(ET_ROBO) -I${SDK}/include/shared/et +ET_ROBO = ${SDK}/systems/drv/et +endif + +# need to add vpath sources +VPATH = ../shared $(ET_ROBO) + +# Add the srcs to be found by vpath +LSRCS += mpool.c +ifdef ROBO_CHIPS +platformsplt = $(subst -, , ${platform}) # change hyphens to spaces +platformbase = $(word 1,${platformsplt}) + +ifeq ($(platformbase), keystone) + LSRCS += etc_robo_spi.c aiutils.c +else + ifeq ($(platformbase), keystone_le) + LSRCS += etc_robo_spi.c aiutils.c + else + ifeq ($(platformbase), iproc) + LSRCS += robo_srab.c robo_spi.c aiutils.c + endif + endif +endif # platformbase + +endif # ROBO_CHIPS + +# Add shared BDE sources +VPATH += ../../shared +LSRCS += shbde_pci.c shbde_iproc.c shbde_mdio.c +CFLAGS += -I../../shared/include + +LHDRS += mpool.h +LOBJS = $(addsuffix .o, $(basename $(LSRCS))) +BOBJS = $(addprefix $(BLDDIR)/,$(LOBJS)) + +ifneq ($(kernel_version),2_4) +KERNEL_MODULE_DIR = kernel_module + +THIS_MOD_NAME := linux-kernel-bde +MODULE = $(LIBDIR)/$(THIS_MOD_NAME).o +KMODULE = $(LIBDIR)/$(THIS_MOD_NAME).ko + +build: kernel_libs $(MODULE) $(KMODULE) +else +MODULE = $(LIBDIR)/linux-kernel-bde.o + +build: kernel_libs $(MODULE) +endif + +$(MODULE): $(BLDDIR)/.tree kernel_libs $(BOBJS) + mkdir -p $(@D) + $(LD) $(MODULE_LDFLAGS) -r -d $(BOBJS) $(LIBS) -o $@ +ifneq ($(kernel_version),2_4) +$(KMODULE): $(MODULE) + rm -fr $(BLDDIR)/$(KERNEL_MODULE_DIR) + mkdir $(BLDDIR)/$(KERNEL_MODULE_DIR) + cp ${SDK}/make/Makefile.linux-kmodule $(BLDDIR)/$(KERNEL_MODULE_DIR)/Makefile + MOD_NAME=$(THIS_MOD_NAME) $(MAKE) -C $(BLDDIR)/$(KERNEL_MODULE_DIR) $(THIS_MOD_NAME).ko +endif + +kernel_libs: + $(MAKE) -C $(SDK)/systems/linux/kernel/modules/shared + +include $(SDK)/make/Make.depend + +# Make.depend is before clean:: so that Make.depend's clean:: runs first. + +clean:: + $(MAKE) -C $(SDK)/systems/linux/kernel/modules/shared $@ + $(RM) $(BOBJS) $(MODULE) + $(RM) $(BLDDIR)/$(KERNEL_MODULE_DIR) + +distclean:: + +ifneq ($(kernel_version),2_4) +.PHONY: build kernel_libs +endif diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux-kernel-bde.c b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux-kernel-bde.c new file mode 100644 index 0000000000..105d3d9bd9 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux-kernel-bde.c @@ -0,0 +1,5173 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: linux-kernel-bde.c,v 1.414 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + * + * Linux Kernel BDE + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "linux_shbde.h" + +#ifdef BCM_ROBO_SUPPORT +/* robo/et related header files */ +#include + +#include + +#if defined(KEYSTONE) +#include +#include +#include +#include +#elif defined(IPROC_CMICD) +#include +#include +#ifdef BCM_STARFIGHTER3_SUPPORT +#include +#endif +#include +#include +#else /* BCM4704 */ +#include +#include +#endif +#endif /* BCM_ROBO_SUPPORT */ + +#define PCI_USE_INT_NONE (-1) +#define PCI_USE_INT_INTX (0) +#define PCI_USE_INT_MSI (1) +#define PCI_USE_INT_MSIX (2) +#ifdef CONFIG_PCI_MSI +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,110)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84)) +#define msix_table_size(flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1) +#endif +#define msi_control_reg(base) (base + PCI_MSI_FLAGS) +#endif +#endif +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_DESCRIPTION("Kernel BDE"); +MODULE_LICENSE("GPL"); + +/* PCIe max payload */ +int maxpayload = 256; +LKM_MOD_PARAM(maxpayload, "i", int, 0); +MODULE_PARM_DESC(maxpayload, +"Limit maximum payload size and request size on PCIe devices"); + +/* Use MSI or MSIX interrupts */ +int usemsi = -1; +LKM_MOD_PARAM(usemsi, "i", int, 0); +MODULE_PARM_DESC(usemsi, +"Use MSI/ MSIX interrupts if supported by kernel"); + +/* Ignore all recognized devices (for debug purposes) */ +int nodevices; +LKM_MOD_PARAM(nodevices, "i", int, 0); +MODULE_PARM_DESC(nodevices, +"Ignore all recognized devices (default no)"); + +/* + * This usually is defined at /usr/include/linux/pci_ids.h + * But this ID is newer. + */ +#ifndef PCI_DEVICE_ID_PLX_9656 +#define PCI_DEVICE_ID_PLX_9656 0x9656 +#endif + +#ifndef PCI_DEVICE_ID_PLX_9056 +#define PCI_DEVICE_ID_PLX_9056 0x9056 +#endif + +/* local defined device IDs, refer to bcmdevs.h */ +#ifndef BCM53000_GMAC_ID +#define BCM53000_GMAC_ID 0x4715 /* 53003 gmac id */ +#endif +#ifndef BCM53010_GMAC_ID +#define BCM53010_GMAC_ID 0x4715 /* 5301x gmac id */ +#endif +#ifndef BCM47XX_ENET_ID +#define BCM47XX_ENET_ID 0x4713 /* 4710 enet */ +#endif +#ifndef BCM53010_CHIP_ID +#define BCM53010_CHIP_ID 0xcf12 /* 53010 chipcommon chipid */ +#endif +#ifndef BCM53018_CHIP_ID +#define BCM53018_CHIP_ID 0xcf1a /* 53018 chipcommon chipid */ +#endif +#ifndef BCM53020_CHIP_ID +#define BCM53020_CHIP_ID 0xcf1e /* 53020 chipcommon chipid */ +#endif + +/* For 2.4.x kernel support */ +#ifndef IRQF_SHARED +#define IRQF_SHARED SA_SHIRQ +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) +typedef unsigned long resource_size_t; +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */ + +#ifdef BCM_ICS +#define BCM_ICS_CMIC_BASE 0x08000000 +#else + +/* Force interrupt line */ +static int forceirq = -1; +static uint32_t forceirqubm = 0xffffffff; +LKM_MOD_PARAM(forceirq, "i", int, 0); +LKM_MOD_PARAM(forceirqubm, "i", uint, 0); +MODULE_PARM_DESC(forceirq, +"Override IRQ line assigned by boot loader"); +MODULE_PARM_DESC(forceirqubm, +"Bitmap for overriding the IRQ line assigned by boot loader for given units"); + +/* Create SPI slave device (cannot be probed) */ +static uint32_t spi_devid = 0; +LKM_MOD_PARAM(spi_devid, "i", uint, 0); +MODULE_PARM_DESC(spi_devid, +"Create SPI slave device using this device ID"); + +/* Select SPI device revision (cannot be probed) */ +static uint32_t spi_revid = 1; +LKM_MOD_PARAM(spi_revid, "i", uint, 0); +MODULE_PARM_DESC(spi_revid, +"Select device revision for SPI slave device"); + +#endif /* BCM_ICS */ + +/* Debug output */ +static int debug; +LKM_MOD_PARAM(debug, "i", int, 0); +MODULE_PARM_DESC(debug, +"Set debug level (default 0"); +/* Use high memory for DMA */ + +/* module param for probing EB devices. */ +static char *eb_bus; +LKM_MOD_PARAM(eb_bus, "s", charp, 0); +MODULE_PARM_DESC(eb_bus, +"List of EB devices on platform. Input format (BA=%x IRQ=%d RD16=%d WR16=%d"); + +#ifdef KEYSTONE +/* Force SPI Frequency */ +static int spifreq = 0; +LKM_MOD_PARAM(spifreq, "i", int, 0); +MODULE_PARM_DESC(spifreq, +"Force SPI Frequency for Keystone CPU (0 for default frequency)"); +#endif + +#if defined(BCM_EA_SUPPORT) +#if defined(BCM_TK371X_SUPPORT) +static int eadevices; +LKM_MOD_PARAM(eadevices, "i", int, 0); +MODULE_PARM_DESC(eadevices, +"Number of TK371X devices"); +#endif /* */ +#endif /* BCM_EA_SUPPORT */ + +/* Compatibility */ +#ifdef LKM_2_4 +#define _ISR_RET void +#define _ISR_PARAMS(_i,_d,_r) int _i, void *_d, struct pt_regs *_r +#define IRQ_NONE +#define IRQ_HANDLED +#define SYNC_IRQ(_i) synchronize_irq() +#else /* LKM_2_6 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)) +#define _ISR_RET irqreturn_t +#else +#define _ISR_RET int +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) +#define _ISR_PARAMS(_i,_d,_r) int _i, void *_d +#else +#define _ISR_PARAMS(_i,_d,_r) int _i, void *_d, struct pt_regs *_r +#endif +#define SYNC_IRQ(_i) synchronize_irq(_i) +char * ___strtok; +char * strtok(char * s,const char * ct) +{ + char *sbegin, *send; + sbegin = s ? s : ___strtok; + if (!sbegin) { + return NULL; + } + sbegin += strspn(sbegin,ct); + if (*sbegin == '\0') { + ___strtok = NULL; + return( NULL ); + } + send = strpbrk( sbegin, ct); + if (send && *send != '\0') + *send++ = '\0'; + ___strtok = send; + return (sbegin); +} +LKM_EXPORT_SYM(___strtok); +LKM_EXPORT_SYM(strtok); +#endif /* LKM_2_x */ + +/* PCIe capabilities */ +#ifndef PCI_CAP_ID_EXP +#define PCI_CAP_ID_EXP 0x10 +#endif +#ifndef PCI_EXP_DEVCAP +#define PCI_EXP_DEVCAP 4 +#endif +#ifndef PCI_EXP_DEVCTL +#define PCI_EXP_DEVCTL 8 +#endif +#ifndef PCI_EXT_CAP_START +#define PCI_EXT_CAP_START 0x100 +#endif +#ifndef PCI_EXT_CAP_ID +#define PCI_EXT_CAP_ID(_hdr) (_hdr & 0x0000ffff) +#endif +#ifndef PCI_EXT_CAP_VER +#define PCI_EXT_CAP_VER(_hdr) ((_hdr >> 16) & 0xf) +#endif +#ifndef PCI_EXT_CAP_NEXT +#define PCI_EXT_CAP_NEXT(_hdr) ((_hdr >> 20) & 0xffc) +#endif +#ifndef PCI_EXT_CAP_ID_VNDR +#define PCI_EXT_CAP_ID_VNDR 0x0b +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +#define PCI_FIND_DEV(_d, _v, _fr) pci_find_device(_d, _v, _fr) +#else +#define PCI_FIND_DEV(_d, _v, _fr) pci_get_device(_d, _v, _fr) +#endif + +#if defined(CONFIG_RESOURCES_64BIT) || defined(CONFIG_PHYS_ADDR_T_64BIT) +#define PHYS_ADDR_IS_64BIT +#endif + +/* Structure of private SPI device */ +struct spi_dev { + uint8 cid; /* Chip ID */ + uint32 part; /* Part number of the chip */ + uint8 rev; /* Revision of the chip */ + void *robo; /* ptr to robo info required to access SPI */ + unsigned short phyid_high; /* PHYID HIGH in MII regs of detected chip */ + unsigned short phyid_low; /* PHYID LOW in MII regs of detected chip */ +}; + +struct bde_spi_device_id { + unsigned short phyid_high; /* PHYID HIGH in MII regs of detected chip */ + unsigned short phyid_low; /* PHYID LOW in MII regs of detected chip */ + uint32 model_info; + uint32 rev_info; + uint32 spifreq; +}; + +/* Control Data */ +typedef struct bde_ctrl_s { + struct list_head list; + + /* Specify the type of device, pci, spi, switch, ether ... */ + uint32 dev_type; + + int domain_no; + int bus_no; + int be_pio; + int use_msi; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84)) + struct msix_entry *entries; +#endif + int msix_cnt; + union { + /* Linux PCI device pointer */ + struct pci_dev* _pci_dev; + + /* SPI device pointer */ + struct spi_dev* _spi_dev; + } dev; +#define pci_device dev._pci_dev +#define spi_device dev._spi_dev + +#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT + struct device *dma_dev; +#endif + + /* Physical addresses */ + resource_size_t phys_address; + resource_size_t phys_address1; + resource_size_t phys_address2; + + /* Secondary mapped base address */ + sal_vaddr_t alt_base_addr; + + /* BDE device description */ + ibde_dev_t bde_dev; + + /* Interrupt Handling */ + int iLine; /* Interrupt line */ + void (*isr)(void *); + void *isr_data; + + /* + * Controls to allow two drivers to share a single set of + * hardware registers. Typically a kernel driver will handle + * a subset of hardware interrupts and a user mode driver + * will handle the remaining interrupts. + */ + void (*isr2)(void *); + void *isr2_data; + uint32_t fmask; /* Interrupts controlled by secondary handler */ + uint32_t imask; /* Enabled interrupts for primary handler */ + uint32_t imask2; /* Enabled interrupts for secondary handler */ + spinlock_t lock; /* Lock for IRQ mask synchronization */ + + /* Hardware abstraction for shared BDE functions */ + shbde_hal_t shbde; + + /* Device state : BDE_DEV_STATE_REMOVED/CHANGED */ + uint32 dev_state; + + /* inst_id */ + uint32 inst_id; +} bde_ctrl_t; + +static bde_ctrl_t _devices[LINUX_BDE_MAX_DEVICES]; +static int _ndevices = 0; +static int _switch_ndevices = 0; +static int _ether_ndevices = 0; +static int _cpu_ndevices = 0; +static int robo_switch = 0; + +#define VALID_DEVICE(_n) ((_n >= 0) && (_n < _ndevices)) + +/* CPU MMIO area used with CPU cards provided on demo boards */ +#if (defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT)) && (defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__)) +static void *cpu_address = NULL; +#endif + +#ifdef BCM_ROBO_SUPPORT + +/* for SPI access via bcm4710 core */ +static void *robo = NULL; +static void *sbh = NULL; + +#ifdef ALTA_ROBO_SPI + +extern void *alta_eth_spi_ctrl; + +extern int +robo_spi_read(void *cookie, uint16_t reg, uint8_t *buf, int len); + +extern int +robo_spi_write(void *cookie, uint16_t reg, uint8_t *buf, int len); + +#define ROBO_RREG(_robo, _dev, _page, _reg, _buf, _len) \ + robo_spi_read(_dev ? NULL : alta_eth_spi_ctrl, \ + (_page << 8) | (_reg), _buf, _len) +#define ROBO_WREG(_robo, _dev, _page, _reg, _buf, _len) \ + robo_spi_write(_dev ? NULL : alta_eth_spi_ctrl, \ + (_page << 8) | (_reg), _buf, _len) + +#else /* !ALTA_ROBO_SPI */ + +#if defined(KEYSTONE) || defined(IPROC_CMICD) +#define ROBO_RREG(_robo, _dev, _page, _reg, _buf, _len) \ + robo_rreg(_robo, _dev, _page, _reg, _buf, _len) +#define ROBO_WREG(_robo, _dev, _page, _reg, _buf, _len) \ + robo_wreg(_robo, _dev, _page, _reg, _buf, _len) +#else +#define ROBO_RREG(_robo, _dev, _page, _reg, _buf, _len) +#define ROBO_WREG(_robo, _dev, _page, _reg, _buf, _len) +#endif + +#endif /* ALTA_ROBO_SPI */ + +#endif /* BCM_ROBO_SUPPORT */ + +/* Broadcom BCM4704 */ +#define BCM4704_VENDOR_ID 0x14E4 +#define BCM4704_DEVICE_ID 0x4704 + +/* SiByte PCI Host */ +#define SIBYTE_PCI_VENDOR_ID 0x166D +#define SIBYTE_PCI_DEVICE_ID 0x0001 + +/* Intel 21150 PCI-PCI Bridge */ +#define DC21150_VENDOR_ID 0x1011 +#define DC21150_DEVICE_ID 0x0022 + +/* HiNT HB4 PCI-PCI Bridge (21150 clone) */ +#define HINT_HB4_VENDOR_ID 0x3388 +#define HINT_HB4_DEVICE_ID 0x0022 + +/* Pericom PI7C8150 PCI-PCI Bridge (21150 clone) */ +#define PI7C8150_VENDOR_ID 0x12D8 +#define PI7C8150_DEVICE_ID 0x8150 + +/* Pericom PI7C9X130 PCI-PCIE Bridge */ +#define PCI_VNDID_PERICOM 0x12D8 +#define PCI_DEVID_PI7C9X130 0xE130 +#define DEV_CTRL_REG 0xb8 + +#define MAX_PAYLOAD_256B (1 << 5) +#define MAX_PAYLOAD_512B (2 << 5) +#define MAX_READ_REQ_256B (1 << 12) + + +/* Freescale 8548 PCI-E host Bridge */ +#define FSL_VENDOR_ID 0x1957 +#define FSL8548PCIE_DEVICE_ID 0x0013 +#define FSL2020EPCIE_DEVICE_ID 0x0070 +#define FSL8548PCIE_DEV_CTRL_REG 0x54 + +/* 4716 PCI-E host Bridge */ +#define BCM4716_VENDOR_ID 0x14e4 +#define BCM4716PCIE_DEVICE_ID 0x4716 +#define BCM4716PCIE_DEV_CAP_REG 0xd4 +#define BCM4716PCIE_DEV_CTRL_REG 0xd8 +#define BCM53000_VENDOR_ID 0x14e4 +#define BCM53000PCIE_DEVICE_ID 0x5300 + +#define BCM53000PCIE_DEV(port) ((port == 0) ? pcie0 : pcie1) +#define BCM53000PCIE_BASE(port) ((port == 0) ? 0xb8005000 : 0xb800e000) +#define BCM53000PCIE_FUNC0_COFIG_SPACE 0x400 +#define BCM53000PCIE_SROM_SPACE 0x800 +#define BCM53000PCIE_DEV_CAP_REG 0xd4 +#define BCM53000PCIE_DEV_CTRL_REG 0xd8 +#define BCM53000PCIE_MAX_PAYLOAD_MASK 0x7 +#define BCM53000PCIE_CAP_MAX_PAYLOAD_256B (1 << 0) +#define BCM53000PCIE_DEFAULT_STATUS 0x00100146 + +/* 16bit wide register. offset 14, 14*2 = 0x1c */ +#define BCM53000PCIE_SPROM_OFFSET 0x1c +/* bit 15:13 spromData.MaxPayloadSize. 1: 256 bytes */ +#define BCM53000PCIE_SPROM_MAX_PAYLOAD_MASK 0xe000 +#define BCM53000PCIE_SPROM_MAX_PAYLOAD_256B (1 << 13) + + +/* Intel 21150, HiNT HB4 and other 21150-compatible */ +#define PCI_CFG_DEC21150_SEC_CLK 0x68 + +#define BCM4704_ENUM_BASE 0x18000000 +#define BCM4704_MEMC_BASE (BCM4704_ENUM_BASE+0x8000) +#define BCM4704_MEMC_PRIORINV 0x18 + +/* PLX PCI-E Switch */ +#define PLX_PEX8608_DEV_ID 0x8608 +#define PLX_PEX8617_DEV_ID 0x8617 +#define PLX_PEX86XX_DEV_CTRL_REG 0x70 + +/* Broadcom BCM58525 */ +#define BCM58525_PCI_VENDOR_ID 0x14E4 +#define BCM58525_PCI_DEVICE_ID 0x8025 +#define BCM58522_PCI_DEVICE_ID 0x8022 + +/* Broadcom BCM58712 */ +#define BCM58712_PCI_VENDOR_ID 0x14E4 +#define BCM58712_PCI_DEVICE_ID 0x168E + +static uint32_t _read(int d, uint32_t addr); + +#ifdef BCM_ICS +#else +/* Used to determine overall memory limits across all devices */ +static uint32_t _pci_mem_start = 0xFFFFFFFF; +static uint32_t _pci_mem_end = 0; + +/* Used to control MSI interrupts */ +static int use_msi = 0; +#endif + +#ifdef BCM_PLX9656_LOCAL_BUS + +#define CPLD_OFFSET 0x00800000 +#define CPLD_REVISION_REG 0x0000 +#define CPLD_REVISION_MASK 0xffff +#define CPLD_RESET_REG 0x0004 +#define CPLD_RESET_NONE 0x0000 + +#define PL0_OFFSET 0x00800000 +#define PL0_SIZE 0x00040000 +#define PL0_REVISION_REG 0x0000 + +/* Assume there's only one PLX PCI-to-Local bus bridge if any */ +static bde_ctrl_t plx_ctrl; +static int num_plx = 0; + +#endif /* BCM_PLX9656_LOCAL_BUS */ + +static spinlock_t bus_lock; + +static int +_parse_eb_args(char *str, char * format, ...) + __attribute__ ((format (scanf, 2, 3))); + +static int +_parse_eb_args(char *str, char * format, ...) +{ + va_list args; + + va_start(args, format); + vsscanf(str, format, args); + va_end(args); + + return 0; +} + +static int +_eb_device_create(resource_size_t paddr, int irq, int rd_hw, int wr_hw) +{ + bde_ctrl_t *ctrl; + uint32 dev_rev_id = 0x0, dev_id; + + dev_id = _ndevices; + + ctrl = _devices + _ndevices++; + _switch_ndevices++; + + ctrl->dev_type |= BDE_EB_DEV_TYPE | BDE_SWITCH_DEV_TYPE; + ctrl->pci_device = NULL; /* No PCI bus */ + + if(rd_hw) { + ctrl->dev_type |= BDE_DEV_BUS_RD_16BIT; + } + + if (wr_hw) { + ctrl->dev_type |= BDE_DEV_BUS_WR_16BIT; + } + + /* Map in the device */ + ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(paddr, 0x10000); + ctrl->phys_address = paddr; + + dev_rev_id = _read(dev_id, 0x178); /* CMIC_DEV_REV_ID */ + + ctrl->bde_dev.device = dev_rev_id & 0xFFFF; + ctrl->bde_dev.rev = (dev_rev_id >> 16) & 0xFF; + + ctrl->iLine = irq; + ctrl->isr = NULL; + ctrl->isr_data = NULL; + + gprintk("Created EB device at BA=%x IRQ=%d RD16=%d WR16=%d device=0x%x\n", + (unsigned int)paddr, irq, rd_hw, wr_hw, ctrl->bde_dev.device); + + return 0; +} + +#if defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT) + +#include + +static int +sand_device_create(void) +{ + bde_ctrl_t* ctrl; + + ctrl = _devices; /* FIX_ME: on petra, take first device */ + +#ifndef __DUNE_LINUX_BCM_CPU_PCIE__ + _switch_ndevices++; + _ndevices++; + + ctrl->dev_type |= BDE_PCI_DEV_TYPE | BDE_SWITCH_DEV_TYPE; + ctrl->pci_device = NULL; /* No PCI bus */ + + /* Map in the device */ /* FIX_ME: not realy map anything */ + ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(0x40000000, 0x100000); + ctrl->phys_address = 0x40000000; + + ctrl->iLine = 0; + ctrl->isr = NULL; + ctrl->isr_data = NULL; + + ctrl->bde_dev.device = BCM88950_DEVICE_ID; + ctrl->bde_dev.rev = BCM88950_A0_REV_ID; +#endif + + /* Map CPU regs */ +#ifdef __DUNE_WRX_BCM_CPU__ + cpu_address = IOREMAP(0x18000000, 0x4000000); +#elif defined(__DUNE_GTO_BCM_CPU__) + cpu_address = IOREMAP(0xe0000000, 0x100000); +#endif + + if ((ctrl->bde_dev.device == PCP_PCI_DEVICE_ID)) { + ctrl->bde_dev.device = GEDI_DEVICE_ID; + ctrl->bde_dev.rev = GEDI_REV_ID; + } + + if ((ctrl->bde_dev.device == ACP_PCI_DEVICE_ID)) { + ctrl->dev_type |= BDE_PCI_DEV_TYPE | BDE_SWITCH_DEV_TYPE; + } + + return 0; +} +#endif + +#ifdef IPROC_CMICD +static void +iproc_cmicd_get_irqres(ibde_dev_t bde_dev, struct resource *res_irq) +{ + shbde_iproc_config_t iproc_config, *icfg = &iproc_config; + + /* iProc configuration parameters */ + memset(icfg, 0, sizeof(*icfg)); + shbde_iproc_config_init(icfg, bde_dev.device, bde_dev.rev); + + if ((icfg->iproc_ver == 0) && (debug >= 1)) { + gprintk("Unable to determine iProc version\n"); + } + + if (icfg->iproc_ver == 7) { + res_irq->start = 221; + } else if (icfg->iproc_ver == 10) { + res_irq->start = 184; + } + +} + +#include +#include + +extern void iproc_platform_driver_register(struct platform_driver *drv); +extern void iproc_platform_driver_unregister(struct platform_driver *drv); +extern void iproc_platform_device_register(struct platform_device *drv); +extern void iproc_platform_device_unregister(struct platform_device *drv); + +extern struct resource * +iproc_platform_get_resource(struct platform_device *dev, unsigned int type, + unsigned int num); + +#define IPROC_CHIPCOMMONA_BASE 0x18000000 +#define IPROC_CMICD_BASE 0x48000000 +#define IPROC_CMICD_SIZE 0x40000 +#define IPROC_CMICD_INT 194 + +#define IPROC_CMICD_COMPATIBLE "brcm,iproc-cmicd" + +static int +iproc_cmicd_probe(struct platform_device *pldev) +{ + bde_ctrl_t *ctrl; + uint32 size, dev_rev_id; + struct resource *memres, *irqres; +#ifdef CONFIG_OF + if (debug >= 1) { + gprintk("iproc_cmicd_probe %s\n", pldev->dev.of_node ? "with device node":""); + } +#endif + memres = iproc_platform_get_resource(pldev, IORESOURCE_MEM, 0); + if (memres == NULL) { + gprintk("Unable to retrieve iProc CMIC resources"); + return -1; + } + size = memres->end - memres->start + 1; + + ctrl = _devices + _ndevices++; + _switch_ndevices++; + + ctrl->dev_type = BDE_AXI_DEV_TYPE | BDE_SWITCH_DEV_TYPE | BDE_256K_REG_SPACE; + ctrl->pci_device = NULL; /* No PCI bus */ + + /* Map CMIC block in the AXI memory space into CPU address space */ + ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(memres->start, size); + if (!ctrl->bde_dev.base_address) { + gprintk("Error mapping iProc CMIC registers"); + return -1; + } + ctrl->phys_address = memres->start; + + /* Read switch device ID from CMIC */ + dev_rev_id = *((uint32_t*)(ctrl->bde_dev.base_address + 0x10224)); +#if defined(BCM_CMICM_SUPPORT) && defined(BE_HOST) + ctrl->bde_dev.device = ( (((dev_rev_id >> 16) & 0xff) << 8) | + ((dev_rev_id >> 24) & 0xff)); + ctrl->bde_dev.rev = (dev_rev_id >> 8) & 0xff ; +#else + ctrl->bde_dev.device = dev_rev_id & 0xffff; + ctrl->bde_dev.rev = (dev_rev_id >> 16) & 0xff; +#endif + +#ifdef CONFIG_OF + if (!pldev->dev.of_node) +#endif + { + /* Assign locally if not available from device node */ + iproc_cmicd_get_irqres(ctrl->bde_dev, &pldev->resource[0]); + } + irqres = iproc_platform_get_resource(pldev, IORESOURCE_IRQ, 0); + + ctrl->iLine = irqres->start; + + ctrl->isr = NULL; + ctrl ->isr_data = NULL; + +#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT + ctrl->dma_dev = &pldev->dev; +#endif + + /* Let's boogie */ + return 0; +} + +static int +iproc_cmicd_remove(struct platform_device *pldev) +{ + return 0; +} +#ifdef CONFIG_OF +static const struct of_device_id iproc_cmicd_of_match[] = { + { .compatible = "brcm,iproc-cmicd" }, + {}, +}; +MODULE_DEVICE_TABLE(of, iproc_cmicd_of_match); +#endif +static char iproc_cmicd_string[] = "bcmiproc-cmicd"; + +static struct platform_driver iproc_cmicd_driver = +{ + .probe = iproc_cmicd_probe, + .remove = iproc_cmicd_remove, + .driver = + { + .name = iproc_cmicd_string, + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = iproc_cmicd_of_match, +#endif + }, +}; + +typedef enum { + IPROC_CMICD_RES_INTR = 0, + IPROC_CMICD_RES_MEM +} IPROC_CMICD_RES_E; + +static struct resource iproc_cmicd_resources[] = { + [IPROC_CMICD_RES_INTR] = { + .flags = IORESOURCE_IRQ, + .start = IPROC_CMICD_INT, + }, + [IPROC_CMICD_RES_MEM] = { + .flags = IORESOURCE_MEM, + .start = IPROC_CMICD_BASE, + .end = IPROC_CMICD_BASE+IPROC_CMICD_SIZE-1, + }, +}; + +static void +iproc_cmicd_release(struct device *dev) +{ +} + +static u64 iproc_cmicd_dmamask = DMA_BIT_MASK(32); + +static struct platform_device iproc_cmicd_pdev = { + .name = iproc_cmicd_string, + .id = 0, + .dev = { + .release = iproc_cmicd_release, + .init_name = iproc_cmicd_string, + .dma_mask = &iproc_cmicd_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = iproc_cmicd_resources, + .num_resources = ARRAY_SIZE(iproc_cmicd_resources), +}; + +static int +iproc_has_cmicd(void) +{ + void *iproc_cca_base; + uint32 cca_cid; + + /* Read ChipcommonA chip id register to identify current SOC */ + iproc_cca_base = IOREMAP(IPROC_CHIPCOMMONA_BASE, 0x3000); + if (iproc_cca_base == NULL) { + gprintk("iproc_has_cmicd: ioremap of ChipcommonA registers failed"); + return 0; + } + cca_cid = readl((uint32 *)iproc_cca_base); + cca_cid &= 0xffff; + iounmap(iproc_cca_base); + + /* Only allowed accessing CMICD module if the SOC has it */ + switch (cca_cid) { + case BCM53010_CHIP_ID: + case BCM53018_CHIP_ID: + case BCM53020_CHIP_ID: + return 0; + default: + break; + } + + /* Device has CMIC */ + return 1; +} + +#define IPROC_CHIPCOMMONA_EROM_PTR_OFFSET (0x180000fc) +#define EROM_MAX_SIZE (0x1000) +#define EROM_PARTNUM_CMICD (0x14) + +#define EROM_DESC_COMPIDENT (0x1) +#define EROM_DESC_MASTER (0x3) +#define EROM_DESC_ADDR (0x5) +#define EROM_DESC_END (0xF) +#define EROM_DESC_EMPTY (0) + +#define EROM_IS_DESC_COMPIDENT(x) ((x & 0x7) == EROM_DESC_COMPIDENT) +#define EROM_IS_DESC_MASTER(x) ((x & 0x7) == EROM_DESC_MASTER) +#define EROM_IS_DESC_ADDR(x) ((x & 0x7) == EROM_DESC_ADDR) +#define EROM_IS_DESC_END(x) ((x & 0xF) == EROM_DESC_END) + +#define EROM_GET_PARTNUM(x) ((x >> 8) & (0xFFF)) /* Bit 8~19 */ +#define EROM_GET_ADDRESS(x) ((x >> 12) & (0xFFFFF)) /* Bit 12~31 */ +#define EROM_GET_SIZETYPE(x) ((x >> 4) & (0x3)) /* Bit 4~5 */ +#define EROM_GET_AG32(x) ((x >> 3) & (0x1)) /* Bit 3 */ +#define EROM_GET_SIZE(x) ((x >> 12) & (0xFFFFF)) /* Bit 12~31 */ +#define EROM_GET_SG32(x) ((x >> 3) & (0x1)) /* Bit 3 */ + +#define EROM_ADDR_SIZETYPE_4K (0) +#define EROM_ADDR_SIZETYPE_8K (1) +#define EROM_ADDR_SIZETYPE_16K (2) +#define EROM_ADDR_SIZETYPE_MORE (3) + +#define EROM_ADDR_FLAG_AG32 (1) /* Address space greater than 32 bit */ +#define EROM_ADDR_FLAG_SIZE (2) /* Addition size descriptor */ +#define EROM_ADDR_FLAG_SG32 (4) /* Size descriptor greater than 32 bit */ + +static void +iproc_cmicd_get_memregion(struct resource *res_mem) +{ + void *erom_ptr_oft; + uint32_t erom_phy_addr; + uint32_t *erom_base; + uint32_t i = 0; + uint32_t word = 0; + uint8_t more_addr_word = 0; /* bit 0: AG32; bit 1: SIZE; bit 2: SG32 */ + uint8_t found_cmicd_dev = 0; + uint8_t size_type = 0; + bool is_compident_a = 1; /* 1: CompidentA; o/w: CompidentB */ + + erom_ptr_oft = IOREMAP(IPROC_CHIPCOMMONA_EROM_PTR_OFFSET, 0x100); + + erom_phy_addr = readl((uint32 *)(erom_ptr_oft)); + iounmap(erom_ptr_oft); + + erom_base = IOREMAP(erom_phy_addr, EROM_MAX_SIZE); + + while (1) { + word = readl((uint32 *)(erom_base + i)); + + if (EROM_IS_DESC_ADDR(word) || more_addr_word) { + if (more_addr_word == 0) { /* Normal Addr Desc */ + if (EROM_GET_AG32(word) == 1) { + more_addr_word |= EROM_ADDR_FLAG_AG32; + } + + size_type = EROM_GET_SIZETYPE(word); + if (size_type == EROM_ADDR_SIZETYPE_MORE) { + more_addr_word |= EROM_ADDR_FLAG_SIZE; + } + + if (found_cmicd_dev == 1) { + res_mem->start = EROM_GET_ADDRESS(word) << 12; + if (size_type < EROM_ADDR_SIZETYPE_MORE) { + res_mem->end = res_mem->start + 4096 * (1 << size_type) - 1; + } + } + } + else if (more_addr_word & EROM_ADDR_FLAG_AG32) { /* UpperAddr Desc */ + more_addr_word &= ~EROM_ADDR_FLAG_AG32; + + if (found_cmicd_dev == 1) { + /* res_mem->start |= word << 32; */ + gprintk("Expect cmicd address to be 32-bit\n"); + } + } + else if (more_addr_word & EROM_ADDR_FLAG_SIZE) { /* Size Desc */ + if (EROM_GET_SG32(word) == 1) { + more_addr_word |= EROM_ADDR_FLAG_SG32; + } + + more_addr_word &= ~EROM_ADDR_FLAG_SIZE; + + if (found_cmicd_dev == 1) { + res_mem->end = res_mem->start + (EROM_GET_SIZE(word) << 12) - 1; + } + } + else if (more_addr_word & EROM_ADDR_FLAG_SG32) { /* UpperSize Desc */ + more_addr_word &= ~EROM_ADDR_FLAG_SG32; + + if (found_cmicd_dev == 1) { + /* res_mem->end += (word) << 32; */ + gprintk("Expect cmicd size to be 32-bit\n"); + } + } + + if (found_cmicd_dev == 1 && more_addr_word == 0) { + break; /* We have gotten all necessary information, exit the loop */ + } + } + else if (EROM_IS_DESC_COMPIDENT(word)) { + if (is_compident_a == 1) { + if (EROM_GET_PARTNUM(word) == EROM_PARTNUM_CMICD) { + found_cmicd_dev = 1; + } + } + + is_compident_a = 1 - is_compident_a; + } + else if (EROM_IS_DESC_END(word)) { + break; + } + + i++; + } + iounmap(erom_base); + + if (debug >= 1) { + gprintk("CMICD info by %s: cmicd_mem.start=%x, cmicd_mem.end=%x\n", + found_cmicd_dev ? "EROM" : "Default", + iproc_cmicd_resources[IPROC_CMICD_RES_MEM].start, + iproc_cmicd_resources[IPROC_CMICD_RES_MEM].end); + } +} +#endif /* IPROC_CMICD */ + +#ifdef BCM_ICS +static int +_ics_bde_create(void) +{ + bde_ctrl_t *ctrl; + uint32 dev_rev_id = 0x0; + resource_size_t paddr; + + if (_ndevices == 0) { + ctrl = _devices + _ndevices++; + _switch_ndevices++; + + ctrl->dev_type |= BDE_ICS_DEV_TYPE | BDE_SWITCH_DEV_TYPE; + ctrl->pci_device = NULL; /* No PCI bus */ + + /* Map in the device */ + paddr = BCM_ICS_CMIC_BASE; + ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(paddr, 0x10000); + ctrl->phys_address = paddr; + + dev_rev_id = *((unsigned int *)(KSEG1ADDR(paddr + 0x178))); + + ctrl->bde_dev.device = dev_rev_id & 0xFFFF; + ctrl->bde_dev.rev = (dev_rev_id >> 16) & 0xFF; + + ctrl->iLine = 5; /* From raptor linux BSP */ + + ctrl->isr = NULL; + ctrl->isr_data = NULL; + printk("Created ICS device ..%x\n", ctrl->bde_dev.base_address); + } + + return 0; +} + +#else /* !BCM_ICS */ + +extern struct pci_bus *pci_find_bus(int domain, int busnr); + +/* + * PCI device table. + * Populated from the include/soc/devids.h file. + */ + +static struct pci_device_id _id_table[] = { + { BROADCOM_VENDOR_ID, BCM5675_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM5676_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56218X_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56218_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56219_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56218R_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56219R_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56214_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56215_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56214R_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56215R_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56216_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56217_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56212_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56213_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56230_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56231_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53718_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53714_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53716_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56018_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56014_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56224_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56225_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56226_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56227_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56228_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56229_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56024_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56025_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53724_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53726_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56100_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56101_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56102_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56105_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56106_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56107_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56110_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56111_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56112_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56115_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56116_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56117_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56300_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56301_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56302_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56303_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56304_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56404_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56305_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56306_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56307_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56308_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56309_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56310_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56311_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56312_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56313_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56314_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56315_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56316_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56317_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56318_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56319_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, +#ifndef EXCLUDE_BCM56324 + { BROADCOM_VENDOR_ID, BCM56322_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56324_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, +#endif /* EXCLUDE_BCM56324 */ + { BROADCOM_VENDOR_ID, BCM53312_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53313_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53314_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53324_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53333_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53334_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53342_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53343_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53344_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53346_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53347_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53393_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53394_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53300_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53301_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53302_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56500_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56501_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56502_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56503_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56504_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56505_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56506_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56507_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56508_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56509_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56510_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56511_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56512_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56513_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56514_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56516_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56517_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56518_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56519_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56580_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56620_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56624_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56626_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56628_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56629_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56680_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56684_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56700_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56701_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56720_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56721_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56725_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56800_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56801_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56802_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56803_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56820_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56821_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56822_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56823_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56825_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56630_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56634_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56636_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56638_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56639_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56538_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56520_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56521_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56522_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56524_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56526_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56534_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56685_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56689_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56331_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56333_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56334_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56338_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56320_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56321_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56132_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56134_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88732_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56140_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56142_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56143_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56144_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56146_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56147_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56149_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56150_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56151_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56152_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56613_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56930_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56931_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56936_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56939_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56840_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56841_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56842_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56843_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56844_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56845_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56846_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56847_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56549_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56053_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56838_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56831_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56835_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56849_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56742_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56743_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56744_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56745_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56746_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56640_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56548_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56547_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56346_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56345_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56344_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56342_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56340_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56049_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56048_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56047_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56042_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56041_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56040_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56643_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56644_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56648_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56649_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56540_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56541_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56542_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56543_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56544_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56545_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56546_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56044_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56045_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56046_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88230_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88030_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88034_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88039_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88231_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88235_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88236_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88239_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM55440_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56440_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56441_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56442_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56443_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56445_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56446_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56447_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56448_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56449_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56240_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56241_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56242_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56243_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56245_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56246_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM55450_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM55455_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56260_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56270_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56271_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56272_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53460_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53461_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56261_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56262_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56263_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56265_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56266_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56267_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56268_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56233_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56460_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56461_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56462_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56463_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56465_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56466_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56467_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56468_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56246_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56248_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56450_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56452_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56454_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56455_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56456_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56457_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56458_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56850_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56851_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56852_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56853_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56854_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56855_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56834_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56750_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56830_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM55440_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM55441_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56060_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56062_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56063_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56064_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56065_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56066_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53401_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53411_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53402_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53412_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53403_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53413_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53404_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53414_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53405_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53415_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53406_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53416_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53408_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53418_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53454_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53455_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53456_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53457_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53422_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53424_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53426_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53365_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53369_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56960_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56961_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56962_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56963_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56930_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56968_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56970_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56971_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56972_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56974_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56168_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56169_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56560_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56561_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56562_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56565_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56566_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56567_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56568_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56760_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56762_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56764_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56765_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56766_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56768_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56069_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56068_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56160_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56162_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56163_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56164_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56166_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53440_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53443_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53442_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53434_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56965_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56969_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56966_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56967_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56170_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56172_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56174_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53570_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53575_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, +#ifdef BCM_ROBO_SUPPORT + { BROADCOM_VENDOR_ID, BCM47XX_ENET_ID, PCI_ANY_ID, PCI_ANY_ID }, +#ifdef KEYSTONE + { BROADCOM_VENDOR_ID, BCM53000_GMAC_ID, PCI_ANY_ID, PCI_ANY_ID }, +#endif +#endif + { SANDBURST_VENDOR_ID, QE2000_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { SANDBURST_VENDOR_ID, BCM88020_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { SANDBURST_VENDOR_ID, BCM88025_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9656, PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9056, PCI_ANY_ID, PCI_ANY_ID }, + { BCM53000_VENDOR_ID, BCM53000PCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, +#ifdef BCM_PETRA_SUPPORT + { BROADCOM_VENDOR_ID, BCM88650_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88350_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88351_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88450_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88451_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88550_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88551_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88552_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88651_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88654_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { PCP_PCI_VENDOR_ID, PCP_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { ACP_PCI_VENDOR_ID, ACP_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88660_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88670_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88671_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88671M_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88672_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88673_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88674_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88675_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88675M_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88676_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88676M_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88677_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88678_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88679_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88370_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88371_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88371M_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88375_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88470_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88470P_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88471_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88473_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88474_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88474H_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88476_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88477_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + + + { BROADCOM_VENDOR_ID, BCM88270_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88272_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88273_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88278_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + + { BROADCOM_VENDOR_ID, BCM8206_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + + { BROADCOM_VENDOR_ID, BCM88376_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88376M_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88377_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88378_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88379_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88680_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88681_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88682_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88683_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88684_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88685_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88380_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88381_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88690_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88202_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88360_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88361_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88363_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88460_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88461_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88560_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88561_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88562_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88661_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88664_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, +#endif +#ifdef BCM_DFE_SUPPORT + { BROADCOM_VENDOR_ID, BCM88750_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88753_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88755_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88770_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88773_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88774_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88775_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88776_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88777_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, +#ifndef DNX_IGNORE_FE3200 + { BROADCOM_VENDOR_ID, BCM88950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, +#endif + { BROADCOM_VENDOR_ID, BCM88953_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88954_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88955_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88956_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88752_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88772_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88952_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, +#endif +#ifdef BCM_DNXF_SUPPORT + { BROADCOM_VENDOR_ID, BCM88790_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, +#endif + { BROADCOM_VENDOR_ID, BCM56860_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56861_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56862_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56864_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56865_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56866_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56867_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56868_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56833_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56832_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56836_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56870_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56873_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { 0, 0, 0, 0 } +};; + +#define pci_bus_b(n) list_entry(n, struct pci_bus, node) +#define pci_dev_b(n) list_entry(n, struct pci_dev, bus_list) +#define MAX_RC_NUM 4 + +static struct pci_bus * +pci_do_bus_find(struct pci_bus* bus, int rc, int vendor, int device) +{ + struct list_head *tmp; + struct pci_dev *dev; + struct pci_bus *sub_bus; + int func = 0; + + if (unlikely(list_empty(&bus->children))) { + return NULL; + } + list_for_each(tmp, &bus->children) { + sub_bus = pci_bus_b(tmp); + dev = sub_bus->self; + func = dev->devfn & 0x7; + if (dev->vendor == vendor && dev->device == device && rc == func) { + if (debug >= 1) { + gprintk("pci_do_bus_find: dev->vendor = 0x%x, dev->device = 0x%x on rc(%d)\n", + dev->vendor, dev->device, rc); + } + return sub_bus; + } + } + return NULL; +} + +static struct pci_dev * +_pci_do_bus_dev_find(struct pci_bus* bus, unsigned int vendor, unsigned int device) +{ + struct list_head *tmp; + struct pci_dev *dev; + + if (unlikely(list_empty(&bus->devices))) { + return NULL; + } + list_for_each(tmp, &bus->devices) { + dev = pci_dev_b(tmp); + if (dev->vendor == vendor && (device == PCI_ANY_ID || dev->device == device)) { + if (debug >= 1) { + gprintk("_pci_do_rc_dev_find: vendor = %x, device = %x\n", vendor, device); + } + return dev; + } + } + return NULL; +} + +static struct pci_dev * +pci_do_rc_dev_find(int rc) +{ + struct pci_bus *root_bus = pci_find_bus(0,0); + struct pci_bus *bus_rc = NULL; + struct pci_dev *dev_on_rc = NULL; + unsigned int pci_dev_id = 0; + + if(NULL == root_bus) { + if (debug >= 1) gprintk("Not find root bus\n"); + return NULL; + } + bus_rc = pci_do_bus_find(root_bus, rc, 0x184e, 0x1004); + if (NULL == bus_rc) { + if (debug >= 1) { + gprintk("Not find vendor(0x184e) device(0x1004) bus\n"); + } + return NULL; + } + for(pci_dev_id = 0; pci_dev_id < sizeof(_id_table)/sizeof(struct pci_device_id); pci_dev_id++) { + dev_on_rc = _pci_do_bus_dev_find(bus_rc, _id_table[pci_dev_id].vendor, _id_table[pci_dev_id].device); + if (NULL != dev_on_rc) { + return dev_on_rc; + } + } + if (debug >= 1) { + gprintk("Not find device at rc(%d)\n", rc); + } + return NULL; +} + +/* + * Function: p2p_bridge + * + * Purpose: + * Finalize initialization secondary PCI-PCI bridge. + * Parameters: + * membase - start of memory address space for secondary PCI bus + * Returns: + * 0 + * Notes: + * The membase depends on the processor architecture, and is + * derived from the memory space addresses set up by the kernel. + */ +static int +p2p_bridge(void) +{ + struct pci_dev *dev, *dev_on_rc; + uint16 cmd; + uint16 mem_base; + uint16 mem_limit; + uint8 bridge_ctrl; + uint8 rc_index; + + if ((dev = PCI_FIND_DEV(DC21150_VENDOR_ID, DC21150_DEVICE_ID, NULL)) != NULL || + (dev = PCI_FIND_DEV(HINT_HB4_VENDOR_ID, HINT_HB4_DEVICE_ID, NULL)) != NULL || + (dev = PCI_FIND_DEV(PI7C8150_VENDOR_ID, PI7C8150_DEVICE_ID, NULL)) != NULL) { + + if (debug >= 1) gprintk("fixing up PCI-to-PCI bridge\n"); + /* Adjust command register */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + /* Disable device */ + pci_write_config_word(dev, PCI_COMMAND, 0); + /* Initialize non-prefetchable memory window if needed */ + pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base); + if (mem_base == 0) { + mem_base = (uint16)((_pci_mem_start & 0xFFF00000) >> 16); + mem_limit = (uint16)((_pci_mem_end & 0xFFF00000) >> 16); + pci_write_config_word(dev, PCI_MEMORY_BASE, mem_base); + pci_write_config_word(dev, PCI_MEMORY_LIMIT, mem_limit); + } + /* Enable PCI clocks on remote end */ + pci_write_config_word(dev, PCI_CFG_DEC21150_SEC_CLK, 0); + /* Re-enable config space */ + pci_write_config_word(dev, PCI_COMMAND, cmd); + + /* Avoid DMA data corruption */ + if (dev->vendor == HINT_HB4_VENDOR_ID) { + /* Fix for HiNT bridge and BCM4704 DMA problem */ + if ((dev = PCI_FIND_DEV(BCM4704_VENDOR_ID, BCM4704_DEVICE_ID, NULL)) != NULL) { + /* Reset PrefetchEn (PE) */ + pci_write_config_dword(dev, 0x8c, 1); + if (debug >= 1) { + gprintk("reset PrefetchEn on BCM4704 when HiNT bridge is present\n"); + } + } + } + } + /* Enable fast back-to-back read/write */ + if ((dev = PCI_FIND_DEV(PI7C8150_VENDOR_ID, PI7C8150_DEVICE_ID, NULL)) != NULL) { + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_FAST_BACK; + pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bridge_ctrl); + bridge_ctrl |= PCI_BRIDGE_CTL_FAST_BACK; + pci_write_config_word(dev, PCI_COMMAND, 0); + pci_write_config_byte(dev, PCI_BRIDGE_CONTROL, bridge_ctrl); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + /* Netlogic XLP CPU */ + for(rc_index = 0; rc_index < MAX_RC_NUM; rc_index++) { + dev_on_rc = pci_do_rc_dev_find(rc_index); + if (dev_on_rc != NULL ) { + dev = PCI_FIND_DEV(0x184e, 0x1004, NULL); + if (dev != NULL ) { + pci_write_config_dword(dev,0x78,MAX_PAYLOAD_256B | + MAX_READ_REQ_256B); + } + } + } + if ((dev = PCI_FIND_DEV(0x14e4, 0xb634, NULL)) != NULL) { + pci_write_config_dword(dev,0x78,MAX_PAYLOAD_256B | + MAX_READ_REQ_256B); + } + + if ((dev = PCI_FIND_DEV(PCI_VNDID_PERICOM, PCI_DEVID_PI7C9X130, NULL)) != NULL) { + /* + * Configure the PCIE cap: Max payload size: 256, Max Read + * Request size: 256, disabling relax ordering. + * Writes to the PCIE capability device control register + */ + pci_write_config_dword(dev, DEV_CTRL_REG, + MAX_PAYLOAD_256B | MAX_READ_REQ_256B); + } + + if ((dev = PCI_FIND_DEV(FSL_VENDOR_ID, FSL8548PCIE_DEVICE_ID, NULL)) != NULL || + (dev = PCI_FIND_DEV(FSL_VENDOR_ID, FSL2020EPCIE_DEVICE_ID, NULL)) != NULL) { + /* + * Configure the PCIE cap: Max payload size: 256, Max Read + * Request size: 256, disabling relax ordering. + * Writes to the PCIE capability device control register + */ + pci_write_config_dword(dev, FSL8548PCIE_DEV_CTRL_REG, + MAX_PAYLOAD_256B | MAX_READ_REQ_256B); + } + if ((dev = PCI_FIND_DEV(BCM4716_VENDOR_ID, BCM4716PCIE_DEVICE_ID, NULL)) != NULL || + (dev = PCI_FIND_DEV(BCM53000_VENDOR_ID, BCM53000PCIE_DEVICE_ID, NULL)) != NULL) { + uint32 tmp, maxpayld, device_bmp=0, mask; + unsigned long addr; + uint16 tmp16, tmp161; + int i, bus0 = -1, bus1 = -1, port; + struct pci_dev *pcie0, *pcie1; + + pcie0 = dev; + bus0 = dev->bus->number; + if ((pcie1 = PCI_FIND_DEV(BCM53000_VENDOR_ID, BCM53000PCIE_DEVICE_ID, pcie0)) != NULL) { + bus1 = pcie1->bus->number; + } + + for(i = 0; i < _ndevices; i++) { + bde_ctrl_t *ctrl = _devices + i; + + mask = BDE_SWITCH_DEV_TYPE | BDE_PCI_DEV_TYPE; + if ((ctrl->dev_type & mask) == mask) { + if (ctrl->pci_device->bus->number == bus0) { + device_bmp |= 1 << 0; + } + if (ctrl->pci_device->bus->number == bus1) { + device_bmp |= 1 << 1; + } + } + } + + /* configure the PCIE cap: Max payload size: 256, Max Read + * Request size: 256, disabling relax ordering. + * Writes to the PCIE capability device control register + */ + + i = 0; + while(device_bmp) { + if (device_bmp & (1 << i)){ + port = i ; + pci_read_config_dword(BCM53000PCIE_DEV(port), + BCM53000PCIE_DEV_CAP_REG, &tmp); + maxpayld = (tmp & BCM53000PCIE_MAX_PAYLOAD_MASK); + if (debug >= 1) { + gprintk("port %d\n",port); + gprintk("DevCap (@%x): 0x%x%c\n", BCM53000PCIE_DEV_CAP_REG, tmp, + (maxpayld != BCM53000PCIE_CAP_MAX_PAYLOAD_256B) ? ' ':'\n'); + } + if (maxpayld != BCM53000PCIE_CAP_MAX_PAYLOAD_256B) { + addr = BCM53000PCIE_BASE(port); + addr |= (BCM53000PCIE_SROM_SPACE | BCM53000PCIE_SPROM_OFFSET); + tmp16 = *((uint16 *)addr); + if (debug >= 1){ + gprintk("addr %lx spromData.MaxPayloadSize: 0x%x\n", addr, tmp16); + } + mask = BCM53000PCIE_SPROM_MAX_PAYLOAD_MASK; + if ((tmp16 & mask) != BCM53000PCIE_SPROM_MAX_PAYLOAD_256B) { + tmp161 = (tmp16 & ~mask) | BCM53000PCIE_SPROM_MAX_PAYLOAD_256B; + *((uint16 *)addr) = tmp161; + if (debug >= 1) { + tmp16 = 0; + tmp16 = *((uint16 *)addr); + gprintk("Enable spromData.MaxPayloadSize to 1 (256 bytes): " + "0x%x (%s w/ 0x%x)\n", tmp161, + ((tmp16 & mask) == BCM53000PCIE_SPROM_MAX_PAYLOAD_256B) ? + "Success":"Fail", + tmp16); + } + } + pci_read_config_dword(BCM53000PCIE_DEV(port), + BCM53000PCIE_DEV_CAP_REG, &tmp); + if (debug >= 1){ + gprintk("DevCap (@%x): now is 0x%x\n\n", + BCM53000PCIE_DEV_CAP_REG, tmp); + } + } + + addr = BCM53000PCIE_BASE(port); + addr |= (BCM53000PCIE_FUNC0_COFIG_SPACE | BCM53000PCIE_DEV_CTRL_REG); + tmp16 = *((uint16 *)addr); + if (debug >= 1) { + gprintk("DevControl (@%x): 0x%x\n", BCM53000PCIE_DEV_CTRL_REG, tmp16); + } + if (!(tmp16 & MAX_PAYLOAD_256B) || !(tmp16 & MAX_READ_REQ_256B)) { + tmp161 = tmp16 | MAX_PAYLOAD_256B | MAX_READ_REQ_256B; + *((uint16 *)addr) = tmp161; + if (debug >= 1) { + tmp16 = 0; + tmp16 = *((uint16 *)addr); + gprintk("addr %lx Enable DevControl MaxPayloadSize to 1 (256 bytes): " + "0x%x (%s w/ 0x%x)\n", addr, tmp161, + (tmp16 & MAX_PAYLOAD_256B) ? "Success":"Fail", + tmp16); + gprintk("Enable DevControl MaxReadRequestSize to 1 (256 bytes): " + "0x%x (%s w/ 0x%x)\n\n", tmp161, + (tmp16 & MAX_READ_REQ_256B) ? "Success":"Fail", + tmp16); + } + } + device_bmp &= ~(1 << i); + } + i++; + } + } + + /* + * Configure max payload to 512 on all ports in the PLX8608/PLX8617. + * The device supports 128, 512, and 1024 max payload sizes. + */ + dev = NULL; + while ((dev = PCI_FIND_DEV(PCI_VENDOR_ID_PLX, PCI_ANY_ID, dev)) != NULL) { + if ((dev->device == PLX_PEX8608_DEV_ID) || + (dev->device == PLX_PEX8617_DEV_ID)) { + uint16 ctrl_reg; + pci_read_config_word(dev, PLX_PEX86XX_DEV_CTRL_REG, &ctrl_reg); + ctrl_reg = (ctrl_reg & ~(7<<5)) | MAX_PAYLOAD_512B; + pci_write_config_word(dev, PLX_PEX86XX_DEV_CTRL_REG, ctrl_reg); + } + } + return 0; +} + +#ifdef BCM_PLX9656_LOCAL_BUS + +#define PLX_LAS0_BA 0x00000004 /* LAS0 Local Base Address Remap */ +#define PLX_LAS1_BA 0x000000f4 /* LAS1 Local Base Address Remap */ +#define PLX_LAS_EN 0x00000001 /* Space Enable bit */ + +#define PLX_MMAP_PCIBAR0 0 /* Memory-Mapped Config (PCIBAR0) */ +#define PLX_LAS0_PCIBAR2 2 /* Local Address Space 0 (PCIBAR2) */ +#define PLX_LAS1_PCIBAR3 3 /* Local Address Space 1 (PCIBAR3) */ + +STATIC int +_plx_las_bar_get(struct pci_dev *dev) +{ + void *local_config_addr; + int bar = -1; + + local_config_addr = IOREMAP(pci_resource_start(dev, PLX_MMAP_PCIBAR0), + pci_resource_len(dev, PLX_MMAP_PCIBAR0)); + if (local_config_addr) { + uint32 las_remap_reg; + /* + * Make sure LAS0BA or LAS1BA is enabled before returning + * BAR that will be used to access the Local Bus + */ + las_remap_reg = ioread32(local_config_addr + PLX_LAS0_BA); + if (las_remap_reg & PLX_LAS_EN) { + bar = PLX_LAS0_PCIBAR2; + } else { + las_remap_reg = ioread32(local_config_addr + PLX_LAS1_BA); + if (las_remap_reg & PLX_LAS_EN) { + bar = PLX_LAS1_PCIBAR3; + } + } + } + iounmap(local_config_addr); + return bar; +} +#endif /* BCM_PLX9656_LOCAL_BUS */ + +static void +_shbde_log_func(int level, const char *str, int param) +{ + level = (level >= SHBDE_DBG) ? 1 : 0; + if (debug >= level) { + gprintk("%s (%d)\n", str, param); + } +} +/* + * Function: _device_rescan_validate + * + * Purpose: + * Check if the device is ever probed or not. + * Parameters: + * dev - Linux PCI device structure + * Returns: + * >= 0 : dev is ever probed + * reutrn value is the index point to the _devices[] + * -1 : dev is not probed before. + */ +static int +_device_rescan_validate(struct pci_dev *dev) +{ + bde_ctrl_t *ctrl; + int i; + + if (PCI_FUNC(dev->devfn) > 0) { + return -1; + } + ctrl = NULL; + for (i = 0; i < _ndevices; i ++) { + ctrl = _devices + i; + /* check the device id */ + if (dev->device == ctrl->bde_dev.device) { + /* check the bus number */ + if ((dev->bus)) { + if ((dev->bus->number == ctrl->bus_no) && + (pci_domain_nr(dev->bus) == ctrl->domain_no)) { + return i; + } + } + } + } + return -1; +} + +#ifdef CONFIG_PCI_MSI + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84)) +/** + * _pci_msix_table_size - return the number of device's MSI-X table entries + * @dev: pointer to the pci_dev data structure of MSI-X device function + */ +static int +_pci_msix_table_size(struct pci_dev *dev) +{ + int nr_entries = 0; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,110)) + u16 control; + int pos; + + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); + if (pos) { + pci_read_config_word(dev, msi_control_reg(pos), &control); + nr_entries = msix_table_size(control); + } +#else +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)) +{ + /* Pass large entry value to enable MSIX to get # of entires */ + struct msix_entry *entries; + entries = kmalloc(sizeof(struct msix_entry) * + PCI_MSIX_FLAGS_QSIZE, GFP_KERNEL); + if (entries != NULL) { + nr_entries = pci_enable_msix(dev, + entries, PCI_MSIX_FLAGS_QSIZE); + if (nr_entries < 0) { + nr_entries = 0; + } + kfree(entries); + } +} +#else + nr_entries = pci_msix_vec_count(dev); +#endif +#endif + + return nr_entries; +} +#endif + +static int +_msi_connect(bde_ctrl_t *ctrl) +{ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84)) + int ret; + if (ctrl->use_msi == PCI_USE_INT_MSIX) { + int i; + ret = _pci_msix_table_size(ctrl->pci_device); + + if (ret == 0) { + /* MSI-X failed */ + gprintk("MSI-X not supported.\n"); + goto er_intx; + } + ctrl->entries = kcalloc(ret, sizeof(struct msix_entry)*ret, GFP_KERNEL); + + if (!ctrl->entries) { + goto er_intx; + } + /* We need only that much interrupt vecotrs */ + ctrl->msix_cnt = ret/4; + if (unlikely(debug > 1)) + gprintk("MSIX Table size = %d\n", ctrl->msix_cnt); + for (i = 0; i < ctrl->msix_cnt; i++) + ctrl->entries[i].entry = i; + + ret = pci_enable_msix(ctrl->pci_device, + ctrl->entries, ctrl->msix_cnt); + if (ret > 0) { + /* Not enough vectors available , Retry MSI-X */ + gprintk("Retrying with MSI-X interrupts = %d\n", ret); + ctrl->msix_cnt = ret; + ret = pci_enable_msix(ctrl->pci_device, + ctrl->entries, ctrl->msix_cnt); + if (ret != 0) + goto er_intx_free; + } else if (ret < 0) { + /* Error */ + goto er_intx_free; + } else { + gprintk("Enabled MSI-X interrupts = %d\n", ctrl->msix_cnt); + } + } +#endif + + if (ctrl->use_msi == PCI_USE_INT_MSI) { + if (pci_enable_msi(ctrl->pci_device) == 0) { + ctrl->iLine = ctrl->pci_device->irq; + } else { + /* MSI failed */ + gprintk("Failed to initialize MSI interrupts.\n"); + goto er_intx; + } + } else { + /* failed */ + gprintk("Not MSI/MSIC interrupt.\n"); + goto er_intx; + } + return 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84)) +er_intx_free: + gprintk("Failed to enable MSI-X interrupts = %d\n", ret); + kfree(ctrl->entries); +#endif +er_intx: + return -1; + +} + +static int +_msi_disconnect(bde_ctrl_t *ctrl) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84)) + if (ctrl->use_msi == PCI_USE_INT_MSIX) { + pci_disable_msix(ctrl->pci_device); + kfree(ctrl->entries); + ctrl->msix_cnt = 0; + } +#endif + if (ctrl->use_msi == PCI_USE_INT_MSI) { + pci_disable_msi(ctrl->pci_device); + } else { + gprintk("MSI not used\n"); + } + return 0; +} + +#endif + + +static void +config_pci_intr_type(bde_ctrl_t *ctrl) +{ + +#ifdef CONFIG_PCI_MSI + int ret; + + ctrl->use_msi = use_msi; + if (unlikely(debug > 1)) + gprintk("%s: msi = %d\n", __func__, ctrl->use_msi); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84)) + if (ctrl->use_msi == PCI_USE_INT_MSIX) { + /* check for support MSIX vector */ + ret = _pci_msix_table_size(ctrl->pci_device); + if (ret == 0) { + gprintk("%s: Zero MSIX table size\n", __func__); + ctrl->use_msi = PCI_USE_INT_MSI; + } + } +#endif + + if (ctrl->use_msi == PCI_USE_INT_MSI) { + /* check for support MSI vector */ + ret = pci_enable_msi(ctrl->pci_device); + if (ret < 0) { + ctrl->use_msi = PCI_USE_INT_INTX; + gprintk("%s: Failed to enable MSI\n", __func__); + } else { + pci_disable_msi(ctrl->pci_device); + } + } +#else + ctrl->use_msi = PCI_USE_INT_INTX; +#endif +} + +/* + * Function: _pci_probe + * + * Purpose: + * Device initialization callback used by the Linux PCI + * subsystem. Called as a result of pci_register_driver(). + * Parameters: + * dev - Linux PCI device structure + * Returns: + * 0 + */ +static int +_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) +{ + bde_ctrl_t *ctrl; + resource_size_t paddr; + uint16 cmd = 0; + uint32 bar_len; + int cmic_bar; + int baroff = 0; + int iproc = 0; + uint32 gmac_base = 0; + int plx_dev = 0; + int eth_dev = 0; + int cpu_dev = 0; + int update_devid = 0; + int paxb_core = 0; + int rescan = 0, rescan_idx = -1; + shbde_hal_t shared_bde, *shbde = &shared_bde; + + if (debug >= 4) {gprintk("probing: vendor_id=0x%x, device_id=0x%x\n", dev->vendor, dev->device);} + if (nodevices == 1) { + return 0; + } + + /* Initialize Linux hardware abstraction for shared BDE functions */ + linux_shbde_hal_init(shbde, _shbde_log_func); + + /* + * If an AXI-based switch device has been found already, then it means + * that the AXI bus has been probed, and that we should ignore devices + * found on PCI bus zero. + */ + +#if defined(IPROC_CMICD) + if ((dev->bus) && (dev->bus->number == 0)) { + int i; + uint32 mask = BDE_SWITCH_DEV_TYPE | BDE_AXI_DEV_TYPE; + + for (i = 0; i < _ndevices; i++) { + ctrl = _devices + i; + + if ((ctrl->dev_type & mask) == mask) { + return 0; + } + } + } +#endif /* IPROC_CMICD */ + + /* + * Note that a few supported devices have a non-Broadcom PCI vendor ID, + * but since none of their associated PCI device IDs collide with the + * Broadcom device IDs, the probe code below only checks the device ID. + */ + + switch (dev->device) { + case PCI_DEVICE_ID_PLX_9056: +#ifdef DNX_TEST_BOARD + break; /* a PCIe bridge to a non PCIe device should be treated as the device */ +#endif /* DNX_TEST_BOARD */ + case PCI_DEVICE_ID_PLX_9656: + plx_dev = 1; + break; +#if defined (BCM_ROBO_SUPPORT) && defined(KEYSTONE) + case BCM53000_GMAC_ID: + eth_dev = 1; + gmac_base = SB_ENUM_BASE; + break; +#endif +#if defined (BCM_ROBO_SUPPORT) + case BCM47XX_ENET_ID: + eth_dev = 1; + break; +#endif + case BCM53000PCIE_DEVICE_ID: + cpu_dev = 1; + break; + /* + * The device ID for 56500, 56100 and 56300 family of devices may + * be incorrect just after a PCI HW reset. It needs to be read + * again after stabilization. + */ + case BCM56102_DEVICE_ID: + case BCM56504_DEVICE_ID: + case BCM56304_DEVICE_ID: + case BCM56314_DEVICE_ID: + case BCM56112_DEVICE_ID: + update_devid = 1; + break; + default: + break; + } + + /* Check if the device is ever probed. */ + rescan_idx = _device_rescan_validate(dev); + if (rescan_idx != -1) { + rescan = 1; + } + + ctrl = NULL; + if (plx_dev) { +#if defined(BCM_PLX9656_LOCAL_BUS) + /* PLX chip itself won't be part of _devices[]. */ + baroff = _plx_las_bar_get(dev); + if (baroff == -1) { + gprintk("No Local Address Space enabled in PLX\n"); + return 0; + } + ctrl = &plx_ctrl; + num_plx++; +#endif + } else if (eth_dev) { + if (_ether_ndevices >= LINUX_BDE_MAX_ETHER_DEVICES) { + return 0;; + } + ctrl = _devices + _ndevices++; + _ether_ndevices++; + ctrl->dev_type |= BDE_ETHER_DEV_TYPE; + ctrl->iLine = dev->irq; + if (debug >= 1) + gprintk("Found PCI device %04x:%04x as Ethernet device\n", + dev->vendor, dev->device); + } else if (cpu_dev) { + if (_cpu_ndevices >= LINUX_BDE_MAX_CPU_DEVICES) { + return 0;; + } + ctrl = _devices + _ndevices++; + _cpu_ndevices++; + ctrl->dev_type |= BDE_CPU_DEV_TYPE; + if (debug >= 1) + gprintk("Found PCI device %04x:%04x as CPU device\n", + dev->vendor, dev->device); + } else { + if (PCI_FUNC(dev->devfn) > 0) { + return 0; + } + if (_switch_ndevices >= LINUX_BDE_MAX_SWITCH_DEVICES) { + return 0;; + } + + if (rescan) { + if (debug >= 1) { + gprintk("PCI device %04x:%04x is re-probed \n", + dev->vendor, dev->device); + } + ctrl = _devices + rescan_idx; + ctrl->dev_state = BDE_DEV_STATE_CHANGED; + } else { + ctrl = _devices + _ndevices++; + _switch_ndevices++; + ctrl->dev_type |= BDE_SWITCH_DEV_TYPE; + ctrl->domain_no = pci_domain_nr(dev->bus); + ctrl->bus_no = dev->bus->number; + ctrl->dev_state = BDE_DEV_STATE_NORMAL; + } + + /* Save shared BDE HAL in device structure */ + memcpy(&ctrl->shbde, shbde, sizeof(ctrl->shbde)); + + if (update_devid) { + /* Re-read the device ID */ + pci_read_config_word(dev, + PCI_DEVICE_ID, + &ctrl->bde_dev.device); + dev->device = ctrl->bde_dev.device; + } + + if (debug >= 4) {gprintk("Enabling PCI device : vendor_id=0x%x, device_id=0x%x\n", dev->vendor, dev->device);} + if (pci_enable_device(dev)) { + gprintk("Cannot enable PCI device : vendor_id = %x, device_id = %x\n", + dev->vendor, dev->device); + } + + /* FIXME: "workarounds" previously called "total h_acks" */ + /* + * These are workarounds to get around some existing + * kernel problems :( + */ + + /* + * While probing we determine the overall limits for the PCI + * memory windows across all devices. These limits are used + * later on by the PCI-PCI bridge code. + */ + if (pci_resource_start(dev, baroff) < _pci_mem_start) { + _pci_mem_start = pci_resource_start(dev, baroff); + } + if (pci_resource_end(dev, baroff) > _pci_mem_end) { + _pci_mem_end = pci_resource_end(dev, baroff); + } + +#ifdef CONFIG_SANDPOINT + /* + * Something wrong with the PCI subsystem in the mousse kernel. + * The device is programmed correctly, but the irq in the pci + * structure is hosed. This checks for the hosed-ness and fixes it. + */ + if (dev->irq > 100) { + dev->irq = 2; + gprintk("irq problem: setting irq = %d\n", dev->irq); + } +#endif + +#ifdef CONFIG_BMW + /* + * PCI subsystem does not always program the system correctly. + */ + if (dev->irq < 16 && dev->irq != 2) { + dev->irq = 2; + gprintk("irq problem: setting irq = %d\n", dev->irq); + } +#endif + +#ifdef CONFIG_IDT_79EB334 + /* + * IDT kernel is not currently mapping interrupts correctly + * Hardwired to core mips interrupt, irq 3 for kernel 2.4.18 + */ + if (dev->irq != 3) { + dev->irq = 3; + gprintk("irq problem: setting irq = %d\n", dev->irq); + } +#endif + +#ifdef CONFIG_BCM94702_CPCI + /* + * Hardwired to core mips interrupt irq 6 on MBZ + */ + if (dev->irq != 6) { + dev->irq = 6; + gprintk("irq problem: setting irq = %d\n", dev->irq); + } +#endif + + if ((PCI_FIND_DEV(BCM4704_VENDOR_ID, BCM4704_DEVICE_ID, NULL)) != NULL) { + /* + * Decrease the PCI bus priority for the CPU for better overall + * system performance. This change significantly reduces the + * number of PCI retries from other devices on the PCI bus. + */ + void * _mc_vbase = IOREMAP(BCM4704_MEMC_BASE, 0x1000); + int priorinv = 0x80; + static int done = 0; + if (!done) { + done = 1; + writel(priorinv, _mc_vbase + BCM4704_MEMC_PRIORINV); + if (debug >= 1) + gprintk("set BCM4704 PriorInvTim register to 0x%x\n", priorinv); + iounmap(_mc_vbase); + } + } + + if ((PCI_FIND_DEV(SIBYTE_PCI_VENDOR_ID, SIBYTE_PCI_DEVICE_ID, NULL)) != NULL) { + /* + * The BCM91125CPCI CPU boards with a PCI-PCI bridge use the same + * interrupt line for all switch ships behind the bridge. + */ + if (PCI_FIND_DEV(DC21150_VENDOR_ID, DC21150_DEVICE_ID, NULL) || + PCI_FIND_DEV(HINT_HB4_VENDOR_ID, HINT_HB4_DEVICE_ID, NULL) || + PCI_FIND_DEV(PI7C8150_VENDOR_ID, PI7C8150_DEVICE_ID, NULL)) { + /* + * By default we try to guess the correct IRQ based on the design. + * For now we only look at the bridge vendor, but it may be necessary + * to look at the switch chip configuration as well. + */ + if (forceirq == -1) { + if ((PCI_FIND_DEV(HINT_HB4_VENDOR_ID, HINT_HB4_DEVICE_ID, NULL)) || + ((dev->device == BCM5674_DEVICE_ID) && + (PCI_FIND_DEV(PI7C8150_VENDOR_ID, PI7C8150_DEVICE_ID, NULL)))) { + forceirq = 58; + } else { + forceirq = 56; + } + } + } + } + + if (((PCI_FIND_DEV(BCM58525_PCI_VENDOR_ID, BCM58525_PCI_DEVICE_ID, NULL)) != NULL) || + ((PCI_FIND_DEV(BCM58525_PCI_VENDOR_ID, BCM58522_PCI_DEVICE_ID, NULL)) != NULL) || + ((PCI_FIND_DEV(BCM58712_PCI_VENDOR_ID, BCM58712_PCI_DEVICE_ID, NULL)) != NULL) ) { + /* BCM58525/BCM58712 CPU boards support 128 Max payload size */ + if (maxpayload) { + maxpayload = 128; + if (debug >= 1) gprintk("force max payload size to 128\n"); + } + } + + if (forceirq > 0 && dev->irq != (uint32) forceirq) { + if (forceirqubm & (1U << (_ndevices - 1))) { + dev->irq = forceirq; + if (debug >= 1) gprintk("force irq to %d\n", forceirq); + } + } else if (debug >= 1) gprintk("found irq %d\n", dev->irq); + + ctrl->iLine = dev->irq; + if (unlikely(debug > 1)) + gprintk("%s:irq = %d\n",__func__, ctrl->iLine); + + if (shbde_pci_is_pcie(shbde, dev)) { + /* Set PCIe max payload */ + shbde_pci_max_payload_set(shbde, dev, maxpayload); + } else { + /* Set PCI retry to infinite on non-PCIe switch device */ + pci_write_config_word(dev, 0x40, 0x0080); + if (debug >= 1) gprintk("set DMA retry to infinite on switch device\n"); + } + } + +#if defined(BCM_DFE_SUPPORT) + switch (dev->device) { + case BCM88750_DEVICE_ID: + case BCM88753_DEVICE_ID: + case BCM88755_DEVICE_ID: + case BCM88770_DEVICE_ID: + case BCM88773_DEVICE_ID: + case BCM88774_DEVICE_ID: + case BCM88775_DEVICE_ID: + case BCM88776_DEVICE_ID: + case BCM88777_DEVICE_ID: + case BCM88950_DEVICE_ID: + case BCM88953_DEVICE_ID: + case BCM88954_DEVICE_ID: + case BCM88955_DEVICE_ID: + case BCM88956_DEVICE_ID: + case BCM88752_DEVICE_ID: + case BCM88772_DEVICE_ID: + case BCM88952_DEVICE_ID: + + /* + * For DMA transactions - set Max_Payload_Size and + * Max_Read_Request_Size to 128 bytes. + */ + pci_write_config_byte(dev, 0xb5, 0x0c); + pci_write_config_byte(dev, 0xb4, 0x0); + break; + default: + break; + } +#endif /* BCM_DFE_SUPPORT */ + +#if defined(BCM_DNXF_SUPPORT) + switch (dev->device) { + case BCM88790_DEVICE_ID: + + /* + * For DMA transactions - set Max_Payload_Size and + * Max_Read_Request_Size to 128 bytes. + */ + pci_write_config_byte(dev, 0xb5, 0x0c); + pci_write_config_byte(dev, 0xb4, 0x0); + break; + default: + break; + } +#endif + + /* Prevent compiler warning */ + if (ctrl == NULL) { + return 0; + } + + ctrl->be_pio = 0; + ctrl->dev_type |= BDE_PCI_DEV_TYPE; + ctrl->pci_device = dev; + pci_set_drvdata(dev, ctrl); + + /* Check for iProc device */ + if (shbde_pci_is_iproc(shbde, dev, &cmic_bar)) { + iproc = 1; + if (cmic_bar >= 0) { + baroff = cmic_bar; + } + } +#ifdef DNX_TEST_BOARD + else if (dev->device == PLX9056_DEVICE_ID && baroff == 0) { + baroff = 2; + ctrl->dev_type |= BDE_NO_IPROC/* | BDE_BYTE_SWAP*/; + } +#endif /* DNX_TEST_BOARD */ + + /* Get the device revision */ + pci_read_config_byte(dev, PCI_REVISION_ID, &ctrl->bde_dev.rev); + + /* Map in the device */ + ctrl->bde_dev.device = dev->device; + paddr = pci_resource_start(dev, baroff); + + switch (dev->device) { +#if defined(BCM_PETRA_SUPPORT) && defined(__DUNE_LINUX_BCM_CPU_PCIE__) + case GEDI_DEVICE_ID: + case PCP_PCI_DEVICE_ID: + bar_len = 0x1000000; + break; +#endif + default: + bar_len = pci_resource_len(dev, baroff); + break; + } + + ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(paddr, bar_len); + ctrl->phys_address = paddr; + if (debug >= 3) { + gprintk("BAR %d: kernel addr:0x%lx phys addr:0x%lx length:%lx\n", + baroff, (unsigned long)ctrl->bde_dev.base_address, (unsigned long)paddr, (unsigned long)bar_len); + } + + /* Map secondary address spaces */ + if (iproc +#ifdef DNX_TEST_BOARD + || (dev->device == PLX9056_DEVICE_ID && baroff == 2) +#endif /* DNX_TEST_BOARD */ + ) { + paddr = pci_resource_start(dev, 0); + bar_len = pci_resource_len(dev, 0); + ctrl->bde_dev.base_address1 = (sal_vaddr_t)IOREMAP(paddr, bar_len); + ctrl->phys_address1 = paddr; + if (debug >= 3) { + gprintk("BAR 0: kernel addr:0x%lx phys addr:0x%lx length:%lx\n", + (unsigned long)ctrl->bde_dev.base_address1, (unsigned long)paddr, (unsigned long)bar_len); + } + } + + /* Each device follows global policy by default */ + ctrl->use_msi = use_msi; + + /* Check is MSI is properly supported in kernel for this device */ + if (ctrl->use_msi) { + if (pci_enable_msi(ctrl->pci_device) == 0) { + /* Release MSI resources until interrupt_connect is called */ + pci_disable_msi(ctrl->pci_device); + } else { + gprintk("Could not enable MSI interrupts\n"); + ctrl->use_msi = 0; + } + } + + /* configure interrupt type */ + config_pci_intr_type(ctrl); + + /* Configure iProc PCI-AXI bridge */ + if (iproc && ctrl->bde_dev.base_address1) { + void *iproc_regs; + shbde_iproc_config_t *icfg = &shbde->icfg; + + /* Mapped iProc regs in PCI BAR 0 */ + iproc_regs = (void *)ctrl->bde_dev.base_address1; + + /* iProc configuration parameters */ + (void)shbde_pci_iproc_version_get(shbde, dev, &icfg->iproc_ver, + &icfg->cmic_ver, &icfg->cmic_rev); + shbde_iproc_config_init(icfg, ctrl->bde_dev.device, ctrl->bde_dev.rev); + + if (debug >=2) { + gprintk("iproc version = %x dma_hi_bits = %x\n", icfg->iproc_ver, icfg->dma_hi_bits); + } + icfg->use_msi = ctrl->use_msi; + + /* Call shared function */ + paxb_core = shbde_iproc_paxb_init(shbde, iproc_regs, icfg); + + /* Save PCI core information for CMIC */ + if (paxb_core == 1) { + ctrl->dev_type |= BDE_DEV_BUS_ALT; + } + + /* Save MSI enable state information */ + if (ctrl->use_msi) { + ctrl->dev_type |= BDE_DEV_BUS_MSI; + } + + /* iProc PCIe preemphasis */ + shbde_iproc_pcie_preemphasis_set(shbde, iproc_regs, icfg, dev); + } + + /* Save shared BDE HAL in device structure */ + memcpy(&ctrl->shbde, shbde, sizeof(ctrl->shbde)); + +#if defined(VENDOR_BROADCOM) +#if defined(BCM_PLX9656_LOCAL_BUS) && defined(SHADOW_SVK) + if (num_plx) { + sal_vaddr_t base_address; + uint32 intr_enable; + + paddr = pci_resource_start(dev, 0); + bar_len = pci_resource_len(dev, 0); + base_address = (sal_vaddr_t)IOREMAP(paddr, bar_len); + + intr_enable = readl((uint32 *)(base_address + 0x68)); + gprintk("PLX Interrupt ENABLE: %x\n", intr_enable); + intr_enable |= 0x00080000; + writel(intr_enable, (uint32 *)(base_address + 0x68)); + gprintk("PLX Interrupt ENABLE: %x\n", intr_enable); + } +#endif +#endif + + /* + * Since the GMAC driver of Robo chips needs access to the + * ChipCommon and Wrapper registers, we set the base address + * as the enumeration base address and its size as 3MB to + * cover all Wrapper register regions. + */ + if (gmac_base) { + uint32_t offset; + + ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(gmac_base, 0x300000); + + /* Record the base address of GMAC core */ + offset = ctrl->phys_address - gmac_base; + ctrl->alt_base_addr = ctrl->bde_dev.base_address + offset; + ctrl->phys_address = gmac_base; + } + + /* + * Workaround bug in FE2K A1 part; shows as A0 part in PCI config space, + * read the FE's regs directly to get the true revision + */ + if (ctrl->bde_dev.device == BCM88020_DEVICE_ID && ctrl->bde_dev.rev == 0) { +#define FE2000_REVISION_OFFSET (0x0) + uint32_t fe_rev; + + fe_rev = *((uint32_t*)(ctrl->bde_dev.base_address + FE2000_REVISION_OFFSET)); + if ((fe_rev >> 16) == BCM88020_DEVICE_ID) { + fe_rev &= 0xff; + } else { + fe_rev = (fe_rev >> 24) & 0xff; + } + ctrl->bde_dev.rev = fe_rev; + } + + ctrl->isr = NULL; + ctrl->isr_data = NULL; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (!(cmd & PCI_COMMAND_MEMORY) || !(cmd & PCI_COMMAND_MASTER)) { + cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + pci_write_config_word(dev, PCI_COMMAND, cmd); + if (debug >= 1) gprintk("enable PCI resources 0x%x (PCI_COMMAND)\n", cmd); + } + + /* Check if we need 256 KB memory window (default is 64 KB) */ + bar_len = pci_resource_len(dev, baroff); + if ((bar_len == 0x40000) || (bar_len == 0x800000)) { + ctrl->dev_type |= BDE_256K_REG_SPACE; + if (debug >= 1) gprintk("PCI resource len 256K\n"); + } + +#if defined (BCM_ROBO_SUPPORT) && !defined(ALTA_ROBO_SPI) + /* MDC/MDIO path for pseudo PHY access to ROBO register on BCM5836/4704 */ + if (dev->device == BCM47XX_ENET_ID) { + ((uint32 *)ctrl->bde_dev.base_address)[0x410 / 4] = 0; + } +#endif + +#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT + ctrl->dma_dev = &dev->dev; +#endif + + if (debug >= 2) { + gprintk("_pci_probe: configured dev:0x%x rev:0x%x with base_addresses: 0x%lx 0x%lx\n", + (unsigned)ctrl->bde_dev.device, (unsigned)ctrl->bde_dev.rev, + (unsigned long)ctrl->bde_dev.base_address, (unsigned long)ctrl->bde_dev.base_address1); + } + /* Let's boogie */ + + return 0; +} + +/* + * Function: _pci_remove + * + * Purpose: + * Detach driver from device. Called from pci_unregister_driver(). + * Parameters: + * dev - Linux PCI device structure + * Returns: + * 0 + */ +static void +_pci_remove(struct pci_dev* dev) +{ + bde_ctrl_t *ctrl; + + if (nodevices == 1) { + return; + } + +#if defined(BCM_DFE_SUPPORT) + if (dev->device == PCI_DEVICE_ID_PLX_9056) { + return; + } +#endif + + ctrl = (bde_ctrl_t *) pci_get_drvdata(dev); + + if (ctrl == NULL) { + /* Unused device */ + return; + } + ctrl->dev_state = BDE_DEV_STATE_REMOVED; + if (debug >= 1) { + gprintk("PCI device %04x:%04x is removed. \n", + dev->vendor, dev->device); + } + if (ctrl->bde_dev.base_address1) { + iounmap((void *)ctrl->bde_dev.base_address1); + } + if (ctrl->bde_dev.base_address) { + iounmap((void *)ctrl->bde_dev.base_address); + } + + /* Free our interrupt handler, if we have one */ + if (ctrl->isr || ctrl->isr2) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84)) + if (ctrl->use_msi >= PCI_USE_INT_MSIX) { + int i; + for (i = 0; i < ctrl->msix_cnt; i++) + free_irq(ctrl->entries[i].vector, ctrl->pci_device); + } + else +#endif + { + free_irq(ctrl->iLine, ctrl); + } + } +#ifdef CONFIG_PCI_MSI + _msi_disconnect(ctrl); +#endif + ctrl->isr = NULL; + ctrl->isr_data = NULL; + ctrl->isr2 = NULL; + ctrl->isr2_data = NULL; +} + +static struct pci_driver _device_driver = { + probe: _pci_probe, + remove: _pci_remove, + id_table: _id_table, + /* The rest are dynamic */ +}; + +static void +_spi_device_setup(void) { + bde_ctrl_t *ctrl; + ctrl = _devices + _ndevices++; + _switch_ndevices++; + ctrl->dev_type |= BDE_SWITCH_DEV_TYPE; + ctrl->iLine = 0xa3; + ctrl->be_pio = 0; + ctrl->dev_type |= BDE_SPI_DEV_TYPE; + ctrl->bde_dev.device = spi_devid; + ctrl->bde_dev.rev = spi_revid; + if (debug >= 1) { + gprintk("SPI Slave Mode: force ctrl->bde_dev.device=0x%x\n",ctrl->bde_dev.device); + gprintk("SPI Slave Mode: force ctrl->bde_dev.rev=0x%x\n",ctrl->bde_dev.rev); + gprintk("SPI Slave Mode: force ctrl->dev_type=0x%x\n",ctrl->dev_type); + } +} +#endif /* BCM_ICS */ + + +#ifdef BCM_ROBO_SUPPORT + +#ifdef KEYSTONE +#define DEFAULT_FREQ (SPI_FREQ_DEFAULT) +#define FREQ_20MHZ (SPI_FREQ_20MHZ) +#else /* IPROC_CMICD */ +#define DEFAULT_FREQ (0) +#define FREQ_20MHZ (0) +#endif + + +/* +* The model_info /rev_info for Robo devices is defined like this: +* +* 31 28 27 24 23 20 19 16 15 8 7 0 +* +----+---------+------+-----+---------+--------+ +* | op | reserved| mask |len | page |offset | +* +----+---------+------+-----+---------+--------+ +* +* op: 1:OR phyidl, 2: use PCIE device ID +* mlen: mask len (in bytes) 1:means 0xf,2 means 0xff +* len: Size of model/rev ID register (in bytes) +* page: Page containing model ID and revision registers +* offset: Model/rev ID register offset +*/ +static struct bde_spi_device_id _spi_id_table[] = { + { BCM53242_PHYID_HIGH, BCM53242_PHYID_LOW , 0, 0, DEFAULT_FREQ}, + { BCM53262_PHYID_HIGH, BCM53262_PHYID_LOW , 0, 0, DEFAULT_FREQ}, + { BCM53115_PHYID_HIGH, BCM53115_PHYID_LOW , 0, 0, DEFAULT_FREQ}, + { BCM53118_PHYID_HIGH, BCM53118_PHYID_LOW , 0, 0, DEFAULT_FREQ}, + { BCM53280_PHYID_HIGH, BCM53280_PHYID_LOW , 0x101800e8, 0, FREQ_20MHZ}, + { BCM53101_PHYID_HIGH, BCM53101_PHYID_LOW , 0, 0x110240, FREQ_20MHZ}, + { BCM53125_PHYID_HIGH, BCM53125_PHYID_LOW , 0, 0x110240, FREQ_20MHZ}, + { BCM53128_PHYID_HIGH, BCM53128_PHYID_LOW , 0, 0x110240, FREQ_20MHZ}, + { BCM53600_PHYID_HIGH, BCM53600_PHYID_LOW , 0x101800e8, 0, FREQ_20MHZ}, + { BCM89500_PHYID_HIGH, BCM89500_PHYID_LOW ,0x240230, 0x110240, FREQ_20MHZ}, + { BCM53010_PHYID_HIGH, BCM53010_PHYID_LOW ,0x240230, 0x110240, 0}, + { BCM53018_PHYID_HIGH, BCM53018_PHYID_LOW ,0x240230, 0x110240, 0}, + { BCM5389_PHYID_HIGH, BCM5389_PHYID_LOW, 0x110230, 0x110240, DEFAULT_FREQ}, + { BCM53020_PHYID_HIGH, BCM53020_PHYID_LOW ,0x20240230, 0x110240, 0}, + { BCM5396_PHYID_HIGH , BCM5396_PHYID_LOW, 0x110230, 0x110240, DEFAULT_FREQ}, + { BCM53134_PHYID_HIGH, BCM53134_PHYID_LOW , 0, 0x110240, DEFAULT_FREQ}, + { 0, 0, 0, 0, 0 }, +}; +#endif + +#ifdef BCM_ROBO_SUPPORT + +static int +_spi_device_valid_check(unsigned short phyidh,unsigned short phyidl, uint8 check_flag) +{ + struct bde_spi_device_id *_ids; + int idx, match_idx; + + match_idx = -1; + idx = 0; + + if (check_flag == 0){ + /* check_flag == 0 check phyidh only*/ + for (_ids = _spi_id_table; + _ids->phyid_high && _ids->phyid_low; _ids++){ + if (_ids->phyid_high == phyidh) { + return 0; + } + } + /* No valid SPI devices found */ + return 1; + } else { + while(_spi_id_table[idx].phyid_high){ + if (phyidh == _spi_id_table[idx].phyid_high && + phyidl == _spi_id_table[idx].phyid_low) { + /* Found a match */ + match_idx = idx; + break; + } + idx++; + } + return match_idx; + } +} + +#if defined(IPROC_CMICD) || defined(KEYSTONE) +#define ROBO_ATTACH_AVAIL +#endif + +#ifdef ROBO_ATTACH_AVAIL + +#define SOC_ATTACH(_sc)\ + ai_soc_kattach(_sc) + +#if defined(IPROC_CMICD) +#ifdef BCM_STARFIGHTER3_SUPPORT +#define ROBO_ATTACH_SPI(_sih, _ss)\ + robo_attach_spi(_sih) +#define ROBO_DETACH_SPI(robo)\ + robo_detach_spi(robo) +#define ROBO_SPI_RREG(_robo, _dev, _page, _reg, _buf, _len) \ + robo_spi_rreg(_robo, _dev, _page, _reg, _buf, _len) +#define ROBO_SPI_WREG(_robo, _dev, _page, _reg, _buf, _len) \ + robo_spi_wreg(_robo, _dev, _page, _reg, _buf, _len) +#endif +#define ROBO_ATTACH(_sih, _ss)\ + robo_attach(_sih) +#define MAX_BUSTYPE 1 +#define ROBO_SWITCH_BUS(_robo, _bustype) +#define ROBO_SELECT_DEVICE(_robo, _phyidh, _phyidl) +#else /* KEYSTONE */ +#define ROBO_ATTACH(_sih, _ss)\ + robo_attach(_sih, _ss) +/* bustype 2: ROBO_MDCMDIO_BUS, 1: ROBO_SPI_BUS */ +#define MAX_BUSTYPE 2 +#define ROBO_SWITCH_BUS(_robo, _bustype)\ + robo_switch_bus(_robo, _bustype) + +#define ROBO_SELECT_DEVICE(_robo, _phyidh, _phyidl) \ + robo_select_device(_robo, _phyidh, _phyidl) +#endif + +#else + +#define SOC_ATTACH(_sc) (NULL) +#define ROBO_ATTACH(_sih, _ss) (NULL) +#define MAX_BUSTYPE (0) +#define ROBO_SWITCH_BUS(_robo, _bustype) +#define ROBO_SELECT_DEVICE(_robo, _phyidh, _phyidl) +#endif + + +#if defined(IPROC_CMICD) && defined(BCM_STARFIGHTER3_SUPPORT) +static int +probe_robo_switch_iproc_spi(void) +{ + int dev; + int max_devices, max_bustype; + uint8 buf[8]; + unsigned short phyidh = 0, phyidl = 0; + + + /* Get Robo device handle */ + if (robo == NULL) { + robo = (void *)ROBO_ATTACH_SPI(sbh, 0); + } + if (robo == NULL) { + return -ENODEV; + } + + max_bustype = MAX_BUSTYPE + 1; + + while(_spi_device_valid_check(phyidh, 0, 0)) { + max_bustype --; + if(!max_bustype) + return -ENODEV; + buf[0] = buf[1] = 0; + ROBO_SPI_RREG(robo, 0, 0x10, 0x04, buf, (uint)2); + phyidh = buf[0] | (buf[1] << 8); + /* re-try */ + if ((phyidh == 0x0) || (phyidh == 0xffff)) { + ROBO_SPI_RREG(robo, 0, 0x10, 0x04, buf, (uint)2); + phyidh = buf[0] | (buf[1] << 8); + } + } + + /* For psedo_phy access, only support one robo switch*/ + /* For Northstar, only one switch on SRAB interface */ + max_devices = (max_bustype == MAX_BUSTYPE) ? 1 : LINUX_BDE_MAX_SWITCH_DEVICES; + + for (dev = 0; dev < max_devices; dev++) { + bde_ctrl_t *ctrl; + int match_idx, i; + unsigned short phyidl_nr; /* phyidl with revision stripped */ + uint16 model_id; + uint8 rev_id; + uint32 addr, len; + uint32 mlen; + + if (_switch_ndevices >= LINUX_BDE_MAX_SWITCH_DEVICES) { + break; + } + buf[0] = buf[1] = 0; + ROBO_SPI_RREG(robo, dev, 0x10, 0x04, buf, (uint)2); + phyidh = buf[0] | (buf[1] << 8); + + buf[0] = buf[1] = 0; + ROBO_SPI_RREG(robo, dev, 0x10, 0x06, buf, (uint)2); + phyidl = buf[0] | (buf[1] << 8); + + /* Strip revision */ + phyidl_nr = phyidl & 0xfff0; + + match_idx = _spi_device_valid_check(phyidh, phyidl_nr, 1); + if (match_idx == -1) { + if (debug >= 1) gprintk("found %d robo device(s).\n", robo_switch); + break; + } + + model_id = phyidl_nr; + + if(_spi_id_table[match_idx].rev_info){ + addr = _spi_id_table[match_idx].rev_info & 0xffff; + len = (_spi_id_table[match_idx].rev_info >> 16) & 0xf; + ROBO_SPI_RREG(robo, dev, (addr >> 8), (addr & 0xff), buf, (uint)len); + mlen = (_spi_id_table[match_idx].rev_info >> 20) & 0xf; + rev_id = 0; + for (i = 0; i < mlen; i++) + rev_id |= buf[i] << (i << 3); + } else { + rev_id = phyidl & 0xf; + } + + gprintk("found robo device with %d:%04x:%04x:%04x:%02x\n", + dev, phyidh, phyidl, model_id, rev_id); + + ROBO_SELECT_DEVICE(robo, phyidh, phyidl); + + /* Match supported chips */ + ctrl = _devices + _ndevices++; + _switch_ndevices++; + + if (NULL == (ctrl->spi_device = (struct spi_dev *) + KMALLOC(sizeof(struct spi_dev), GFP_KERNEL))) { + gprintk("no memory available"); + return -ENOMEM; + } + ctrl->dev_type = (BDE_SPI_DEV_TYPE | BDE_SWITCH_DEV_TYPE); + ctrl->spi_device->cid = dev; + ctrl->spi_device->part = model_id; + ctrl->spi_device->rev = rev_id; + ctrl->spi_device->robo = robo; + ctrl->spi_device->phyid_high = phyidh; + ctrl->spi_device->phyid_low = phyidl; + ctrl->bde_dev.device = model_id; + ctrl->bde_dev.rev = rev_id; + ctrl->bde_dev.base_address = (sal_vaddr_t)NULL; + ctrl->isr = NULL; + ctrl->isr_data = NULL; + robo_switch++; + + } + + return robo_switch; + +} + +int spi_device_found = 0; + +#endif /* IPROC_CMICD || SF3 */ + + +static int +probe_robo_switch(void) +{ + int dev; + int max_devices, max_bustype; + uint8 buf[8]; + unsigned short phyidh = 0, phyidl = 0; +#if defined(KEYSTONE) + uint32 spi_freq = 0; +#endif +#if defined(IPROC_CMICD) + sal_vaddr_t addr_base; + uint32 data_reg; +#endif /* IPROC_CMICD */ + + + spin_lock_init(&bus_lock); + + if (_switch_ndevices) { + /* + * Currently skip probe robo if esw chips were found + * FIX this while combined plateform support. + */ + return robo_switch; + } + + /* Get Robo device handle */ + if (robo == NULL) { + sbh = (void *)SOC_ATTACH(NULL); + if (sbh == NULL) { + return -ENODEV; + } + } + +#if defined(IPROC_CMICD) && defined(BCM_STARFIGHTER3_SUPPORT) + robo_switch = probe_robo_switch_iproc_spi(); + + if (robo_switch > 0) { + /* Robo switch found by SPI probe */ + spi_device_found = 1; + gprintk("SPI device found, Skipping SRAB probe\n"); + return robo_switch; + } else { + gprintk("SPI device NOT found, Probe SRAB probe\n"); + ROBO_DETACH_SPI(robo); + } +#endif + + if (robo == NULL) { + robo = (void *)ROBO_ATTACH(sbh, 0); + } + if (robo == NULL) { + return -ENODEV; + } + + max_bustype = MAX_BUSTYPE + 1; + + while(_spi_device_valid_check(phyidh, 0, 0)) { + max_bustype --; + if(!max_bustype) + return -ENODEV; + ROBO_SWITCH_BUS(robo, max_bustype); + buf[0] = buf[1] = 0; + ROBO_RREG(robo, 0, 0x10, 0x04, buf, (uint)2); + phyidh = buf[0] | (buf[1] << 8); + /* re-try */ + if ((phyidh == 0x0) || (phyidh == 0xffff)) { + ROBO_RREG(robo, 0, 0x10, 0x04, buf, (uint)2); + phyidh = buf[0] | (buf[1] << 8); + } + } + + /* For psedo_phy access, only support one robo switch*/ + /* For Northstar, only one switch on SRAB interface */ + max_devices = (max_bustype == MAX_BUSTYPE) ? 1 : LINUX_BDE_MAX_SWITCH_DEVICES; + + for (dev = 0; dev < max_devices; dev++) { + bde_ctrl_t *ctrl; + int match_idx, i; + unsigned short phyidl_nr; /* phyidl with revision stripped */ + uint16 model_id; + uint8 rev_id; +#if defined(KEYSTONE) || defined(IPROC_CMICD) + uint32 addr, len; +#endif + uint32 mlen, op; + + if (_switch_ndevices >= LINUX_BDE_MAX_SWITCH_DEVICES) { + break; + } + buf[0] = buf[1] = 0; + ROBO_RREG(robo, dev, 0x10, 0x04, buf, (uint)2); + phyidh = buf[0] | (buf[1] << 8); + + buf[0] = buf[1] = 0; + ROBO_RREG(robo, dev, 0x10, 0x06, buf, (uint)2); + phyidl = buf[0] | (buf[1] << 8); + + /* Strip revision */ + phyidl_nr = phyidl & 0xfff0; + + match_idx = _spi_device_valid_check(phyidh, phyidl_nr, 1); + if (match_idx == -1) { + if (debug >= 1) gprintk("found %d robo device(s).\n", robo_switch); + break; + } + + if(_spi_id_table[match_idx].model_info){ +#if defined(KEYSTONE) || defined(IPROC_CMICD) + addr = _spi_id_table[match_idx].model_info & 0xffff; + len = (_spi_id_table[match_idx].model_info >> 16) & 0xf; +#endif + ROBO_RREG(robo, dev, (addr >> 8), (addr & 0xff), buf, (uint)len); + mlen = (_spi_id_table[match_idx].model_info >> 20) & 0xf; + model_id = 0; + for (i = 0; i < mlen; i++) + model_id |= buf[i] << (i << 3); + op = (_spi_id_table[match_idx].model_info >> 28) & 0xf; + if(op == 1) { + model_id |= phyidl_nr; +#if defined(IPROC_CMICD) + } else if (op == 2) { + /* The package id of NS+ is determined by : + * Write 0 to 0x18012120 (PAXB_0_CONFIG_IND_ADDR) + * Read 0x18012124 (PAX_B_CONFIG_IND_DATA), + * bits 31:16 will be the device id from OTP space + */ +#define PAXB_ENUM_BASE (0x18012000) +#define PAXB_CONFIG_IND_ADDR_OFFSET (0x120) +#define PAXB_CONFIG_IND_DATA_OFFSET (0x124) + + addr_base = (sal_vaddr_t)IOREMAP(PAXB_ENUM_BASE, 0x1000); + if (!addr_base) { + gprintk("ioremap of PAXB registers failed\n"); + } else { + writel(0x0, (uint32 *)(addr_base + + PAXB_CONFIG_IND_ADDR_OFFSET)); + data_reg = readl((uint32 *)(addr_base + + PAXB_CONFIG_IND_DATA_OFFSET)); + model_id = (data_reg >> 16); + iounmap((void *)addr_base); + + /* + * Some model ID can't be determined by PCIE device ID + * It needs to refer some OTP values. + */ + robo_model_id_adjust_from_otp(robo, &model_id); + } + +#undef PAXB_ENUM_BASE +#undef PAXB_CONFIG_IND_ADDR_OFFSET +#undef PAXB_CONFIG_IND_DATA_OFFSET +#endif /* IPROC_CMICD */ + } + } else { + model_id = phyidl_nr; + } + if(_spi_id_table[match_idx].rev_info){ +#if defined(KEYSTONE) || defined(IPROC_CMICD) + addr = _spi_id_table[match_idx].rev_info & 0xffff; + len = (_spi_id_table[match_idx].rev_info >> 16) & 0xf; +#endif + ROBO_RREG(robo, dev, (addr >> 8), (addr & 0xff), buf, (uint)len); + mlen = (_spi_id_table[match_idx].rev_info >> 20) & 0xf; + rev_id = 0; + for (i = 0; i < mlen; i++) + rev_id |= buf[i] << (i << 3); + } else { + rev_id = phyidl & 0xf; + } + gprintk("found robo device with %d:%04x:%04x:%04x:%02x\n", + dev, phyidh, phyidl, model_id, rev_id); + + ROBO_SELECT_DEVICE(robo, phyidh, phyidl); + + /* Match supported chips */ + ctrl = _devices + _ndevices++; + _switch_ndevices++; + + if (NULL == (ctrl->spi_device = (struct spi_dev *) + KMALLOC(sizeof(struct spi_dev), GFP_KERNEL))) { + gprintk("no memory available"); + return -ENOMEM; + } + ctrl->dev_type = (BDE_SPI_DEV_TYPE | BDE_SWITCH_DEV_TYPE); + ctrl->spi_device->cid = dev; + ctrl->spi_device->part = model_id; + ctrl->spi_device->rev = rev_id; + ctrl->spi_device->robo = robo; + ctrl->spi_device->phyid_high = phyidh; + ctrl->spi_device->phyid_low = phyidl; + ctrl->bde_dev.device = model_id; + ctrl->bde_dev.rev = rev_id; + ctrl->bde_dev.base_address = (sal_vaddr_t)NULL; + ctrl->isr = NULL; + ctrl->isr_data = NULL; + robo_switch++; + +#if defined(KEYSTONE) + spi_freq = _spi_id_table[match_idx].spifreq; +#endif + } + +#if defined(KEYSTONE) + /* Override the SPI frequency from user configuration */ + if (spifreq != 0) { + spi_freq = spifreq; + } + if (spi_freq != 0) { + /* + * The underlying chip can support the SPI frequency + * higher than default (2MHz). + */ + if (spi_freq != SPI_FREQ_DEFAULT) { + chipc_spi_set_freq(robo, 0, spi_freq); + } + } +#endif + return robo_switch; + +} + +#endif + +#if defined(BCM_METROCORE_LOCAL_BUS) +static bde_ctrl_t* +map_local_bus(uint64_t addr, uint32_t size) +{ + bde_ctrl_t *ctrl; + + ctrl = _devices + _ndevices++; + _switch_ndevices++; + + /* + * For now: use EB type as `local bus' + * (memory mapped, no DMA, no interrupts) + * metrocore local bus supports interrupts, but we don't use them. + */ + ctrl->dev_type |= BDE_EB_DEV_TYPE | BDE_SWITCH_DEV_TYPE + | (size > 64 * 1024 ? BDE_128K_REG_SPACE : 0); + ctrl->pci_device = NULL; /* No PCI bus */ + + /* Map in the device */ + ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(addr, size); + ctrl->phys_address = addr; + + return(ctrl); +} + +#define BME_REVISION_OFFSET (0x0) + +#endif + + +#ifdef BCM_METROCORE_LOCAL_BUS + /* + * SBX platform has both PCI- and local bus-attached devices + * The local bus devices have fixed address ranges (and don't + * support or require DMA), but are otherwise the same as PCI devices + */ +#define FPGA_IRQ 37 +#define FPGA_PHYS 0x100E0000 +#define BME_PHYS 0x100C0000 +#define SE_PHYS 0x100D0000 +#define FPGA_SIZE 0x00004000 +#define BME_SIZE 0x00004000 +#define MAC0_PHYS 0x100B0000 +#define MAC1_PHYS 0x100B8000 +#define MAC_SIZE 0x800 + + +/* + * Please refer to "Supervisor Fabric Module (SFM) Specification" + * page 23 for the following registers. + */ +#define FPGA_LC_POWER_DISABLE_OFFSET 0x4 +#define FPGA_LC_POWER_DISABLE_ENABLE_ALL_MASK 0x1e + +#define FPGA_LC_POWER_RESET_OFFSET 0x5 +#define FPGA_LC_POWER_RESET_ENABLE_ALL_MASK 0x1e + +#define FPGA_SW_SFM_MASTER_MODE_OFFSET 0x14 +#define FPGA_SW_SFM_MASTER_MODE_ENABLE_MASK 0x10 + + +static int +probe_metrocore_local_bus(void) { + bde_ctrl_t *ctrl; + uint32_t dev_rev_id; + VOL uint8_t *fpga; + + /* + * Write the FPGA on the fabric card, to let metrocore + * line cards out of reset. We actually don't bother to determine whether + * the card is a line card or a fabric card because when we do + * this on the line cards, it has no effect. + */ + fpga = (uint8_t *) IOREMAP(FPGA_PHYS, FPGA_SIZE); + fpga[FPGA_SW_SFM_MASTER_MODE_OFFSET] + |= FPGA_SW_SFM_MASTER_MODE_ENABLE_MASK; + fpga[FPGA_LC_POWER_DISABLE_OFFSET] + |= FPGA_LC_POWER_DISABLE_ENABLE_ALL_MASK; + fpga[FPGA_LC_POWER_RESET_OFFSET] + |= FPGA_LC_POWER_RESET_ENABLE_ALL_MASK; + + ctrl = map_local_bus(BME_PHYS, BME_SIZE); + + dev_rev_id = + *((uint32_t *) + (((uint8_t *) ctrl->bde_dev.base_address) + BME_REVISION_OFFSET)); + ctrl->bde_dev.device = dev_rev_id >> 16; + ctrl->bde_dev.rev = (dev_rev_id & 0xFF); + + if ((ctrl->bde_dev.device != BME3200_DEVICE_ID) && + (ctrl->bde_dev.device != BCM88130_DEVICE_ID)) { + gprintk("probe_metrocore_local_bus: wrong BME type: " + "0x%x (vs 0x%x or 0x%x)\n", + ctrl->bde_dev.device, BME3200_DEVICE_ID, BCM88130_DEVICE_ID); + return -1; + } + + ctrl->iLine = FPGA_IRQ; + ctrl->isr = NULL; + ctrl->isr_data = NULL; + + /* + * + * We start from SE & include the FPGA, which is 128k + */ + ctrl = map_local_bus(SE_PHYS, 128 * 1024); + + dev_rev_id = + *((uint32_t *) + (((uint8_t *) ctrl->bde_dev.base_address) + BME_REVISION_OFFSET)); + ctrl->bde_dev.device = dev_rev_id >> 16; + ctrl->bde_dev.rev = (dev_rev_id & 0xFF); + + if ((ctrl->bde_dev.device != BME3200_DEVICE_ID) && + (ctrl->bde_dev.device != BCM88130_DEVICE_ID)) { + gprintk("probe_metrocore_local_bus: wrong SE (BME) type: " + "0x%x (vs 0x%x)\n", + ctrl->bde_dev.device, BME3200_DEVICE_ID); + return -1; + } + + ctrl->iLine = FPGA_IRQ; + ctrl->isr = NULL; + ctrl->isr_data = NULL; + + return 0; +} +#endif + +#ifdef BCM_PLX9656_LOCAL_BUS + +#if 1 +#define DEV_REG_BASE_OFFSET PL0_OFFSET /* Polaris register base */ +#define DEV_REG_DEVID 0 /* Device ID is first register */ +#endif + +/* + * The difference at map_local_bus2: + * + * The PLX9656 PCI-to-LOCAL bridge chip already has been iomapped the + * whole address space. So the devices off local bus don't need to be + * mapped again. They only need to claim their own sub-space. + */ +static bde_ctrl_t * +map_local_bus2(bde_ctrl_t *plx_ctrl, uint32_t dev_base, uint32_t size) +{ + uint32_t dev_rev_id; + uint8_t *addr; + bde_ctrl_t *ctrl; + + ctrl = _devices + _ndevices++; + _switch_ndevices++; + + /* + * For now: use EB type as `local bus' + * (memory mapped, no DMA, no interrupts) + * metrocore local bus supports interrupts, but we don't use them. + */ + ctrl->dev_type |= BDE_EB_DEV_TYPE | BDE_SWITCH_DEV_TYPE; + ctrl->dev_type |= BDE_320K_REG_SPACE; /* Polaris 18 bits address + FPGA */ + ctrl->pci_device = NULL; /* No PCI bus */ + + /* Map in the device */ + ctrl->bde_dev.base_address = plx_ctrl->bde_dev.base_address + dev_base; + ctrl->phys_address = plx_ctrl->phys_address + (resource_size_t)dev_base; + +#if 1 + addr = (uint8_t *)ctrl->bde_dev.base_address + PL0_REVISION_REG; +#endif + dev_rev_id = readl(addr); + ctrl->bde_dev.device = dev_rev_id >> 16; + ctrl->bde_dev.rev = (dev_rev_id & 0xFF); + + switch (ctrl->bde_dev.device) { + case BCM88130_DEVICE_ID: + case BME3200_DEVICE_ID: + break; + default: + gprintk("wrong BME type: 0x%x (vs 0x%x or 0x%x)\n", + ctrl->bde_dev.device, BME3200_DEVICE_ID, BCM88130_DEVICE_ID); + return 0; + } + return(ctrl); +} + +static int +probe_plx_local_bus(void) +{ + bde_ctrl_t *ctrl; + uint32_t val; + uint8_t *addr; + char addr_hi_str[16]; + + if (num_plx > 1) { + printk(KERN_ERR "There's more than one PLX 9656/9056 chip\n"); + return -1; + } + addr_hi_str[0] = 0; +#ifdef PHYS_ADDR_IS_64BIT + sprintf(addr_hi_str, "%08x", (uint32_t)(plx_ctrl.phys_address >> 32)); +#endif + printk(KERN_ERR "Found PLX %04x:%04x vir: 0x%08x phy: 0x%s%08x\n", + plx_ctrl.bde_dev.device, plx_ctrl.bde_dev.rev, + plx_ctrl.bde_dev.base_address, addr_hi_str, + (uint32_t)(plx_ctrl.phys_address)); + + addr = (uint8_t *)plx_ctrl.bde_dev.base_address + CPLD_OFFSET + CPLD_REVISION_REG; + val = readl(addr); + printk(KERN_ERR "plx: CPLD revision %d\n", val & CPLD_REVISION_MASK); +#if 000 + addr = (uint8_t *)plx_ctrl.bde_dev.base_address + CPLD_OFFSET + CPLD_RESET_REG; + writel(CPLD_RESET_NONE, addr); +#endif +#if 1 + ctrl = map_local_bus2(&plx_ctrl, PL0_OFFSET, PL0_SIZE); +#endif + if (ctrl == 0) + return -1; + + /* Uses PLX IRQ for Polaris LC */ + ctrl->iLine = 48; + ctrl->isr = NULL; + ctrl->isr_data = NULL; + + return 0; +} + +#endif /* BCM_PLX9656_LOCAL_BUS */ + +#if defined(BCM_EA_SUPPORT) +#if defined(BCM_TK371X_SUPPORT) +static void +probe_tk371x_dev(void) +{ + bde_ctrl_t *ctrl; + int ea_uid=0; + + /* eadevices is from the argument of insmod */ + for (ea_uid = 0; ea_uid < eadevices; ea_uid++) { + ctrl = _devices + _ndevices++; + _switch_ndevices++; + ctrl->dev_type = (BDE_MII_DEV_TYPE | BDE_SWITCH_DEV_TYPE); + ctrl->bde_dev.device = TK371X_DEVICE_ID; + ctrl->bde_dev.rev = 0x0; + ctrl->bde_dev.base_address = (sal_vaddr_t)NULL; + ctrl->iLine = 0; + } +} +#endif /* BCM_TK371X_SUPPORT*/ +#endif /* BCM_EA_SUPPORT */ + + +#if defined(BCM_ROBO_SUPPORT) +#if defined(IPROC_CMICD) +struct chip_device_info { + uint32 cc_base; /* Chip-common register base */ + uint32 cc_size; /* Chip-common register limit */ + uint32 cid_reg_off; /* Chip id register offset */ +}; + +static struct chip_device_info _chip_table = { +#if defined(IPROC_CMICD) + 0x18000000, 0x00000300, 0x00000000 +#else + 0,0,0 +#endif +}; + +struct gmac_device_info { + uint32 cid; /* chip id */ + uint32 rid; /* revision id */ + uint32 pid; /* package id */ + + uint32 gmac_dev_id; /* gmac core device id */ + uint32 gmac_base_addr; /* gmac core base address */ + int gmac_irq; /* gmac irq number */ +}; + +static struct gmac_device_info _gmac_table[] = { +#if defined(IPROC_CMICD) + {BCM53010_CHIP_ID, 0, 0, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53012 */ + {BCM53010_CHIP_ID, 0, 2, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53011 */ + {BCM53010_CHIP_ID, 0, 1, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53010 */ + {BCM53018_CHIP_ID, 0, 0, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53018 */ + {BCM53018_CHIP_ID, 0, 2, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53017 */ + {BCM53018_CHIP_ID, 0, 1, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53019 */ + {BCM53020_CHIP_ID, 0, 0, BCM53010_GMAC_ID, 0x18024000, 181}, /* BCM53022 */ + {BCM53020_CHIP_ID, 4, 0, BCM53010_GMAC_ID, 0x18023000, 180}, /* BCM53022 */ +#endif + {0,0,0,0,0,0} +}; + +static sal_vaddr_t _cca_base = 0; + +static int +_gmac_dev_create(void) +{ + bde_ctrl_t *ctrl; + uint32 gmac_base = 0; + uint32 offset = 0; + uint32 cca_cid; + uint32 cid, rid, pid; + int i = 0, found; + + if (_chip_table.cc_base == 0) { + gprintk("Create GMAC device failed. Unable to identify CPU.\n"); + return -1; + } + + /* 1. Determine which CPU/GMAC configuration is now */ + _cca_base = (sal_vaddr_t)IOREMAP(_chip_table.cc_base, _chip_table.cc_size); + cca_cid = readl((uint32 *)(_cca_base + _chip_table.cid_reg_off)); + + cid = cca_cid & CID_ID_MASK; + rid = (cca_cid & CID_REV_MASK) >> CID_REV_SHIFT; + pid = (cca_cid & CID_PKG_MASK) >> CID_PKG_SHIFT; + + found = 0; + for (i = 0; ; i++) { + if (_gmac_table[i].cid == 0) { + /* End of table */ + break; + } + if ((_gmac_table[i].cid == cid) && + (_gmac_table[i].rid == rid) && + (_gmac_table[i].pid == pid)) { + /* found */ + found = 1; + break; + } + } + if (!found) { + gprintk("Create GMAC device failed. Unable to identify GMAC device.\n"); + } + + /* 2. Create GMAC device */ + /* fill-in necessary information depends on the CPU/GMAC configuration */ + if ((cid == BCM53010_CHIP_ID) || (cid == BCM53018_CHIP_ID) || + (cid == BCM53020_CHIP_ID)) { + ctrl = _devices + _ndevices++; + _ether_ndevices++; + + ctrl->dev_type |= BDE_ETHER_DEV_TYPE; + ctrl->dev_type |= BDE_PCI_DEV_TYPE; + + ctrl->iLine = _gmac_table[i].gmac_irq; + + ctrl->be_pio = 0; + + ctrl->bde_dev.rev = _gmac_table[i].rid; + ctrl->bde_dev.device = _gmac_table[i].gmac_dev_id; + + gmac_base = 0x18000000; + offset = _gmac_table[i].gmac_base_addr - gmac_base; + ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(gmac_base, 0x300000); + ctrl->alt_base_addr = ctrl->bde_dev.base_address + offset; + ctrl->phys_address = gmac_base; + + ctrl->isr = NULL; + ctrl->isr_data = NULL; + } + + return 0; +} +#endif +#endif + +/* + * Generic module functions + */ + +/* + * Function: _init + * + * Purpose: + * Module initialization. + * Attaches to kernel BDE. + * Parameters: + * None + * Returns: + * 0 on success, < 0 on error. + */ +static int +_init(void) +{ + +#ifdef IPROC_CMICD + if (iproc_has_cmicd()) { + iproc_cmicd_get_memregion(&iproc_cmicd_resources[IPROC_CMICD_RES_MEM]); + iproc_platform_driver_register(&iproc_cmicd_driver); +#ifdef CONFIG_OF + if (!of_find_compatible_node(NULL, NULL, IPROC_CMICD_COMPATIBLE)) +#endif + { + /* Register platform device if no device node in dtb */ + iproc_platform_device_register(&iproc_cmicd_pdev); + } + } +#endif /* IPROC_CMICD */ + +#ifdef BCM_ICS + _ics_bde_create(); +#else /* PCI */ + /* Register our goodies */ + _device_driver.name = LINUX_KERNEL_BDE_NAME; + +#if defined(BCM_ROBO_SUPPORT) +#if defined(IPROC_CMICD) + if (_gmac_dev_create()) { + return -ENODEV; + } +#endif +#endif /* defined (BCM_ROBO_SUPPORT) */ + + /* Configure MSI interrupt support */ + use_msi = usemsi; + +#ifdef CONFIG_PCI_MSI + if (use_msi == PCI_USE_INT_NONE) { + /* Compilation flag determines default value */ +#ifdef BDE_LINUX_USE_MSIX_INTERRUPT +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84)) + use_msi = PCI_USE_INT_MSIX; +#else + use_msi = PCI_USE_INT_MSI; +#endif +#elif defined(BDE_LINUX_USE_MSI_INTERRUPT) + use_msi = PCI_USE_INT_MSI; +#else + use_msi = PCI_USE_INT_INTX; +#endif + } +#else + if (use_msi > PCI_USE_INT_INTX) { + /* Warn if invalid configuration */ + gprintk("MSI interrupts not supported by kernel\n"); + } + use_msi = PCI_USE_INT_INTX; +#endif /* CONFIG_PCI_MSI */ + + if (unlikely(debug >= 1)) + gprintk("%s(%d):use_mse = %d\n", __func__, __LINE__, use_msi); + if (spi_devid) { + _spi_device_setup(); + } else { + if (pci_register_driver(&_device_driver) < 0) { + return -ENODEV; + } + } + + /* Note: PCI-PCI bridge uses results from pci_register_driver */ + p2p_bridge(); + +#ifdef BCM_METROCORE_LOCAL_BUS + if (probe_metrocore_local_bus()) { + return -1; + } +#endif +#ifdef BCM_PLX9656_LOCAL_BUS + if (num_plx > 0) { + probe_plx_local_bus(); + } +#endif +#endif /* BCM_ICS */ + +#ifdef BCM_ROBO_SUPPORT + probe_robo_switch(); +#endif + +#if defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT) + sand_device_create(); +#endif + +#if defined(BCM_TK371X_SUPPORT) + probe_tk371x_dev(); +#endif + /* + * Probe for EB Bus devices. + */ + if (eb_bus) { + char *tok; + uint irq = -1, eb_rd16bit=0, eb_wr16bit =0; + unsigned int eb_ba = 0x0; + + gprintk("EB bus info: %s\n", eb_bus); + tok = strtok(eb_bus,","); + while (tok) { + _parse_eb_args(tok, "BA=%x IRQ=%d RD16=%d WR16=%d", + &eb_ba, &irq, &eb_rd16bit, &eb_wr16bit); + _eb_device_create(eb_ba, irq, eb_rd16bit, eb_wr16bit); + tok = strtok(NULL,","); + } + } + + _dma_init(robo_switch); + + /* + * In order to be backward compatible with the user mode BDE + * (specifically the interrupt IOCTLs) and the CM, switch devices + * *must* come first. If this is not the case (due to the probing + * order), we let the non-switch device(s) drop down to the end of + * the device array. + */ + if (_switch_ndevices > 0) { + bde_ctrl_t tmp_dev; + int i, s = 0; + + while (s < _switch_ndevices) { + if (_devices[s].dev_type & BDE_SWITCH_DEV_TYPE) { + s++; + continue; + } + tmp_dev = _devices[s]; + for (i = s; i < _ndevices - 1; i++) { + _devices[i] = _devices[i+1]; + } + _devices[i] = tmp_dev; + } + } + + /* Initialize device locks */ + if (_ndevices > 0) { + int i; + + for (i = 0; i < _ndevices; i++) { + spin_lock_init(&_devices[i].lock); + } + } + + return 0; +} + +/* + * Function: _cleanup + * + * Purpose: + * Module cleanup function. + * Parameters: + * None + * Returns: + * Always 0 + */ +static int +_cleanup(void) +{ + int i; + + _dma_cleanup(); + +#ifdef IPROC_CMICD + if (iproc_has_cmicd()) { +#ifdef CONFIG_OF + if (!of_find_compatible_node(NULL, NULL, IPROC_CMICD_COMPATIBLE)) +#endif + { + iproc_platform_device_unregister(&iproc_cmicd_pdev); + } + iproc_platform_driver_unregister(&iproc_cmicd_driver); + } +#endif + +#if defined(BCM_ROBO_SUPPORT) +#if defined(IPROC_CMICD) + if (_cca_base) { + iounmap((void *)_cca_base); + } +#endif + + if (robo) { +#if defined(KEYSTONE) || defined(IPROC_CMICD) + robo_detach(robo); +#endif /* KEYSTONE || IPROC_CMICD */ + } + if (sbh) { +#if defined(KEYSTONE) || defined(IPROC_CMICD) + ai_soc_detach(sbh); +#endif /* KEYSTONE || IPROC_CMICD */ + } +#endif + for (i = 0; i < _ndevices; i++) { + bde_ctrl_t *ctrl = _devices + i; + + /* free allocated kernel space memory */ + if (ctrl->dev_type & BDE_SPI_DEV_TYPE) { + if (ctrl->spi_device) { + kfree(ctrl->spi_device); + } + } + } +#if (defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT)) && (defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__)) + if (cpu_address) { /* unmap CPU card MMIO */ + iounmap(cpu_address); + cpu_address = NULL; + } +#endif + +#ifdef BCM_ICS +#else + pci_unregister_driver(&_device_driver); +#endif /* BCM_ICS */ + return 0; +} + +/* + * Function: _pprint + * + * Purpose: + * Print proc filesystem information. + * Parameters: + * None + * Returns: + * Always 0 + */ +static int +_pprint(void) +{ + int i = 0; + + pprintf("Broadcom Device Enumerator (%s)\n", LINUX_KERNEL_BDE_NAME); + + _dma_pprint(); + + if (_ndevices == 0) { + pprintf("No devices found\n"); + } else { + pprintf("Devices:\n"); + } + for (i = 0; i < _ndevices; i++) { + bde_ctrl_t *ctrl = _devices + i; + + if (ctrl->dev_type & BDE_SWITCH_DEV_TYPE) { + pprintf("\t%d (swi) : ", i); + } else if (ctrl->dev_type & BDE_ETHER_DEV_TYPE) { + pprintf("\t%d (eth) : ", i); + } else if (ctrl->dev_type & BDE_CPU_DEV_TYPE) { + pprintf("\t%d (cpu) : ", i); + } else { + pprintf("\t%d (?) : ", i); + } + + if (ctrl->dev_state == BDE_DEV_STATE_REMOVED) { + pprintf("PCI device 0x%x:0x%x:%d REMOVED\n", + ctrl->pci_device->vendor, + ctrl->pci_device->device, + ctrl->bde_dev.rev); + continue; + } + if (ctrl->dev_type & BDE_PCI_DEV_TYPE) { + pprintf("PCI device 0x%x:0x%x:%d:0x%.8lx:0x%.8lx:%d%s\n", + ctrl->pci_device->vendor, + ctrl->pci_device->device, + ctrl->bde_dev.rev, + (unsigned long)pci_resource_start(ctrl->pci_device, 0), + (unsigned long)pci_resource_start(ctrl->pci_device, 2), + ctrl->pci_device->irq, + ctrl->use_msi ? " (MSI)" : ""); + } else if (ctrl->dev_type & BDE_SPI_DEV_TYPE) { + pprintf("SPI Device %d:%x:%x:0x%x:0x%x:%d\n", + ctrl->spi_device->cid, + ctrl->spi_device->part, + ctrl->spi_device->rev, + ctrl->spi_device->phyid_high, + ctrl->spi_device->phyid_low, + ctrl->bde_dev.rev); + } else if (ctrl->dev_type & BDE_ICS_DEV_TYPE) { + pprintf("ICS Device 0x%x:0x%x\n", + ctrl->bde_dev.device, + ctrl->bde_dev.rev); + } else if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + pprintf("AXI Device 0x%x:0x%x:0x%.8lx:%d\n", + ctrl->bde_dev.device, + ctrl->bde_dev.rev, + (unsigned long)ctrl->phys_address, + ctrl->iLine); + } else if (ctrl->dev_type & BDE_EB_DEV_TYPE) { + pprintf("EB Bus Device 0x%x:0x%x\n", + ctrl->bde_dev.device, + ctrl->bde_dev.rev); + } + if (debug >= 1) { + pprintf("\t\timask:imask2:fmask 0x%x:0x%x:0x%x\n", + ctrl->imask, + ctrl->imask2, + ctrl->fmask); + } + } + return 0; +} + +#if USE_LINUX_BDE_MMAP +/* + * Some kernels (mainly x86) prevent mapping of kernel RAM memory to + * user space via the /dev/mem device. The function below provides a + * backdoor to mapping the DMA pool to user space via the + * /dev/linux-kernel-bde device. + */ +static int _mmap(struct file *filp, struct vm_area_struct *vma) +{ + unsigned long phys_addr = vma->vm_pgoff << PAGE_SHIFT; + unsigned long size = vma->vm_end - vma->vm_start; + + if(!_dma_range_valid(phys_addr, size)) { + return -EINVAL; + } + +#ifdef REMAP_DMA_NONCACHED + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); +#endif + + if (remap_pfn_range(vma, + vma->vm_start, + vma->vm_pgoff, + size, + vma->vm_page_prot)) { + gprintk("Failed to mmap phys range 0x%lx-0x%lx to 0x%lx-0x%lx\n", + phys_addr, phys_addr + size, vma->vm_start,vma->vm_end); + return -EAGAIN; + } + + return 0; +} +#endif /* USE_LINUX_BDE_MMAP */ + +/* Workaround for broken Busybox/PPC insmod */ +static char _modname[] = LINUX_KERNEL_BDE_NAME; + +static gmodule_t _gmodule = { + name: LINUX_KERNEL_BDE_NAME, + major: LINUX_KERNEL_BDE_MAJOR, + init: _init, + cleanup: _cleanup, + pprint: _pprint, +#if USE_LINUX_BDE_MMAP + mmap: _mmap, +#endif +}; + +gmodule_t * +gmodule_get(void) +{ + _gmodule.name = _modname; + return &_gmodule; +} + + +/* + * BDE Interface + */ + +static const char * +_name(void) +{ + return LINUX_KERNEL_BDE_NAME; +} + +static int +_num_devices(int type) +{ + switch (type) { + case BDE_ALL_DEVICES: + return _ndevices; + case BDE_SWITCH_DEVICES: + return _switch_ndevices; + case BDE_ETHER_DEVICES: + return _ether_ndevices; + case BDE_CPU_DEVICES: + return _cpu_ndevices; + } + + return 0; +} + +static const ibde_dev_t * +_get_dev(int d) +{ + if (!VALID_DEVICE(d)) { + gprintk("_get_dev: Invalid device index %d\n", d); + return NULL; + } + + return &_devices[d].bde_dev; +} + +static uint32 +_get_dev_type(int d) +{ + if (!VALID_DEVICE(d)) { + gprintk("_get_dev: Invalid device index %d\n", d); + return 0; + } + + return _devices[d].dev_type; +} + +static uint32 +_pci_conf_read(int d, uint32 addr) +{ +#ifdef BCM_ICS + return 0xFFFFFFFF; +#else + uint32 rc = 0; + + if (!VALID_DEVICE(d)) { + gprintk("_pci_conf_read: Invalid device index %d\n", d); + return 0xFFFFFFFF; + } + + if (!(_devices[d].dev_type & BDE_PCI_DEV_TYPE)) { + gprintk("_pci_conf_read: Not PCI device %d, type %x\n", + d, _devices[d].dev_type); + return 0xFFFFFFFF; + } + + pci_read_config_dword(_devices[d].pci_device, addr, &rc); + return rc; +#endif /* BCM_ICS */ +} + +static int +_pci_conf_write(int d, uint32 addr, uint32 data) +{ +#ifdef BCM_ICS + return -1; +#else + if (!VALID_DEVICE(d)) { + gprintk("_pci_conf_write: Invalid device index %d\n", d); + return -1; + } + + if (!(_devices[d].dev_type & BDE_PCI_DEV_TYPE)) { + gprintk("_pci_conf_write: Not PCI device %d, type %x\n", + d, _devices[d].dev_type); + return -1; + } + + pci_write_config_dword(_devices[d].pci_device, addr, data); + return 0; +#endif /* BCM_ICS */ +} + +/* Initialized when the bde is created */ +static linux_bde_bus_t _bus; + +static void +_pci_bus_features(int unit, int *be_pio, int *be_packet, int *be_other) +{ + if ((_devices[unit].bde_dev.device & 0xFF00) != 0x5600 && + (_devices[unit].bde_dev.device & 0xF000) != 0xc000 && + (_devices[unit].bde_dev.device & 0xF000) != 0xb000 && + (_devices[unit].bde_dev.device & 0xF000) != 0x8000 && + (_devices[unit].bde_dev.device & 0xFFF0) != 0x0230 && + (_devices[unit].bde_dev.device & 0xFFF0) != 0xa440) { + if (be_pio) *be_pio = 0; + if (be_packet) *be_packet = 0; + if (be_other) *be_other = 0; + } else { + if (be_pio) *be_pio = _bus.be_pio; + if (be_packet) *be_packet = _bus.be_packet; + if (be_other) *be_other = _bus.be_other; + } +#if defined(BCM_METROCORE_LOCAL_BUS) + if (_devices[unit].dev_type & BDE_EB_DEV_TYPE && be_pio) { + *be_pio = 1; + } +#endif + +} + +static uint32_t +_read(int d, uint32_t addr) +{ + unsigned long flags; + volatile uint16 msb, lsb; + uint32 sl_addr, data; + + if (!VALID_DEVICE(d)) { + return -1; + } + + if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) { + return -1; + } + + if (_devices[d].dev_type & BDE_DEV_BUS_RD_16BIT) { + /* + * Adjust the address presented to Eb slave. Move A15:A0 to A16:A1. + */ + sl_addr = (addr & 0xffff0000) | ((addr & 0xffff) << 1); + /* Disable interrupts */ + spin_lock_irqsave(&bus_lock, flags); + + lsb = *((uint16 *)(_devices[d].bde_dev.base_address + sl_addr)); + msb = *((uint16 *)(_devices[d].bde_dev.base_address + sl_addr)); + spin_unlock_irqrestore(&bus_lock, flags); + + return (msb << 16) | lsb; + } else { + data = ((VOL uint32_t *)_devices[d].bde_dev.base_address)[addr / 4]; +#if defined(CMIC_SOFT_BYTE_SWAP) + data = CMIC_SWAP32(data); +#endif + return data; + } +} + +static int +_write(int d, uint32_t addr, uint32_t data) +{ + unsigned long flags; + uint32 sl_addr; + + if (!VALID_DEVICE(d)) { + return -1; + } + + if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) { + return -1; + } + + if (_devices[d].dev_type & BDE_DEV_BUS_WR_16BIT) { + /* + * Adjust the address presented to Eb slave. Move A15:A0 to A16:A1. + */ + sl_addr = (addr & 0xffff0000) | ((addr & 0xffff) << 1); + + /* Disable interrupts */ + spin_lock_irqsave(&bus_lock, flags); + + *((VOL uint16 *)(_devices[d].bde_dev.base_address + sl_addr)) = + data & 0xffff; + *((VOL uint16 *)(_devices[d].bde_dev.base_address + sl_addr)) = + (data >> 16) & 0xffff; + spin_unlock_irqrestore(&bus_lock, flags); + } else { +#if defined(CMIC_SOFT_BYTE_SWAP) + data = CMIC_SWAP32(data); +#endif + ((VOL uint32_t *)_devices[d].bde_dev.base_address)[addr / 4] = data; +#ifdef KEYSTONE + /* Enforce PCIe transaction ordering. Commit the write transaction */ + __asm__ __volatile__("sync"); +#endif + } + return 0; + +} + +static _ISR_RET +_isr(_ISR_PARAMS(irq, dev_id, iregs)) +{ + bde_ctrl_t *ctrl = (bde_ctrl_t *) dev_id; + + if (ctrl && ctrl->isr) { + ctrl->isr(ctrl->isr_data); + } + if (ctrl && ctrl->isr2) { + ctrl->isr2(ctrl->isr2_data); + } + return IRQ_HANDLED; +} + +static int +_interrupt_connect(int d, + void (*isr)(void *), + void *isr_data) +{ + bde_ctrl_t *ctrl; + unsigned long irq_flags; + int isr2_dev; + int isr_active; + int ret = 0; + + isr2_dev = d & LKBDE_ISR2_DEV; + d &= ~LKBDE_ISR2_DEV; + + if (!VALID_DEVICE(d)) { + gprintk("_interrupt_connect: Invalid device index %d\n", d); + return -1; + } + if (debug >= 1) { + gprintk("_interrupt_connect d %d\n", d); + } + if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) { + gprintk("_interrupt_connect: Not PCI device %d, type %x\n", + d, _devices[d].dev_type); + return -1; + } + + ctrl = _devices + d; + + isr_active = (ctrl->isr || ctrl->isr2) ? 1 : 0; + + if (unlikely(debug > 1)) + gprintk("%s:isr_active = %d\n", __func__, isr_active); + + if (isr2_dev) { + if (debug >= 1) { + gprintk("connect secondary isr\n"); + } + ctrl->isr2_data = isr_data; + ctrl->isr2 = isr; + if (isr_active) { + /* Main handler (_isr) already installed */ + return 0; + } + } else { + if (debug >= 1) { + gprintk("connect primary isr\n"); + } + ctrl->isr = isr; + ctrl->isr_data = isr_data; + if (isr_active) { + /* Main handler (_isr) already installed */ + return 0; + } + } + + if (ctrl->iLine != -1) { + irq_flags = IRQF_SHARED; +#ifdef CONFIG_PCI_MSI + if (ctrl->use_msi >= PCI_USE_INT_MSI) { + ret = _msi_connect(ctrl); + if(ret != 0) + goto msi_exit; + } +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84)) + if (ctrl->use_msi == PCI_USE_INT_MSIX) { + int i; + for (i = 0; i < ctrl->msix_cnt; i++) { + ret = request_irq(ctrl->entries[i].vector, _isr, + irq_flags, LINUX_KERNEL_BDE_NAME, ctrl); + if (ret < 0) + break; + } + if (ret < 0) { + while (i >= 0) + free_irq(ctrl->entries[i--].vector, ctrl->pci_device); + + goto err_disable_msi; + } + } + else +#endif + { + ret = request_irq(ctrl->iLine, _isr, irq_flags, + LINUX_KERNEL_BDE_NAME, ctrl); + if (ret < 0) + goto err_disable_msi; + + if (unlikely(debug >= 1)) + gprintk("%s(%d):device# = %d, \ + irq_flags = %lu, irq = %d\n", + __func__, __LINE__, d, + irq_flags, ctrl->pci_device ? ctrl->pci_device->irq : ctrl->iLine); + } + } + return 0; + +err_disable_msi: +#ifdef CONFIG_PCI_MSI + _msi_disconnect(ctrl); + +msi_exit: +#endif + gprintk("could not request IRQ\n"); + ctrl->isr = NULL; + ctrl->isr_data = NULL; + ctrl->isr2 = NULL; + ctrl->isr2_data = NULL; + + return -1; +} + +static int +_interrupt_disconnect(int d) +{ + bde_ctrl_t *ctrl; + int isr2_dev; + int isr_active; + + isr2_dev = d & LKBDE_ISR2_DEV; + d &= ~LKBDE_ISR2_DEV; + + if (!VALID_DEVICE(d)) { + return -1; + } + + if (debug >= 1) { + gprintk("_interrupt_disconnect d %d\n", d); + } + if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) { + gprintk("_interrupt_disconnect: Not PCI device %d, type %x\n", + d, _devices[d].dev_type); + return -1; + } + + ctrl = _devices + d; + + isr_active = (ctrl->isr || ctrl->isr2) ? 1 : 0; + + if (unlikely(debug > 1)) + gprintk("%s: isr_active = %d\n", __func__, isr_active); + + if (isr2_dev) { + if (debug >= 1) { + gprintk("disconnect secondary isr\n"); + } + ctrl->isr2 = NULL; + ctrl->isr2_data = NULL; + ctrl->fmask = 0; + if (ctrl->isr) { + /* Primary handler still active */ + SYNC_IRQ(ctrl->iLine); + return 0; + } + } else { + if (debug >= 1) { + gprintk("disconnect primary isr\n"); + } + ctrl->isr = NULL; + ctrl->isr_data = NULL; + if (ctrl->isr2) { + /* Secondary handler still active */ + SYNC_IRQ(ctrl->iLine); + return 0; + } + } + + if (isr_active) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84)) + if (ctrl->use_msi >= PCI_USE_INT_MSIX) { + int i; + for (i = 0; i < ctrl->msix_cnt; i++) + free_irq(ctrl->entries[i].vector, ctrl->pci_device); + } + else +#endif + { + free_irq(ctrl->iLine, ctrl); + } +#ifdef CONFIG_PCI_MSI + if (ctrl->use_msi >= PCI_USE_INT_MSI) { + _msi_disconnect(ctrl); + } +#endif + } + + return 0; +} + +static uint32_t +_iproc_ihost_read(int d, uint32_t addr) +{ + uint32_t *mapaddr; + uint32_t reg_val; + mapaddr = IOREMAP(addr, sizeof(uint32_t)); + if (mapaddr == NULL) { + return -1; + } + reg_val = readl(mapaddr); + iounmap(mapaddr); + return reg_val; +} + +static int +_iproc_ihost_write(int d, uint32_t addr, uint32_t data) +{ + uint32_t *mapaddr; + mapaddr = IOREMAP(addr, sizeof(uint32_t)); + if (mapaddr == NULL) { + return -1; + } + writel(data, mapaddr); + iounmap(mapaddr); + return 0; +} + +static uint32_t +_iproc_read(int d, uint32_t addr) +{ + if (!VALID_DEVICE(d)) { + return -1; + } + + if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) { + return -1; + } + + if (_devices[d].dev_type & BDE_AXI_DEV_TYPE) { + return _iproc_ihost_read(d, addr); + } + + return shbde_iproc_pci_read(&_devices[d].shbde, + (void *)_devices[d].bde_dev.base_address1, + addr); +} + +static int +_iproc_write(int d, uint32_t addr, uint32_t data) +{ + if (!VALID_DEVICE(d)) { + return -1; + } + + if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) { + return -1; + } + + if (_devices[d].dev_type & BDE_AXI_DEV_TYPE) { + return _iproc_ihost_write(d, addr, data); + } + + shbde_iproc_pci_write(&_devices[d].shbde, + (void *)_devices[d].bde_dev.base_address1, + addr, data); + + return 0; +} + +static int +_get_cmic_ver(int d , uint32_t *ver) +{ + + unsigned int cap_base; + uint32_t rval = 0; + + if (!VALID_DEVICE(d)) { + gprintk("%s: Invalid device index %d\n", __func__, d); + return -1; + } + + if (!(_devices[d].dev_type & BDE_PCI_DEV_TYPE)) { + gprintk("%s: Not PCI device %d, type %x\n", __func__, + d, _devices[d].dev_type); + return -1; + } + + /* Look for PCIe vendor-specific extended capability (VSEC) */ + cap_base = PCI_EXT_CAP_START; + while (cap_base) { + pci_read_config_dword(_devices[d].pci_device, cap_base, &rval); + if (rval == 0xffffffff) { + /* Assume PCI HW read error */ + gprintk("%s: PCI HW read error\n", __func__); + return -1; + } + + if (PCI_EXT_CAP_ID(rval) == PCI_EXT_CAP_ID_VNDR) { + break; + } + cap_base = PCI_EXT_CAP_NEXT(rval); + } + if (cap_base) { + /* + * VSEC layout: + * + * 0x00: PCI Express Extended Capability Header + * 0x04: Vendor-Specific Header + * 0x08: Vendor-Specific Register 1 + * 0x0c: Vendor-Specific Register 2 + * ... + * 0x24: Vendor-Specific Register 8 + */ + pci_read_config_dword(_devices[d].pci_device, cap_base + 8, &rval); + if (unlikely(debug > 1)) + gprintk("%s:Found VSEC = %u\n", __func__, rval); + + /* Determine if CMICX */ + rval = ((rval >> 12) & 0xf); + *ver = rval; + + return 0; + } else { + gprintk("%s:VSEC not found\n", __func__); + } + + return -1; +} + +#ifdef BCM_ROBO_SUPPORT +#define SOC_ROBO_PAGE_BP 8 /* for Robo Chip only */ + +#if defined(IPROC_CMICD) +extern int ccb_mii_read(int dev_type, int phy_addr, int reg_off, uint16 *data); +extern int ccb_mii_write(int dev_type, int phy_addr, int reg_off, uint16 data); + +/* device type */ +#define MII_DEV_LOCAL 0 +#define MII_DEV_EXT 1 +#endif + +static int +_spi_read(int d, uint32 addr, uint8 *buf, int len) +{ +#if defined(KEYSTONE) || defined(IPROC_CMICD) + bde_ctrl_t *ctrl; + uint8 page, offset; +#endif +#if defined(IPROC_CMICD) + int rv = 0; + uint16 value = 0; +#endif + + if (!VALID_DEVICE(d)) { + return -1; + } + + if (!(_devices[d].dev_type & BDE_SPI_DEV_TYPE)) { + gprintk("_spi_read: Not SPI device %d, type %x\n", + d, _devices[d].dev_type); + return -1; + } + +#if defined(KEYSTONE) || defined(IPROC_CMICD) + ctrl = _devices + d; +#endif + +#if defined(IPROC_CMICD) + if (addr & SOC_EXTERNAL_PHY_BUS_CPUMDIO) { + rv = ccb_mii_read(MII_DEV_EXT, (addr >> 8) & 0xff, addr & 0xff, &value); + memcpy(buf, &value, 2); + return rv; + } +#endif + +#if defined(KEYSTONE) || defined(IPROC_CMICD) + page = (addr >> SOC_ROBO_PAGE_BP) & 0xFF; + offset = addr & 0xFF; +#endif + +#if defined(IPROC_CMICD) && defined(BCM_STARFIGHTER3_SUPPORT) + if (spi_device_found) { + ROBO_SPI_RREG(ctrl->spi_device->robo, ctrl->spi_device->cid, + page, offset, buf, (uint)len); + } else +#endif + { + ROBO_RREG(ctrl->spi_device->robo, ctrl->spi_device->cid, + page, offset, buf, (uint)len); + } + + return 0; +} + +static int +_spi_write(int d, uint32 addr, uint8 *buf, int len) +{ +#if defined(KEYSTONE) || defined(IPROC_CMICD) + bde_ctrl_t *ctrl; + uint8 page, offset; +#endif +#if defined(IPROC_CMICD) + int rv = 0; + uint16 value = 0; +#endif + if (!VALID_DEVICE(d)) { + return -1; + } + + if (!(_devices[d].dev_type & BDE_SPI_DEV_TYPE)) { + gprintk("_spi_write: Not SPI device %d, type %x\n", + d, _devices[d].dev_type); + return -1; + } + +#if defined(KEYSTONE) || defined(IPROC_CMICD) + ctrl = _devices + d; +#endif + +#if defined(IPROC_CMICD) + if (addr & SOC_EXTERNAL_PHY_BUS_CPUMDIO) { + memcpy(&value, buf, 2); + rv = ccb_mii_write(MII_DEV_EXT, (addr >> 8) & 0xff, addr & 0xff, value); + return rv; + } +#endif + +#if defined(KEYSTONE) || defined(IPROC_CMICD) + page = (addr >> SOC_ROBO_PAGE_BP) & 0xFF; + offset = addr & 0xFF; +#endif + +#if defined(IPROC_CMICD) && defined(BCM_STARFIGHTER3_SUPPORT) + if (spi_device_found) { + ROBO_SPI_WREG(ctrl->spi_device->robo, ctrl->spi_device->cid, + page, offset, buf, (uint)len); + } else +#endif + { + ROBO_WREG(ctrl->spi_device->robo, ctrl->spi_device->cid, + page, offset, buf, (uint)len); + } + + return 0; +} + +#endif + +#if defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT) +int +lkbde_cpu_write(int d, uint32 addr, uint32 *buf) +{ +#if defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__) + *((uint32_t*)((uint8_t*)cpu_address + addr)) = *buf; +#endif + + return 0; +} + +int +lkbde_cpu_read(int d, uint32 addr, uint32 *buf) +{ +#if defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__) + *buf = *((uint32_t*)((uint8_t*)cpu_address + addr)); +#else + *buf = (uint32_t)(-1); +#endif + + return 0; +} + +int +lkbde_cpu_pci_register(int d) +{ + bde_ctrl_t* ctrl; + uint16 cmd = 0; + + if (!VALID_DEVICE(d)) { + return -1; + } + + ctrl = &_devices[d]; + + /* enable device */ + if (pci_enable_device(ctrl->pci_device)) { + gprintk("Cannot enable pci device : vendor_id = %x, device_id = %x\n", + ctrl->pci_device->vendor, ctrl->pci_device->device); + } + + /* Add PCI_COMMAND_MEMORY and PCI_COMMAND_MASTER */ + pci_read_config_word(ctrl->pci_device, PCI_COMMAND, &cmd); + if (!(cmd & PCI_COMMAND_MEMORY) || !(cmd & PCI_COMMAND_MASTER)) { + cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + pci_write_config_word(ctrl->pci_device, PCI_COMMAND, cmd); + } + + switch (ctrl->bde_dev.device) { + case GEDI_DEVICE_ID: + /* Fix bar 0 address */ /* FIXME: write full phy address */ + pci_write_config_byte(ctrl->pci_device, 0x13, 0x60); + + /* Fix Max payload size */ + pci_write_config_byte(ctrl->pci_device, 0x88, 0x2f); + pci_write_config_byte(ctrl->pci_device, 0x89, 0x10); + break; + case BCM88750_DEVICE_ID: + case BCM88753_DEVICE_ID: + case BCM88755_DEVICE_ID: + case BCM88770_DEVICE_ID: + case BCM88773_DEVICE_ID: + case BCM88774_DEVICE_ID: + case BCM88775_DEVICE_ID: + case BCM88776_DEVICE_ID: + case BCM88777_DEVICE_ID: + case BCM88950_DEVICE_ID: + case BCM88953_DEVICE_ID: + case BCM88954_DEVICE_ID: + case BCM88955_DEVICE_ID: + case BCM88956_DEVICE_ID: + case BCM88752_DEVICE_ID: + case BCM88772_DEVICE_ID: + case BCM88952_DEVICE_ID: + case ACP_PCI_DEVICE_ID: + case BCM88650_DEVICE_ID: + + case BCM88670_DEVICE_ID: + case BCM88671_DEVICE_ID: + case BCM88671M_DEVICE_ID: + case BCM88672_DEVICE_ID: + case BCM88673_DEVICE_ID: + case BCM88674_DEVICE_ID: + case BCM88675_DEVICE_ID: + case BCM88675M_DEVICE_ID: + case BCM88676_DEVICE_ID: + case BCM88676M_DEVICE_ID: + case BCM88677_DEVICE_ID: + case BCM88678_DEVICE_ID: + case BCM88679_DEVICE_ID: + + case BCM88370_DEVICE_ID: + case BCM88371_DEVICE_ID: + case BCM88371M_DEVICE_ID: + case BCM88375_DEVICE_ID: + case BCM88376_DEVICE_ID: + case BCM88376M_DEVICE_ID: + case BCM88377_DEVICE_ID: + case BCM88378_DEVICE_ID: + case BCM88379_DEVICE_ID: + case BCM88681_DEVICE_ID: + case BCM88682_DEVICE_ID: + case BCM88683_DEVICE_ID: + case BCM88684_DEVICE_ID: + case BCM88685_DEVICE_ID: + case BCM88380_DEVICE_ID: + case BCM88381_DEVICE_ID: + case BCM88680_DEVICE_ID: + case BCM88690_DEVICE_ID: + case BCM88470_DEVICE_ID: + case BCM88470P_DEVICE_ID: + case BCM88471_DEVICE_ID: + case BCM88473_DEVICE_ID: + case BCM88474_DEVICE_ID: + case BCM88474H_DEVICE_ID: + case BCM88476_DEVICE_ID: + case BCM88477_DEVICE_ID: + case BCM88270_DEVICE_ID: + case BCM88272_DEVICE_ID: + case BCM88273_DEVICE_ID: + case BCM88278_DEVICE_ID: + case BCM8206_DEVICE_ID: + case BCM88350_DEVICE_ID: + case BCM88351_DEVICE_ID: + case BCM88450_DEVICE_ID: + case BCM88451_DEVICE_ID: + case BCM88550_DEVICE_ID: + case BCM88551_DEVICE_ID: + case BCM88552_DEVICE_ID: + case BCM88651_DEVICE_ID: + case BCM88654_DEVICE_ID: + case BCM88660_DEVICE_ID: + case BCM88360_DEVICE_ID: + case BCM88361_DEVICE_ID: + case BCM88363_DEVICE_ID: + case BCM88460_DEVICE_ID: + case BCM88461_DEVICE_ID: + case BCM88560_DEVICE_ID: + case BCM88561_DEVICE_ID: + case BCM88562_DEVICE_ID: + case BCM88661_DEVICE_ID: + case BCM88664_DEVICE_ID: + /* Fix bar 0 address */ /* FIXME: write full phy address */ + pci_write_config_byte(ctrl->pci_device, 0x12, 0x10); + pci_write_config_byte(ctrl->pci_device, 0x13, 0x60); + + /* + * For DMA transactions - set Max_Payload_Size and + * Max_Read_Request_Size to 128 bytes. + */ + pci_write_config_byte(ctrl->pci_device, 0xb5, 0x0c); + pci_write_config_byte(ctrl->pci_device, 0xb4, 0x0); + break; + default: + break; + } + + /* Redo ioremap */ + if (ctrl->bde_dev.base_address) { + iounmap((void *)ctrl->bde_dev.base_address); + } + ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(ctrl->phys_address, 0x1000000); + + if (debug >= 1) { + gprintk("%s, %s(): info:\n", __FILE__, __FUNCTION__); + gprintk("_ndevices=%d, _switch_ndevices=%d\n", + _ndevices, _switch_ndevices); + gprintk("ctrl->dev_type=0x%x, ctrl->phys_address=0x%lx\n", + ctrl->dev_type, (unsigned long)ctrl->phys_address); + gprintk("ctrl->bde_dev.device=0x%x, ctrl->bde_dev.rev=0x%x, " + "ctrl->bde_dev.base_address=0x%lx\n", + ctrl->bde_dev.device, ctrl->bde_dev.rev, + (unsigned long)ctrl->bde_dev.base_address); + } + + return 0; +} + +/* + * Export Low level access function - currently for PCP DMA Kernel module. + */ +int +lkbde_mem_write(int d, uint32 addr, uint32 *buf) +{ + bde_ctrl_t* ctrl; + void *full_addr; + + if (!VALID_DEVICE(d)) return -1; + ctrl = &_devices[d]; + + full_addr = (void *)ctrl->bde_dev.base_address + addr; + *((uint32_t*)full_addr) = *buf; + return 0; +} +LKM_EXPORT_SYM(lkbde_mem_write); + +int +lkbde_mem_read(int d, uint32 addr, uint32 *buf) +{ + bde_ctrl_t* ctrl; + void *full_addr; + + if (!VALID_DEVICE(d)) return -1; + ctrl = &_devices[d]; + + full_addr = (void *)ctrl->bde_dev.base_address + addr; + *buf = *((uint32_t*)full_addr); + return 0; +} +LKM_EXPORT_SYM(lkbde_mem_read); +#endif /* defined(BCM_PETRA_SUPPORT) */ + +static ibde_t _ibde = { + name: _name, + num_devices: _num_devices, + get_dev: _get_dev, + get_dev_type: _get_dev_type, + pci_conf_read: _pci_conf_read, + pci_conf_write: _pci_conf_write, + pci_bus_features: _pci_bus_features, + read: _read, + write: _write, + salloc: _salloc, + sfree: _sfree, + sinval: _sinval, + sflush: _sflush, + interrupt_connect: _interrupt_connect, + interrupt_disconnect: _interrupt_disconnect, + l2p: _l2p, + p2l: _p2l, +#if defined(BCM_ROBO_SUPPORT) + spi_read: _spi_read, + spi_write: _spi_write, +#else + NULL, + NULL, +#endif /* defined(BCM_ROBO_SUPPORT) */ + iproc_read: _iproc_read, + iproc_write: _iproc_write, + get_cmic_ver: _get_cmic_ver, +}; + +/* + * Function: linux_bde_create + * + * Purpose: + * Creator function for this BDE interface. + * Parameters: + * bus - pointer to the bus features structure you want this + * bde to export. Depends on the system. + * ibde - pointer to a location to recieve the bde interface pointer. + * Returns: + * 0 on success + * -1 on failure. + * Notes: + * This is the main BDE create function for this interface. + * Used by the external system initialization code. + */ +int +linux_bde_create(linux_bde_bus_t *bus, ibde_t **ibde) +{ + + memset(&_bus, 0, sizeof(_bus)); + + if (bus) { + _bus = *bus; + } +#ifdef NONCOHERENT_DMA_MEMORY +#ifdef REMAP_DMA_NONCACHED + /* + * If we have a non-cached DMA memory pool + * there is no need to flush and invalidate. + */ + if (_dma_pool_allocated()) { + _ibde.sinval = NULL; + _ibde.sflush = NULL; + } +#endif +#else + _ibde.sinval = NULL; + _ibde.sflush = NULL; +#endif + *ibde = &_ibde; + return 0; +} + +/* + * Function: linux_bde_destroy + * + * Purpose: + * destroy this bde + * Parameters: + * BDE interface pointer + * Returns: + * 0 on success, < 0 on error. + */ +int +linux_bde_destroy(ibde_t *ibde) +{ + /* nothing */ + return 0; +} + +/* + * Backdoors provided by the kernel bde + */ + +uint32_t +lkbde_get_dev_phys(int d) +{ + if (!VALID_DEVICE(d)) { + return -1; + } + + if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) { + gprintk("lkbde_get_dev_phys: Not PCI device %d, type %x\n", + d, _devices[d].dev_type); + return 0; + } + return _devices[d].phys_address; +} + +uint32_t +lkbde_get_dev_phys_hi(int d) +{ + if (!VALID_DEVICE(d)) { + return -1; + } + + if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) { + gprintk("lkbde_get_dev_phys: Not PCI device %d, type %x\n", + d, _devices[d].dev_type); + return 0; + } +#ifdef PHYS_ADDR_IS_64BIT + return (uint32_t)(_devices[d].phys_address >> 32); +#else + return 0; +#endif +} + +void * +lkbde_get_dev_virt(int d) +{ + if (!VALID_DEVICE(d)) { + return NULL; + } + + if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) { + gprintk("lkbde_get_dev_virt: Not PCI device %d, type %x\n", + d, _devices[d].dev_type); + return 0; + } + + if (_devices[d].alt_base_addr) { + return (void *)_devices[d].alt_base_addr; + } + + return (void *)_devices[d].bde_dev.base_address; +} + +int +lkbde_get_dev_resource(int d, int rsrc, uint32_t *flags, + uint32_t *phys_lo, uint32_t *phys_hi) +{ + if (!VALID_DEVICE(d)) { + return -1; + } + + *flags = 0; + *phys_lo = 0; + *phys_hi = 0; + + if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) { + gprintk("lkbde_get_dev_phys: Not PCI device %d, type %x\n", + d, _devices[d].dev_type); + return 0; + } + + switch (rsrc) { + case 0: + *phys_lo = (uint32_t)(_devices[d].phys_address); +#ifdef PHYS_ADDR_IS_64BIT + *phys_hi = (uint32_t)(_devices[d].phys_address >> 32); +#endif + break; + case 1: + *phys_lo = (uint32_t)(_devices[d].phys_address1); +#ifdef PHYS_ADDR_IS_64BIT + *phys_hi = (uint32_t)(_devices[d].phys_address1 >> 32); +#endif + break; + default: + break; + } + + return 0; +} + +void * +lkbde_get_dma_dev(int d) +{ + if (!VALID_DEVICE(d)) { + return NULL; + } + +#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT + return (void *)_devices[d].dma_dev; +#else + return (void *)_devices[d].pci_device; +#endif +} + +void * +lkbde_get_hw_dev(int d) +{ + if (!VALID_DEVICE(d)) { + return NULL; + } + + return (void *)_devices[d].pci_device; +} + +int +lkbde_dev_state_set(int d, uint32 state) +{ + bde_ctrl_t *ctrl; + + if (!VALID_DEVICE(d)) { + return -1; + } + ctrl = _devices + d; + ctrl->dev_state = state; + return 0; +} + +int +lkbde_dev_state_get(int d, uint32 *state) +{ + bde_ctrl_t *ctrl; + if (!VALID_DEVICE(d)) { + gprintk("_get_dev: Invalid device index %d\n", d); + return -1; + } + ctrl = _devices + d; + + *state = ctrl->dev_state; + return 0; +} + +int +lkbde_dev_instid_set(int d, uint32 instid) +{ + bde_ctrl_t *ctrl; + + if (!VALID_DEVICE(d)) { + return -1; + } + ctrl = _devices + d; + ctrl->inst_id = instid; + + return 0; +} + +int +lkbde_dev_instid_get(int d, uint32 *instid) +{ + bde_ctrl_t *ctrl; + + if (!VALID_DEVICE(d)) { + return -1; + } + ctrl = _devices + d; + *instid = ctrl->inst_id; + + return 0; +} +/* + * When a secondary interrupt handler is installed this function + * is used for synchronizing hardware access to the IRQ mask + * register. The secondary driver will supply a non-zero fmask + * (filter mask) to indicate which interrupt bits it controls. + * The fmask is ignored for the primary driver. + */ +int +lkbde_irq_mask_set(int d, uint32_t addr, uint32_t mask, uint32_t fmask) +{ + bde_ctrl_t *ctrl; + int isr2_dev; + unsigned long flags; + + isr2_dev = d & LKBDE_ISR2_DEV; + d &= ~LKBDE_ISR2_DEV; + + if (!VALID_DEVICE(d)) { + return -1; + } + + ctrl = _devices + d; + + /* Lock is required to synchronize access from user space */ + spin_lock_irqsave(&ctrl->lock, flags); + + if (isr2_dev) { + /* This is the secondary interrupt handler */ + ctrl->fmask = fmask; + ctrl->imask2 = mask & ctrl->fmask; + } else { + /* This is the primary interrupt handler */ + ctrl->imask = mask & ~ctrl->fmask; + } + _write(d, addr, ctrl->imask | ctrl->imask2); + + spin_unlock_irqrestore(&ctrl->lock, flags); + + return 0; +} + +/* + * When a secondary interrupt handler is installed, this function + * is used to avoid activating the user mode interrupt handler + * thread if all pending interrupts are handled in kernel space. + * + * The mask returned is the mask of all interrupts, it can be used + * to do a logical AND with fmask, the result will tell you if + * the user mode interrupt handler needs to be invoked. + * + * Note that if no secondary handler is installed, the value of + * "mask & fmask" will be zero, and hence there will be no need to read the + * current interrupt status from hardware (from kernel space). + */ +int +lkbde_irq_mask_get(int d, uint32_t *mask, uint32_t *fmask) +{ + bde_ctrl_t *ctrl; + + d &= ~LKBDE_ISR2_DEV; + + if (!VALID_DEVICE(d)) { + return -1; + } + + if (mask == NULL) { + return -1; + } + + ctrl = _devices + d; + + *fmask = ctrl->fmask; + *mask = ctrl->imask | ctrl->imask2; + + return 0; +} + + +/* + * Export functions + */ +LKM_EXPORT_SYM(linux_bde_create); +LKM_EXPORT_SYM(linux_bde_destroy); +LKM_EXPORT_SYM(lkbde_get_dev_phys); +LKM_EXPORT_SYM(lkbde_get_dev_virt); +LKM_EXPORT_SYM(lkbde_get_dev_resource); +LKM_EXPORT_SYM(lkbde_get_hw_dev); +LKM_EXPORT_SYM(lkbde_get_dma_dev); +LKM_EXPORT_SYM(lkbde_irq_mask_set); +LKM_EXPORT_SYM(lkbde_irq_mask_get); +LKM_EXPORT_SYM(lkbde_get_dev_phys_hi); +LKM_EXPORT_SYM(lkbde_dev_state_set); +LKM_EXPORT_SYM(lkbde_dev_state_get); +LKM_EXPORT_SYM(lkbde_dev_instid_set); +LKM_EXPORT_SYM(lkbde_dev_instid_get); +#if (defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT)) +LKM_EXPORT_SYM(lkbde_cpu_write); +LKM_EXPORT_SYM(lkbde_cpu_read); +LKM_EXPORT_SYM(lkbde_cpu_pci_register); +#endif diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_dma.c b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_dma.c new file mode 100644 index 0000000000..bd7eab6032 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_dma.c @@ -0,0 +1,906 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: linux_dma.c,v 1.414 Broadcom SDK $ + * $Copyright: (c) 2016 Broadcom Corp. + * All Rights Reserved.$ + * + * Linux Kernel BDE DMA memory allocation + * + * + * DMA memory allocation modes + * =========================== + * + * 1. Using private pool in kernel memory + * -------------------------------------- + * In this mode the BDE module will try to assemble a physically contiguous + * of memory using the kernel page allocator. This memory block is then + * administered by the mpool allocation functions. Note that once a system + * has been running for a while, the memory fragmentation may prevent the + * allocator from assembling a contiguous memory block, however, if the + * module is loaded shortly after system startup, it is very unlikely to + * fail. + * + * This allocation method is used by default. + * + * 2. Using private pool in high memory + * ------------------------------------ + * In this mode the BDE module will assume that unused physical memory is + * present at the high_memory address, i.e. memory not managed by the Linux + * memory manager. This memory block is mapped into kernel space and + * administered by the mpool allocation functions. High memory must be + * reserved using either the mem=xxx kernel parameter (recommended), or by + * hardcoding the memory limit in the kernel image. + * + * The module parameter himem=1 enables this allocation mode. + * + * 3. Using kernel allocators (kmalloc, __get_free_pages) + * ------------------------------------------------------ + * In this mode all DMA memory is allocated from the kernel on the fly, i.e. + * no private DMA memory pool will be created. If large memory blocks are + * only allocated at system startup (or not at all), this allocation method + * is the most flexible and memory-efficient, however, it is not recommended + * for non-coherent memory platforms due to an overall system performance + * degradation arising from the use of cache flush/invalidate instructions. + * + * The module parameter dmasize=0M enables this allocation mode, however if + * DMA memory is requested from a user mode application, a private memory + * pool will be created and used irrespectively. + */ + +#include +#include +#include +#include +#include + +#ifdef BCM_PLX9656_LOCAL_BUS +#include +#endif + +/* allocation types/methods for the DMA memory pool */ +#define ALLOC_TYPE_CHUNK 0 /* use small allocations and join them */ +#define ALLOC_TYPE_API 1 /* use one allocation */ +#if _SIMPLE_MEMORY_ALLOCATION_ +#include +#if defined(IPROC_CMICD) && defined(CONFIG_CMA) && defined(CONFIG_CMA_SIZE_MBYTES) +#define DMA_MAX_ALLOC_SIZE (CONFIG_CMA_SIZE_MBYTES * 1024 * 1024) +#else +#define DMA_MAX_ALLOC_SIZE (1 << (MAX_ORDER - 1 + PAGE_SHIFT)) /* Maximum size the kernel can allocate in one allocation */ +#endif +#endif /* _SIMPLE_MEMORY_ALLOCATION_ */ + +#if _SIMPLE_MEMORY_ALLOCATION_ == 1 +#define ALLOC_METHOD_DEFAULT ALLOC_TYPE_API +#else +#define ALLOC_METHOD_DEFAULT ALLOC_TYPE_CHUNK +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) +#include +#define virt_to_bus virt_to_phys +#define bus_to_virt phys_to_virt +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) +#define VIRT_TO_PAGE(p) virt_to_page((void*)(p)) +#else +#define VIRT_TO_PAGE(p) virt_to_page((p)) +#endif + +/* Compatibility */ +#ifdef LKM_2_4 +#define MEM_MAP_RESERVE mem_map_reserve +#define MEM_MAP_UNRESERVE mem_map_unreserve +#else /* LKM_2_6 */ +#define MEM_MAP_RESERVE SetPageReserved +#define MEM_MAP_UNRESERVE ClearPageReserved +#endif /* LKM_2_x */ + +#ifndef GFP_DMA32 +#define GFP_DMA32 0 +#endif + +/* Flags for memory allocations */ +#ifdef SAL_BDE_XLP +static int mem_flags = GFP_ATOMIC | GFP_KERNEL | GFP_DMA; +#else +#if defined(CONFIG_ZONE_DMA32) +static int mem_flags = GFP_ATOMIC | GFP_DMA32; +#else +static int mem_flags = GFP_ATOMIC | GFP_DMA; +#endif +#endif + +/* Debug output */ +static int dma_debug = 0; +module_param(dma_debug, int, 0); +MODULE_PARM_DESC(dma_debug, +"DMA debug output enable (default 0)."); + +/* DMA memory pool size */ +static char *dmasize; +LKM_MOD_PARAM(dmasize, "s", charp, 0); +MODULE_PARM_DESC(dmasize, +"Specify DMA memory size (default 4MB)"); + +/* Select DMA memory pool allocation method */ +static int dmaalloc = ALLOC_METHOD_DEFAULT; +LKM_MOD_PARAM(dmaalloc, "i", int, 0); +MODULE_PARM_DESC(dmaalloc, "Select DMA memory allocation method"); + +/* Use high memory for DMA */ +static char *himem; +LKM_MOD_PARAM(himem, "s", charp, 0); +MODULE_PARM_DESC(himem, +"Use high memory for DMA (default no)"); + +/* DMA memory allocation */ + +#define ONE_KB 1024 +#define ONE_MB (1024*1024) + +/* Default DMA memory size */ +#ifdef SAL_BDE_DMA_MEM_DEFAULT +#define DMA_MEM_DEFAULT (SAL_BDE_DMA_MEM_DEFAULT * ONE_MB) +#else +#define DMA_MEM_DEFAULT (8 * ONE_MB) +#endif +#define DMA_MEM_DEFAULT_ROBO (4 * ONE_MB) + +/* We try to assemble a contiguous segment from chunks of this size */ +#define DMA_BLOCK_SIZE (512 * ONE_KB) + +typedef struct _dma_segment { + struct list_head list; + unsigned long req_size; /* Requested DMA segment size */ + unsigned long blk_size; /* DMA block size */ + unsigned long blk_order; /* DMA block size in alternate format */ + unsigned long seg_size; /* Current DMA segment size */ + unsigned long seg_begin; /* Logical address of segment */ + unsigned long seg_end; /* Logical end address of segment */ + unsigned long *blk_ptr; /* Array of logical DMA block addresses */ + int blk_cnt_max; /* Maximum number of block to allocate */ + int blk_cnt; /* Current number of blocks allocated */ +} dma_segment_t; + +static unsigned int _dma_mem_size = DMA_MEM_DEFAULT; +static mpool_handle_t _dma_pool = NULL; +static void __iomem *_dma_vbase = NULL; +/* cpu physical address for mmap */ +static phys_addr_t _cpu_pbase = 0; +/* + * DMA bus address, it is either identical to cpu physical address + * or another address(IOVA) translated by IOMMU. + */ +static phys_addr_t _dma_pbase = 0; +static int _use_himem = 0; +static int _use_dma_mapping = 0; +static LIST_HEAD(_dma_seg); + +#define DMA_DEV(n) lkbde_get_dma_dev(n) + +/* + * Function: _find_largest_segment + * + * Purpose: + * Find largest contiguous segment from a pool of DMA blocks. + * Parameters: + * dseg - DMA segment descriptor + * Returns: + * 0 on success, < 0 on error. + * Notes: + * Assembly stops if a segment of the requested segment size + * has been obtained. + * + * Lower address bits of the DMA blocks are used as follows: + * 0: Untagged + * 1: Discarded block + * 2: Part of largest contiguous segment + * 3: Part of current contiguous segment + */ +static int +_find_largest_segment(dma_segment_t *dseg) +{ + int i, j, blks, found; + unsigned long b, e, a; + + blks = dseg->blk_cnt; + /* Clear all block tags */ + for (i = 0; i < blks; i++) { + dseg->blk_ptr[i] &= ~3; + } + for (i = 0; i < blks && dseg->seg_size < dseg->req_size; i++) { + /* First block must be an untagged block */ + if ((dseg->blk_ptr[i] & 3) == 0) { + /* Initial segment size is the block size */ + b = dseg->blk_ptr[i]; + e = b + dseg->blk_size; + dseg->blk_ptr[i] |= 3; + /* Loop looking for adjacent blocks */ + do { + found = 0; + for (j = i + 1; j < blks && (e - b) < dseg->req_size; j++) { + a = dseg->blk_ptr[j]; + /* Check untagged blocks only */ + if ((a & 3) == 0) { + if (a == (b - dseg->blk_size)) { + /* Found adjacent block below current segment */ + dseg->blk_ptr[j] |= 3; + b = a; + found = 1; + } else if (a == e) { + /* Found adjacent block above current segment */ + dseg->blk_ptr[j] |= 3; + e += dseg->blk_size; + found = 1; + } + } + } + } while (found); + if ((e - b) > dseg->seg_size) { + /* The current block is largest so far */ + dseg->seg_begin = b; + dseg->seg_end = e; + dseg->seg_size = e - b; + /* Re-tag current and previous largest segment */ + for (j = 0; j < blks; j++) { + if ((dseg->blk_ptr[j] & 3) == 3) { + /* Tag current segment as the largest */ + dseg->blk_ptr[j] &= ~1; + } else if ((dseg->blk_ptr[j] & 3) == 2) { + /* Discard previous largest segment */ + dseg->blk_ptr[j] ^= 3; + } + } + } else { + /* Discard all blocks in current segment */ + for (j = 0; j < blks; j++) { + if ((dseg->blk_ptr[j] & 3) == 3) { + dseg->blk_ptr[j] &= ~2; + } + } + } + } + } + return 0; +} + +/* + * Function: _alloc_dma_blocks + * + * Purpose: + * Allocate DMA blocks and add them to the pool. + * Parameters: + * dseg - DMA segment descriptor + * blks - number of DMA blocks to allocate + * Returns: + * 0 on success, < 0 on error. + * Notes: + * DMA blocks are allocated using the page allocator. + */ +static int +_alloc_dma_blocks(dma_segment_t *dseg, int blks) +{ + int i, start; + unsigned long addr; + + if (dseg->blk_cnt + blks > dseg->blk_cnt_max) { + gprintk("No more DMA blocks\n"); + return -1; + } + start = dseg->blk_cnt; + dseg->blk_cnt += blks; + for (i = start; i < dseg->blk_cnt; i++) { + /* + * Note that we cannot use pci_alloc_consistent when we + * want to be able to map DMA memory to user space. + * + * The GFP_DMA flag is omitted as this imposes the ISA + * addressing limitations on x86 platforms. As long as + * we have less than 1GB of memory, we can do PCI DMA + * to all physical RAM locations. + */ + addr = __get_free_pages(mem_flags, dseg->blk_order); + if (addr) { + dseg->blk_ptr[i] = addr; + } else { + gprintk("DMA allocation failed\n"); + return -1; + } + } + return 0; +} + +/* + * Function: _dma_segment_alloc + * + * Purpose: + * Allocate large physically contiguous DMA segment. + * Parameters: + * size - requested DMA segment size + * blk_size - assemble segment from blocks of this size + * Returns: + * DMA segment descriptor. + * Notes: + * Since we cannot allocate large blocks of contiguous + * memory from the kernel, we simply keep allocating + * smaller chunks until we can assemble a contiguous + * block of the desired size. + * + * When system allowed maximum bytes of memory has been allocated + * without a successful assembly of a contiguous DMA + * segment, the allocation function will return the + * largest contiguous segment found so far. It is up + * to the calling function to decide whether this + * amount is sufficient to proceed. + */ +static dma_segment_t * +_dma_segment_alloc(size_t size, size_t blk_size) +{ + dma_segment_t *dseg; + int i, blk_ptr_size; + unsigned long page_addr; + struct sysinfo si; + + /* Sanity check */ + if (size == 0 || blk_size == 0) { + return NULL; + } + /* Allocate an initialize DMA segment descriptor */ + if ((dseg = kmalloc(sizeof(dma_segment_t), GFP_KERNEL)) == NULL) { + return NULL; + } + memset(dseg, 0, sizeof(dma_segment_t)); + dseg->req_size = size; + dseg->blk_size = PAGE_ALIGN(blk_size); + while ((PAGE_SIZE << dseg->blk_order) < dseg->blk_size) { + dseg->blk_order++; + } + + si_meminfo(&si); + dseg->blk_cnt_max = (si.totalram << PAGE_SHIFT) / dseg->blk_size; + blk_ptr_size = dseg->blk_cnt_max * sizeof(unsigned long); + /* Allocate an initialize DMA block pool */ + dseg->blk_ptr = KMALLOC(blk_ptr_size, GFP_KERNEL); + if (dseg->blk_ptr == NULL) { + kfree(dseg); + return NULL; + } + memset(dseg->blk_ptr, 0, blk_ptr_size); + /* Allocate minimum number of blocks */ + _alloc_dma_blocks(dseg, dseg->req_size / dseg->blk_size); + /* Allocate more blocks until we have a complete segment */ + do { + _find_largest_segment(dseg); + if (dseg->seg_size >= dseg->req_size) { + break; + } + } while (_alloc_dma_blocks(dseg, 8) == 0); + /* Reserve all pages in the DMA segment and free unused blocks */ + for (i = 0; i < dseg->blk_cnt; i++) { + if ((dseg->blk_ptr[i] & 3) == 2) { + dseg->blk_ptr[i] &= ~3; + for (page_addr = dseg->blk_ptr[i]; + page_addr < dseg->blk_ptr[i] + dseg->blk_size; + page_addr += PAGE_SIZE) { + MEM_MAP_RESERVE(VIRT_TO_PAGE(page_addr)); + } + } else if (dseg->blk_ptr[i]) { + dseg->blk_ptr[i] &= ~3; + free_pages(dseg->blk_ptr[i], dseg->blk_order); + dseg->blk_ptr[i] = 0; + } + } + return dseg; +} + +/* + * Function: _dma_segment_free + * + * Purpose: + * Release resources used by DMA segment. + * Parameters: + * dseg - DMA segment descriptor + * Returns: + * Nothing. + */ +static void +_dma_segment_free(dma_segment_t *dseg) +{ + int i; + unsigned long page_addr; + + if (dseg->blk_ptr) { + for (i = 0; i < dseg->blk_cnt; i++) { + if (dseg->blk_ptr[i]) { + for (page_addr = dseg->blk_ptr[i]; + page_addr < dseg->blk_ptr[i] + dseg->blk_size; + page_addr += PAGE_SIZE) { + MEM_MAP_UNRESERVE(VIRT_TO_PAGE(page_addr)); + } + free_pages(dseg->blk_ptr[i], dseg->blk_order); + } + } + kfree(dseg->blk_ptr); + kfree(dseg); + } +} + +/* + * Function: _pgalloc + * + * Purpose: + * Allocate DMA memory using page allocator + * Parameters: + * size - number of bytes to allocate + * Returns: + * Pointer to allocated DMA memory or NULL if failure. + * Notes: + * For any sizes less than DMA_BLOCK_SIZE, we ask the page + * allocator for the entire memory block, otherwise we try + * to assemble a contiguous segment ourselves. + */ +static void * +_pgalloc(size_t size) +{ + dma_segment_t *dseg; + size_t blk_size; + + blk_size = (size < DMA_BLOCK_SIZE) ? size : DMA_BLOCK_SIZE; + if ((dseg = _dma_segment_alloc(size, blk_size)) == NULL) { + return NULL; + } + if (dseg->seg_size < size) { + /* If we didn't get the full size then forget it */ + _dma_segment_free(dseg); + return NULL; + } + list_add(&dseg->list, &_dma_seg); + return (void *)dseg->seg_begin; +} + +/* + * Function: _pgfree + * + * Purpose: + * Free memory allocated by _pgalloc + * Parameters: + * ptr - pointer returned by _pgalloc + * Returns: + * 0 if succesfully freed, otherwise -1. + */ +static int +_pgfree(void *ptr) +{ + struct list_head *pos; + list_for_each(pos, &_dma_seg) { + dma_segment_t *dseg = list_entry(pos, dma_segment_t, list); + if (ptr == (void *)dseg->seg_begin) { + list_del(&dseg->list); + _dma_segment_free(dseg); + return 0; + } + } + return -1; +} + +/* + * Function: _pgcleanup + * + * Purpose: + * Free all memory allocated by _pgalloc + * Parameters: + * None + * Returns: + * Nothing. + */ +static void +_pgcleanup(void) +{ + switch (dmaalloc) { +#if _SIMPLE_MEMORY_ALLOCATION_ + case ALLOC_TYPE_API: + if (_dma_vbase) { + if (dma_debug >= 1) gprintk("freeing v=%p p=0x%lx size=0x%lx\n", _dma_vbase,(unsigned long) _dma_pbase, (unsigned long)_dma_mem_size); + dma_free_coherent(DMA_DEV(0), _dma_mem_size, _dma_vbase, _dma_pbase); + } + break; +#endif /* _SIMPLE_MEMORY_ALLOCATION_ */ + + case ALLOC_TYPE_CHUNK: { + struct list_head *pos, *tmp; + if (_use_dma_mapping) { + dma_unmap_single(DMA_DEV(0), (dma_addr_t)_dma_pbase, _dma_mem_size, DMA_BIDIRECTIONAL); + _use_dma_mapping = 0; + } + list_for_each_safe(pos, tmp, &_dma_seg) { + dma_segment_t *dseg = list_entry(pos, dma_segment_t, list); + list_del(&dseg->list); + _dma_segment_free(dseg); + } + break; + } + + default: + gprintk("DMA memory allocation method dmaalloc=%d is not supported\n", dmaalloc); + } +} + +/* + * Function: _alloc_mpool + * + * Purpose: + * Allocate DMA memory pool + * Parameters: + * size - size of DMA memory pool + * Returns: + * Nothing. + * Notes: + * If set up to use high memory, we simply map the memory into + * kernel space. + * It is assumed there is only one pool. + */ +static void +_alloc_mpool(size_t size) +{ + unsigned long pbase = 0; + +#if defined(__arm__) && !defined(CONFIG_HIGHMEM) + if (_use_himem) { + gprintk("DMA in high memory requires CONFIG_HIGHMEM on ARM CPUs.\n"); + return; + } +#endif + + if (_use_himem) { + /* Use high memory for DMA */ + pbase = virt_to_bus(high_memory); + if (((pbase + (size - 1)) >> 16) > DMA_BIT_MASK(16)) { + gprintk("DMA in high memory at 0x%lx size 0x%lx is beyond the 4GB limit and not supported.\n", pbase, (unsigned long)size); + return; + } + _cpu_pbase = _dma_pbase = pbase; + _dma_vbase = IOREMAP(_dma_pbase, size); + } else { + /* Get DMA memory from kernel */ + switch (dmaalloc) { +#if _SIMPLE_MEMORY_ALLOCATION_ + case ALLOC_TYPE_API: { + size_t alloc_size = size; /* size of memory allocated in current iteration */ + if (alloc_size > DMA_MAX_ALLOC_SIZE) { + alloc_size = DMA_MAX_ALLOC_SIZE; + } + /* get a memory allocation from the kernel */ + { + dma_addr_t dma_handle; + if (!(_dma_vbase = dma_alloc_coherent(DMA_DEV(0), alloc_size, &dma_handle, GFP_KERNEL)) || !dma_handle) { + gprintk("_alloc_mpool: Kernel failed to allocate the memory pool of size 0x%lx\n", (unsigned long)alloc_size); + return; + } + pbase = dma_handle; + } + + if (alloc_size != size) { + gprintk("_alloc_mpool: allocated 0x%lx bytes instead of 0x%lx bytes.\n", + (unsigned long)alloc_size, (unsigned long)size); + } + size = _dma_mem_size = alloc_size; + break; + } +#endif /* _SIMPLE_MEMORY_ALLOCATION_ */ + + case ALLOC_TYPE_CHUNK: + _dma_vbase = _pgalloc(size); + if (DMA_DEV(0)) { + /* + * Use dma_map_single to obtain dma bus address or IOVA if iommu is present. + */ + pbase = dma_map_single(DMA_DEV(0), _dma_vbase, size, DMA_BIDIRECTIONAL); + _use_dma_mapping = 1; + } else { + pbase = virt_to_bus(_dma_vbase); + } + break; + default: + _dma_vbase = NULL; + pbase = 0; + gprintk("DMA memory allocation method dmaalloc=%d is not supported\n", dmaalloc); + } + + _dma_pbase = pbase; + + if (dma_debug >= 1) { + gprintk("_alloc_mpool:%s _dma_vbase:%p pbase:%lx allocated:%lx dmaalloc:%d\n", + DMA_DEV(0)?"dma_dev":"", _dma_vbase, pbase, (unsigned long)size, dmaalloc); + } + + if (((pbase + (size - 1)) >> 16) > DMA_BIT_MASK(16)) { + gprintk("DMA memory allocated at 0x%lx size 0x%lx is beyond the 4GB limit and not supported.\n", pbase, (unsigned long)size); + _pgcleanup(); + _dma_vbase = NULL; + _dma_pbase = 0; + return; + } + + if (_dma_vbase) { + _cpu_pbase = virt_to_bus(_dma_vbase); + if (dma_debug >= 1) gprintk("_cpu_pbase at %lx\n", (unsigned long)_cpu_pbase); + } +#ifdef REMAP_DMA_NONCACHED + _dma_vbase = IOREMAP(_dma_pbase, size); +#endif + + } +} + +/* + * Function: _dma_cleanup + * + * Purpose: + * DMA cleanup function. + * Parameters: + * None + * Returns: + * Always 0 + */ +int +_dma_cleanup(void) +{ + if (_dma_vbase) { + mpool_destroy(_dma_pool); + if (_use_himem) { + iounmap(_dma_vbase); + } else { +#ifdef REMAP_DMA_NONCACHED + iounmap(_dma_vbase); +#endif + _pgcleanup(); + } + _dma_vbase = NULL; + _dma_pbase = 0; + _cpu_pbase = 0; + } + return 0; +} + +void _dma_init(int robo_switch) +{ + /* DMA Setup */ + if (dmasize) { + if ((dmasize[strlen(dmasize)-1] & ~0x20) == 'M') { + _dma_mem_size = simple_strtoul(dmasize, NULL, 0); + _dma_mem_size *= ONE_MB; + } else { + gprintk("DMA memory size must be specified as e.g. dmasize=8M\n"); + } + if (_dma_mem_size & (_dma_mem_size-1)) { + gprintk("dmasize must be a power of 2 (1M, 2M, 4M, 8M etc.)\n"); + _dma_mem_size = 0; + } + } else { + if(robo_switch){ + _dma_mem_size = DMA_MEM_DEFAULT_ROBO; + } + } + + if (himem) { + if ((himem[0] & ~0x20) == 'Y' || himem[0] == '1') { + _use_himem = 1; + } else if ((himem[0] & ~0x20) == 'N' || himem[0] == '0') { + _use_himem = 0; + } + } + + if (_dma_mem_size) { + _alloc_mpool(_dma_mem_size); + if (_dma_vbase == NULL) { + gprintk("no DMA memory available\n"); + } + else { + mpool_init(); + _dma_pool = mpool_create(_dma_vbase, _dma_mem_size); + } + } +} + +#if USE_LINUX_BDE_MMAP +/* + * Function: _dma_range_valid + * + * Purpose: + * Check if DMA address range is valid. + * Parameters: + * phys_addr - start physical address + * size - range size + * Returns: + * 0 : not valid + * 1 : valid + */ +int +_dma_range_valid(unsigned long phys_addr, unsigned long size) +{ + unsigned long pool_start = _cpu_pbase; + unsigned long pool_end = pool_start + _dma_mem_size; + + if (phys_addr < pool_start || (phys_addr + size) > pool_end) { + gprintk("range 0x%lx-0x%lx outside DMA pool 0x%lx-0x%lx\n", + phys_addr, phys_addr + size, pool_start, pool_end); + return 0; + } + return 1; +} +#endif + +/* + * Function: _dma_pool_allocated + * + * Purpose: + * Check if DMA pool has been allocated. + * Parameters: + * None + * Returns: + * 0 : not allocated + * 1 : allocated + */ +int +_dma_pool_allocated(void) +{ + return (_dma_vbase) ? 1 : 0; +} + +sal_paddr_t +_l2p(int d, void *vaddr) +{ + if (_dma_mem_size) { + /* dma memory is a contiguous block */ + if (vaddr) { + return _dma_pbase + (PTR_TO_UINTPTR(vaddr) - PTR_TO_UINTPTR(_dma_vbase)); + } + return 0; + } + return ((sal_paddr_t)virt_to_bus(vaddr)); +} + +void * +_p2l(int d, sal_paddr_t paddr) +{ + sal_vaddr_t vaddr = (sal_vaddr_t)_dma_vbase; + + if (_dma_mem_size) { + /* DMA memory is a contiguous block */ + if (paddr == 0) { + return NULL; + } + return (void *)(vaddr + (sal_vaddr_t)(paddr - _dma_pbase)); + } + return bus_to_virt(paddr); +} + +/* + * Some of the driver malloc's are too large for + * kmalloc(), so 'sal_alloc' and 'sal_free' in the + * linux kernel sal cannot be implemented with kmalloc(). + * + * Instead, they expect someone to provide an allocator + * that can handle the gimongous size of some of the + * allocations, and we provide it here, by allocating + * this memory out of the boot-time dma pool. + * + * These are the functions in question: + */ + +void* kmalloc_giant(int sz) +{ + return mpool_alloc(_dma_pool, sz); +} + +void kfree_giant(void* ptr) +{ + return mpool_free(_dma_pool, ptr); +} + +uint32_t * +_salloc(int d, int size, const char *name) +{ + void *ptr; + + if (_dma_mem_size) { + return mpool_alloc(_dma_pool, size); + } + if ((ptr = kmalloc(size, mem_flags)) == NULL) { + ptr = _pgalloc(size); + } + return ptr; +} + +void +_sfree(int d, void *ptr) +{ + if (_dma_mem_size) { + return mpool_free(_dma_pool, ptr); + } + if (_pgfree(ptr) < 0) { + kfree(ptr); + } +} + +int +_sinval(int d, void *ptr, int length) +{ +#if defined(dma_cache_wback_inv) + dma_cache_wback_inv((unsigned long)ptr, length); +#else +#if defined(IPROC_CMICD) || defined(BCM958525) + /* FIXME: need proper function to replace dma_cache_sync */ + dma_sync_single_for_cpu(NULL, (unsigned long)ptr, length, DMA_BIDIRECTIONAL); +#else + dma_cache_sync(NULL, ptr, length, DMA_BIDIRECTIONAL); +#endif +#endif + return 0; +} + +int +_sflush(int d, void *ptr, int length) +{ +#if defined(dma_cache_wback_inv) + dma_cache_wback_inv((unsigned long)ptr, length); +#else +#if defined(IPROC_CMICD) || defined(BCM958525) + /* FIXME: need proper function to replace dma_cache_sync */ + dma_sync_single_for_cpu(NULL, (unsigned long)ptr, length, DMA_BIDIRECTIONAL); +#else + dma_cache_sync(NULL, ptr, length, DMA_BIDIRECTIONAL); +#endif +#endif + + return 0; +} + +int +lkbde_get_dma_info(phys_addr_t* cpu_pbase, phys_addr_t* dma_pbase, ssize_t* size) +{ + if (_dma_vbase == NULL) { + if (_dma_mem_size == 0) { + _dma_mem_size = DMA_MEM_DEFAULT; + } + _alloc_mpool(_dma_mem_size); + } + *cpu_pbase = _cpu_pbase; + *dma_pbase = _dma_pbase; + *size = (_dma_vbase) ? _dma_mem_size : 0; + return 0; +} + +void +_dma_pprint(void) +{ + pprintf("DMA Memory (%s): %d bytes, %d used, %d free%s\n", + (_use_himem) ? "high" : "kernel", + (_dma_vbase) ? _dma_mem_size : 0, + (_dma_vbase) ? mpool_usage(_dma_pool) : 0, + (_dma_vbase) ? _dma_mem_size - mpool_usage(_dma_pool) : 0, + USE_LINUX_BDE_MMAP ? ", local mmap" : ""); +} + +/* + * Export functions + */ +LKM_EXPORT_SYM(kmalloc_giant); +LKM_EXPORT_SYM(kfree_giant); +LKM_EXPORT_SYM(lkbde_get_dma_info); diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_shbde.c b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_shbde.c new file mode 100644 index 0000000000..312062b846 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_shbde.c @@ -0,0 +1,121 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#include +#include +#include +#include "linux_shbde.h" + +/* Hardware abstractions for shared BDE functions */ + +static unsigned short +linux_pcic16_read(void *pci_dev, unsigned int addr) +{ + u16 data = 0; + + pci_read_config_word((struct pci_dev *)pci_dev, addr, &data); + + return data; +} + +static void +linux_pcic16_write(void *pci_dev, unsigned int addr, unsigned short data) +{ + pci_write_config_word((struct pci_dev *)pci_dev, addr, (u16)data); +} + +static unsigned int +linux_pcic32_read(void *pci_dev, unsigned int addr) +{ + u32 data = 0; + + pci_read_config_dword((struct pci_dev *)pci_dev, addr, &data); + + return data; +} + +static void +linux_pcic32_write(void *pci_dev, unsigned int addr, unsigned int data) +{ + pci_write_config_dword((struct pci_dev *)pci_dev, addr, (u32)data); +} + +static unsigned int +linux_io32_read(void *addr) +{ + return *((volatile u32 *)addr); +} + +static void +linux_io32_write(void *addr, unsigned int data) +{ + *((volatile u32 *)addr) = data; +} + +static void +linux_usleep(int usec) +{ + udelay(usec); +} + + +/* To get the PCI parent device under linux, from only the device pointer */ +static void * +linux_pci_parent_device_get(void *pci_dev) +{ + return (void *)(((struct pci_dev *)pci_dev)->bus->self); +} + + +/* + * Function: + * linux_shbde_hal_init + * Purpose: + * Initialize hardware abstraction module for Linux kernel. + * Parameters: + * shbde - pointer to uninitialized hardware abstraction module + * log_func - optional log output function + * Returns: + * Always 0 + */ +int +linux_shbde_hal_init(shbde_hal_t *shbde, shbde_log_func_t log_func) +{ + memset(shbde, 0, sizeof(*shbde)); + + shbde->log_func = log_func; + + shbde->pcic16_read = linux_pcic16_read; + shbde->pcic16_write = linux_pcic16_write; + shbde->pcic32_read = linux_pcic32_read; + shbde->pcic32_write = linux_pcic32_write; + + shbde->io32_read = linux_io32_read; + shbde->io32_write = linux_io32_write; + + shbde->usleep = linux_usleep; + + shbde->pci_parent_device_get = linux_pci_parent_device_get; + + return 0; +} diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_shbde.h b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_shbde.h new file mode 100644 index 0000000000..73d497925e --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_shbde.h @@ -0,0 +1,34 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#ifndef __LINUX_SHBDE_H__ +#define __LINUX_SHBDE_H__ + +#include +#include +#include + +extern int +linux_shbde_hal_init(shbde_hal_t *shbde, shbde_log_func_t log_func); + +#endif /* __LINUX_SHBDE_H__ */ diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/shared/mpool.c b/platform/broadcom/saibcm-modules/systems/bde/linux/shared/mpool.c new file mode 100644 index 0000000000..7f7332b3a7 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/shared/mpool.c @@ -0,0 +1,295 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: mpool.c,v 1.18 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ + +#include + +#ifdef __KERNEL__ + +/* + * Abstractions used when compiling for Linux kernel mode. + */ + +#include + +/* + * We cannot use the linux kernel SAL for MALLOC/FREE because + * the current implementation of sal_alloc() allocates memory + * out of an mpool created by this module... + */ +#define MALLOC(x) kmalloc(x, GFP_ATOMIC) +#define FREE(x) kfree(x) + +static spinlock_t _mpool_lock; +#define MPOOL_LOCK_INIT() spin_lock_init(&_mpool_lock) +#define MPOOL_LOCK() unsigned long flags; spin_lock_irqsave(&_mpool_lock, flags) +#define MPOOL_UNLOCK() spin_unlock_irqrestore(&_mpool_lock, flags) + +#else /* !__KERNEL__*/ + +/* + * Abstractions used when compiling for Linux user mode. + */ + +#include +#include + +#define MALLOC(x) malloc(x) +#define FREE(x) free(x) + +static sal_sem_t _mpool_lock; +#define MPOOL_LOCK_INIT() _mpool_lock = sal_sem_create("mpool_lock", 1, 1) +#define MPOOL_LOCK() sal_sem_take(_mpool_lock, sal_sem_FOREVER) +#define MPOOL_UNLOCK() sal_sem_give(_mpool_lock) + +#endif /* __KERNEL__ */ + +/* Allow external override for system cache line size */ +#ifndef BCM_CACHE_LINE_BYTES +#ifdef L1_CACHE_BYTES +#define BCM_CACHE_LINE_BYTES L1_CACHE_BYTES +#else +#define BCM_CACHE_LINE_BYTES 128 /* Should be fine on most platforms */ +#endif +#endif + +typedef struct mpool_mem_s { + unsigned char *address; + int size; + struct mpool_mem_s *next; +} mpool_mem_t; + +/* + * Function: mpool_init + * + * Purpose: + * Initialize mpool lock. + * Parameters: + * None + * Returns: + * Always 0 + */ +int +mpool_init(void) +{ + MPOOL_LOCK_INIT(); + return 0; +} + +#ifdef TRACK_DMA_USAGE +static int _dma_mem_used = 0; +#endif + +/* + * Function: mpool_alloc + * + * Purpose: + * Allocate memory block from mpool. + * Parameters: + * pool - mpool handle (from mpool_create) + * size - size of memory block to allocate + * Returns: + * Pointer to allocated memory block or NULL if allocation fails. + */ +void * +mpool_alloc(mpool_handle_t pool, int size) +{ + mpool_mem_t *ptr = pool, *newptr = NULL; + int mod; + + MPOOL_LOCK(); + + mod = size & (BCM_CACHE_LINE_BYTES - 1); + if (mod != 0 ) { + size += (BCM_CACHE_LINE_BYTES - mod); + } + while (ptr && ptr->next) { + if (ptr->next->address - (ptr->address + ptr->size) >= size) { + break; + } + ptr = ptr->next; + } + + if (!(ptr && ptr->next)) { + MPOOL_UNLOCK(); + return NULL; + } + newptr = MALLOC(sizeof(mpool_mem_t)); + if (!newptr) { + MPOOL_UNLOCK(); + return NULL; + } + + newptr->address = ptr->address + ptr->size; + newptr->size = size; + newptr->next = ptr->next; + ptr->next = newptr; +#ifdef TRACK_DMA_USAGE + _dma_mem_used += size; +#endif + MPOOL_UNLOCK(); + + return newptr->address; +} + + +/* + * Function: mpool_free + * + * Purpose: + * Free memory block allocated from mpool.. + * Parameters: + * pool - mpool handle (from mpool_create) + * addr - address of memory block to free + * Returns: + * Nothing + */ +void +mpool_free(mpool_handle_t pool, void *addr) +{ + unsigned char *address = (unsigned char *)addr; + mpool_mem_t *ptr = pool, *prev = NULL; + + MPOOL_LOCK(); + + while (ptr && ptr->next) { + if (ptr->next->address == address) { +#ifdef TRACK_DMA_USAGE + _dma_mem_used -= ptr->next->size; +#endif + break; + } + ptr = ptr->next; + } + + if (ptr && ptr->next) { + prev = ptr; + ptr = ptr->next; + prev->next = ptr->next; + FREE(ptr); + } + + MPOOL_UNLOCK(); +} + +/* + * Function: mpool_create + * + * Purpose: + * Create and initialize mpool control structures. + * Parameters: + * base_ptr - pointer to mpool memory block + * size - total size of mpool memory block + * Returns: + * mpool handle + * Notes + * The mpool handle returned must be used for subsequent + * memory allocations from the mpool. + */ +mpool_handle_t +mpool_create(void *base_ptr, int size) +{ + mpool_mem_t *head, *tail; + int mod = (int)(((unsigned long)base_ptr) & (BCM_CACHE_LINE_BYTES - 1)); + + MPOOL_LOCK(); + + if (mod) { + base_ptr = (char*)base_ptr + (BCM_CACHE_LINE_BYTES - mod); + size -= (BCM_CACHE_LINE_BYTES - mod); + } + size &= ~(BCM_CACHE_LINE_BYTES - 1); + + + head = (mpool_mem_t *)MALLOC(sizeof(mpool_mem_t)); + if (head == NULL) { + return NULL; + } + tail = (mpool_mem_t *)MALLOC(sizeof(mpool_mem_t)); + if (tail == NULL) { + FREE(head); + return NULL; + } + + head->size = tail->size = 0; + head->address = base_ptr; + tail->address = head->address + size; + head->next = tail; + tail->next = NULL; + + MPOOL_UNLOCK(); + + return head; +} + +/* + * Function: mpool_destroy + * + * Purpose: + * Free mpool control structures. + * Parameters: + * pool - mpool handle (from mpool_create) + * Returns: + * Always 0 + */ +int +mpool_destroy(mpool_handle_t pool) +{ + mpool_mem_t *ptr, *next; + + MPOOL_LOCK(); + + for (ptr = pool; ptr; ptr = next) { + next = ptr->next; + FREE(ptr); + } + + MPOOL_UNLOCK(); + + return 0; +} + +/* + * Function: mpool_usage + * + * Purpose: + * Report total sum of allocated mpool memory. + * Parameters: + * pool - mpool handle (from mpool_create) + * Returns: + * Number of bytes currently allocated using mpool_alloc. + */ +int +mpool_usage(mpool_handle_t pool) +{ + int usage = 0; + mpool_mem_t *ptr; + + MPOOL_LOCK(); + + for (ptr = pool; ptr; ptr = ptr->next) { + usage += ptr->size; + } + + MPOOL_UNLOCK(); + + return usage; +} diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/Makefile b/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/Makefile new file mode 100644 index 0000000000..ac8b04ac9b --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/Makefile @@ -0,0 +1,71 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# -*- Makefile -*- +# $Id: Makefile,v 1.1 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ +# +LOCALDIR = systems/bde/linux/user/kernel + +# Make sure we build for the kernel if this is a user-mode build +ifneq ($(platform), ) +override-target=linux-$(platform) +endif + +include $(SDK)/make/Make.config + +LIBS = $(LIBDIR)/libkern.a + +ifneq ($(kernel_version),2_4) +KERNEL_MODULE_DIR = kernel_module + +THIS_MOD_NAME := linux-user-bde +MODULE = $(LIBDIR)/$(THIS_MOD_NAME).o +KMODULE = $(LIBDIR)/$(THIS_MOD_NAME).ko + +build: kernel_libs $(MODULE) $(KMODULE) +else +MODULE = $(LIBDIR)/linux-user-bde.o + +build: kernel_libs $(MODULE) +endif + +KBUILD_EXTRA_SYMBOLS := ${BLDDIR}/../../kernel/kernel_module/Module.symvers + +$(MODULE): $(BLDDIR)/.tree $(BOBJS) $(LIBS) + $(LD) $(MODULE_LDFLAGS) -r -d $(BOBJS) $(LIBS) -o $@ +ifneq ($(kernel_version),2_4) +$(KMODULE): $(MODULE) + rm -fr $(BLDDIR)/$(KERNEL_MODULE_DIR) + mkdir $(BLDDIR)/$(KERNEL_MODULE_DIR) + cp ${SDK}/make/Makefile.linux-kmodule $(BLDDIR)/$(KERNEL_MODULE_DIR)/Makefile + cat ${KBUILD_EXTRA_SYMBOLS} > $(BLDDIR)/$(KERNEL_MODULE_DIR)/Module.symvers + MOD_NAME=$(THIS_MOD_NAME) $(MAKE) -C $(BLDDIR)/$(KERNEL_MODULE_DIR) $(THIS_MOD_NAME).ko +endif + +kernel_libs: + $(MAKE) -C $(SDK)/systems/linux/kernel/modules/shared + +include $(SDK)/make/Make.depend + +# Make.depend is before clean:: so that Make.depend's clean:: runs first. + +clean:: + $(MAKE) -C $(SDK)/systems/linux/kernel/modules/shared $@ + $(RM) $(BOBJS) $(MODULE) + +.PHONY: build kernel_libs diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.c b/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.c new file mode 100644 index 0000000000..c237f9429e --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.c @@ -0,0 +1,1264 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: linux-user-bde.c,v 1.80 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + * + * Linux User BDE Helper Module + */ +#include +#include +#include + +#include +#include +#include + +#include "linux-user-bde.h" + +#ifdef KEYSTONE +#include +#endif + + +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_DESCRIPTION("User BDE Helper Module"); +MODULE_LICENSE("GPL"); + +/* CMIC/CMICe defines */ +#define CMIC_IRQ_STAT 0x00000144 +#define CMIC_IRQ_MASK 0x00000148 +#define CMIC_IRQ_MASK_1 0x0000006C +#define CMIC_IRQ_MASK_2 0x00000070 + +/* CMICm defines */ +#define CMIC_CMCx_IRQ_STAT0_OFFSET(x) (0x31400 + (0x1000 * x)) +#define CMIC_CMCx_IRQ_STAT1_OFFSET(x) (0x31404 + (0x1000 * x)) +#define CMIC_CMCx_IRQ_STAT2_OFFSET(x) (0x31408 + (0x1000 * x)) +#define CMIC_CMCx_IRQ_STAT3_OFFSET(x) (0x3140c + (0x1000 * x)) +#define CMIC_CMCx_IRQ_STAT4_OFFSET(x) (0x31410 + (0x1000 * x)) + +#define CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(x) (0x31414 + (0x1000 * x)) +#define CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(x) (0x31418 + (0x1000 * x)) +#define CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(x) (0x3141c + (0x1000 * x)) +#define CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(x) (0x31420 + (0x1000 * x)) +#define CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(x) (0x31424 + (0x1000 * x)) + +/* CMICd defines */ +#define CMIC_CMCx_IRQ_STAT5_OFFSET(x) (0x314b0 + (0x1000 * x)) +#define CMIC_CMCx_IRQ_STAT6_OFFSET(x) (0x314b4 + (0x1000 * x)) +#define CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(x) (0x314b8 + (0x1000 * x)) +#define CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(x) (0x314bc + (0x1000 * x)) + +#define CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(x) (0x31428 + (0x1000 * x)) +#define CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(x) (0x3142c + (0x1000 * x)) +#define CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(x) (0x31430 + (0x1000 * x)) +#define CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(x) (0x31434 + (0x1000 * x)) +#define CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(x) (0x31438 + (0x1000 * x)) + +/* CMICX defines */ +#define INTC_INTR_REG_NUM (8) + +#define INTC_INTR_ENABLE_REG0 (0x180130f0) +#define INTC_INTR_STATUS_REG0 (0x18013190) +#define INTC_INTR_RAW_STATUS_REG0 (0x18013140) + +#define INTC_INTR_ENABLE_BASE (INTC_INTR_ENABLE_REG0) +#define INTC_INTR_STATUS_BASE (INTC_INTR_STATUS_REG0) +#define INTC_INTR_RAW_STATUS_BASE (INTC_INTR_RAW_STATUS_REG0) + + +#define READ_INTC_INTR(d, reg, v) \ + (v = user_bde->iproc_read(d, reg)) +#define WRITE_INTC_INTR(d, reg, v) \ + (user_bde->iproc_write(d, reg, v)) + +/* Allow override of default CMICm CMC */ +#ifndef BDE_CMICM_PCIE_CMC +#define BDE_CMICM_PCIE_CMC 0 +#endif + +/* Allow override of default CMICm CMC */ +#ifndef BDE_CMICD_PCIE_CMC +#define BDE_CMICD_PCIE_CMC 0 +#endif + +/* Defines used to distinguish CMICe from CMICm */ +#define CMICE_DEV_REV_ID (0x178 / sizeof(uint32)) + +static ibde_t *user_bde = NULL; + +typedef void (*isr_f)(void *); + +typedef struct bde_ctrl_s { + uint32 dev_type; + int irq; + int enabled; + int devid; + isr_f isr; + uint32 *ba; + int inst; /* associate to _bde_inst_resource[] */ +} bde_ctrl_t; + +#define VALID_DEVICE(_n) (_n < LINUX_BDE_MAX_DEVICES) + +static bde_ctrl_t _devices[LINUX_BDE_MAX_DEVICES]; + +static wait_queue_head_t _ether_interrupt_wq; +static atomic_t _ether_interrupt_has_taken_place = ATOMIC_INIT(0); + +/* + * Multiple instance resource data structure. + * To keep the DMA resource per instance. + * And track the DMA pool usage. + */ +static int _bde_multi_inst = 0; + +typedef struct { + unsigned int inst_id; + unsigned int dma_offset; + unsigned int dma_size; + wait_queue_head_t intr_wq; + atomic_t intr; +} bde_inst_resource_t; + +static bde_inst_resource_t _bde_inst_resource[LINUX_BDE_MAX_DEVICES]; + +typedef struct { + phys_addr_t cpu_pbase; /* CPU physical base address of the DMA pool */ + phys_addr_t dma_pbase; /* Bus base address of the DMA pool */ + uint32 total_size; /* Total size of the pool in MB */ + uint32 offset; /* Current offset of the pool in MB */ +}_dma_pool_t; + +static _dma_pool_t _dma_pool; + +#define ONE_MB (1024 * 1024) + +#ifdef KEYSTONE +/* + * Enforce PCIE transaction ordering. Commit the write transaction. + */ + +#define SSOC_WRITEL(val, addr) \ + do { \ + writel((val), (addr)); \ + __asm__ __volatile__("sync"); \ + } while(0) + +#else + +#define SSOC_WRITEL(val, addr) \ + writel((val), (addr)) + +#endif +/* + * Function: _interrupt + * + * Purpose: + * Interrupt Handler. + * Mask all interrupts on device and wake up interrupt + * thread. It is assumed that the interrupt thread unmasks + * interrupts again when interrupt handling is complete. + * Parameters: + * ctrl - BDE control structure for this device. + * Returns: + * Nothing + */ +static void +_cmic_interrupt(bde_ctrl_t *ctrl) +{ + int d; + uint32_t mask = 0, stat, imask = 0, fmask = 0; + bde_inst_resource_t *res; + + d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t)); + res = &_bde_inst_resource[ctrl->inst]; + + /* Check for secondary interrupt handler */ + if (lkbde_irq_mask_get(d, &mask, &fmask) < 0) { + fmask = 0; + } + + if (fmask != 0) { + imask = mask & ~fmask; + /* Check for pending user mode interrupts */ + stat = user_bde->read(d, CMIC_IRQ_STAT); + if ((stat & imask) == 0) { + /* All handled in kernel mode */ + lkbde_irq_mask_set(d, CMIC_IRQ_MASK, imask, 0); + return; + } + } + + lkbde_irq_mask_set(d, CMIC_IRQ_MASK, 0, 0); + + atomic_set(&res->intr, 1); + +#ifdef BDE_LINUX_NON_INTERRUPTIBLE + wake_up(&res->intr_wq); +#else + wake_up_interruptible(&res->intr_wq); +#endif +} + +static void +_cmicx_interrupt(bde_ctrl_t *ctrl) +{ + int d, i; + bde_inst_resource_t *res; + + d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t)); + res = &_bde_inst_resource[ctrl->inst]; + + /* Disable all interrupts.. Re-enable unserviced interrupts later + * So as to avoid getting new interrupts until the user level driver + * enumerates the interrupts to be serviced + */ + for (i = 0 ; i < INTC_INTR_REG_NUM ; i++) { + WRITE_INTC_INTR(d, (INTC_INTR_ENABLE_BASE + 4*i), 0); + } + + /* Notify */ + atomic_set(&res->intr, 1); +#ifdef BDE_LINUX_NON_INTERRUPTIBLE + wake_up(&res->intr_wq); +#else + wake_up_interruptible(&res->intr_wq); +#endif +} + +static void +_cmicm_interrupt(bde_ctrl_t *ctrl) +{ + int d; + int cmc = BDE_CMICM_PCIE_CMC; + uint32 stat, mask = 0, fmask = 0, imask = 0; + bde_inst_resource_t *res; + + d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t)); + res = &_bde_inst_resource[ctrl->inst]; + + lkbde_irq_mask_get(d, &mask, &fmask); + + while (fmask) { + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT0_OFFSET(cmc)); + imask = mask & ~fmask; + if (stat & imask) { + break; + } + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT1_OFFSET(cmc)); + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc)); + } else { + mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc)); + } + if (stat & mask) { + break; + } + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT2_OFFSET(cmc)); + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc)); + } else { + mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc)); + } + if (stat & mask) { + break; + } + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT3_OFFSET(cmc)); + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc)); + } else { + mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc)); + } + if (stat & mask) { + break; + } + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT4_OFFSET(cmc)); + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc)); + } else { + mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc)); + } + if (stat & mask) { + break; + } + return; + } + + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + lkbde_irq_mask_set(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(cmc), 0, 0); + user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(1), 0); + user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(2), 0); + } + else { + lkbde_irq_mask_set(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(cmc), 0, 0); + user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(1), 0); + user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(2), 0); + } + atomic_set(&res->intr, 1); +#ifdef BDE_LINUX_NON_INTERRUPTIBLE + wake_up(&res->intr_wq); +#else + wake_up_interruptible(&res->intr_wq); +#endif +} + + +static void +_cmicd_interrupt(bde_ctrl_t *ctrl) +{ + int d; + int cmc = BDE_CMICD_PCIE_CMC; + uint32 stat, mask = 0, fmask = 0, imask = 0; + bde_inst_resource_t *res; + + d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t)); + res = &_bde_inst_resource[ctrl->inst]; + lkbde_irq_mask_get(d, &mask, &fmask); + + while (fmask) { + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT0_OFFSET(cmc)); + imask = mask & ~fmask; + if (stat & imask) { + break; + } + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT1_OFFSET(cmc)); + mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc)); + if (stat & mask) { + break; + } + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT2_OFFSET(cmc)); + mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc)); + if (stat & mask) { + break; + } + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT3_OFFSET(cmc)); + mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc)); + if (stat & mask) { + break; + } + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT4_OFFSET(cmc)); + mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc)); + if (stat & mask) { + break; + } + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT5_OFFSET(cmc)); + mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(cmc)); + if (stat & mask) { + break; + } + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT6_OFFSET(cmc)); + mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(cmc)); + if (stat & mask) { + break; + } + return; + } + + lkbde_irq_mask_set(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(cmc), 0, 0); + user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(cmc), 0); + + atomic_set(&res->intr, 1); +#ifdef BDE_LINUX_NON_INTERRUPTIBLE + wake_up(&res->intr_wq); +#else + wake_up_interruptible(&res->intr_wq); +#endif +} + +static void +_bcm88750_interrupt(bde_ctrl_t *ctrl) +{ + int d; + bde_inst_resource_t *res; + + d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t)); + res = &_bde_inst_resource[ctrl->inst]; + lkbde_irq_mask_set(d, CMIC_IRQ_MASK, 0, 0); + + lkbde_irq_mask_set(d, CMIC_IRQ_MASK_1, 0, 0); + lkbde_irq_mask_set(d, CMIC_IRQ_MASK_2, 0, 0); + atomic_set(&res->intr, 1); +#ifdef BDE_LINUX_NON_INTERRUPTIBLE + wake_up(&res->intr_wq); +#else + wake_up_interruptible(&res->intr_wq); +#endif +} + +static void +_qe2k_interrupt(bde_ctrl_t *ctrl) +{ + bde_inst_resource_t *res; + + res = &_bde_inst_resource[ctrl->inst]; + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x20/sizeof(uint32)); + + atomic_set(&res->intr, 1); +#ifdef BDE_LINUX_NON_INTERRUPTIBLE + wake_up(&res->intr_wq); +#else + wake_up_interruptible(&res->intr_wq); +#endif +} + +static void +_fe2k_interrupt(bde_ctrl_t *ctrl) +{ + bde_inst_resource_t *res; + + res = &_bde_inst_resource[ctrl->inst]; + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x18/sizeof(uint32)); /* PC_INTERRUPT_MASK */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x24/sizeof(uint32)); /* PC_ERROR0_MASK */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x2c/sizeof(uint32)); /* PC_ERROR1_MASK */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x34/sizeof(uint32)); /* PC_UNIT_MASK */ + + atomic_set(&res->intr, 1); +#ifdef BDE_LINUX_NON_INTERRUPTIBLE + wake_up(&res->intr_wq); +#else + wake_up_interruptible(&res->intr_wq); +#endif +} + +static void +_fe2kxt_interrupt(bde_ctrl_t *ctrl) +{ + bde_inst_resource_t *res; + + res = &_bde_inst_resource[ctrl->inst]; + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x2c/sizeof(uint32)); /* PC_INTERRUPT_MASK */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x38/sizeof(uint32)); /* PC_ERROR0_MASK */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x40/sizeof(uint32)); /* PC_ERROR1_MASK */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x50/sizeof(uint32)); /* PC_UNIT_MASK */ + + atomic_set(&res->intr, 1); +#ifdef BDE_LINUX_NON_INTERRUPTIBLE + wake_up(&res->intr_wq); +#else + wake_up_interruptible(&res->intr_wq); +#endif +} + +static void +_bme3200_interrupt(bde_ctrl_t *ctrl) +{ + bde_inst_resource_t *res; + + res = &_bde_inst_resource[ctrl->inst]; + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x54/sizeof(uint32)); /* PI_PT_ERROR0 */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x5c/sizeof(uint32)); /* PI_PT_ERROR1 */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x64/sizeof(uint32)); /* PI_PT_ERROR2 */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x6c/sizeof(uint32)); /* PI_PT_ERROR3 */ + + atomic_set(&res->intr, 1); +#ifdef BDE_LINUX_NON_INTERRUPTIBLE + wake_up(&res->intr_wq); +#else + wake_up_interruptible(&res->intr_wq); +#endif +} + + +static void +_bm9600_interrupt(bde_ctrl_t *ctrl) +{ + bde_inst_resource_t *res; + + res = &_bde_inst_resource[ctrl->inst]; + + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x5c/sizeof(uint32)); /* PI_INTERRUPT_MASK */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0xc/sizeof(uint32)); /* PI_UNIT_INTERRUPT0_MASK */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x14/sizeof(uint32)); /* PI_UNIT_INTERRUPT1_MASK */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x1c/sizeof(uint32)); /* PI_UNIT_INTERRUPT2_MASK */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x24/sizeof(uint32)); /* PI_UNIT_INTERRUPT3_MASK */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x2c/sizeof(uint32)); /* PI_UNIT_INTERRUPT4_MASK */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x34/sizeof(uint32)); /* PI_UNIT_INTERRUPT5_MASK */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x3c/sizeof(uint32)); /* PI_UNIT_INTERRUPT6_MASK */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x44/sizeof(uint32)); /* PI_UNIT_INTERRUPT7_MASK */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x4c/sizeof(uint32)); /* PI_UNIT_INTERRUPT8_MASK */ + SSOC_WRITEL(0xffffffff, ctrl->ba + 0x54/sizeof(uint32)); /* PI_UNIT_INTERRUPT9_MASK */ + + atomic_set(&res->intr, 1); +#ifdef BDE_LINUX_NON_INTERRUPTIBLE + wake_up(&res->intr_wq); +#else + wake_up_interruptible(&res->intr_wq); +#endif +} + + + +/* The actual interrupt handler of ethernet devices */ +static void +_ether_interrupt(bde_ctrl_t *ctrl) +{ +#ifdef KEYSTONE + /* + * Since the two GMAC cores are sharing the same IRQ. + * Add the checking to handle the interrupt events. + */ + if ((ctrl->devid == BCM53000_GMAC_ID)) { + if ((readl(ctrl->ba + 0x020/4) & readl(ctrl->ba + 0x024/4)) == 0) { + return; + } + } +#endif + SSOC_WRITEL(0, ctrl->ba + 0x024/4); + + atomic_set(&_ether_interrupt_has_taken_place, 1); +#ifdef BDE_LINUX_NON_INTERRUPTIBLE + wake_up(&_ether_interrupt_wq); +#else + wake_up_interruptible(&_ether_interrupt_wq); +#endif +} + + +static struct _intr_mode_s { + isr_f isr; + const char *name; +} _intr_mode[] = { + { (isr_f)_cmic_interrupt, "CMIC/CMICe" }, + { (isr_f)_cmicm_interrupt, "CMICm" }, + { (isr_f)_cmicd_interrupt, "CMICd" }, + { (isr_f)_qe2k_interrupt, "QE2K" }, + { (isr_f)_fe2k_interrupt, "FE2K" }, + { (isr_f)_fe2kxt_interrupt, "FE2KXT" }, + { (isr_f)_bme3200_interrupt, "BME3200" }, + { (isr_f)_bm9600_interrupt, "BM9600" }, + { (isr_f)_bcm88750_interrupt, "BCM88750" }, + { (isr_f)_cmicx_interrupt, "CMICx" }, + { NULL, NULL } +}; + +static const char * +_intr_mode_str(void *isr) +{ + int imx; + + imx = 0; + while (_intr_mode[imx].isr != NULL) { + if (isr == _intr_mode[imx].isr) { + return _intr_mode[imx].name; + } + imx++; + } + return NULL; +} + +static void +_devices_init(int d) +{ + bde_ctrl_t *ctrl; + uint32 ver; + + ctrl = &_devices[d]; + /* Initialize our control info */ + ctrl->dev_type = user_bde->get_dev_type(d); + ctrl->devid = user_bde->get_dev(d)->device; + ctrl->inst = 0; + + if (BDE_DEV_MEM_MAPPED(ctrl->dev_type)) { + ctrl->enabled = 0; + ctrl->ba = lkbde_get_dev_virt(d); + } + if (ctrl->dev_type & BDE_SWITCH_DEV_TYPE) { + switch (user_bde->get_dev(d)->device) { + case QE2000_DEVICE_ID: + ctrl->isr = (isr_f)_qe2k_interrupt; + break; + case BCM88020_DEVICE_ID: + ctrl->isr = (isr_f)_fe2k_interrupt; + break; + case BCM88025_DEVICE_ID: + ctrl->isr = (isr_f)_fe2kxt_interrupt; + break; + case BME3200_DEVICE_ID: + ctrl->isr = (isr_f)_bme3200_interrupt; + break; + case BM9600_DEVICE_ID: + ctrl->isr = (isr_f)_bm9600_interrupt; + break; + case BCM88750_DEVICE_ID: + case BCM88753_DEVICE_ID: + case BCM88754_DEVICE_ID: + case BCM88755_DEVICE_ID: + case BCM88752_DEVICE_ID: + ctrl->isr = (isr_f)_bcm88750_interrupt; + break; + /* FIXME: might use _devices[i].dev_type & BDE_AXI_DEV_TYPE*/ + case BCM88670_DEVICE_ID: + case BCM88671_DEVICE_ID: + case BCM88671M_DEVICE_ID: + case BCM88672_DEVICE_ID: + case BCM88673_DEVICE_ID: + case BCM88674_DEVICE_ID: + case BCM88675_DEVICE_ID: + case BCM88675M_DEVICE_ID: + case BCM88676_DEVICE_ID: + case BCM88676M_DEVICE_ID: + case BCM88677_DEVICE_ID: + case BCM88678_DEVICE_ID: + case BCM88679_DEVICE_ID: + case BCM88370_DEVICE_ID: + case BCM88371_DEVICE_ID: + case BCM88371M_DEVICE_ID: + case BCM88375_DEVICE_ID: + case BCM88376_DEVICE_ID: + case BCM88376M_DEVICE_ID: + case BCM88377_DEVICE_ID: + case BCM88378_DEVICE_ID: + case BCM88379_DEVICE_ID: + case BCM88681_DEVICE_ID: + case BCM88682_DEVICE_ID: + case BCM88683_DEVICE_ID: + case BCM88684_DEVICE_ID: + case BCM88685_DEVICE_ID: + case BCM88380_DEVICE_ID: + case BCM88381_DEVICE_ID: + case BCM88680_DEVICE_ID: + case BCM88690_DEVICE_ID: + case BCM88770_DEVICE_ID: + case BCM88773_DEVICE_ID: + case BCM88774_DEVICE_ID: + case BCM88775_DEVICE_ID: + case BCM88776_DEVICE_ID: + case BCM88777_DEVICE_ID: + case BCM88470_DEVICE_ID: + case BCM88470P_DEVICE_ID: + case BCM88471_DEVICE_ID: + case BCM88473_DEVICE_ID: + case BCM88474_DEVICE_ID: + case BCM88474H_DEVICE_ID: + case BCM88476_DEVICE_ID: + case BCM88477_DEVICE_ID: + + case BCM88270_DEVICE_ID: + case BCM88272_DEVICE_ID: + case BCM88273_DEVICE_ID: + case BCM88278_DEVICE_ID: + case BCM8206_DEVICE_ID: + case BCM88950_DEVICE_ID: + case BCM88953_DEVICE_ID: + case BCM88954_DEVICE_ID: + case BCM88955_DEVICE_ID: + case BCM88956_DEVICE_ID: + case BCM88790_DEVICE_ID: + case BCM88772_DEVICE_ID: + case BCM88952_DEVICE_ID: + ctrl->isr = (isr_f)_cmicd_interrupt; + break; + default: + /* Get CMIC version */ + if (user_bde->get_cmic_ver(d, &ver) != 0) { + ver = -1; + } + /* check if version is CMICX */ + if (ver == 0x04) { + ctrl->isr = (isr_f)_cmicx_interrupt; + } else { + ctrl->isr = (isr_f)_cmic_interrupt; + if ((ctrl->dev_type & BDE_256K_REG_SPACE) && +#ifdef BCM_PETRA_SUPPORT /* FIXME remove code when hardware design is fixed */ + ctrl->devid != 0x1234 && +#endif + readl(ctrl->ba + CMICE_DEV_REV_ID) == 0) { + ctrl->isr = (isr_f)_cmicm_interrupt; + } + } + break; + } + if (_intr_mode_str(ctrl->isr) == NULL) { + gprintk("Warning: Unknown interrupt mode\n"); + } + } +} +/* + * Function: _init + * + * Purpose: + * Module initialization. + * Attaches to kernel BDE. + * Parameters: + * None + * Returns: + * Always 0 + */ +static int +_init(void) +{ + int i; + phys_addr_t cpu_pbase, dma_pbase; + ssize_t dmasize; + bde_inst_resource_t *res; + + /* Connect to the kernel bde */ + if ((linux_bde_create(NULL, &user_bde) < 0) || user_bde == NULL) { + return -ENODEV; + } + + init_waitqueue_head(&_ether_interrupt_wq); + + lkbde_get_dma_info(&cpu_pbase, &dma_pbase, &dmasize); + + memset(&_dma_pool, 0, sizeof(_dma_pool)); + _dma_pool.cpu_pbase = cpu_pbase; + _dma_pool.dma_pbase = dma_pbase; + _dma_pool.total_size = dmasize / ONE_MB; + + memset(_devices, 0, sizeof(_devices)); + + /* Use _bde_inst_resource[0] as the default resource */ + memset(_bde_inst_resource, 0, sizeof(_bde_inst_resource)); + res = &_bde_inst_resource[0]; + res->dma_offset = 0; + res->dma_size = _dma_pool.total_size; + init_waitqueue_head(&res->intr_wq); + atomic_set(&res->intr, 0); + + for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) { + res->inst_id |= (1 << i); + _devices_init(i); + } + return 0; +} + +/* + * Function: _cleanup + * + * Purpose: + * Module cleanup function. + * Parameters: + * None + * Returns: + * Always 0 + */ +static int +_cleanup(void) +{ + int i; + + if (user_bde) { + for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) { + if (_devices[i].enabled && + BDE_DEV_MEM_MAPPED(_devices[i].dev_type)) { + user_bde->interrupt_disconnect(i); + } + lkbde_dev_instid_set(i, 0); + } + linux_bde_destroy(user_bde); + user_bde = NULL; + } + return 0; +} + +/* + * Function: _pprint + * + * Purpose: + * Print proc filesystem information. + * Parameters: + * None + * Returns: + * Always 0 + */ +static int +_pprint(void) +{ + int idx; + const char *name; + bde_inst_resource_t *res; + uint32 state, instid; + + pprintf("Broadcom Device Enumerator (%s)\n", LINUX_USER_BDE_NAME); + for (idx = 0; idx < user_bde->num_devices(BDE_ALL_DEVICES); idx++) { + name = _intr_mode_str(_devices[idx].isr); + if (name == NULL) { + name = "unknown"; + } + pprintf("\t%d: Interrupt mode %s ",idx, name); + (void)lkbde_dev_state_get(idx, &state); + if (state == BDE_DEV_STATE_REMOVED) { + pprintf(" Device REMOVED ! \n"); + } else { + (void)lkbde_dev_instid_get(idx, &instid); + if (instid) { + pprintf("Inst id 0x%x\n",instid); + } else { + pprintf("\n"); + } + } + } + pprintf("Instance resource \n"); + + for (idx = 0; idx < user_bde->num_devices(BDE_ALL_DEVICES); idx++) { + res = &_bde_inst_resource[idx]; + if (res->inst_id) { + pprintf("\tDev mask 0x%x : " + "DMA offset %d size %d MB\n", + res->inst_id, + res->dma_offset, + res->dma_size); + } + } + + return 0; +} + +/* + * Allocate the DMA resource from DMA pool + * Parameter : + * dma_size (IN): allocate dma_size in MB + * dma_offset (OUT): dma offset in MB + */ +static int +_dma_resource_alloc(unsigned int dma_size, unsigned int *dma_offset) +{ + uint32 left; + + left = _dma_pool.total_size - _dma_pool.offset; + if (dma_size > left) { + gprintk("ERROR: Run out the dma resource!\n"); + return -1; + } + *dma_offset = _dma_pool.offset; + _dma_pool.offset += dma_size; + return 0; +} + +static int +_dma_resource_get(int inst_id, phys_addr_t *cpu_pbase, phys_addr_t *dma_pbase, ssize_t* size) +{ + int i; + unsigned int dma_size = 0, dma_offset = 0; + bde_inst_resource_t *res; + + for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) { + res = &_bde_inst_resource[i]; + if (res->inst_id == inst_id) { + dma_size = res->dma_size; + dma_offset = res->dma_offset; + break; + } + } + + *cpu_pbase = _dma_pool.cpu_pbase + dma_offset * ONE_MB; + *dma_pbase = _dma_pool.dma_pbase + dma_offset * ONE_MB; + *size = dma_size * ONE_MB; + + return 0; +} + +static int +_instance_validate(unsigned int inst_id, unsigned int dmasize) +{ + int i; + bde_inst_resource_t *res; + + for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) { + res = &_bde_inst_resource[i]; + if (res->inst_id == inst_id) { + if (res->dma_size != dmasize) { + if(_devices[i].inst == 0){ + /* Skip _instance_validate (not init yet) */ + return LUBDE_SUCCESS; + } + gprintk("ERROR: dma_size mismatch\n"); + return LUBDE_FAIL; + } + return (1); + } + } + return LUBDE_SUCCESS; +} + +static int +_device_reprobe(void) +{ + int i; + for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) { + if (_devices[i].devid == 0) { + _devices_init(i); + } + } + return 0; +} + +static int +_instance_attach(unsigned int inst_id, unsigned int dma_size) +{ + unsigned int dma_offset; + int i, exist; + bde_inst_resource_t *res; + int inst_idx = -1; + uint32 instid; + + /* Reprobe the system for hot-plugged device */ + _device_reprobe(); + + /* Validate the resource with inst_id */ + exist = _instance_validate(inst_id, dma_size); + if (exist < 0) { + return LUBDE_FAIL; + } + if (exist > 0) { + return LUBDE_SUCCESS; + } + if (_dma_resource_alloc(dma_size, &dma_offset) < 0) { + return LUBDE_FAIL; + } + for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) { + res = &_bde_inst_resource[i]; + if ((_bde_multi_inst == 0) || (res->inst_id == 0)) { + res->inst_id = inst_id; + res->dma_offset = dma_offset; + res->dma_size = dma_size; + _bde_multi_inst++; + inst_idx = i; + init_waitqueue_head(&res->intr_wq); + atomic_set(&res->intr, 0); + break; + } + } + + for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) { + if (inst_id & (1 << i)) { + _devices[i].inst = inst_idx; + /* Pass the instid to the kernel BDE */ + if (lkbde_dev_instid_get(i, &instid) == 0) { + if (!instid) { + lkbde_dev_instid_set(i, inst_id); + } + } + } + } + + return LUBDE_SUCCESS; +} + +/* + * Function: _ioctl + * + * Purpose: + * Handle IOCTL commands from user mode. + * Parameters: + * cmd - IOCTL cmd + * arg - IOCTL parameters + * Returns: + * 0 on success, <0 on error + */ +static int +_ioctl(unsigned int cmd, unsigned long arg) +{ + lubde_ioctl_t io; + phys_addr_t cpu_pbase, dma_pbase; + ssize_t size; + const ibde_dev_t *bde_dev; + int inst_id; + bde_inst_resource_t *res; + + if (copy_from_user(&io, (void *)arg, sizeof(io))) { + return -EFAULT; + } + + io.rc = LUBDE_SUCCESS; + + switch(cmd) { + case LUBDE_VERSION: + io.d0 = KBDE_VERSION; + break; + case LUBDE_GET_NUM_DEVICES: + io.d0 = user_bde->num_devices(io.dev); + break; + case LUBDE_GET_DEVICE: + if (!VALID_DEVICE(io.dev)) { + return -EINVAL; + } + bde_dev = user_bde->get_dev(io.dev); + if (bde_dev) { + io.d0 = bde_dev->device; + io.d1 = bde_dev->rev; + if (BDE_DEV_MEM_MAPPED(_devices[io.dev].dev_type)) { + /* Get physical address to map */ + io.d2 = lkbde_get_dev_phys(io.dev); + io.d3 = lkbde_get_dev_phys_hi(io.dev); + } + } else { + io.rc = LUBDE_FAIL; + } + break; + case LUBDE_GET_DEVICE_TYPE: + if (!VALID_DEVICE(io.dev)) { + return -EINVAL; + } + io.d0 = _devices[io.dev].dev_type; + break; + case LUBDE_GET_BUS_FEATURES: + user_bde->pci_bus_features(io.dev, (int *) &io.d0, (int *) &io.d1, + (int *) &io.d2); + break; + case LUBDE_PCI_CONFIG_PUT32: + if (!VALID_DEVICE(io.dev)) { + return -EINVAL; + } + if (_devices[io.dev].dev_type & BDE_PCI_DEV_TYPE) { + user_bde->pci_conf_write(io.dev, io.d0, io.d1); + } else { + io.rc = LUBDE_FAIL; + } + break; + case LUBDE_PCI_CONFIG_GET32: + if (!VALID_DEVICE(io.dev)) { + return -EINVAL; + } + if (_devices[io.dev].dev_type & BDE_PCI_DEV_TYPE) { + io.d0 = user_bde->pci_conf_read(io.dev, io.d0); + } else { + io.rc = LUBDE_FAIL; + } + break; + case LUBDE_GET_DMA_INFO: + inst_id = io.dev; + if (_bde_multi_inst){ + _dma_resource_get(inst_id, &cpu_pbase, &dma_pbase, &size); + } else { + lkbde_get_dma_info(&cpu_pbase, &dma_pbase, &size); + } + io.d0 = dma_pbase; + io.d1 = size; + /* Optionally enable DMA mmap via /dev/linux-kernel-bde */ + io.d2 = USE_LINUX_BDE_MMAP; + /* Get physical address for mmap */ + io.dx.dw[0] = cpu_pbase; +#ifdef PHYS_ADDRS_ARE_64BITS + io.dx.dw[1] = cpu_pbase >> 32; +#else + io.dx.dw[1] = 0; +#endif + break; + case LUBDE_ENABLE_INTERRUPTS: + if (!VALID_DEVICE(io.dev)) { + return -EINVAL; + } + if (_devices[io.dev].dev_type & BDE_SWITCH_DEV_TYPE) { + if (_devices[io.dev].isr && !_devices[io.dev].enabled) { + user_bde->interrupt_connect(io.dev, + _devices[io.dev].isr, + _devices+io.dev); + _devices[io.dev].enabled = 1; + } + } else { + /* Process ethernet device interrupt */ + /* FIXME: for multiple chips */ + if (!_devices[io.dev].enabled) { + user_bde->interrupt_connect(io.dev, + (void(*)(void *))_ether_interrupt, + _devices+io.dev); + _devices[io.dev].enabled = 1; + } + } + break; + case LUBDE_DISABLE_INTERRUPTS: + if (!VALID_DEVICE(io.dev)) { + return -EINVAL; + } + if (_devices[io.dev].enabled) { + user_bde->interrupt_disconnect(io.dev); + _devices[io.dev].enabled = 0; + } + break; + case LUBDE_WAIT_FOR_INTERRUPT: + if (!VALID_DEVICE(io.dev)) { + return -EINVAL; + } + if (_devices[io.dev].dev_type & BDE_SWITCH_DEV_TYPE) { + res = &_bde_inst_resource[_devices[io.dev].inst]; +#ifdef BDE_LINUX_NON_INTERRUPTIBLE + wait_event_timeout(res->intr_wq, + atomic_read(&res->intr) != 0, 100); + +#else + wait_event_interruptible(res->intr_wq, + atomic_read(&res->intr) != 0); +#endif + /* + * Even if we get multiple interrupts, we + * only run the interrupt handler once. + */ + atomic_set(&res->intr, 0); + } else { +#ifdef BDE_LINUX_NON_INTERRUPTIBLE + wait_event_timeout(_ether_interrupt_wq, + atomic_read(&_ether_interrupt_has_taken_place) != 0, 100); +#else + wait_event_interruptible(_ether_interrupt_wq, + atomic_read(&_ether_interrupt_has_taken_place) != 0); +#endif + /* + * Even if we get multiple interrupts, we + * only run the interrupt handler once. + */ + atomic_set(&_ether_interrupt_has_taken_place, 0); + } + break; + case LUBDE_USLEEP: + sal_usleep(io.d0); + break; + case LUBDE_UDELAY: + sal_udelay(io.d0); + break; + case LUBDE_SEM_OP: + switch (io.d0) { + case LUBDE_SEM_OP_CREATE: + io.p0 = (bde_kernel_addr_t)sal_sem_create("", io.d1, io.d2); + break; + case LUBDE_SEM_OP_DESTROY: + sal_sem_destroy((sal_sem_t)io.p0); + break; + case LUBDE_SEM_OP_TAKE: + io.rc = sal_sem_take((sal_sem_t)io.p0, io.d2); + break; + case LUBDE_SEM_OP_GIVE: + io.rc = sal_sem_give((sal_sem_t)io.p0); + break; + default: + io.rc = LUBDE_FAIL; + break; + } + break; + case LUBDE_WRITE_IRQ_MASK: + io.rc = lkbde_irq_mask_set(io.dev, io.d0, io.d1, 0); + break; + case LUBDE_SPI_READ_REG: + if (user_bde->spi_read(io.dev, io.d0, io.dx.buf, io.d1) == -1) { + io.rc = LUBDE_FAIL; + } + break; + case LUBDE_SPI_WRITE_REG: + if (user_bde->spi_write(io.dev, io.d0, io.dx.buf, io.d1) == -1) { + io.rc = LUBDE_FAIL; + } + break; + case LUBDE_READ_REG_16BIT_BUS: + io.d1 = user_bde->read(io.dev, io.d0); + break; + case LUBDE_WRITE_REG_16BIT_BUS: + io.rc = user_bde->write(io.dev, io.d0, io.d1); + break; +#if (defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT)) + case LUBDE_CPU_WRITE_REG: + { + if (lkbde_cpu_write(io.dev, io.d0, (uint32*)io.dx.buf) == -1) { + io.rc = LUBDE_FAIL; + } + break; + } + case LUBDE_CPU_READ_REG: + { + if (lkbde_cpu_read(io.dev, io.d0, (uint32*)io.dx.buf) == -1) { + io.rc = LUBDE_FAIL; + } + break; + } + case LUBDE_CPU_PCI_REGISTER: + { + if (lkbde_cpu_pci_register(io.dev) == -1) { + io.rc = LUBDE_FAIL; + } + break; + } +#endif + case LUBDE_DEV_RESOURCE: + if (!VALID_DEVICE(io.dev)) { + return -EINVAL; + } + bde_dev = user_bde->get_dev(io.dev); + if (bde_dev) { + if (BDE_DEV_MEM_MAPPED(_devices[io.dev].dev_type)) { + /* Get physical address to map */ + io.rc = lkbde_get_dev_resource(io.dev, io.d0, + &io.d1, &io.d2, &io.d3); + } + } else { + io.rc = LUBDE_FAIL; + } + break; + case LUBDE_IPROC_READ_REG: + io.d1 = user_bde->iproc_read(io.dev, io.d0); + if (io.d1 == -1) { + io.rc = LUBDE_FAIL; + } + break; + case LUBDE_IPROC_WRITE_REG: + if (user_bde->iproc_write(io.dev, io.d0, io.d1) == -1) { + io.rc = LUBDE_FAIL; + } + break; + case LUBDE_ATTACH_INSTANCE: + io.rc = _instance_attach(io.d0, io.d1); + break; + case LUBDE_GET_DEVICE_STATE: + io.rc = lkbde_dev_state_get(io.dev, &io.d0); + break; + default: + gprintk("Error: Invalid ioctl (%08x)\n", cmd); + io.rc = LUBDE_FAIL; + break; + } + + if (copy_to_user((void *)arg, &io, sizeof(io))) { + return -EFAULT; + } + + return 0; +} + +/* Workaround for broken Busybox/PPC insmod */ +static char _modname[] = LINUX_USER_BDE_NAME; + +static gmodule_t _gmodule = +{ + name: LINUX_USER_BDE_NAME, + major: LINUX_USER_BDE_MAJOR, + init: _init, + cleanup: _cleanup, + pprint: _pprint, + ioctl: _ioctl, +}; + +gmodule_t* +gmodule_get(void) +{ + _gmodule.name = _modname; + return &_gmodule; +} diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.h b/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.h new file mode 100644 index 0000000000..edf5f63bf5 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.h @@ -0,0 +1,113 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: linux-user-bde.h,v 1.23 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ + +#ifndef __LINUX_USER_BDE_H__ +#define __LINUX_USER_BDE_H__ + +#include +#include +#include +#ifndef __KERNEL__ +#include +#endif + +#if defined(SAL_BDE_32BIT_USER_64BIT_KERNEL) || defined(PTRS_ARE_64BITS) +typedef uint64_t bde_kernel_addr_t; +#else +typedef uint32_t bde_kernel_addr_t; +#endif + +/* Ioctl control structure */ +typedef struct { + unsigned int dev; /* Device ID */ + unsigned int rc; /* Operation Return Code */ + unsigned int d0; /* Operation specific data */ + unsigned int d1; + unsigned int d2; + unsigned int d3; + bde_kernel_addr_t p0; + union { + unsigned int dw[2]; + unsigned char buf[64]; + } dx; +} lubde_ioctl_t; + + +/* LUBDE ioctls */ +#define LUBDE_MAGIC 'L' + +#define LUBDE_VERSION _IO(LUBDE_MAGIC, 0) +#define LUBDE_GET_NUM_DEVICES _IO(LUBDE_MAGIC, 1) +#define LUBDE_GET_DEVICE _IO(LUBDE_MAGIC, 2) +#define LUBDE_PCI_CONFIG_PUT32 _IO(LUBDE_MAGIC, 3) +#define LUBDE_PCI_CONFIG_GET32 _IO(LUBDE_MAGIC, 4) +#define LUBDE_GET_DMA_INFO _IO(LUBDE_MAGIC, 5) +#define LUBDE_ENABLE_INTERRUPTS _IO(LUBDE_MAGIC, 6) +#define LUBDE_DISABLE_INTERRUPTS _IO(LUBDE_MAGIC, 7) +#define LUBDE_USLEEP _IO(LUBDE_MAGIC, 8) +#define LUBDE_WAIT_FOR_INTERRUPT _IO(LUBDE_MAGIC, 9) +#define LUBDE_SEM_OP _IO(LUBDE_MAGIC, 10) +#define LUBDE_UDELAY _IO(LUBDE_MAGIC, 11) +#define LUBDE_GET_DEVICE_TYPE _IO(LUBDE_MAGIC, 12) +#define LUBDE_SPI_READ_REG _IO(LUBDE_MAGIC, 13) +#define LUBDE_SPI_WRITE_REG _IO(LUBDE_MAGIC, 14) +#define LUBDE_READ_REG_16BIT_BUS _IO(LUBDE_MAGIC, 19) +#define LUBDE_WRITE_REG_16BIT_BUS _IO(LUBDE_MAGIC, 20) +#define LUBDE_GET_BUS_FEATURES _IO(LUBDE_MAGIC, 21) +#define LUBDE_WRITE_IRQ_MASK _IO(LUBDE_MAGIC, 22) +#define LUBDE_CPU_WRITE_REG _IO(LUBDE_MAGIC, 23) +#define LUBDE_CPU_READ_REG _IO(LUBDE_MAGIC, 24) +#define LUBDE_CPU_PCI_REGISTER _IO(LUBDE_MAGIC, 25) +#define LUBDE_DEV_RESOURCE _IO(LUBDE_MAGIC, 26) +#define LUBDE_IPROC_READ_REG _IO(LUBDE_MAGIC, 27) +#define LUBDE_IPROC_WRITE_REG _IO(LUBDE_MAGIC, 28) +#define LUBDE_ATTACH_INSTANCE _IO(LUBDE_MAGIC, 29) +#define LUBDE_GET_DEVICE_STATE _IO(LUBDE_MAGIC, 30) + +#define LUBDE_SEM_OP_CREATE 1 +#define LUBDE_SEM_OP_DESTROY 2 +#define LUBDE_SEM_OP_TAKE 3 +#define LUBDE_SEM_OP_GIVE 4 + +#define LUBDE_SUCCESS 0 +#define LUBDE_FAIL ((unsigned int)-1) + + +/* + * Version history + * 1:add LUBDE_GET_DEVICE_STATE to support PCI hot plug + */ +#define KBDE_VERSION 1 + + +/* This is the signal that will be used + * when an interrupt occurs + */ + +#ifndef __KERNEL__ +#include +#endif + +#define LUBDE_INTERRUPT_SIGNAL SIGUSR1 +#define LUBDE_ETHER_INTERRUPT_SIGNAL SIGUSR2 + +#endif /* __LUBDE_H__ */ diff --git a/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde.h b/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde.h new file mode 100644 index 0000000000..0a9df3a6e4 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde.h @@ -0,0 +1,77 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#ifndef __SHBDE_H__ +#define __SHBDE_H__ + +typedef void (*shbde_log_func_t)(int level, const char *str, int param); + +#define SHBDE_ERR 0 +#define SHBDE_WARN 1 +#define SHBDE_DBG 2 + +/* iProc configuration (primarily used for PCI-AXI bridge) */ +typedef struct shbde_iproc_config_s { + unsigned int dev_id; + unsigned int dev_rev; + unsigned int use_msi; + unsigned int iproc_ver; + unsigned int cmic_ver; + unsigned int cmic_rev; + unsigned int dma_hi_bits; + unsigned int mdio_base_addr; + unsigned int pcie_phy_addr; + unsigned int adjust_pcie_preemphasis; +} shbde_iproc_config_t; + +/* Hardware abstraction functions */ +typedef struct shbde_hal_s { + + /* Optional log output interface */ + shbde_log_func_t log_func; + + /* PCI configuration access */ + unsigned char (*pcic8_read)(void *pci_dev, unsigned int reg); + void (*pcic8_write)(void *pci_dev, unsigned int reg, unsigned char data); + unsigned short (*pcic16_read)(void *pci_dev, unsigned int reg); + void (*pcic16_write)(void *pci_dev, unsigned int reg, unsigned short data); + unsigned int (*pcic32_read)(void *pci_dev, unsigned int reg); + void (*pcic32_write)(void *pci_dev, unsigned int reg, unsigned int data); + + /* iProc register access */ + unsigned int (*io32_read)(void *addr); + void (*io32_write)(void *addr, unsigned int); + + /* usleep function (optional) */ + void (*usleep)(int usec); + + /* PCI parent device access */ + void *(*pci_parent_device_get)(void *pci_dev); + + /* iProc configuration */ + shbde_iproc_config_t icfg; + +} shbde_hal_t; + + +#endif /* __SHBDE_H__ */ diff --git a/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_iproc.h b/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_iproc.h new file mode 100644 index 0000000000..4841a3167d --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_iproc.h @@ -0,0 +1,49 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#ifndef __SHBDE_IPROC_H__ +#define __SHBDE_IPROC_H__ + +#include + +extern int +shbde_iproc_config_init(shbde_iproc_config_t *icfg, + unsigned int dev_id, unsigned int dev_rev); + +extern int +shbde_iproc_paxb_init(shbde_hal_t *shbde, void *iproc_regs, + shbde_iproc_config_t *icfg); + +extern unsigned int +shbde_iproc_pci_read(shbde_hal_t *shbde, void *iproc_regs, + unsigned int addr); + +extern void +shbde_iproc_pci_write(shbde_hal_t *shbde, void *iproc_regs, + unsigned int addr, unsigned int data); + +extern int +shbde_iproc_pcie_preemphasis_set(shbde_hal_t *shbde, void *iproc_regs, + shbde_iproc_config_t *icfg, void *pci_dev); + +#endif /* __SHBDE_IPROC_H__ */ diff --git a/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_mdio.h b/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_mdio.h new file mode 100644 index 0000000000..b5a2f8b3f3 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_mdio.h @@ -0,0 +1,60 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: $ + * $Copyright: (c) 2015 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#ifndef __SHBDE_MDIO_H__ +#define __SHBDE_MDIO_H__ + +#include + +typedef struct shbde_mdio_ctrl_s { + + /* Primary HAL*/ + shbde_hal_t *shbde; + + /* Context for iProc MDIO register access */ + void *regs; + + /* Base address for MDIO registers */ + unsigned int base_addr; + + /* iProc MDIO register access */ + unsigned int (*io32_read)(shbde_hal_t *shbde, void *iproc_regs, + unsigned int addr); + void (*io32_write)(shbde_hal_t *shbde, void *iproc_regs, + unsigned int addr, unsigned int data); + +} shbde_mdio_ctrl_t; + + +extern int +shbde_iproc_mdio_init(shbde_mdio_ctrl_t *smc); + +extern int +shbde_iproc_mdio_read(shbde_mdio_ctrl_t *smc, unsigned int phy_addr, + unsigned int reg, unsigned int *val); + +extern int +shbde_iproc_mdio_write(shbde_mdio_ctrl_t *smc, unsigned int phy_addr, + unsigned int reg, unsigned int val); + +#endif /* __SHBDE_MDIO_H__ */ diff --git a/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_pci.h b/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_pci.h new file mode 100644 index 0000000000..06aadfae5b --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_pci.h @@ -0,0 +1,47 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#ifndef __SHBDE_PCI_H__ +#define __SHBDE_PCI_H__ + +#include + +extern unsigned int +shbde_pci_pcie_cap(shbde_hal_t *shbde, void *pci_dev); + +extern int +shbde_pci_is_pcie(shbde_hal_t *shbde, void *pci_dev); + +extern int +shbde_pci_is_iproc(shbde_hal_t *shbde, void *pci_dev, int *cmic_bar); + +extern int +shbde_pci_max_payload_set(shbde_hal_t *shbde, void *pci_dev, int maxpayload); + +extern int +shbde_pci_iproc_version_get(shbde_hal_t *shbde, void *pci_dev, + unsigned int *iproc_ver, + unsigned int *cmic_ver, + unsigned int *cmic_rev); + +#endif /* __SHBDE_PCI_H__ */ diff --git a/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_iproc.c b/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_iproc.c new file mode 100644 index 0000000000..2db25df585 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_iproc.c @@ -0,0 +1,466 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#include +#include +#include + +/* PAXB register offsets within PCI BAR0 window */ +#define BAR0_PAXB_ENDIANESS 0x2030 +#define BAR0_PAXB_PCIE_EP_AXI_CONFIG 0x2104 +#define BAR0_PAXB_CONFIG_IND_ADDR 0x2120 +#define BAR0_PAXB_CONFIG_IND_DATA 0x2124 + +#define BAR0_PAXB_IMAP0_0 (0x2c00) +#define BAR0_PAXB_IMAP0_1 (0x2c04) +#define BAR0_PAXB_IMAP0_2 (0x2c08) +#define BAR0_PAXB_IMAP0_7 (0x2c1c) + +#define BAR0_PAXB_OARR_FUNC0_MSI_PAGE 0x2d34 +#define BAR0_PAXB_OARR_2 0x2d60 +#define BAR0_PAXB_OARR_2_UPPER 0x2d64 +#define BAR0_DMU_PCU_PCIE_SLAVE_RESET_MODE 0x7024 + +/* Force byte pointer for offset adjustments */ +#define ROFFS(_ptr, _offset) ((unsigned char*)(_ptr) + (_offset)) + +#define PAXB_CONFIG_IND_ADDRr_PROTOCOL_LAYERf_SHFT 11 +#define PAXB_CONFIG_IND_ADDRr_PROTOCOL_LAYERf_MASK 0x3 +#define PAXB_CONFIG_IND_ADDRr_ADDRESSf_SHFT 0 +#define PAXB_CONFIG_IND_ADDRr_ADDRESSf_MASK 0x7ff + +/* Register value set/get by field */ +#define REG_FIELD_SET(_r, _f, _r_val, _f_val) \ + _r_val = ((_r_val) & ~(_r##_##_f##_MASK << _r##_##_f##_SHFT)) | \ + (((_f_val) & _r##_##_f##_MASK) << _r##_##_f##_SHFT) +#define REG_FIELD_GET(_r, _f, _r_val) \ + (((_r_val) >> _r##_##_f##_SHFT) & _r##_##_f##_MASK) + +/* PCIe capabilities definition */ +#ifndef PCI_EXP_LNKSTA +#define PCI_EXP_LNKSTA 0x12 +#endif +/* Current Link Speed 5.0GT/s */ +#ifndef PCI_EXP_LNKSTA_CLS_5_0GB +#define PCI_EXP_LNKSTA_CLS_5_0GB 2 +#endif +#ifndef PCI_EXP_LNKSTA2 +#define PCI_EXP_LNKSTA2 0x32 +#endif +/* Current Deemphasis Level -3.5 dB */ +#ifndef PCI_EXP_LNKSTA2_CDL_3_5DB +#define PCI_EXP_LNKSTA2_CDL_3_5DB 0x1 +#endif + +static unsigned int +iproc32_read(shbde_hal_t *shbde, void *addr) +{ + if (!shbde || !shbde->io32_read) { + return 0; + } + return shbde->io32_read(addr); +} + +static void +iproc32_write(shbde_hal_t *shbde, void *addr, unsigned int data) +{ + if (!shbde || !shbde->io32_write) { + return; + } + shbde->io32_write(addr, data); +} + +static void +wait_usec(shbde_hal_t *shbde, int usec) +{ + if (shbde && shbde->usleep) { + shbde->usleep(usec); + } else { + int idx; + volatile int count; + for (idx = 0; idx < usec; idx++) { + for (count = 0; count < 100; count++); + } + } +} + +/* + * Function: + * shbde_iproc_config_init + * Purpose: + * Initialize iProc configuration parameters + * Parameters: + * icfg - pointer to empty iProc configuration structure + * Returns: + * -1 if error, otherwise 0 + */ +int +shbde_iproc_config_init(shbde_iproc_config_t *icfg, + unsigned int dev_id, unsigned int dev_rev) +{ + if (!icfg) { + return -1; + } + + /* Save device ID and revision */ + icfg->dev_id = dev_id; + icfg->dev_rev = dev_rev; + + /* Check device families first */ + switch (icfg->dev_id & 0xfff0) { + case 0x8400: /* Greyhound Lite */ + case 0x8410: /* Greyhound */ + case 0x8420: /* Bloodhound */ + case 0x8450: /* Elkhound */ + case 0xb060: /* Ranger2(Greyhound) */ + case 0x8360: /* Greyhound 53365 & 53369 */ + case 0xb260: /* saber2 */ + case 0xb460: /* saber2+ */ + case 0xb170: /* Hurricane3-MG */ + case 0x8570: /* Greyhound2 */ + case 0xb070: /* Greyhound2(emulation) */ + case 0x8580: /* Greyhound2(emulation) */ + case 0xb230: /* Dagger2 */ + icfg->iproc_ver = 7; + icfg->dma_hi_bits = 0x2; + break; + case 0xb560: /* Apache */ + case 0xb760: /* Maverick */ + icfg->iproc_ver = 0xB; + break; + case 0xb160: /* Hurricane3 */ + case 0x8440: /* Wolfhound2 */ + case 0x8430: /* Foxhound2 */ + icfg->iproc_ver = 10; + icfg->dma_hi_bits = 0x2; + break; + default: + break; + } + + /* Check for exceptions */ + switch (icfg->dev_id) { + case 0xb069: + case 0xb068: + icfg->iproc_ver = 0xB; /*Ranger2+ Apache Family */ + icfg->dma_hi_bits = 0; + break; + case 0xb168: /* Ranger3+ */ + case 0xb169: + icfg->iproc_ver = 0; + icfg->dma_hi_bits = 0; + break; + default: + break; + } + /* Check for PCIe PHY address that needs PCIe preemphasis and + * assign the MDIO base address + */ + switch (icfg->dev_id & 0xfff0) { + case 0xb150: /* Hurricane2 */ + case 0x8340: /* Wolfhound */ + case 0x8330: /* Foxhound */ + case 0x8390: /* Dearhound */ + icfg->mdio_base_addr = 0x18032000; + icfg->pcie_phy_addr = 0x2; + break; + case 0xb340: /* Helilx4 */ + case 0xb540: /* FireScout */ + case 0xb040: /* Spiral, Ranger */ + icfg->mdio_base_addr = 0x18032000; + icfg->pcie_phy_addr = 0x5; + icfg->adjust_pcie_preemphasis = 1; + break; + case 0xa450: /* Katana2 */ + case 0xb240: + case 0xb450: + icfg->mdio_base_addr = 0x18032000; + icfg->pcie_phy_addr = 0x5; + icfg->adjust_pcie_preemphasis = 1; + break; + default: + break; + } + + /* Check for exceptions */ + switch (icfg->dev_id) { + default: + break; + } + + return 0; +} + +/* + * Function: + * shbde_iproc_paxb_init + * Purpose: + * Initialize iProc PCI-AXI bridge for CMIC access + * Parameters: + * shbde - pointer to initialized hardware abstraction module + * iproc_regs - memory mapped iProc registers in PCI BAR + * icfg - iProc configuration parameters + * Returns: + * -1 if error, otherwise 0 + */ +int +shbde_iproc_paxb_init(shbde_hal_t *shbde, void *iproc_regs, + shbde_iproc_config_t *icfg) +{ + void *reg; + unsigned int data; + int pci_num; + + if (!iproc_regs || !icfg) { + return -1; + } + + /* + * The following code attempts to auto-detect the correct + * iProc PCI endianess configuration by reading a well-known + * register (the endianess configuration register itself). + * Note that the PCI endianess may be different for different + * big endian host processors. + */ + reg = ROFFS(iproc_regs, BAR0_PAXB_ENDIANESS); + /* Select big endian */ + iproc32_write(shbde, reg, 0x01010101); + /* Check if endianess register itself is correct endian */ + if (iproc32_read(shbde, reg) != 1) { + /* If not, then assume little endian */ + iproc32_write(shbde, reg, 0x0); + } + + /* Select which PCI core to use */ + pci_num = 0; + reg = ROFFS(iproc_regs, BAR0_PAXB_IMAP0_2); + data = iproc32_read(shbde, reg); + if (data & 0x1000) { + /* PAXB_1 is mapped to sub-window 2 */ + pci_num = 1; + } + + /* Default DMA mapping if uninitialized */ + if (icfg->dma_hi_bits == 0) { + icfg->dma_hi_bits = 0x1; + if (pci_num == 1) { + icfg->dma_hi_bits = 0x2; + } + } + + /* Enable iProc DMA to external host memory */ + reg = ROFFS(iproc_regs, BAR0_PAXB_PCIE_EP_AXI_CONFIG); + iproc32_write(shbde, reg, 0x0); + if(icfg->cmic_ver < 4) { /* Non-CMICX */ + reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_2); + iproc32_write(shbde, reg, 0x1); + reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_2_UPPER); + iproc32_write(shbde, reg, icfg->dma_hi_bits); + + /* Configure MSI interrupt page */ + if (icfg->use_msi) { + reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_FUNC0_MSI_PAGE); + data = iproc32_read(shbde, reg); + iproc32_write(shbde, reg, data | 0x1); + } + } + return pci_num; +} + +/* + * Function: + * shbde_iproc_pci_read + * Purpose: + * Read iProc register through PCI BAR 0 + * Parameters: + * shbde - pointer to initialized hardware abstraction module + * iproc_regs - memory mapped iProc registers in PCI BAR + * addr - iProc register address in AXI memory space + * Returns: + * Register value + */ +unsigned int +shbde_iproc_pci_read(shbde_hal_t *shbde, void *iproc_regs, + unsigned int addr) +{ + unsigned int subwin_base; + void *reg; + shbde_iproc_config_t *icfg = &shbde->icfg; + + if (!iproc_regs) { + return -1; + } + + /* Sub-window size is 0x1000 (4K) */ + subwin_base = (addr & ~0xfff); + + if((icfg->cmic_ver >= 4) && (subwin_base == 0x18013000)) { + /* Route the INTC block access through IMAP0_6 */ + reg = ROFFS(iproc_regs, 0x6000 + (addr & 0xfff)); + } else { + /* Update base address for sub-window 7 */ + subwin_base |= 1; /* Valid bit */ + reg = ROFFS(iproc_regs, BAR0_PAXB_IMAP0_7); + iproc32_write(shbde, reg, subwin_base); + /* Read it to make sure the write actually goes through */ + subwin_base = iproc32_read(shbde, reg); + + /* Read register through sub-window 7 */ + reg = ROFFS(iproc_regs, 0x7000 + (addr & 0xfff)); + } + + return iproc32_read(shbde, reg); +} + +/* + * Function: + * shbde_iproc_pci_write + * Purpose: + * Write iProc register through PCI BAR 0 + * Parameters: + * shbde - pointer to initialized hardware abstraction module + * iproc_regs - memory mapped iProc registers in PCI BAR + * addr - iProc register address in AXI memory space + * data - data to write to iProc register + * Returns: + * Register value + */ +void +shbde_iproc_pci_write(shbde_hal_t *shbde, void *iproc_regs, + unsigned int addr, unsigned int data) +{ + unsigned int subwin_base; + void *reg; + shbde_iproc_config_t *icfg = &shbde->icfg; + + if (!iproc_regs) { + return; + } + + /* Sub-window size is 0x1000 (4K) */ + subwin_base = (addr & ~0xfff); + + if((icfg->cmic_ver >= 4) && (subwin_base == 0x18013000)) { + /* Route the INTC block access through IMAP0_6 */ + reg = ROFFS(iproc_regs, 0x6000 + (addr & 0xfff)); + } else { + /* Update base address for sub-window 7 */ + subwin_base |= 1; /* Valid bit */ + reg = ROFFS(iproc_regs, BAR0_PAXB_IMAP0_7); + iproc32_write(shbde, reg, subwin_base); + /* Read it to make sure the write actually goes through */ + subwin_base = iproc32_read(shbde, reg); + + /* Read register through sub-window 7 */ + reg = ROFFS(iproc_regs, 0x7000 + (addr & 0xfff)); + } + + iproc32_write(shbde, reg, data); +} + +int +shbde_iproc_pcie_preemphasis_set(shbde_hal_t *shbde, void *iproc_regs, + shbde_iproc_config_t *icfg, void *pci_dev) +{ + shbde_mdio_ctrl_t mdio_ctrl, *smc = &mdio_ctrl; + unsigned int phy_addr, data; + void *reg; + unsigned int pcie_cap_base; + unsigned short link_stat, link_stat2; + + if (!icfg) { + return -1; + } + + /* PHY address for PCIe link */ + phy_addr = icfg->pcie_phy_addr; + if (phy_addr == 0 || icfg->mdio_base_addr == 0) { + return 0; + } + + /* Initialize MDIO control */ + smc->shbde = shbde; + smc->regs = iproc_regs; + smc->base_addr = icfg->mdio_base_addr; + smc->io32_read = shbde_iproc_pci_read; + smc->io32_write = shbde_iproc_pci_write; + shbde_iproc_mdio_init(smc); + + /* PCIe SerDes Gen1/Gen2 CDR Track Bandwidth Adjustment + * for Better Jitter Tolerance + */ + shbde_iproc_mdio_write(smc, phy_addr, 0x1f, 0x8630); + shbde_iproc_mdio_write(smc, phy_addr, 0x13, 0x190); + shbde_iproc_mdio_write(smc, phy_addr, 0x19, 0x191); + + if (!icfg->adjust_pcie_preemphasis) { + return 0; + } + + /* Check to see if the PCIe SerDes deemphasis needs to be changed + * based on the advertisement from the root complex + */ + /* Find PCIe capability base */ + if (!shbde || !shbde->pcic16_read || !pci_dev) { + return -1; + } + pcie_cap_base = shbde_pci_pcie_cap(shbde, pci_dev); + if (pcie_cap_base) { + link_stat = shbde->pcic16_read(pci_dev, + pcie_cap_base + PCI_EXP_LNKSTA); + link_stat2 = shbde->pcic16_read(pci_dev, + pcie_cap_base + PCI_EXP_LNKSTA2); + if (((link_stat & 0xf) == PCI_EXP_LNKSTA_CLS_5_0GB) && + (link_stat2 & PCI_EXP_LNKSTA2_CDL_3_5DB)) { + /* Device is operating at Gen2 speeds and RC requested -3.5dB */ + /* Change the transmitter setting */ + shbde_iproc_mdio_write(smc, phy_addr, 0x1f, 0x8610); + shbde_iproc_mdio_read(smc, phy_addr, 0x17, &data); + data &= ~0xf00; + data |= 0x700; + shbde_iproc_mdio_write(smc, phy_addr, 0x17, data); + + /* Force the PCIe link to retrain */ + data = 0; + REG_FIELD_SET(PAXB_CONFIG_IND_ADDRr, PROTOCOL_LAYERf, data, 0x2); + REG_FIELD_SET(PAXB_CONFIG_IND_ADDRr, ADDRESSf, data, 0x4); + reg = ROFFS(iproc_regs, BAR0_PAXB_CONFIG_IND_ADDR); + iproc32_write(shbde, reg, data); + + reg = ROFFS(iproc_regs, BAR0_PAXB_CONFIG_IND_DATA); + data = iproc32_read(shbde, reg); + data &= ~0x4000; + iproc32_write(shbde, reg, data); + data |= 0x4000; + iproc32_write(shbde, reg, data); + data &= ~0x4000; + iproc32_write(shbde, reg, data); + + /* Wait a short while for the retraining to complete */ + wait_usec(shbde, 1000); + } + } + + return 0; +} + diff --git a/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_mdio.c b/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_mdio.c new file mode 100644 index 0000000000..434312d560 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_mdio.c @@ -0,0 +1,187 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: $ + * $Copyright: (c) 2015 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#include + +/* iProc MDIO register offset */ +#define MII_MGMT_CTRL 0x0 +#define MII_MGMT_CMD_DATA 0x4 + +/* iProc MII register with fields definition */ +#define MII_MGMT_CTRLr_MDCDIVf_SHFT 0 +#define MII_MGMT_CTRLr_MDCDIVf_MASK 0x7f +#define MII_MGMT_CTRLr_BSYf_SHFT 8 +#define MII_MGMT_CTRLr_BSYf_MASK 0x1 + +#define MII_MGMT_CMD_DATAr_DATAf_SHFT 0 +#define MII_MGMT_CMD_DATAr_DATAf_MASK 0xffff +#define MII_MGMT_CMD_DATAr_TAf_SHFT 16 +#define MII_MGMT_CMD_DATAr_TAf_MASK 0x3 +#define MII_MGMT_CMD_DATAr_RAf_SHFT 18 +#define MII_MGMT_CMD_DATAr_RAf_MASK 0x1f +#define MII_MGMT_CMD_DATAr_PAf_SHFT 23 +#define MII_MGMT_CMD_DATAr_PAf_MASK 0x1f +#define MII_MGMT_CMD_DATAr_OPf_SHFT 28 +#define MII_MGMT_CMD_DATAr_OPf_MASK 0x3 +#define MII_MGMT_CMD_DATAr_SBf_SHFT 30 +#define MII_MGMT_CMD_DATAr_SBf_MASK 0x3 + +/* Register field value set/get */ +#define REG_FIELD_SET(_r, _f, _r_val, _f_val) \ + _r_val = ((_r_val) & ~(_r##_##_f##_MASK << _r##_##_f##_SHFT)) | \ + (((_f_val) & _r##_##_f##_MASK) << _r##_##_f##_SHFT) +#define REG_FIELD_GET(_r, _f, _r_val) \ + (((_r_val) >> _r##_##_f##_SHFT) & _r##_##_f##_MASK) + +#define LOG_OUT(_shbde, _lvl, _str, _prm) \ + if ((_shbde)->log_func) { \ + (_shbde)->log_func(_lvl, _str, _prm); \ + } +#define LOG_ERR(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_ERR, _str, _prm) +#define LOG_WARN(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_WARN, _str, _prm) +#define LOG_DBG(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_DBG, _str, _prm) + +static unsigned int +mdio32_read(shbde_mdio_ctrl_t *smc, unsigned int offset) +{ + if (!smc || !smc->io32_read) { + return 0; + } + return smc->io32_read(smc->shbde, smc->regs, smc->base_addr + offset); +} + +static void +mdio32_write(shbde_mdio_ctrl_t *smc, unsigned int offset, unsigned int data) +{ + if (!smc || !smc->io32_read) { + return; + } + smc->io32_write(smc->shbde, smc->regs, smc->base_addr + offset, data); +} + +static void +wait_usec(shbde_mdio_ctrl_t *smc, int usec) +{ + shbde_hal_t *shbde = smc->shbde; + + if (shbde && shbde->usleep) { + shbde->usleep(usec); + } else { + int idx; + volatile int count; + for (idx = 0; idx < usec; idx++) { + for (count = 0; count < 100; count++); + } + } +} + +static int +iproc_mdio_wait_for_busy(shbde_mdio_ctrl_t *smc) +{ + int mii_busy; + unsigned int reg_val; + int count = 1000; + + /* Wait until MII is not busy */ + do { + reg_val = mdio32_read(smc, MII_MGMT_CTRL); + mii_busy = REG_FIELD_GET(MII_MGMT_CTRLr, BSYf, reg_val); + if (!mii_busy) { + break; + } + wait_usec(smc, 10); + count --; + } while (count > 0); + + return mii_busy; +} + +int +shbde_iproc_mdio_init(shbde_mdio_ctrl_t *smc) +{ + shbde_hal_t *shbde = smc->shbde; + unsigned int reg_val = 0; + + /* Enable the iProc internal MDIO interface */ + REG_FIELD_SET(MII_MGMT_CTRLr, MDCDIVf, reg_val, 0x7f); + mdio32_write(smc, MII_MGMT_CTRL, reg_val); + + if (shbde && !shbde->usleep) { + LOG_DBG(shbde, "shbde_mdio: no registration of usleep vector", 0); + } + + wait_usec(smc, 100); + + return 0; +} + +int +shbde_iproc_mdio_read(shbde_mdio_ctrl_t *smc, unsigned int phy_addr, + unsigned int reg, unsigned int *val) +{ + unsigned int reg_val = 0; + + REG_FIELD_SET(MII_MGMT_CMD_DATAr, SBf, reg_val, 0x1); + REG_FIELD_SET(MII_MGMT_CMD_DATAr, TAf, reg_val, 0x2); + REG_FIELD_SET(MII_MGMT_CMD_DATAr, OPf, reg_val, 0x2); + REG_FIELD_SET(MII_MGMT_CMD_DATAr, PAf, reg_val, phy_addr); + REG_FIELD_SET(MII_MGMT_CMD_DATAr, RAf, reg_val, reg); + mdio32_write(smc, MII_MGMT_CMD_DATA, reg_val); + + if (iproc_mdio_wait_for_busy(smc)) { + *val = 0; + LOG_DBG(smc->shbde, "shbde_iproc_mdio_read busy", reg); + return -1; + } + + reg_val = mdio32_read(smc, MII_MGMT_CMD_DATA); + *val = REG_FIELD_GET(MII_MGMT_CMD_DATAr, DATAf, reg_val); + + return 0; +} + +int +shbde_iproc_mdio_write(shbde_mdio_ctrl_t *smc, unsigned int phy_addr, + unsigned int reg, unsigned int val) +{ + unsigned int reg_val = 0; + + REG_FIELD_SET(MII_MGMT_CMD_DATAr, SBf, reg_val, 0x1); + REG_FIELD_SET(MII_MGMT_CMD_DATAr, TAf, reg_val, 0x2); + REG_FIELD_SET(MII_MGMT_CMD_DATAr, OPf, reg_val, 0x1); + REG_FIELD_SET(MII_MGMT_CMD_DATAr, PAf, reg_val, phy_addr); + REG_FIELD_SET(MII_MGMT_CMD_DATAr, RAf, reg_val, reg); + REG_FIELD_SET(MII_MGMT_CMD_DATAr, DATAf, reg_val, val); + mdio32_write(smc, MII_MGMT_CMD_DATA, reg_val); + + if (iproc_mdio_wait_for_busy(smc)) { + LOG_DBG(smc->shbde, "shbde_iproc_mdio_write busy", reg); + return -1; + } + + /* Wait for some time for the write to take effect */ + wait_usec(smc, 100); + + return 0; +} + diff --git a/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_pci.c b/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_pci.c new file mode 100644 index 0000000000..22408a84c3 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_pci.c @@ -0,0 +1,393 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#include + +/* PCIe capabilities */ +#ifndef PCI_CAPABILITY_LIST +#define PCI_CAPABILITY_LIST 0x34 +#endif +#ifndef PCI_CAP_ID_EXP +#define PCI_CAP_ID_EXP 0x10 +#endif +#ifndef PCI_EXP_DEVCAP +#define PCI_EXP_DEVCAP 4 +#endif +#ifndef PCI_EXP_DEVCTL +#define PCI_EXP_DEVCTL 8 +#endif +#ifndef PCI_EXT_CAP_START +#define PCI_EXT_CAP_START 0x100 +#endif +#ifndef PCI_EXT_CAP_ID +#define PCI_EXT_CAP_ID(_hdr) (_hdr & 0x0000ffff) +#endif +#ifndef PCI_EXT_CAP_VER +#define PCI_EXT_CAP_VER(_hdr) ((_hdr >> 16) & 0xf) +#endif +#ifndef PCI_EXT_CAP_NEXT +#define PCI_EXT_CAP_NEXT(_hdr) ((_hdr >> 20) & 0xffc) +#endif +#ifndef PCI_EXT_CAP_ID_VNDR +#define PCI_EXT_CAP_ID_VNDR 0x0b +#endif + +#define LOG_OUT(_shbde, _lvl, _str, _prm) \ + if ((_shbde)->log_func) { \ + (_shbde)->log_func(_lvl, _str, _prm); \ + } +#define LOG_ERR(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_ERR, _str, _prm) +#define LOG_WARN(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_WARN, _str, _prm) +#define LOG_DBG(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_DBG, _str, _prm) + +#ifndef NULL +#define NULL (void *)0 +#endif + +/* + * Warpper functions with null-pointer checks. + */ +static unsigned int +pcic16_read(shbde_hal_t *shbde, void *pci_dev, + unsigned int addr) +{ + if (!shbde || !shbde->pcic16_read) { + return 0; + } + return shbde->pcic16_read(pci_dev, addr); +} + +static void +pcic16_write(shbde_hal_t *shbde, void *pci_dev, + unsigned int addr, unsigned int data) +{ + if (!shbde || !shbde->pcic16_write) { + return; + } + shbde->pcic16_write(pci_dev, addr, data); +} + +static unsigned int +pcic32_read(shbde_hal_t *shbde, void *pci_dev, + unsigned int addr) +{ + if (!shbde || !shbde->pcic32_read) { + return 0; + } + return shbde->pcic32_read(pci_dev, addr); +} + +static void * +pci_parent_device_get(shbde_hal_t *shbde, void *pci_dev) +{ + if (!shbde || !shbde->pci_parent_device_get) { + return NULL; + } + return shbde->pci_parent_device_get(pci_dev); +} + +/* + * Function: + * shbde_pci_pcie_cap + * Purpose: + * Return offset of PCIe capabilities in PCI configuration space + * Parameters: + * shbde - pointer to initialized hardware abstraction module + * dev - PCI device handle (passed back to PCI HAL functions) + * Returns: + * PCI_CAP_ID_EXP offset in PCI configuration space if PCIe, otherwise 0 + */ +unsigned int +shbde_pci_pcie_cap(shbde_hal_t *shbde, void *pci_dev) +{ + unsigned int cap_base, rval; + + cap_base = pcic16_read(shbde, pci_dev, PCI_CAPABILITY_LIST); + while (cap_base) { + rval = pcic16_read(shbde, pci_dev, cap_base); + if ((rval & 0xff) == PCI_CAP_ID_EXP) { + break; + } + cap_base = (rval >> 8) & 0xff; + } + + return cap_base; +} + +/* + * Function: + * shbde_pci_is_pcie + * Purpose: + * Check if PCI device is PCIe device + * Parameters: + * shbde - pointer to initialized hardware abstraction module + * dev - PCI device handle (passed back to PCI HAL functions) + * Returns: + * 1 if PCIe, otherwise 0 + */ +int +shbde_pci_is_pcie(shbde_hal_t *shbde, void *pci_dev) +{ + return shbde_pci_pcie_cap(shbde, pci_dev) ? 1 : 0; +} + +/* + * Function: + * shbde_pci_is_iproc + * Purpose: + * Check if PCI device is iProc-based + * Parameters: + * shbde - pointer to initialized hardware abstraction module + * dev - PCI device handle (passed back to PCI HAL functions) + * cmic_bar - (OUT) PCI BAR which contains switch CMIC registers + * Returns: + * 1 if iProc-based, otherwise 0 + */ +int +shbde_pci_is_iproc(shbde_hal_t *shbde, void *pci_dev, int *cmic_bar) +{ + unsigned int cap_base, rval; + + if (!shbde_pci_is_pcie(shbde, pci_dev)) { + return 0; + } + + /* Look for PCIe vendor-specific extended capability (VSEC) */ + cap_base = PCI_EXT_CAP_START; + while (cap_base) { + rval = pcic32_read(shbde, pci_dev, cap_base); + if (rval == 0xffffffff) { + /* Assume PCI HW read error */ + return 0; + } + + if (PCI_EXT_CAP_ID(rval) == PCI_EXT_CAP_ID_VNDR) { + break; + } + cap_base = PCI_EXT_CAP_NEXT(rval); + } + if (cap_base) { + /* + * VSEC layout: + * + * 0x00: PCI Express Extended Capability Header + * 0x04: Vendor-Specific Header + * 0x08: Vendor-Specific Register 1 + * 0x0c: Vendor-Specific Register 2 + * ... + * 0x24: Vendor-Specific Register 8 + */ + /* 32'b // 31:12=0 Reserved; 11:08=CMIC BAR; 07:00=iProc Configuration ID */ + rval = pcic32_read(shbde, pci_dev, cap_base + 8); + LOG_DBG(shbde, "Found VSEC", rval); + + /* Determine PCI BAR of CMIC */ + *cmic_bar = 0; + if ((rval & 0x100) == 0x100) { + *cmic_bar = 2; + } + /* Assume iProc device */ + return 1; + } + + return 0; +} + +/* + * Function: + * shbde_pci_iproc_version_get + * Purpose: + * Get iproc, cmic versions and revisions + * Parameters: + * shbde - pointer to initialized hardware abstraction module + * dev - PCI device handle (passed back to PCI HAL functions) + * iproc_ver - (OUT) iProc version + * cmic_ver - (OUT) CMIC version + * cmic_rev - (OUT) CMIC revision + * Returns: + * 1 for no error, otherwise 0 + */ +int +shbde_pci_iproc_version_get(shbde_hal_t *shbde, void *pci_dev, + unsigned int *iproc_ver, + unsigned int *cmic_ver, + unsigned int *cmic_rev) +{ + unsigned int cap_base, rval; + + if (!shbde_pci_is_pcie(shbde, pci_dev)) { + return 0; + } + + /* Look for PCIe vendor-specific extended capability (VSEC) */ + cap_base = PCI_EXT_CAP_START; + while (cap_base) { + rval = pcic32_read(shbde, pci_dev, cap_base); + if (rval == 0xffffffff) { + /* Assume PCI HW read error */ + return 0; + } + + if (PCI_EXT_CAP_ID(rval) == PCI_EXT_CAP_ID_VNDR) { + break; + } + cap_base = PCI_EXT_CAP_NEXT(rval); + } + if (cap_base) { + /* + * VSEC layout: + * + * 0x00: PCI Express Extended Capability Header + * 0x04: Vendor-Specific Header + * 0x08: Vendor-Specific Register 1 + * 0x0c: Vendor-Specific Register 2 + * ... + * 0x24: Vendor-Specific Register 8 + */ + + /* Read PCIe Vendor Specific Register 1 */ + /* VENODR REG FORMAT + * [7:0] iProc Rev = 8'h0E (for P14) + * [11:8] CMIC BAR = 4'h1 (BAR64-1) + * [15:12] CMIC Version = 4'h4 + * [19:16] CMIC Rev = 4'h1 + * [22:20] SBUS Version = 4'h4 + */ + + rval = pcic32_read(shbde, pci_dev, cap_base + 8); + LOG_DBG(shbde, "Found VSEC", rval); + + /* Determine PCI BAR of CMIC */ + *iproc_ver = rval & 0xff; + *cmic_ver = (rval >> 12) & 0xf; + *cmic_rev = (rval >> 16) & 0xf; + return 1; + } + + return 0; +} + +/* + * Function: + * shbde_pci_max_payload_set + * Purpose: + * Set PCIe maximum payload + * Parameters: + * shbde - pointer to initialized hardware abstraction module + * dev - PCI device handle (passed back to PCI HAL functions) + * maxpayload - maximum payload (in byte) + * Returns: + * -1 if error, otherwise 0 + * Notes: + * If not PCIe device, set the PCI retry count to infinte instead. + */ +int +shbde_pci_max_payload_set(shbde_hal_t *shbde, void *pci_dev, int maxpayload) +{ + unsigned int cap_base, parent_cap_base; + unsigned int devcap, devctl, parent_devctl; + int max_val, max_cap, parent_max_val; + void *parent_pci_dev; + + cap_base = shbde_pci_pcie_cap(shbde, pci_dev); + + if (cap_base == 0) { + /* Not PCIe */ + return 0; + } + + /* Get current device control settings */ + devctl = pcic16_read(shbde, pci_dev, cap_base + PCI_EXP_DEVCTL); + + /* Get current max payload setting */ + max_val = (devctl >> 5) & 0x7; + + if (maxpayload) { + /* Get encoding from byte value */ + max_val = 0; + while ((1 << (max_val + 7)) < maxpayload) { + max_val++; + } + LOG_DBG(shbde, "Set max payload size", maxpayload); + LOG_DBG(shbde, "Set max payload val", max_val); + + /* Get max supported payload size */ + devcap = pcic16_read(shbde, pci_dev, cap_base + PCI_EXP_DEVCAP); + max_cap = (devcap & 0x7); + + /* Do not exceed device capabilities */ + if (max_val > max_cap) { + max_val = max_cap; + LOG_DBG(shbde, + "Payload size exceeds device capability", + maxpayload); + } + + /* Get currently set max payload size for the parent device + * in the PCI tree (if it exists). + */ + parent_pci_dev = pci_parent_device_get(shbde, pci_dev); + if (parent_pci_dev != NULL) { + parent_cap_base = shbde_pci_pcie_cap(shbde, parent_pci_dev); + parent_devctl = pcic16_read(shbde, + parent_pci_dev, + parent_cap_base + PCI_EXP_DEVCTL); + parent_max_val = (parent_devctl >> 5) & 0x7; + + /* Do not exceed current parent max payload setting (our device + * should have an MPS setting <= current parent MPS setting in + * the tree of PCIe devices). + */ + if (max_val > parent_max_val) { + max_val = parent_max_val; + LOG_DBG(shbde, + "Payload size exceeds current parent device setting", + maxpayload); + } + } + + /* Update max payload size */ + devctl &= ~(0x7 << 5); + devctl |= (max_val) << 5; + + /* Update max request size */ + devctl &= ~(0x7 << 12); + devctl |= (max_val << 12); + } + + /* Always disable relaxed ordering */ + devctl &= ~(1 << 4); + + /* Update device control settings */ + pcic16_write(shbde, pci_dev, cap_base + PCI_EXP_DEVCTL, devctl); + + /* Warn if non-default setting is used */ + if (max_val > 0) { + LOG_WARN(shbde, + "Selected payload size may not be supported by all " + "PCIe bridges by default.", + (1 << (max_val + 7))); + } + + return 0; +} diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/Makefile b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/Makefile new file mode 100644 index 0000000000..37f35b2e27 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/Makefile @@ -0,0 +1,32 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# -*- Makefile -*- +# $Id: Makefile,v 1.10 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ +# +# Makefile for SOC SAL support +# +LOCALDIR = systems/linux/kernel/modules + +include ${SDK}/make/Make.config + +subdirs=shared uk-proxy bcm-diag-full bcm-core bcm-net bcm-diag + +include ${SDK}/make/Make.subdirs + +include ${SDK}/make/Make.depend diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/Makefile b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/Makefile new file mode 100644 index 0000000000..5459b399aa --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/Makefile @@ -0,0 +1,68 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# -*- Makefile -*- +# $Id: Makefile,v 1.3 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ +# +LOCALDIR = systems/linux/kernel/modules/bcm-knet + +include ${SDK}/make/Make.config + +LIBS = $(LIBDIR)/libkern.a + +ifeq ($(kernel_version),2_4) +MODULE = $(LIBDIR)/linux-bcm-knet.o +else +KERNEL_MODULE_DIR = kernel_module + +THIS_MOD_NAME := linux-bcm-knet +MODULE = $(LIBDIR)/$(THIS_MOD_NAME).o +KMODULE = $(LIBDIR)/$(THIS_MOD_NAME).ko + +build: $(MODULE) $(KMODULE) +endif + +KBUILD_EXTRA_SYMBOLS := ${BLDDIR}/../../../../bde/linux/kernel/kernel_module/Module.symvers +ifeq (,$(findstring -DPROXY_SUPPORT=0,$(CFLAGS))) +KBUILD_EXTRA_SYMBOLS += ${BLDDIR}/../uk-proxy/kernel_module/Module.symvers +endif + +# BCM Network Device + +$(MODULE): $(BLDDIR)/.tree $(BOBJS) $(LIBS) + $(LD) $(MODULE_LDFLAGS) -r -d $(BOBJS) $(LIBS) -o $@ +ifneq ($(kernel_version),2_4) +$(KMODULE): $(MODULE) + rm -fr $(BLDDIR)/$(KERNEL_MODULE_DIR) + mkdir $(BLDDIR)/$(KERNEL_MODULE_DIR) + cp ${SDK}/make/Makefile.linux-kmodule $(BLDDIR)/$(KERNEL_MODULE_DIR)/Makefile + cat ${KBUILD_EXTRA_SYMBOLS} > $(BLDDIR)/$(KERNEL_MODULE_DIR)/Module.symvers + MOD_NAME=$(THIS_MOD_NAME) $(MAKE) -C $(BLDDIR)/$(KERNEL_MODULE_DIR) $(THIS_MOD_NAME).ko +endif + +# Make.depend is before clean:: so that Make.depend's clean:: runs first. + +include ${SDK}/make/Make.depend + +clean:: + $(RM) $(BLDDIR)/version.c $(BLDDIR)/version.o + $(RM) $(BOBJS) $(MODULE) + +ifneq ($(kernel_version),2_4) +.PHONY: build +endif diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c new file mode 100644 index 0000000000..fe6fd53850 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c @@ -0,0 +1,6874 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: bcm-knet.c,v 1.90 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ + +/* + * This module implements a Linux network driver for Broadcom + * XGS switch devices. The driver simultaneously serves a + * number of vitual Linux network devices and a Tx/Rx API + * implemented in user space. + * + * Packets received from the switch device are sent to either + * a virtual Linux network device or the user mode Rx API + * based on a set of packet filters.susp + * + * Packets from the virtual Linux network devices and the user + * mode Tx API are multiplexed with priority given to the Tx API. + * + * A message-based IOCTL interface is used for managing packet + * filters and virtual Linux network interfaces. + * + * A virtual network interface can be configured to work in RCPU + * mode, which means that packets from the switch device will + * be encasulated with a RCPU header and a block of meta data + * that basically contains the core DCB information. Likewise, + * packets received from the Linux network stack are assumed to + * be RCPU encapsulated when going out on an interface in RCPU + * mode. + * + * The module implements basic Rx DMA rate control. The rate is + * specified in packets per second, and different Rx DMA channels + * can be configured to use different maximum packet rates. + * The packet rate can be configure as a module parameter, and + * it can also be changed dynamically through the proc file + * system (syntax is described in function header comment). + * + * To support multiple instance, each instance has its event queue. + * + * To support pci hot-plug in this module, the resource update + * should be handled when the PCI device is re-plugged. + * NOTE: the KNET detach should be invoked befere removing the + * device. + * + * For a list of supported module parameters, please see below. + */ + +#include /* Must be included first */ +#include +#include +#include + +#include +#include +#include +#include + + +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_DESCRIPTION("Network Device Driver for Broadcom BCM TxRx API"); +MODULE_LICENSE("GPL"); + +static int debug; +LKM_MOD_PARAM(debug, "i", int, 0); +MODULE_PARM_DESC(debug, +"Debug level (default 0)"); + +static char *mac_addr = NULL; +LKM_MOD_PARAM(mac_addr, "s", charp, 0); +MODULE_PARM_DESC(mac_addr, +"Ethernet MAC address (default 02:10:18:xx:xx:xx)"); + +static int rx_buffer_size = 9216; +LKM_MOD_PARAM(rx_buffer_size, "i", int, 0); +MODULE_PARM_DESC(rx_buffer_size, +"Size of RX packet buffers (default 9216)"); + +static int default_mtu = 1500; +LKM_MOD_PARAM(default_mtu, "i", int, 0); +MODULE_PARM_DESC(default_mtu, +"Default MTU for KNET network interfaces (default 1500)"); + +static int rx_sync_retry = 1000; +LKM_MOD_PARAM(rx_sync_retry, "i", int, 0); +MODULE_PARM_DESC(rx_sync_retry, +"Retries if chain is incomplete on interrupt (default 10)"); + +static char *base_dev_name = NULL; +LKM_MOD_PARAM(base_dev_name, "s", charp, 0); +MODULE_PARM_DESC(base_dev_name, +"Base device name (default bcm0, bcm1, etc.)"); + +static int rcpu_mode = 0; +LKM_MOD_PARAM(rcpu_mode, "i", int, 0); +MODULE_PARM_DESC(rcpu_mode, +"Enable RCPU encapsulation (default 0)"); + +static char *rcpu_dmac = NULL; +LKM_MOD_PARAM(rcpu_dmac, "s", charp, 0); +MODULE_PARM_DESC(rcpu_dmac, +"RCPU destination MAC address (by default use L2 destination MAC address)"); + +static char *rcpu_smac = NULL; +LKM_MOD_PARAM(rcpu_smac, "s", charp, 0); +MODULE_PARM_DESC(rcpu_smac, +"RCPU source MAC address (by default use L2 source MAC address)"); + +static int rcpu_ethertype = 0xde08; +LKM_MOD_PARAM(rcpu_ethertype, "i", int, 0); +MODULE_PARM_DESC(rcpu_ethertype, +"RCPU EtherType (default DE08h)"); + +static int rcpu_signature = 0; +LKM_MOD_PARAM(rcpu_signature, "i", int, 0); +MODULE_PARM_DESC(rcpu_signature, +"RCPU Signature (default is PCI device ID)"); + +static int rcpu_vlan = 1; +LKM_MOD_PARAM(rcpu_vlan, "i", int, 0); +MODULE_PARM_DESC(rcpu_vlan, +"RCPU VLAN ID (default 1)"); + +static int use_rx_skb = 0; +LKM_MOD_PARAM(use_rx_skb, "i", int, 0); +MODULE_PARM_DESC(use_rx_skb, +"Use socket buffers for receive operation (default 0)"); + +static int num_rx_prio = 1; +LKM_MOD_PARAM(num_rx_prio, "i", int, 0); +MODULE_PARM_DESC(num_rx_prio, +"Number of filter priorities per Rx DMA channel"); + +static int rx_rate[4] = { 100000, 100000, 100000, 0 }; +LKM_MOD_PARAM_ARRAY(rx_rate, "1-4i", int, NULL, 0); +MODULE_PARM_DESC(rx_rate, +"Rx rate in packets per second (default 100000)"); + +static int rx_burst[4] = { 0, 0, 0, 0 }; +LKM_MOD_PARAM_ARRAY(rx_burst, "1-4i", int, NULL, 0); +MODULE_PARM_DESC(rx_burst, +"Rx rate burst maximum in packets (default rx_rate/10)"); + +static int check_rcpu_signature = 0; +LKM_MOD_PARAM(check_rcpu_signature, "i", int, 0); +MODULE_PARM_DESC(check_rcpu_signature, +"Check RCPU Signature for Tx packets from RCPU interfaces"); + +static int basedev_suspend = 0; +LKM_MOD_PARAM(basedev_suspend, "i", int, 0); +MODULE_PARM_DESC(basedev_suspend, +"Pause traffic till base device is up (enabled by default in NAPI mode)"); + +static int ftmh_lb_key_ext = 0; +LKM_MOD_PARAM(ftmh_lb_key_ext, "i", int, 0); +MODULE_PARM_DESC(ftmh_lb_key_ext, +"FTMH LB-Key Extension header is present (default 0)"); + +static int ftmh_stacking_ext = 0; +LKM_MOD_PARAM(ftmh_stacking_ext, "i", int, 0); +MODULE_PARM_DESC(ftmh_stacking_ext, +"FTMH Stacking Extension header is present (default 0)"); + +/* Debug levels */ +#define DBG_LVL_VERB 0x1 +#define DBG_LVL_DCB 0x2 +#define DBG_LVL_PKT 0x4 +#define DBG_LVL_SKB 0x8 +#define DBG_LVL_CMD 0x10 +#define DBG_LVL_EVT 0x20 +#define DBG_LVL_IRQ 0x40 +#define DBG_LVL_NAPI 0x80 +#define DBG_LVL_PDMP 0x100 +#define DBG_LVL_FLTR 0x200 +#define DBG_LVL_KCOM 0x400 +#define DBG_LVL_RCPU 0x800 +#define DBG_LVL_WARN 0x1000 +#define DBG_LVL_NDEV 0x2000 +#define DBG_LVL_INST 0x4000 +/* Level to output Dune internal headers Parsing */ +#define DBG_LVL_DUNE 0x8000 +#define DBG_LVL_DCB_TX 0x10000 +#define DBG_LVL_DCB_RX 0x20000 +#define DBG_LVL_PDMP_TX 0x40000 +#define DBG_LVL_PDMP_RX 0x80000 + +#define DBG_VERB(_s) do { if (debug & DBG_LVL_VERB) gprintk _s; } while (0) +#define DBG_PKT(_s) do { if (debug & DBG_LVL_PKT) gprintk _s; } while (0) +#define DBG_SKB(_s) do { if (debug & DBG_LVL_SKB) gprintk _s; } while (0) +#define DBG_CMD(_s) do { if (debug & DBG_LVL_CMD) gprintk _s; } while (0) +#define DBG_EVT(_s) do { if (debug & DBG_LVL_EVT) gprintk _s; } while (0) +#define DBG_IRQ(_s) do { if (debug & DBG_LVL_IRQ) gprintk _s; } while (0) +#define DBG_NAPI(_s) do { if (debug & DBG_LVL_NAPI) gprintk _s; } while (0) +#define DBG_PDMP(_s) do { if (debug & DBG_LVL_PDMP) gprintk _s; } while (0) +#define DBG_FLTR(_s) do { if (debug & DBG_LVL_FLTR) gprintk _s; } while (0) +#define DBG_KCOM(_s) do { if (debug & DBG_LVL_KCOM) gprintk _s; } while (0) +#define DBG_RCPU(_s) do { if (debug & DBG_LVL_RCPU) gprintk _s; } while (0) +#define DBG_WARN(_s) do { if (debug & DBG_LVL_WARN) gprintk _s; } while (0) +#define DBG_NDEV(_s) do { if (debug & DBG_LVL_NDEV) gprintk _s; } while (0) +#define DBG_INST(_s) do { if (debug & DBG_LVL_INST) gprintk _s; } while (0) +#define DBG_DUNE(_s) do { if (debug & DBG_LVL_DUNE) gprintk _s; } while (0) +#define DBG_DCB_TX(_s) do { if (debug & (DBG_LVL_DCB|DBG_LVL_DCB_TX)) \ + gprintk _s; } while (0) +#define DBG_DCB_RX(_s) do { if (debug & (DBG_LVL_DCB|DBG_LVL_DCB_RX)) \ + gprintk _s; } while (0) +#define DBG_DCB(_s) do { if (debug & (DBG_LVL_DCB|DBG_LVL_DCB_TX| \ + DBG_LVL_DCB_RX)) \ + gprintk _s; } while (0) + + +/* This flag is used to indicate if debugging packet function is open or closed */ +static int dbg_pkt_enable = 0; + +/* Module Information */ +#define MODULE_MAJOR 122 +#define MODULE_NAME "linux-bcm-knet" + +#ifndef NAPI_SUPPORT +#define NAPI_SUPPORT 1 +#endif + +#if NAPI_SUPPORT + +static int use_napi = 0; +LKM_MOD_PARAM(use_napi, "i", int, 0); +MODULE_PARM_DESC(use_napi, +"Use NAPI interface (default 0)"); + +static int napi_weight = 64; +LKM_MOD_PARAM(napi_weight, "i", int, 0); +MODULE_PARM_DESC(napi_weight, +"Weight of NAPI interfaces (default 64)"); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) +#define bkn_napi_enable(_dev, _napi) netif_poll_enable(_dev) +#define bkn_napi_disable(_dev, _napi) netif_poll_disable(_dev) +#define bkn_napi_schedule(_dev, _napi) netif_rx_schedule(_dev) +#define bkn_napi_schedule_prep(_dev, _napi) netif_rx_schedule_prep(_dev) +#define __bkn_napi_schedule(_dev, _napi) __netif_rx_schedule(_dev) +#define bkn_napi_complete(_dev, _napi) netif_rx_complete(_dev) +#else +#define bkn_napi_enable(_dev, _napi) napi_enable(_napi) +#define bkn_napi_disable(_dev, _napi) napi_disable(_napi) +#define bkn_napi_schedule(_dev, _napi) napi_schedule(_napi) +#define bkn_napi_schedule_prep(_dev, _napi) napi_schedule_prep(_napi) +#define __bkn_napi_schedule(_dev, _napi) __napi_schedule(_napi) +#define bkn_napi_complete(_dev, _napi) napi_complete(_napi) +#endif + +#else + +static int use_napi = 0; +static int napi_weight = 0; + +#define bkn_napi_enable(_dev, _napi) +#define bkn_napi_disable(_dev, _napi) +#define bkn_napi_schedule(_dev, _napi) +#define bkn_napi_schedule_prep(_dev, _napi) (0) +#define __bkn_napi_schedule(_dev, _napi) +#define bkn_napi_complete(_dev, _napi) + +#endif + +/* + * If proxy support is compiled in the module will attempt to use + * the user/kernel message service provided by the linux-uk-proxy + * kernel module, otherwise device IOCTL will be used. + */ +#ifndef PROXY_SUPPORT +#define PROXY_SUPPORT 0 +#endif + +#if PROXY_SUPPORT + +#include + +static int use_proxy = 1; +LKM_MOD_PARAM(use_proxy, "i", int, 0); +MODULE_PARM_DESC(use_proxy, +"Use Linux User/Kernel proxy (default 1)"); + +#define PROXY_SERVICE_CREATE(_s,_q,_f) linux_uk_proxy_service_create(_s,_q,_f) +#define PROXY_SERVICE_DESTROY(_s) linux_uk_proxy_service_destroy(_s); +#define PROXY_SEND(_s,_m,_l) linux_uk_proxy_send(_s,_m,_l) +#define PROXY_RECV(_s,_m,_l) linux_uk_proxy_recv(_s,_m,_l) + +#else + +static int use_proxy = 0; + +#define PROXY_SERVICE_CREATE(_s,_q,_f) +#define PROXY_SERVICE_DESTROY(_s) +#define PROXY_SEND(_s,_m,_l) +#define PROXY_RECV(_s,_m,_l) (-1) + +#endif + +/* Compatibility */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) +#define skb_copy_to_linear_data(_skb, _pkt, _len) \ + eth_copy_and_sum(_skb, _pkt, _len, 0) +struct napi_struct { int not_used; }; +#define netif_napi_add(_dev, _napi, _poll, _weight) do { \ + (_dev)->poll = _poll; \ + (_dev)->weight = _weight; \ +} while(0) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) +#define SKB_PADTO(_skb,_len) (((_skb = skb_padto(_skb,_len)) == NULL) ? -1 : 0) +#else +#define SKB_PADTO(_skb,_len) skb_padto(_skb,_len) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)) +#define skb_header_cloned(_skb) \ + skb_cloned(_skb) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27) +static inline void *netdev_priv(struct net_device *dev) +{ + return dev->priv; +} +#endif /* KERNEL_VERSION(2,4,27) */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23) +/* Special check for MontaVista 2.4.20 MIPS */ +#if !(defined(MAX_USER_RT_PRIO) && defined(CONFIG_MIPS)) +static inline void free_netdev(struct net_device *dev) +{ + kfree(dev); +} +#endif +static inline void netif_poll_disable(struct net_device *dev) +{ + while (test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state)) { + /* No hurry. */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } +} +static inline void netif_poll_enable(struct net_device *dev) +{ + clear_bit(__LINK_STATE_RX_SCHED, &dev->state); +} +#endif /* KERNEL_VERSION(2,4,23) */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21) +static struct sk_buff *skb_pad(struct sk_buff *skb, int pad) +{ + struct sk_buff *nskb; + + /* If the skbuff is non linear tailroom is always zero.. */ + if(skb_tailroom(skb) >= pad) + { + memset(skb->data+skb->len, 0, pad); + return skb; + } + + nskb = skb_copy_expand(skb, skb_headroom(skb), skb_tailroom(skb) + pad, GFP_ATOMIC); + kfree_skb(skb); + if(nskb) + memset(nskb->data+nskb->len, 0, pad); + return nskb; +} +static inline struct sk_buff *skb_padto(struct sk_buff *skb, unsigned int len) +{ + unsigned int size = skb->len; + if(likely(size >= len)) + return skb; + return skb_pad(skb, len-size); +} +#endif /* KERNEL_VERSION(2,4,21) */ + +#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT +#define DMA_DEV device +#define DMA_FROMDEV DMA_FROM_DEVICE +#define DMA_TODEV DMA_TO_DEVICE +#define DMA_MAP_SINGLE(d,p,s,r) dma_map_single(d,p,s,r) +#define DMA_UNMAP_SINGLE(d,a,s,r) dma_unmap_single(d,a,s,r) +#define DMA_ALLOC_COHERENT(d,s,h) dma_alloc_coherent(d,s,h,GFP_ATOMIC|GFP_DMA32) +#define DMA_FREE_COHERENT(d,s,a,h) dma_free_coherent(d,s,a,h) +#else +#define DMA_DEV pci_dev +#define DMA_FROMDEV PCI_DMA_FROMDEVICE +#define DMA_TODEV PCI_DMA_TODEVICE +#define DMA_MAP_SINGLE(d,p,s,r) pci_map_single(d,p,s,r) +#define DMA_UNMAP_SINGLE(d,a,s,r) pci_unmap_single(d,a,s,r) +#define DMA_ALLOC_COHERENT(d,s,h) pci_alloc_consistent(d,s,h) +#define DMA_FREE_COHERENT(d,s,a,h) pci_free_consistent(d,s,a,h) +#endif + +/* RCPU operations */ +#define RCPU_OPCODE_RX 0x10 +#define RCPU_OPCODE_TX 0x20 + +/* RCPU flags */ +#define RCPU_F_MODHDR 0x4 + +/* RCPU encapsulation */ +#define RCPU_HDR_SIZE 32 +#define RCPU_TX_META_SIZE 32 +#define RCPU_TX_ENCAP_SIZE (RCPU_HDR_SIZE + RCPU_TX_META_SIZE) +#define RCPU_RX_META_SIZE 64 +#define RCPU_RX_ENCAP_SIZE (RCPU_HDR_SIZE + RCPU_RX_META_SIZE) + +static volatile int module_initialized; + +static ibde_t *kernel_bde = NULL; + +/* Descriptor info */ +typedef struct bkn_desc_info_s { + uint32_t *dcb_mem; + dma_addr_t dcb_dma; + struct sk_buff *skb; + dma_addr_t skb_dma; + uint32_t dma_size; +} bkn_desc_info_t; + +/* DCB chain info */ +typedef struct bkn_dcb_chain_s { + struct list_head list; + int dcb_cnt; + int dcb_cur; + uint32_t *dcb_mem; + dma_addr_t dcb_dma; +} bkn_dcb_chain_t; + +#define MAX_TX_DCBS 32 +#define MAX_RX_DCBS 32 + +#define NUM_DMA_CHAN 4 +#define NUM_RX_CHAN 3 +#define API_RX_CHAN 0 + +/* Device control info */ +typedef struct bkn_switch_info_s { + struct list_head list; + struct list_head ndev_list; /* Associated virtual Ethernet interfaces */ + struct net_device **ndevs; /* Indexed array of ndev_list */ + int ndev_max; /* Size of indexed array */ + struct list_head rxpf_list; /* Associated Rx packet filters */ + volatile void *base_addr; /* Base address for PCI register access */ + struct DMA_DEV *dma_dev; /* Required for DMA memory control */ + struct pci_dev *pdev; /* Required for DMA memory control */ + struct net_device *dev; /* Base network device */ + struct napi_struct napi; /* New NAPI */ + struct timer_list timer; /* Retry/resource timer */ + int timer_queued; /* Flag indicating queued timer function */ + uint32_t timer_runs; /* Timer function runs (debug only) */ + struct timer_list rxtick; /* Rx rate control timer */ + uint32_t rxticks_per_sec; /* Rx rate control update frequency */ + uint32_t rxtick_jiffies; /* Time between updates (in jiffies) */ + uint32_t rxticks; /* Rx rate control debug counter */ + uint32_t interrupts; /* Total number of interrupts */ + spinlock_t lock; /* Main lock for device */ + int dev_no; /* Device number (from BDE) */ + int cpu_no; /* Cpu number. 1 for iHost(AXI),0 for others */ + int dcb_type; /* DCB type */ + int dcb_wsize; /* DCB size (in 32-bit words) */ + uint32_t cmic_type; /* CMIC type (CMICe or CMICm) */ + uint32_t irq_mask; /* Active IRQs for DMA control */ + uint32_t napi_poll_mode; /* NAPI is in polling mode */ + uint32_t napi_not_done; /* NAPI poll did not process all packets */ + uint32_t napi_poll_again; /* Used if DCB chain is restarted */ + uint32_t tx_yield; /* Tx schedule for Continuous DMA and Non-NAPI mode */ + void *dcb_mem; /* Logical pointer to DCB memory */ + dma_addr_t dcb_dma; /* Physical bus address for DCB memory */ + int dcb_mem_size; /* Total size of allocated DCB memory */ + uint32_t dma_events; /* DMA events pending for BCM API */ + uint32_t rcpu_sig; /* RCPU signature */ + dma_addr_t halt_addr[NUM_DMA_CHAN]; /* DMA halt address */ + uint32_t cdma_channels; /* Active channels for Continuous DMA mode */ + uint32_t inst_id; /* Instance id of this device */ + int evt_idx; /* Event queue index for this device*/ + int basedev_suspended; /* Base device suspended */ + struct { + bkn_desc_info_t desc[MAX_TX_DCBS+1]; + int free; /* Number of free Tx DCBs */ + int cur; /* Index of current Tx DCB */ + int dirty; /* Index of next Tx DCB to complete */ + int api_active; /* BCM Tx API is in progress */ + int suspends; /* Calls to netif_stop_queue (debug only) */ + struct list_head api_dcb_list; /* Tx DCB chains from BCM Tx API */ + bkn_dcb_chain_t *api_dcb_chain; /* Current Tx DCB chain */ + bkn_dcb_chain_t *api_dcb_chain_end; /* Tx DCB chain end */ + uint32_t pkts; /* Tx packet counter */ + uint32_t pkts_d_no_skb; /* Tx drop - skb allocation failed */ + uint32_t pkts_d_rcpu_encap; /* Tx drop - bad RCPU encapsulation */ + uint32_t pkts_d_rcpu_sig; /* Tx drop - bad RCPU signature */ + uint32_t pkts_d_rcpu_meta; /* Tx drop - bad RCPU meta data */ + uint32_t pkts_d_pad_fail; /* Tx drop - pad to minimum size failed */ + uint32_t pkts_d_dma_resrc; /* Tx drop - no DMA resources */ + uint32_t pkts_d_callback; /* Tx drop - consumed by call-back */ + uint32_t pkts_d_no_link; /* Tx drop - software link down */ + uint32_t pkts_d_over_limit; /* Tx drop - length is out of range */ + } tx; + struct { + bkn_desc_info_t desc[MAX_RX_DCBS+1]; + int free; /* Number of free Rx DCBs */ + int cur; /* Index of current Rx DCB */ + int dirty; /* Index of next Rx DCB to complete */ + int running; /* Rx DMA is active */ + int api_active; /* BCM Rx API is active */ + int chain_complete; /* All DCBs in chain processed */ + int sync_err; /* Chain done with incomplete DCBs (debug) */ + int sync_retry; /* Total retry times for sync error (debug) */ + int sync_maxloop; /* Max loop times once in recovering sync (debug) */ + int use_rx_skb; /* Use SKBs for DMA */ + uint32_t rate_max; /* Rx rate in packets/sec */ + uint32_t burst_max; /* Rx burst size in number of packets */ + uint32_t tokens; /* Tokens for Rx rate control */ + uint32_t rate; /* Current packet rate */ + unsigned long tok_jif; /* Jiffies at last token update */ + unsigned long rate_jif; /* Jiffies at last rate update */ + struct list_head api_dcb_list; /* Rx DCB chains from BCM Rx API */ + bkn_dcb_chain_t *api_dcb_chain; /* Current Rx DCB chain */ + bkn_dcb_chain_t *api_dcb_chain_end; /* Rx DCB chain end */ + uint32_t pkts; /* Rx packet counter */ + uint32_t pkts_ref; /* Rx packet count for rate calculation */ + uint32_t pkts_f_api; /* Rx packets filtered to API */ + uint32_t pkts_f_netif; /* Rx packets filtered to net interface */ + uint32_t pkts_m_api; /* Rx packets mirrored to API */ + uint32_t pkts_m_netif; /* Rx packets mirrored to net interface */ + uint32_t pkts_d_no_skb; /* Rx drop - skb allocation failed */ + uint32_t pkts_d_no_match; /* Rx drop - no matching filters */ + uint32_t pkts_d_unkn_netif; /* Rx drop - unknown net interface ID */ + uint32_t pkts_d_unkn_dest; /* Rx drop - unknown destination type */ + uint32_t pkts_d_callback; /* Rx drop - consumed by call-back */ + uint32_t pkts_d_no_link; /* Rx drop - software link down */ + uint32_t pkts_d_no_api_buf; /* Rx drop - no API buffers */ + } rx[NUM_RX_CHAN]; +} bkn_switch_info_t; + +#define BKN_DNX_HDR_MAX_SIZE 40 +/* FTMH */ +#define BKN_DNX_FTMH_SIZE_BYTE 9 +#define BKN_DNX_FTMH_LB_EXT_SIZE_BYTE 1 +#define BKN_DNX_FTMH_STACKING_SIZE_BYTE 2 +#define BKN_DNX_FTMH_DEST_EXT_SIZE_BYTE 2 +#define BKN_DNX_FTMH_LB_EXT_SIZE_BYTE 1 +#define BKN_DNX_FTMH_PKT_SIZE_MSB 0 +#define BKN_DNX_FTMH_PKT_SIZE_NOF_BITS 14 +#define BKN_DNX_FTMH_TC_MSB 14 +#define BKN_DNX_FTMH_TC_NOF_BITS 3 +#define BKN_DNX_FTMH_SRC_SYS_PORT_MSB 17 +#define BKN_DNX_FTMH_SRC_SYS_PORT_NOF_BITS 16 +#define BKN_DNX_FTMH_EXT_DSP_EXIST_MSB 68 +#define BKN_DNX_FTMH_EXT_DSP_EXIST_NOF_BITS 1 +#define BKN_DNX_FTMH_EXT_MSB 45 +#define BKN_DNX_FTMH_EXT_NOF_BITS 2 +#define BKN_DNX_FTMH_FIRST_EXT_MSB 72 +#define BKN_DNX_FTMH_ACTION_TYPE_MSB 43 +#define BKN_DNX_FTMH_ACTION_TYPE_NOF_BITS 2 +#define BKN_DNX_FTMH_PPH_TYPE_MSB 45 +#define BKN_DNX_FTMH_PPH_TYPE_NOF_BITS 2 +/* PPH */ +#define BKN_DNX_PPH_SIZE_BYTE 7 +#define BKN_DNX_PPH_EEI_EXTENSION_PRESENT_MSB 0 +#define BKN_DNX_PPH_EEI_EXTENSION_PRESENT_NOF_BITS 1 +#define BKN_DNX_PPH_LEARN_EXENSION_PRESENT_MSB 1 +#define BKN_DNX_PPH_LEARN_EXENSION_PRESENT_NOF_BITS 1 +#define BKN_DNX_PPH_FHEI_SIZE_MSB 2 +#define BKN_DNX_PPH_FHEI_SIZE_NOF_BITS 2 +#define BKN_DNX_PPH_FORWARD_CODE_MSB 4 +#define BKN_DNX_PPH_FORWARD_CODE_NOF_BITS 4 +#define BKN_DNX_PPH_VSI_MSB 22 +#define BKN_DNX_PPH_VSI_NOF_BITS 16 +/* FHEI TRAP/SNOOP 3B */ +#define BKN_DNX_PPH_FHEI_3B_SIZE_BYTE 3 +#define BKN_DNX_PPH_FHEI_5B_SIZE_BYTE 5 +#define BKN_DNX_PPH_FHEI_8B_SIZE_BYTE 8 +#define BKN_DNX_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_MSB 0 +#define BKN_DNX_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_NOF_BITS 16 +#define BKN_DNX_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_MSB 16 +#define BKN_DNX_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_NOF_BITS 8 +/* PPH extension */ +#define BKN_DNX_PPH_EXPLICIT_EDITING_INFOMATION_EXTENSION_SIZE_BYTE 3 +#define BKN_DNX_PPH_LEARN_EXTENSION_SIZE_BYTE 5 + + +/* ftmh action type. */ +typedef enum bkn_dnx_ftmh_action_type_e { + BKN_DNX_FTMH_ACTION_TYPE_FORWARD = 0, /* TM action is forward */ + BKN_DNX_FTMH_ACTION_TYPE_SNOOP = 1, /* TM action is snoop */ + BKN_DNX_FTMH_ACTION_TYPE_INBOUND_MIRROR = 2, /* TM action is inbound mirror. */ + BKN_DNX_FTMH_ACTION_TYPE_OUTBOUND_MIRROR = 3 /* TM action is outbound mirror. */ +}bkn_dnx_ftmh_action_type_t; + +/* ftmh dest extension. */ +typedef struct bkn_dnx_ftmh_dest_extension_s { + uint8 valid; /* Set if the extension is present */ + uint32_t dst_sys_port; /* Destination System Port */ +} bkn_dnx_ftmh_dest_extension_t; + +/* dnx packet */ +typedef struct bkn_pkt_dnx_s { + uint32_t ntwrk_header_ptr; + struct { + uint32_t packet_size; /* Packet size in bytes */ + uint32_t action_type; /* Indicates if the copy is one of the Forward Snoop or Mirror packet copies */ + uint32_t pph_type; + uint32_t prio; /* Traffic class */ + uint32_t src_sys_port; /* Source System port*/ + } ftmh; + struct { + uint32_t vsi; + uint32_t trap_qualifier; /* RAW Data */ + uint32_t trap_id; /* RAW Data */ + } internal; +} bkn_dnx_packet_info; + + +#define PREV_IDX(_cur, _max) (((_cur) == 0) ? (_max) - 1 : (_cur) - 1) + +#if defined(CMIC_SOFT_BYTE_SWAP) + +#define CMIC_SWAP32(_x) ((((_x) & 0xff000000) >> 24) \ + | (((_x) & 0x00ff0000) >> 8) \ + | (((_x) & 0x0000ff00) << 8) \ + | (((_x) & 0x000000ff) << 24)) + +#define DEV_READ32(_d, _a, _p) \ + do { \ + uint32_t _data; \ + _data = (((volatile uint32_t *)(_d)->base_addr)[(_a)/4]); \ + *(_p) = CMIC_SWAP32(_data); \ + } while(0) + +#define DEV_WRITE32(_d, _a, _v) \ + do { \ + uint32_t _data = CMIC_SWAP32(_v); \ + ((volatile uint32_t *)(_d)->base_addr)[(_a)/4] = (_data); \ + } while(0) + +#else + +#define DEV_READ32(_d, _a, _p) \ + do { \ + *(_p) = (((volatile uint32_t *)(_d)->base_addr)[(_a)/4]); \ + } while(0) + +#define DEV_WRITE32(_d, _a, _v) \ + do { \ + ((volatile uint32_t *)(_d)->base_addr)[(_a)/4] = (_v); \ + } while(0) + +#endif /* defined(CMIC_SOFT_BYTE_SWAP) */ + +#define MEMORY_BARRIER mb() + +/* Default random MAC address has Broadcom OUI with local admin bit set */ +static u8 bkn_dev_mac[6] = { 0x02, 0x10, 0x18, 0x00, 0x00, 0x00 }; + +static u8 bkn_rcpu_dmac[6]; +static u8 bkn_rcpu_smac[6]; + +/* Driver Proc Entry root */ +static struct proc_dir_entry *bkn_proc_root = NULL; + +typedef struct bkn_priv_s { + struct list_head list; + struct net_device_stats stats; + struct net_device *dev; + bkn_switch_info_t *sinfo; + int id; + int type; + int port; + uint8_t itmh[4]; + int qnum; + uint32_t vlan; + uint32_t flags; + uint32_t cb_user_data; +} bkn_priv_t; + +typedef struct bkn_filter_s { + struct list_head list; + int dev_no; + unsigned long hits; + kcom_filter_t kf; +} bkn_filter_t; + + +/* + * Multiple instance support in KNET + */ +static int _bkn_multi_inst = 0; +typedef struct { + wait_queue_head_t evt_wq; + int evt_wq_put; + int evt_wq_get; + uint32_t inst_id; +} bkn_evt_resource_t; + +static bkn_evt_resource_t _bkn_evt[LINUX_BDE_MAX_DEVICES]; + +static int bkn_knet_dev_init(int d); +static int bkn_knet_dev_reinit(int d); + +/* IOCTL debug counters */ +static int ioctl_cmd; +static int ioctl_evt; + +/* Switch devices */ +LIST_HEAD(_sinfo_list); + +/* Reallocation chunk size for netif array */ +#define NDEVS_CHUNK 64 + +/* User call-backs */ +static knet_skb_cb_f knet_rx_cb = NULL; +static knet_skb_cb_f knet_tx_cb = NULL; +static knet_filter_cb_f knet_filter_cb = NULL; + +/* + * Thread management + */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)) +/* + * Old style using kernel_thread() + */ +typedef struct { + const char * name; + volatile int pid; + volatile int run; + struct completion completion; + int state; +} bkn_thread_ctrl_t; + +static int +bkn_thread_start(bkn_thread_ctrl_t *tc, const char *name, + int (*threadfn)(void *)) +{ + if (name == NULL) { + return -1; + } + tc->name = name; + tc->pid = kernel_thread(threadfn, tc, 0); + if (tc->pid < 0) { + tc->pid = 0; + return -1; + } + tc->run = 1; + init_completion(&tc->completion); + return 0; +} + +static int +bkn_thread_stop(bkn_thread_ctrl_t *tc) +{ + if (tc->pid == 0) { + return 0; + } + tc->run = 0; + kill_proc(tc->pid, SIGTERM, 1); + wait_for_completion(&tc->completion); + return 0; +} + +static int +bkn_thread_should_stop(bkn_thread_ctrl_t *tc) +{ + if (tc->run) { + return 0; + } + tc->pid = 0; + return 1; +} + +static void +bkn_thread_boot(bkn_thread_ctrl_t *tc) +{ + siginitsetinv(¤t->blocked, sigmask(SIGTERM) | sigmask(SIGKILL)); +} + +static void +bkn_thread_exit(bkn_thread_ctrl_t *tc) +{ + complete_and_exit(&tc->completion, 0); +} + +static void +bkn_sleep(int clicks) +{ + wait_queue_head_t wq; + + init_waitqueue_head(&wq); + sleep_on_timeout(&wq, clicks); +} +#else +/* + * New style using kthread API + */ +#include +typedef struct { + const char * name; + struct task_struct *task; + int state; +} bkn_thread_ctrl_t; + +static int +bkn_thread_start(bkn_thread_ctrl_t *tc, const char *name, + int (*threadfn)(void *)) +{ + if (name == NULL) { + return -1; + } + tc->name = name; + tc->task = kthread_run(threadfn, tc, name); + if (IS_ERR(tc->task)) { + tc->task = NULL; + return -1; + } + return 0; +} + +static int +bkn_thread_stop(bkn_thread_ctrl_t *tc) +{ + if (tc->task == NULL) { + return 0; + } + send_sig(SIGTERM, tc->task, 0); + return kthread_stop(tc->task); +} + +static int +bkn_thread_should_stop(bkn_thread_ctrl_t *tc) +{ + return kthread_should_stop(); +} + +static void +bkn_thread_boot(bkn_thread_ctrl_t *tc) +{ + allow_signal(SIGTERM); + allow_signal(SIGKILL); +} + +static void +bkn_thread_exit(bkn_thread_ctrl_t *tc) +{ +} + +static void +bkn_sleep(int clicks) +{ + wait_queue_head_t wq; + + init_waitqueue_head(&wq); + wait_event_timeout(wq, 0, clicks); +} +#endif + +static bkn_thread_ctrl_t bkn_cmd_ctrl; +static bkn_thread_ctrl_t bkn_evt_ctrl; + +/* + * On XGS devices bit 15 fo the Transferred Bytes field in + * the DCBs is used to indicate that kernel processing is + * complete. Using this bit reduces the theoretically maximum + * supported packet size from 64K to 32K, but this is still + * adequate for 16K jumbo packets. + */ +#define SOC_DCB_KNET_DONE 0x8000 +#define SOC_DCB_KNET_COUNT_MASK 0x7fff +#define SOC_DCB_META_OFFSET 2 + +/* Default channel configuration */ +#define XGS_DMA_TX_CHAN 0 +#define XGS_DMA_RX_CHAN 1 + +/* CMIC registers */ +#define CMIC_DMA_CTRLr 0x00000100 +#define CMIC_DMA_STATr 0x00000104 +#define CMIC_DMA_DESC0r 0x00000110 +#define CMIC_IRQ_STATr 0x00000144 +#define CMIC_IRQ_MASKr 0x00000148 +#define CMIC_DEV_REV_IDr 0x00000178 + +/* CMIC interrupts reserved for kernel handler */ +#define CMIC_TXRX_IRQ_MASK 0x7f80 + +/* CMICm registers */ +#define CMICM_CMC_BASE 0x00031000 +#define CMICM_DMA_CTRLr (CMICM_CMC_BASE + 0x00000140) +#define CMICM_DMA_STATr (CMICM_CMC_BASE + 0x00000150) +#define CMICM_DMA_STAT_CLRr (CMICM_CMC_BASE + 0x000001a4) +#define CMICM_DMA_DESC0r (CMICM_CMC_BASE + 0x00000158) +#define CMICM_DMA_HALT_ADDRr (CMICM_CMC_BASE + 0x00000120) +#define CMICM_IRQ_STATr (CMICM_CMC_BASE + 0x00000400) +#define CMICM_IRQ_PCI_MASKr (CMICM_CMC_BASE + 0x00000414) +#define CMICM_IRQ_UC0_MASKr (CMICM_CMC_BASE + 0x00000428) +#define CMICM_DEV_REV_IDr 0x00010224 + +/* CMICm interrupts reserved for kernel handler */ +#define CMICM_TXRX_IRQ_MASK 0xff00 + +/* CMICd increased interrupts reserved for kernel handler */ +#define CMICD_CTRLD_IRQ_MASK 0x78000000 + +#define DEV_HAS_CMICM(_sinfo) ((_sinfo)->cmic_type == 'm') +#define CDMA_CH(_d, _ch) ((_d)->cdma_channels & (1 << (_ch))) + +/* + * DMA_STAT: control bits + * + * xxx_SET and xxx_CLR can be WRITTEN to CMIC_DMA_STAT + * xxx_TST can be masked against values read from CMIC_DMA_STAT. + * Argument required: 0 <= ch <= 3 + */ + +#define DS_DMA_ACTIVE(ch) (0x00040000 << (ch)) +#define DS_DMA_EN_SET(ch) (0x80|(ch)) +#define DS_DMA_EN_CLR(ch) (0x00|(ch)) +#define DS_DMA_EN_TST(ch) (0x00000001 << (ch)) + +#define DS_CHAIN_DONE_SET(ch) (0x80|(4+(ch))) +#define DS_CHAIN_DONE_CLR(ch) (0x00|(4+(ch))) +#define DS_CHAIN_DONE_TST(ch) (0x00000010 << (ch)) + +#define DS_DESC_DONE_SET(ch) (0x80|(8+(ch))) +#define DS_DESC_DONE_CLR(ch) (0x00|(8+(ch))) +#define DS_DESC_DONE_TST(ch) (0x00000100 << (ch)) + +#define DC_ABORT_DMA(ch) (0x04 << (8 * (ch))) + +#define DS_CMC_DESCRD_CMPLT_CLR(ch) (0x00000001 << (ch)) +#define DS_CMC_CTRLD_INT_CLR(ch) (0x00000100 << (ch)) +#define DS_CMC_DMA_ACTIVE(ch) (0x00000100 << (ch)) + +/* + * DMA_CTRL: control bits + */ +#define DC_CMC_DIRECTION (0x00000001) +#define DC_CMC_ENABLE (0x00000002) +#define DC_CMC_ABORT (0x00000004) +#define DC_CMC_CTRLD_INT (0x00000100) +#define DC_CMC_CONTINUOUS (0x00000200) + +/* + * Per-channel operations. + * These are the basis for the TX/RX functions + */ + +static inline void +xgs_dma_chain_clear(bkn_switch_info_t *sinfo, int chan) +{ + DBG_IRQ(("Clear chain on device %d chan %d\n", + sinfo->dev_no, chan)); + DEV_WRITE32(sinfo, CMIC_DMA_STATr, DS_DMA_EN_CLR(chan)); + DEV_WRITE32(sinfo, CMIC_DMA_STATr, DS_CHAIN_DONE_CLR(chan)); + + MEMORY_BARRIER; +} + +static inline void +xgs_dma_desc_clear(bkn_switch_info_t *sinfo, int chan) +{ + uint32_t val; + + DBG_IRQ(("Clear desc on device %d chan %d\n", + sinfo->dev_no, chan)); + DEV_WRITE32(sinfo, CMIC_DMA_STATr, DS_DESC_DONE_CLR(chan)); + + MEMORY_BARRIER; + + /* Flush write buffer */ + DEV_READ32(sinfo, CMIC_DMA_STATr, &val); + + MEMORY_BARRIER; +} + +static int +xgs_dma_chan_clear(bkn_switch_info_t *sinfo, int chan) +{ + xgs_dma_chain_clear(sinfo, chan); + xgs_dma_desc_clear(sinfo, chan); + + return 0; +} + +static int +xgs_dma_chan_init(bkn_switch_info_t *sinfo, int chan, int dir) +{ + uint32_t cdc; + + DEV_READ32(sinfo, CMIC_DMA_CTRLr, &cdc); + + cdc &= ~(0x9 << (8 * chan)); + if (dir) { + cdc |= 0x1 << (8 * chan); + } else { + cdc |= 0x8 << (8 * chan); + } + + DEV_WRITE32(sinfo, CMIC_DMA_CTRLr, cdc); + + return 0; +} + +static int +xgs_dma_chan_start(bkn_switch_info_t *sinfo, int chan, dma_addr_t dcb) +{ + /* Write the DCB address to the DESC address for this channel */ + DEV_WRITE32(sinfo, CMIC_DMA_DESC0r + 4 * chan, dcb); + + MEMORY_BARRIER; + + /* Kick it off */ + DEV_WRITE32(sinfo, CMIC_DMA_STATr, DS_DMA_EN_SET(chan)); + + MEMORY_BARRIER; + + return 0; +} + +static int +xgs_dma_chan_abort(bkn_switch_info_t *sinfo, int chan, int polls) +{ + uint32_t ctrl, dma_stat; + int p; + + /* Clear enable */ + DEV_WRITE32(sinfo, CMIC_DMA_STATr, DS_DMA_EN_CLR(chan)); + + MEMORY_BARRIER; + + /* Abort the channel */ + DEV_READ32(sinfo, CMIC_DMA_CTRLr, &ctrl); + DEV_WRITE32(sinfo, CMIC_DMA_CTRLr, ctrl | DC_ABORT_DMA(chan)); + + MEMORY_BARRIER; + + /* Poll for abort completion */ + for (p = 0; p < polls; p++) { + DEV_READ32(sinfo, CMIC_DMA_STATr, &dma_stat); + if (!(dma_stat & DS_DMA_ACTIVE(chan))) { + /* Restore previous control value */ + DEV_WRITE32(sinfo, CMIC_DMA_CTRLr, ctrl); + + MEMORY_BARRIER; + + /* Clear up channel */ + xgs_dma_chan_clear(sinfo, chan); + + return polls; + } + } + DBG_WARN(("DMA channel %d abort failed\n", chan)); + + return -1; +} + +static inline void +xgs_irq_mask_set(bkn_switch_info_t *sinfo, uint32_t mask) +{ + if (sinfo->napi_poll_mode) { + mask = 0; + } + lkbde_irq_mask_set(sinfo->dev_no | LKBDE_ISR2_DEV, CMIC_IRQ_MASKr, + mask, CMIC_TXRX_IRQ_MASK); +} + +static inline void +xgs_irq_mask_enable(bkn_switch_info_t *sinfo, int chan, int update_hw) +{ + uint32_t mask; + + if (chan == XGS_DMA_TX_CHAN) { + mask = 0x100; + } else { + mask = 0x180 << (2 * chan); + } + + sinfo->irq_mask |= mask; + + if (update_hw) { + xgs_irq_mask_set(sinfo, sinfo->irq_mask); + } +} + +static inline void +xgs_irq_mask_disable(bkn_switch_info_t *sinfo, int chan, int update_hw) +{ + uint32_t mask; + + if (chan == XGS_DMA_TX_CHAN) { + mask = 0x100; + } else { + mask = 0x180 << (2 * chan); + } + + sinfo->irq_mask &= ~mask; + + if (update_hw) { + xgs_irq_mask_set(sinfo, sinfo->irq_mask); + } +} + +static inline void +xgsm_dma_chain_clear(bkn_switch_info_t *sinfo, int chan) +{ + uint32_t cdc; + + /* Disabing DMA clears chain done */ + DEV_READ32(sinfo, CMICM_DMA_CTRLr + 4 * chan, &cdc); + cdc &= ~(DC_CMC_ENABLE | DC_CMC_ABORT); + DEV_WRITE32(sinfo, CMICM_DMA_CTRLr + 4 * chan, cdc); + + MEMORY_BARRIER; +} + +static inline void +xgsm_dma_desc_clear(bkn_switch_info_t *sinfo, int chan) +{ + uint32_t val; + + val = DS_CMC_DESCRD_CMPLT_CLR(chan); + if (CDMA_CH(sinfo, chan)) { + val |= DS_CMC_CTRLD_INT_CLR(chan); + } + DEV_WRITE32(sinfo, CMICM_DMA_STAT_CLRr, val); + + MEMORY_BARRIER; + + /* Flush write buffer */ + DEV_READ32(sinfo, CMICM_DMA_STAT_CLRr, &val); + + MEMORY_BARRIER; +} + +static int +xgsm_dma_chan_clear(bkn_switch_info_t *sinfo, int chan) +{ + xgsm_dma_chain_clear(sinfo, chan); + xgsm_dma_desc_clear(sinfo, chan); + + return 0; +} + +static inline void +xgsm_cdma_halt_set(bkn_switch_info_t *sinfo, int chan) +{ + DEV_WRITE32(sinfo, CMICM_DMA_HALT_ADDRr + 4 * chan, + sinfo->halt_addr[chan]); + + MEMORY_BARRIER; +} + +static int +xgsm_dma_chan_init(bkn_switch_info_t *sinfo, int chan, int dir) +{ + uint32_t cdc; + + DEV_READ32(sinfo, CMICM_DMA_CTRLr + 4 * chan, &cdc); + cdc &= ~DC_CMC_DIRECTION; + if (dir) { + cdc |= DC_CMC_DIRECTION; + } + if (CDMA_CH(sinfo, chan)) { + cdc |= DC_CMC_CONTINUOUS | DC_CMC_CTRLD_INT; + xgsm_cdma_halt_set(sinfo, chan); + } + DEV_WRITE32(sinfo, CMICM_DMA_CTRLr + 4 * chan, cdc); + + return 0; +} + +static int +xgsm_dma_chan_start(bkn_switch_info_t *sinfo, int chan, dma_addr_t dcb) +{ + uint32_t cdc; + + /* Write the DCB address to the DESC address for this channel */ + DEV_WRITE32(sinfo, CMICM_DMA_DESC0r + 4 * chan, dcb); + + MEMORY_BARRIER; + + /* Kick it off */ + DEV_READ32(sinfo, CMICM_DMA_CTRLr + 4 * chan, &cdc); + cdc |= DC_CMC_ENABLE; + DEV_WRITE32(sinfo, CMICM_DMA_CTRLr + 4 * chan, cdc); + + MEMORY_BARRIER; + + return 0; +} + +static int +xgsm_dma_chan_abort(bkn_switch_info_t *sinfo, int chan, int polls) +{ + uint32_t ctrl, dma_stat; + int p; + + /* Skip abort sequence if channel is not active */ + DEV_READ32(sinfo, CMICM_DMA_STATr, &dma_stat); + if (!(dma_stat & DS_CMC_DMA_ACTIVE(chan))) { + return 0; + } + + /* Abort the channel */ + DEV_READ32(sinfo, CMICM_DMA_CTRLr + 4 * chan, &ctrl); + ctrl |= (DC_CMC_ENABLE | DC_CMC_ABORT); + DEV_WRITE32(sinfo, CMICM_DMA_CTRLr + 4 * chan, ctrl); + + MEMORY_BARRIER; + + /* Poll for abort completion */ + for (p = 0; p < polls; p++) { + DEV_READ32(sinfo, CMICM_DMA_STATr, &dma_stat); + if (!(dma_stat & DS_CMC_DMA_ACTIVE(chan))) { + /* Clear up channel */ + xgsm_dma_chan_clear(sinfo, chan); + return polls; + } + } + DBG_WARN(("DMA channel %d abort failed\n", chan)); + + return -1; +} + +static inline void +xgsm_irq_mask_set(bkn_switch_info_t *sinfo, uint32_t mask) +{ + uint32_t irq_mask_reg = CMICM_IRQ_PCI_MASKr; + uint32_t ctrld_mask = 0; + + if (sinfo->napi_poll_mode) { + mask = 0; + } + if (sinfo->cpu_no == 1) { + irq_mask_reg = CMICM_IRQ_UC0_MASKr; + } + + /* Get the Controlled Interrupts mask for Continuous DMA mode */ + ctrld_mask |= (sinfo->cdma_channels << 27) & CMICD_CTRLD_IRQ_MASK; + + lkbde_irq_mask_set(sinfo->dev_no | LKBDE_ISR2_DEV, irq_mask_reg, + mask, CMICM_TXRX_IRQ_MASK | ctrld_mask); +} + +static inline void +xgsm_irq_mask_enable(bkn_switch_info_t *sinfo, int chan, int update_hw) +{ + uint32_t mask; + + if (CDMA_CH(sinfo, chan)) { + mask = 0x08000000 << chan; + } else { + if (chan == XGS_DMA_TX_CHAN) { + mask = 0x8000; + } else { + mask = 0xc000 >> (2 * chan); + } + } + + sinfo->irq_mask |= mask; + + if (update_hw) { + xgsm_irq_mask_set(sinfo, sinfo->irq_mask); + } +} + +static inline void +xgsm_irq_mask_disable(bkn_switch_info_t *sinfo, int chan, int update_hw) +{ + uint32_t mask; + + if (CDMA_CH(sinfo, chan)) { + mask = 0x08000000 << chan; + } else { + if (chan == XGS_DMA_TX_CHAN) { + mask = 0x8000; + } else { + mask = 0xc000 >> (2 * chan); + } + } + + sinfo->irq_mask &= ~mask; + + if (update_hw) { + xgsm_irq_mask_set(sinfo, sinfo->irq_mask); + } +} + +static inline void +dev_dma_chain_clear(bkn_switch_info_t *sinfo, int chan) +{ + if (DEV_HAS_CMICM(sinfo)) { + xgsm_dma_chain_clear(sinfo, chan); + } else { + xgs_dma_chain_clear(sinfo, chan); + } +} + +static inline void +dev_dma_desc_clear(bkn_switch_info_t *sinfo, int chan) +{ + if (DEV_HAS_CMICM(sinfo)) { + xgsm_dma_desc_clear(sinfo, chan); + } else { + xgs_dma_desc_clear(sinfo, chan); + } +} + +static int +dev_dma_chan_clear(bkn_switch_info_t *sinfo, int chan) +{ + if (DEV_HAS_CMICM(sinfo)) { + return xgsm_dma_chan_clear(sinfo, chan); + } + return xgs_dma_chan_clear(sinfo, chan); +} + +static void +dev_cdma_halt_set(bkn_switch_info_t *sinfo, int chan) +{ + if (DEV_HAS_CMICM(sinfo)) { + xgsm_cdma_halt_set(sinfo, chan); + } +} + +static int +dev_dma_chan_init(bkn_switch_info_t *sinfo, int chan, int dir) +{ + if (DEV_HAS_CMICM(sinfo)) { + return xgsm_dma_chan_init(sinfo, chan, dir); + } + return xgs_dma_chan_init(sinfo, chan, dir); +} + +static int +dev_dma_chan_start(bkn_switch_info_t *sinfo, int chan, dma_addr_t dcb) +{ + if (DEV_HAS_CMICM(sinfo)) { + return xgsm_dma_chan_start(sinfo, chan, dcb); + } + return xgs_dma_chan_start(sinfo, chan, dcb); +} + +static int +dev_dma_chan_abort(bkn_switch_info_t *sinfo, int chan, int polls) +{ + if (DEV_HAS_CMICM(sinfo)) { + return xgsm_dma_chan_abort(sinfo, chan, polls); + } + return xgs_dma_chan_abort(sinfo, chan, polls); +} + +static inline void +dev_irq_mask_set(bkn_switch_info_t *sinfo, uint32_t mask) +{ + if (DEV_HAS_CMICM(sinfo)) { + xgsm_irq_mask_set(sinfo, mask); + } else { + xgs_irq_mask_set(sinfo, mask); + } +} + +static inline void +dev_irq_mask_enable(bkn_switch_info_t *sinfo, int chan, int update_hw) +{ + if (DEV_HAS_CMICM(sinfo)) { + xgsm_irq_mask_enable(sinfo, chan, update_hw); + } else { + xgs_irq_mask_enable(sinfo, chan, update_hw); + } +} + +static void +dev_irq_mask_disable(bkn_switch_info_t *sinfo, int chan, int update_hw) +{ + if (DEV_HAS_CMICM(sinfo)) { + xgsm_irq_mask_disable(sinfo, chan, update_hw); + } else { + xgs_irq_mask_disable(sinfo, chan, update_hw); + } +} + + +static int +bkn_alloc_dcbs(bkn_switch_info_t *sinfo) +{ + int dcb_size; + int tx_ring_size, rx_ring_size; + + dcb_size = sinfo->dcb_wsize * sizeof(uint32_t); + tx_ring_size = dcb_size * (MAX_TX_DCBS + 1); + rx_ring_size = dcb_size * (MAX_RX_DCBS + 1); + sinfo->dcb_mem_size = tx_ring_size + rx_ring_size * NUM_RX_CHAN; + + sinfo->dcb_mem = DMA_ALLOC_COHERENT(sinfo->dma_dev, + sinfo->dcb_mem_size, + &sinfo->dcb_dma); + if (sinfo->dcb_mem == NULL) { + gprintk("DCB memory allocation (%d bytes) failed.\n", + sinfo->dcb_mem_size); + return -ENOMEM; + } + + return 0; +} + +static void +bkn_free_dcbs(bkn_switch_info_t *sinfo) +{ + if (sinfo->dcb_mem != NULL) { + DMA_FREE_COHERENT(sinfo->dma_dev, sinfo->dcb_mem_size, + sinfo->dcb_mem, sinfo->dcb_dma); + sinfo->dcb_mem = NULL; + } +} + +static void +bkn_clean_tx_dcbs(bkn_switch_info_t *sinfo) +{ + bkn_desc_info_t *desc; + + DBG_DCB_TX(("Cleaning Tx DCBs (%d %d).\n", + sinfo->tx.cur, sinfo->tx.dirty)); + while (sinfo->tx.free < MAX_TX_DCBS) { + desc = &sinfo->tx.desc[sinfo->tx.dirty]; + if (desc->skb != NULL) { + DBG_SKB(("Cleaning Tx SKB from DCB %d.\n", + sinfo->tx.dirty)); + DMA_UNMAP_SINGLE(sinfo->dma_dev, + desc->skb_dma, desc->dma_size, + DMA_TODEV); + desc->skb_dma = 0; + dev_kfree_skb_any(desc->skb); + desc->skb = NULL; + } + if (++sinfo->tx.dirty >= MAX_TX_DCBS) { + sinfo->tx.dirty = 0; + } + sinfo->tx.free++; + } + sinfo->tx.api_active = 0; + DBG_DCB_TX(("Cleaned Tx DCBs (%d %d).\n", + sinfo->tx.cur, sinfo->tx.dirty)); +} + +static void +bkn_clean_rx_dcbs(bkn_switch_info_t *sinfo, int chan) +{ + bkn_desc_info_t *desc; + + DBG_DCB_RX(("Cleaning Rx%d DCBs (%d %d).\n", + chan, sinfo->rx[chan].cur, sinfo->rx[chan].dirty)); + while (sinfo->rx[chan].free) { + desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty]; + if (desc->skb != NULL) { + DBG_SKB(("Cleaning Rx%d SKB from DCB %d.\n", + chan, sinfo->rx[chan].dirty)); + DMA_UNMAP_SINGLE(sinfo->dma_dev, + desc->skb_dma, desc->dma_size, + DMA_FROMDEV); + desc->skb_dma = 0; + dev_kfree_skb_any(desc->skb); + desc->skb = NULL; + } + if (++sinfo->rx[chan].dirty >= MAX_RX_DCBS) { + sinfo->rx[chan].dirty = 0; + } + sinfo->rx[chan].free--; + } + sinfo->rx[chan].running = 0; + sinfo->rx[chan].api_active = 0; + DBG_DCB_RX(("Cleaned Rx%d DCBs (%d %d).\n", + chan, sinfo->rx[chan].cur, sinfo->rx[chan].dirty)); +} + +static void +bkn_clean_dcbs(bkn_switch_info_t *sinfo) +{ + int chan; + + bkn_clean_tx_dcbs(sinfo); + + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + bkn_clean_rx_dcbs(sinfo, chan); + } +} + +static void +bkn_init_dcbs(bkn_switch_info_t *sinfo) +{ + int dcb_size; + uint32_t *dcb_mem; + dma_addr_t dcb_dma; + bkn_desc_info_t *desc; + int idx; + int chan; + + memset(sinfo->dcb_mem, 0, sinfo->dcb_mem_size); + + dcb_size = sinfo->dcb_wsize * sizeof(uint32_t); + dcb_mem = sinfo->dcb_mem; + dcb_dma = sinfo->dcb_dma; + + for (idx = 0; idx < (MAX_TX_DCBS + 1); idx++) { + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) { + dcb_mem[1] |= (1 << 24) | (1 << 16); + if (idx == MAX_TX_DCBS) { + dcb_mem[1] |= 1 << 18; + dcb_mem[0] = sinfo->tx.desc[0].dcb_dma; + } + } + desc = &sinfo->tx.desc[idx]; + desc->dcb_mem = dcb_mem; + desc->dcb_dma = dcb_dma; + dcb_mem += sinfo->dcb_wsize; + dcb_dma += dcb_size; + } + sinfo->halt_addr[XGS_DMA_TX_CHAN] = sinfo->tx.desc[0].dcb_dma; + sinfo->tx.free = MAX_TX_DCBS; + + DBG_DCB_TX(("Tx DCBs @ 0x%08x.\n", + (uint32_t)sinfo->tx.desc[0].dcb_dma)); + + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + for (idx = 0; idx < (MAX_RX_DCBS + 1); idx++) { + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + dcb_mem[1] |= (1 << 24) | (1 << 16); + if (idx == MAX_RX_DCBS) { + dcb_mem[1] |= 1 << 18; + dcb_mem[0] = sinfo->rx[chan].desc[0].dcb_dma; + } + } + desc = &sinfo->rx[chan].desc[idx]; + desc->dcb_mem = dcb_mem; + desc->dcb_dma = dcb_dma; + dcb_mem += sinfo->dcb_wsize; + dcb_dma += dcb_size; + } + sinfo->halt_addr[XGS_DMA_RX_CHAN + chan] = sinfo->rx[chan].desc[MAX_RX_DCBS].dcb_dma; + sinfo->rx[chan].free = 0; + + DBG_DCB_RX(("Rx%d DCBs @ 0x%08x.\n", + chan, (uint32_t)sinfo->rx[chan].desc[0].dcb_dma)); + } +} + +static void +bkn_dump_dcb(char *prefix, uint32_t *dcb, int wsize, int txrx) +{ + if (XGS_DMA_TX_CHAN == txrx) { + DBG_DCB_TX(("%s: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x ... 0x%08x\n", + prefix, dcb[0], dcb[1], dcb[2], dcb[3], dcb[4], dcb[5], + dcb[wsize - 1])); + } else { + DBG_DCB_RX(("%s: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x ... 0x%08x\n", + prefix, dcb[0], dcb[1], dcb[2], dcb[3], dcb[4], dcb[5], + dcb[wsize - 1])); + } +} + +static void +bkn_dump_pkt(uint8_t *data, int size, int txrx) +{ + int idx; + char str[128]; + + if (!(debug & DBG_LVL_PDMP) && + !(txrx == XGS_DMA_TX_CHAN && debug & DBG_LVL_PDMP_TX) && + !(txrx == XGS_DMA_RX_CHAN && debug & DBG_LVL_PDMP_RX)) { + return; + } + size =32; + + for (idx = 0; idx < size; idx++) { + if ((idx & 0xf) == 0) { + sprintf(str, "%04x: ", idx); + } + if ((idx & 0xf) == 8) { + sprintf(&str[strlen(str)], "- "); + } + sprintf(&str[strlen(str)], "%02x ", data[idx]); + if ((idx & 0xf) == 0xf) { + sprintf(&str[strlen(str)], "\n"); + gprintk(str); + } + } + if ((idx & 0xf) != 0) { + sprintf(&str[strlen(str)], "\n"); + gprintk(str); + } +} + +static bkn_switch_info_t * +bkn_sinfo_from_unit(int unit) +{ + struct list_head *list; + bkn_switch_info_t *sinfo; + + list_for_each(list, &_sinfo_list) { + sinfo = (bkn_switch_info_t *)list; + if (sinfo->dev_no == unit || unit == -1) { + return sinfo; + } + } + return NULL; +} + +static void +bkn_api_rx_restart(bkn_switch_info_t *sinfo) +{ + bkn_dcb_chain_t *dcb_chain; + int chan = API_RX_CHAN; + int start_dma; + + if (sinfo->basedev_suspended) { + return; + } + + /* If resume from basedev suspended, there could be a suspended chain */ + if (sinfo->rx[chan].api_dcb_chain) { + return; + } + + /* Assume that driver lock is held */ + if (!list_empty(&sinfo->rx[chan].api_dcb_list)) { + dcb_chain = list_entry(sinfo->rx[chan].api_dcb_list.next, + bkn_dcb_chain_t, list); + start_dma = 0; + if (sinfo->rx[chan].use_rx_skb == 0) { + sinfo->rx[chan].chain_complete = 0; + start_dma = 1; + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) && + sinfo->rx[chan].api_active) { + /* HW is running already, so we just move to the next chain */ + start_dma = 0; + } + } + sinfo->rx[chan].api_dcb_chain = dcb_chain; + sinfo->rx[chan].api_active = 1; + if (start_dma) { + DBG_DCB_RX(("Start API Rx DMA, first DCB @ 0x%08x (%d DCBs).\n", + (uint32_t)dcb_chain->dcb_dma, dcb_chain->dcb_cnt)); + dev_dma_chan_clear(sinfo, XGS_DMA_RX_CHAN + chan); + dev_irq_mask_enable(sinfo, XGS_DMA_RX_CHAN + chan, 1); + dev_dma_chan_start(sinfo, XGS_DMA_RX_CHAN + chan, + dcb_chain->dcb_dma); + } + + list_del(&dcb_chain->list); + } +} + +static void +bkn_api_rx_chain_done(bkn_switch_info_t *sinfo, int chan) +{ + DBG_DCB_RX(("API Rx DMA chain done\n")); + + if (!CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + sinfo->rx[chan].api_active = 0; + } + if (sinfo->rx[chan].api_dcb_chain) { + kfree(sinfo->rx[chan].api_dcb_chain); + sinfo->rx[chan].api_dcb_chain = NULL; + } + bkn_api_rx_restart(sinfo); + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) && + sinfo->rx[chan].api_dcb_chain == NULL) { + sinfo->rx[chan].api_active = 0; + } +} + +static int +bkn_api_rx_copy_from_skb(bkn_switch_info_t *sinfo, + int chan, bkn_desc_info_t *desc) +{ + bkn_dcb_chain_t *dcb_chain; + uint32_t *dcb; + uint32_t dcb_stat; + uint8_t *pkt; + int pktlen; + int i; + bkn_evt_resource_t *evt; + + dcb_stat = desc->dcb_mem[sinfo->dcb_wsize-1]; + pktlen = dcb_stat & SOC_DCB_KNET_COUNT_MASK; + + dcb_chain = sinfo->rx[chan].api_dcb_chain; + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) && dcb_chain == NULL) { + /* Last chain done, try to get a new one */ + bkn_api_rx_chain_done(sinfo, chan); + dcb_chain = sinfo->rx[chan].api_dcb_chain; + } + if (dcb_chain == NULL) { + DBG_WARN(("No Rx API buffers\n")); + sinfo->rx[chan].pkts_d_no_api_buf++; + return -1; + } + dcb = &dcb_chain->dcb_mem[dcb_chain->dcb_cur * sinfo->dcb_wsize]; + if (dcb[1] < pktlen) { + DBG_WARN(("Rx API buffer too small\n")); + return -1; + } + pkt = (uint8_t *)kernel_bde->p2l(sinfo->dev_no, dcb[0]); + if (pkt == NULL) { + DBG_WARN(("Invalid Rx API buffer\n")); + return -1; + } + + /* Copy packet data */ + memcpy(pkt, desc->skb->data, pktlen); + + /* Copy packet metadata and mark as done */ + for (i = SOC_DCB_META_OFFSET; i < sinfo->dcb_wsize; i++) { + dcb[i] = desc->dcb_mem[i]; + } + dcb[sinfo->dcb_wsize-1] = dcb_stat | SOC_DCB_KNET_DONE; + + dcb_chain->dcb_cur++; + + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + dcb = &dcb_chain->dcb_mem[dcb_chain->dcb_cur * sinfo->dcb_wsize]; + if (dcb[1] & (1 << 18)) { + /* Get the next chain if reload done */ + dcb[sinfo->dcb_wsize - 1] |= (1 << 31) | SOC_DCB_KNET_DONE; + bkn_api_rx_chain_done(sinfo, chan); + dcb_chain = sinfo->rx[chan].api_dcb_chain; + if (dcb_chain == NULL) { + sinfo->rx[chan].api_dcb_chain_end = NULL; + } + } + } else { + if ((dcb[1] & (1 << 16)) == 0) { + bkn_api_rx_chain_done(sinfo, chan); + } + } + + sinfo->dma_events |= KCOM_DMA_INFO_F_RX_DONE; + + evt = &_bkn_evt[sinfo->evt_idx]; + evt->evt_wq_put++; + wake_up_interruptible(&evt->evt_wq); + + return 0; +} + +static void +bkn_rx_refill(bkn_switch_info_t *sinfo, int chan) +{ + struct sk_buff *skb; + bkn_desc_info_t *desc; + uint32_t *dcb; + int prev; + + if (sinfo->rx[chan].use_rx_skb == 0) { + /* Rx buffers are provided by BCM Rx API */ + return; + } + + if (!CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) && + sinfo->rx[chan].tokens < MAX_RX_DCBS) { + /* Pause DMA for now */ + return; + } + + while (sinfo->rx[chan].free < MAX_RX_DCBS) { + desc = &sinfo->rx[chan].desc[sinfo->rx[chan].cur]; + if (desc->skb == NULL) { + skb = dev_alloc_skb(rx_buffer_size + RCPU_RX_ENCAP_SIZE); + if (skb == NULL) { + break; + } + skb_reserve(skb, RCPU_RX_ENCAP_SIZE); + desc->skb = skb; + } else { + DBG_DCB_RX(("Refill Rx%d SKB in DCB %d recycled.\n", + chan, sinfo->rx[chan].cur)); + } + skb = desc->skb; + desc->dma_size = rx_buffer_size; +#ifdef KNET_NO_AXI_DMA_INVAL + /* + * FIXME: Need to retain this code until iProc customers have been + * migrated to updated u-boot. Old u-boot versions are unable to load + * the kernel into non-ACP memory. + */ + /* + * Cache invalidate may corrupt DMA memory on some iProc-based devices + * if the kernel is mapped to ACP memory. + */ + if (sinfo->pdev == NULL) { + desc->dma_size = 0; + } +#endif + desc->skb_dma = DMA_MAP_SINGLE(sinfo->dma_dev, + skb->data, desc->dma_size, + DMA_FROMDEV); + DBG_DCB_RX(("Refill Rx%d DCB %d (0x%08x).\n", + chan, sinfo->rx[chan].cur, (uint32_t)desc->skb_dma)); + dcb = desc->dcb_mem; + memset(dcb, 0, sizeof(uint32_t) * sinfo->dcb_wsize); + dcb[0] = desc->skb_dma; + dcb[1] = rx_buffer_size; + + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + dcb[1] |= (1 << 24) | (1 << 16); + } else { + prev = PREV_IDX(sinfo->rx[chan].cur, MAX_RX_DCBS); + if (prev < (MAX_RX_DCBS - 1)) { + sinfo->rx[chan].desc[prev].dcb_mem[1] |= (1 << 16); + } + } + if (++sinfo->rx[chan].cur >= MAX_RX_DCBS) { + sinfo->rx[chan].cur = 0; + } + sinfo->rx[chan].free++; + sinfo->rx[chan].tokens--; + } +} + +static int +bkn_rx_restart(bkn_switch_info_t *sinfo, int chan) +{ + bkn_desc_info_t *desc; + + if (sinfo->basedev_suspended) { + return 0; + } + + if (sinfo->rx[chan].running) { + return 0; + } + + if (sinfo->rx[chan].free < MAX_RX_DCBS) { + return 1; + } + + desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty]; + sinfo->rx[chan].chain_complete = 0; + DBG_DCB_RX(("Restart Rx%d DMA, DCB @ 0x%08x (%d).\n", + chan, (uint32_t)desc->dcb_dma, sinfo->rx[chan].dirty)); + dev_dma_chan_clear(sinfo, XGS_DMA_RX_CHAN + chan); + dev_irq_mask_enable(sinfo, XGS_DMA_RX_CHAN + chan, 1); + dev_dma_chan_start(sinfo, XGS_DMA_RX_CHAN + chan, desc->dcb_dma); + sinfo->rx[chan].running = 1; + + /* Request one extra poll if chain was restarted during poll */ + if (sinfo->napi_poll_mode) { + sinfo->napi_poll_again = 1; + } + + return 0; +} + +static int +bkn_tx_dma_start(bkn_switch_info_t *sinfo) +{ + bkn_desc_info_t *desc; + + desc = &sinfo->tx.desc[sinfo->tx.cur]; + if (sinfo->tx.free == MAX_TX_DCBS) { + if (!sinfo->tx.api_active) { + DBG_DCB_TX(("Start Tx DMA, DCB @ 0x%08x (%d).\n", + (uint32_t)desc->dcb_dma, sinfo->tx.cur)); + dev_dma_chan_clear(sinfo, XGS_DMA_TX_CHAN); + dev_irq_mask_enable(sinfo, XGS_DMA_TX_CHAN, 1); + dev_dma_chan_start(sinfo, XGS_DMA_TX_CHAN, desc->dcb_dma); + } + } + + return 0; +} + +static int +bkn_dma_init(bkn_switch_info_t *sinfo) +{ + int chan; + + dev_dma_chan_init(sinfo, XGS_DMA_TX_CHAN, 1); + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) { + bkn_tx_dma_start(sinfo); + } + + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + dev_dma_chan_init(sinfo, XGS_DMA_RX_CHAN + chan, 0); + bkn_rx_refill(sinfo, chan); + bkn_rx_restart(sinfo, chan); + } + + return 0; +} + +static void +bkn_cdma_goto(bkn_switch_info_t *sinfo, int chan, dma_addr_t dcb) +{ + if (sinfo->basedev_suspended) { + return; + } + + /* Set the new halt location */ + sinfo->halt_addr[chan] = dcb; + dev_cdma_halt_set(sinfo, chan); +} + +static int +bkn_dma_abort_tx(bkn_switch_info_t *sinfo) +{ + bkn_dcb_chain_t *dcb_chain; + + DBG_VERB(("Aborting Tx DMA.\n")); + + dev_irq_mask_disable(sinfo, XGS_DMA_TX_CHAN, 1); + + dev_dma_chan_abort(sinfo, XGS_DMA_TX_CHAN, 10000); + + if (sinfo->tx.api_dcb_chain) { + DBG_DCB_TX(("Freeing active Tx DCB chain.\n")); + kfree(sinfo->tx.api_dcb_chain); + sinfo->tx.api_dcb_chain = NULL; + } + while (!list_empty(&sinfo->tx.api_dcb_list)) { + dcb_chain = list_entry(sinfo->tx.api_dcb_list.next, + bkn_dcb_chain_t, list); + list_del(&dcb_chain->list); + DBG_DCB_TX(("Freeing Tx DCB chain.\n")); + kfree(dcb_chain); + } + sinfo->tx.api_dcb_chain_end = NULL; + + return 0; +} + +static int +bkn_dma_abort_rx(bkn_switch_info_t *sinfo, int chan) +{ + bkn_dcb_chain_t *dcb_chain; + + DBG_VERB(("Aborting Rx%d DMA.\n", chan)); + + dev_irq_mask_disable(sinfo, XGS_DMA_RX_CHAN + chan, 1); + + dev_dma_chan_abort(sinfo, XGS_DMA_RX_CHAN + chan, 10000); + + if (sinfo->rx[chan].api_dcb_chain) { + DBG_DCB_RX(("Freeing active Rx%d DCB chain.\n", chan)); + kfree(sinfo->rx[chan].api_dcb_chain); + sinfo->rx[chan].api_dcb_chain = NULL; + } + while (!list_empty(&sinfo->rx[chan].api_dcb_list)) { + dcb_chain = list_entry(sinfo->rx[chan].api_dcb_list.next, + bkn_dcb_chain_t, list); + list_del(&dcb_chain->list); + DBG_DCB_RX(("Freeing Rx%d DCB chain.\n", chan)); + kfree(dcb_chain); + } + sinfo->rx[chan].api_dcb_chain_end = NULL; + + return 0; +} + +static int +bkn_dma_abort(bkn_switch_info_t *sinfo) +{ + int chan; + + bkn_dma_abort_tx(sinfo); + + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + bkn_dma_abort_rx(sinfo, chan); + } + + return 0; +} + +static bkn_filter_t * +bkn_match_rx_pkt(bkn_switch_info_t *sinfo, uint32_t *desc, + uint8_t *pkt, int chan, bkn_filter_t *cbf) +{ + struct list_head *list; + bkn_filter_t *filter; + kcom_filter_t scratch, *kf; + uint8_t *oob = (uint8_t *)desc; + int size, wsize; + int idx, match; + + list_for_each(list, &sinfo->rxpf_list) { + filter = (bkn_filter_t *)list; + kf = &filter->kf; + memcpy(&scratch.data.b[0], + &oob[kf->oob_data_offset], kf->oob_data_size); + memcpy(&scratch.data.b[kf->oob_data_size], + &pkt[kf->pkt_data_offset], kf->pkt_data_size); + size = kf->oob_data_size + kf->pkt_data_size; + wsize = BYTES2WORDS(size); + DBG_VERB(("Filter: size = %d (%d), data = 0x%08x, mask = 0x%08x\n", + size, wsize, kf->data.w[0], kf->mask.w[0])); + match = 1; + if (match) { + if (kf->priority < (num_rx_prio * NUM_RX_CHAN)) { + if (kf->priority < (num_rx_prio * chan) || + kf->priority >= (num_rx_prio * (chan + 1))) { + match = 0; + } + } + } + if (match) { + for (idx = 0; idx < wsize; idx++) { + scratch.data.w[idx] &= kf->mask.w[idx]; + if (scratch.data.w[idx] != kf->data.w[idx]) { + match = 0; + break; + } + } + } + if (match) { + if (kf->dest_type == KCOM_DEST_T_CB) { + /* Check for custom filters */ + if (knet_filter_cb != NULL && cbf != NULL) { + size = desc[sinfo->dcb_wsize-1] & SOC_DCB_KNET_COUNT_MASK; + memset(cbf, 0, sizeof(*cbf)); + memcpy(&cbf->kf, kf, sizeof(cbf->kf)); + if (knet_filter_cb(pkt, size, sinfo->dev_no, + desc, chan, &cbf->kf)) { + filter->hits++; + return cbf; + } + } else { + DBG_FLTR(("Match, but not filter callback\n")); + } + } else { + filter->hits++; + return filter; + } + } + } + + return NULL; +} + +static bkn_priv_t * +bkn_netif_lookup(bkn_switch_info_t *sinfo, int id) +{ + struct list_head *list; + bkn_priv_t *priv; + int found; + + /* Fast path */ + if (id < sinfo->ndev_max) { + if (sinfo->ndevs[id] != NULL) { + DBG_NDEV(("Look up netif ID %d successful\n", id)); + return netdev_priv(sinfo->ndevs[id]); + } + } + + /* Slow path - should normally not get here */ + found = 0; + priv = NULL; + list_for_each(list, &sinfo->ndev_list) { + priv = (bkn_priv_t *)list; + if (priv->id == id) { + found = 1; + break; + } + } + if (found && priv != NULL) { + return priv; + } + return NULL; +} + +static int +bkn_add_rcpu_encap(bkn_switch_info_t *sinfo, struct sk_buff *skb, uint32_t *dcb) +{ + int pktlen = skb->len; + uint32_t *metadata; + int idx; + + /* Add and clear RCPU encapsulation */ + skb_push(skb, RCPU_RX_ENCAP_SIZE); + memset(skb->data, 0, RCPU_RX_ENCAP_SIZE); + + /* RCPU Header */ + memcpy(skb->data, &skb->data[RCPU_RX_ENCAP_SIZE], 12); + if (rcpu_dmac != NULL) { + memcpy(skb->data, bkn_rcpu_dmac, 6); + } + if (rcpu_smac != NULL) { + memcpy(&skb->data[6], bkn_rcpu_smac, 6); + } + skb->data[12] = 0x81; + skb->data[14] = rcpu_vlan >> 8; + skb->data[15] = rcpu_vlan & 0xff; + skb->data[16] = rcpu_ethertype >> 8; + skb->data[17] = rcpu_ethertype & 0xff; + skb->data[18] = sinfo->rcpu_sig >> 8; + skb->data[19] = sinfo->rcpu_sig & 0xff; + skb->data[20] = RCPU_OPCODE_RX; + skb->data[21] = RCPU_F_MODHDR; + skb->data[24] = pktlen >> 8; + skb->data[25] = pktlen & 0xff; + + /* Meta data */ + metadata = (uint32_t *)&skb->data[RCPU_HDR_SIZE]; + for (idx = 0; idx < sinfo->dcb_wsize - 3; idx++) { + metadata[idx] = htonl(dcb[idx+2]); + } + + return 0; +} + +static void +bkn_eth_type_update(struct sk_buff *skb, int ethertype) +{ +#if defined(PM_ETH_TYPE) && defined(PM_FC_TYPE) + /* Optionally override standard protocol */ + skb->protocol = PM_ETH_TYPE; + if (ethertype == ETH_P_FCOE) { + skb->protocol = PM_FC_TYPE; + } +#endif +} + + + +#define BKN_DNX_BIT(x) (1<<(x)) +#define BKN_DNX_RBIT(x) (~(1<<(x))) +#ifdef __LITTLE_ENDIAN +#define BKN_DNX_BYTE_SWAP(x) (x) +#else +#define BKN_DNX_BYTE_SWAP(x) ((((x) << 24)) | (((x) & 0xff00) << 8) | (((x) & 0xff0000) >> 8) | (((x) >> 24))) +#endif +static int +device_is_dune(bkn_switch_info_t *sinfo) +{ + int is_dune = 0; + + is_dune = (sinfo->dcb_type == 28) ? 1 : 0; + return is_dune; +} +static int +packet_is_untagged(uint16_t tpid) +{ + int is_untagged = 0; + + /* Fixme SDK-111398 */ + /* 0x8100 is used in 802.1Q */ + /* 0x8848 is used in 802.11ad, the dtag tpid can be set to anything besides 0x8848, 0x9100 is a typical value, but couldn't cover all scenarios. */ + is_untagged = ((tpid != 0x8100) && (tpid != 0x8848) && (tpid != 0x9100)); + return is_untagged; +} + +static void +bkn_dnx_bitstream_set_field(uint32_t *input_buffer, uint32_t start_bit, uint32_t nof_bits, uint32_t field) +{ + uint32_t place; + uint32_t field_bit_i; + uint32_t bit_indicator; + + if( nof_bits > 32) + { + return; + } + + for( place=start_bit, field_bit_i = 0; field_bit_i< nof_bits; ++place, ++field_bit_i) + { + bit_indicator = field & BKN_DNX_BIT(nof_bits-field_bit_i-1); + if(bit_indicator) + { + input_buffer[place>>5] |= (0x80000000 >> (place & 0x0000001F)); + } + else + { + input_buffer[place>>5] &= ~(0x80000000 >> (place & 0x0000001F)); + } + } + return; +} + +static void +bkn_dnx_bitstream_get_field(uint8_t *input_buffer, uint32_t start_bit, uint32_t nof_bits, uint32_t *output_value) +{ + uint32_t idx; + uint32_t buf_sizes=0; + uint32_t tmp_output_value[2]={0}; + uint32_t first_byte_ndx; + uint32_t last_byte_ndx; + uint32_t place; + uint32_t field_bit_i; + uint8_t *tmp_output_value_u8_ptr = (uint8_t*)&tmp_output_value; + uint32_t bit_indicator; + + if (nof_bits > 32) + { + return; + } + + first_byte_ndx = start_bit / 8; + last_byte_ndx = ((start_bit + nof_bits - 1) / 8); + *output_value=0; + + /* get 32 bit value, MSB */ + for (idx = first_byte_ndx; idx <= last_byte_ndx; ++idx) + { + tmp_output_value_u8_ptr[last_byte_ndx - idx] = input_buffer[idx]; + buf_sizes += 8; + } + tmp_output_value[0] = BKN_DNX_BYTE_SWAP(tmp_output_value[0]); + if (last_byte_ndx > 4) + { + tmp_output_value[1] = BKN_DNX_BYTE_SWAP(tmp_output_value[1]); + } + + place = buf_sizes - (start_bit % 8 + nof_bits); + for (field_bit_i = 0; field_bit_i< nof_bits; ++place, ++field_bit_i) + { + uint32_t result; + result = tmp_output_value[place>>5] & BKN_DNX_BIT(place & 0x0000001F); + if (result) + { + bit_indicator = 1; + } else { + bit_indicator = 0; + } + *output_value |= bit_indicator << field_bit_i; + } + return; +} + +static void +bkn_dnx_packet_parse_ftmh(uint8_t hdr_buff[], bkn_dnx_packet_info *packet_info) +{ + uint32_t header_ptr = 0; + uint32_t dsp_ext_exist=0; + uint32_t fld_val; + + header_ptr = packet_info->ntwrk_header_ptr; + + /* Packet-size */ + bkn_dnx_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DNX_FTMH_PKT_SIZE_MSB, + BKN_DNX_FTMH_PKT_SIZE_NOF_BITS, + &fld_val); + packet_info->ftmh.packet_size = fld_val; + /* Traffic-class */ + bkn_dnx_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DNX_FTMH_TC_MSB, + BKN_DNX_FTMH_TC_NOF_BITS, + &fld_val); + packet_info->ftmh.prio = fld_val; + /* Source-system-port-aggregate */ + bkn_dnx_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DNX_FTMH_SRC_SYS_PORT_MSB, + BKN_DNX_FTMH_SRC_SYS_PORT_NOF_BITS, + &fld_val); + packet_info->ftmh.src_sys_port = fld_val; + /* TM-action-type */ + bkn_dnx_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DNX_FTMH_ACTION_TYPE_MSB, + BKN_DNX_FTMH_ACTION_TYPE_NOF_BITS, + &fld_val); + packet_info->ftmh.action_type = fld_val; + /* PPH-type */ + bkn_dnx_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DNX_FTMH_PPH_TYPE_MSB, + BKN_DNX_FTMH_PPH_TYPE_NOF_BITS, + &fld_val); + packet_info->ftmh.pph_type = fld_val; + + packet_info->ntwrk_header_ptr += BKN_DNX_FTMH_SIZE_BYTE; + DBG_DUNE(("FTMH(%d) Packet-size %d Action-type %d PPH-type %d Source-system-port 0x%x Traffic-class %d\n", + packet_info->ntwrk_header_ptr, packet_info->ftmh.packet_size, packet_info->ftmh.action_type, + packet_info->ftmh.pph_type, packet_info->ftmh.src_sys_port, packet_info->ftmh.prio)); + + /* LB-Key ext */ + if (ftmh_lb_key_ext) + { + packet_info->ntwrk_header_ptr += BKN_DNX_FTMH_LB_EXT_SIZE_BYTE; + DBG_DUNE(("FTMH(%d) FTMH LB-Key Extension is present\n", packet_info->ntwrk_header_ptr)); + } + /* DSP ext*/ + fld_val = 0; + bkn_dnx_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DNX_FTMH_EXT_DSP_EXIST_MSB, + BKN_DNX_FTMH_EXT_DSP_EXIST_NOF_BITS, + &dsp_ext_exist); + if (dsp_ext_exist) + { + packet_info->ntwrk_header_ptr += BKN_DNX_FTMH_DEST_EXT_SIZE_BYTE; + DBG_DUNE(("FTMH(%d) DSP Extension is present\n", packet_info->ntwrk_header_ptr)); + } + /* stacking ext */ + if (ftmh_stacking_ext) + { + packet_info->ntwrk_header_ptr += BKN_DNX_FTMH_STACKING_SIZE_BYTE; + DBG_DUNE(("FTMH(%d) FTMH Stacking Extension is present\n", packet_info->ntwrk_header_ptr)); + } + return; +} + +static void +bkn_dnx_packet_parse_internal(uint8_t hdr_buff[], bkn_dnx_packet_info *packet_info) +{ + uint32_t header_ptr = 0; + uint32_t fld_val; + uint32_t eei_extension_present = 0; + uint32_t learn_extension_present = 0; + uint32_t fhei_size = 0; + uint32_t forward_code; + uint8_t is_trapped = 0; + + header_ptr = packet_info->ntwrk_header_ptr; + + bkn_dnx_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DNX_PPH_EEI_EXTENSION_PRESENT_MSB, + BKN_DNX_PPH_EEI_EXTENSION_PRESENT_NOF_BITS, + &eei_extension_present); + bkn_dnx_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DNX_PPH_LEARN_EXENSION_PRESENT_MSB, + BKN_DNX_PPH_LEARN_EXENSION_PRESENT_NOF_BITS, + &learn_extension_present); + bkn_dnx_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DNX_PPH_FHEI_SIZE_MSB, + BKN_DNX_PPH_FHEI_SIZE_NOF_BITS, + &fhei_size); + bkn_dnx_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DNX_PPH_FORWARD_CODE_MSB, + BKN_DNX_PPH_FORWARD_CODE_NOF_BITS, + &forward_code); + /* 7: CPU-Trap */ + is_trapped = (uint8_t)(forward_code == 7); + + bkn_dnx_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DNX_PPH_VSI_MSB, + BKN_DNX_PPH_VSI_NOF_BITS, + &fld_val); + packet_info->internal.vsi = fld_val; + + /* size of PPH base is 7 */ + packet_info->ntwrk_header_ptr += BKN_DNX_PPH_SIZE_BYTE; + header_ptr = packet_info->ntwrk_header_ptr; + + DBG_DUNE(("PPH(%d) Forward-Code %d EEI-Extension %d Learn-Extension %d VSI %d FHEI-size %d\n", packet_info->ntwrk_header_ptr, + forward_code, eei_extension_present, learn_extension_present, packet_info->internal.vsi, fhei_size)); + + /* PPH extension */ + if (is_trapped && (fhei_size == 1)) + { + /* CPU trap code qualifier */ + bkn_dnx_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DNX_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_MSB, + BKN_DNX_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_NOF_BITS, + &fld_val); + packet_info->internal.trap_qualifier = fld_val; + /* CPU trap code */ + bkn_dnx_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DNX_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_MSB, + BKN_DNX_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_NOF_BITS, + &fld_val); + packet_info->internal.trap_id = fld_val; + } + switch(fhei_size) { + case 1: + packet_info->ntwrk_header_ptr += BKN_DNX_PPH_FHEI_3B_SIZE_BYTE; + break; + case 2: + packet_info->ntwrk_header_ptr += BKN_DNX_PPH_FHEI_5B_SIZE_BYTE; + break; + case 3: + packet_info->ntwrk_header_ptr += BKN_DNX_PPH_FHEI_8B_SIZE_BYTE; + break; + default: + break; + } + if (eei_extension_present) { + packet_info->ntwrk_header_ptr += BKN_DNX_PPH_EXPLICIT_EDITING_INFOMATION_EXTENSION_SIZE_BYTE; + } + if (learn_extension_present) { + packet_info->ntwrk_header_ptr += BKN_DNX_PPH_LEARN_EXTENSION_SIZE_BYTE; + } + + DBG_DUNE(("FHEI(%d) trap_qualifier 0x%x trap_id 0x%x\n", packet_info->ntwrk_header_ptr, packet_info->internal.trap_qualifier, packet_info->internal.trap_id)); + return; +} + +static int +bkn_dnx_packet_header_parse(uint8 *buff, uint32_t buff_len, bkn_dnx_packet_info *packet_info) +{ + uint8_t hdr_buff[BKN_DNX_HDR_MAX_SIZE]; + uint32_t hdr_size; + uint8_t has_internal = 0; + + if ((buff == NULL) || (packet_info == NULL)) { + return -1; + } + hdr_size = buff_len < BKN_DNX_HDR_MAX_SIZE ? buff_len: BKN_DNX_HDR_MAX_SIZE; + memcpy(hdr_buff, buff, hdr_size); + + /* FTMH */ + bkn_dnx_packet_parse_ftmh(hdr_buff, packet_info); + if (packet_info->ftmh.packet_size != (buff_len + 2)) { + DBG_DUNE(("FTMH packet size verfication failed, %d-%d\n", packet_info->ftmh.packet_size, buff_len)); + memset(packet_info, 0, sizeof(bkn_dnx_packet_info)); + return -1; + } + switch (packet_info->ftmh.pph_type) { + case 0: + has_internal = 0; + break; + case 1: + has_internal = 1; + break; + case 2: /* PPH OAM-TS only */ + case 3: /* PPH Base + OAM-TS */ + /* OTSH immediately follows the FTMH when present */ + packet_info->ntwrk_header_ptr += 6; + DBG_DUNE(("FTMH + OAM-TS(%d)\n", packet_info->ntwrk_header_ptr)); + has_internal = 1; + break; + default: + break; + } + + if (has_internal) { + bkn_dnx_packet_parse_internal(&hdr_buff[0], packet_info); + } + + /* FIXME: */ + /* ignore packets with a double set of FTMH,internals */ + /* ignore the user header size */ + return 0; +} + +static int +bkn_do_api_rx(bkn_switch_info_t *sinfo, int chan, int budget) +{ + bkn_priv_t *priv; + bkn_dcb_chain_t *dcb_chain; + struct sk_buff *skb; + bkn_filter_t cbf; + bkn_filter_t *filter; + uint32_t *dcb; + uint8_t *pkt; + int ethertype; + int pktlen; + int drop_api; + int idx; + int dcbs_done; + bkn_dnx_packet_info packet_info = {0}; + dcbs_done = 0; + + dcb_chain = sinfo->rx[chan].api_dcb_chain; + if (dcb_chain == NULL) { + /* No active chains */ + return 0; + } + + while (dcb_chain->dcb_cur < dcb_chain->dcb_cnt) { + dcb = &dcb_chain->dcb_mem[dcb_chain->dcb_cur * sinfo->dcb_wsize]; + DBG_VERB(("DCB %2d: 0x%08x\n", + dcb_chain->dcb_cur, dcb[sinfo->dcb_wsize-1])); + if ((dcb[sinfo->dcb_wsize-1] & (1 << 31)) == 0) { + break; + } + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + /* Handle for Continuous DMA mode */ + if (dcbs_done >= budget) { + break; + } + if (dcb[1] & (1 << 18)) { + dcb[sinfo->dcb_wsize - 1] |= SOC_DCB_KNET_DONE; + bkn_api_rx_chain_done(sinfo, chan); + dcb_chain = sinfo->rx[chan].api_dcb_chain; + if (dcb_chain == NULL) { + break; + } + continue; + } + } + if ((dcb[1] & (1 << 16)) == 0) { + sinfo->rx[chan].chain_complete = 1; + } + sinfo->rx[chan].pkts++; + pkt = (uint8_t *)kernel_bde->p2l(sinfo->dev_no, dcb[0]); + pktlen = dcb[sinfo->dcb_wsize-1] & SOC_DCB_KNET_COUNT_MASK; + bkn_dump_pkt(pkt, 32, XGS_DMA_RX_CHAN); + + if (device_is_dune(sinfo)) { + uint16_t tpid = 0; + uint16_t vid = 0; + int res = -1; + + memset(&packet_info, 0, sizeof(bkn_dnx_packet_info)); + res = bkn_dnx_packet_header_parse(pkt, (uint32_t)pktlen, &packet_info); + if (res == 0) { + if (packet_info.ftmh.action_type == 0x2) { + bkn_dnx_bitstream_set_field((uint32_t *)dcb, 192, 32, 0x8); + } else if (packet_info.ftmh.action_type == 0x1) { + bkn_dnx_bitstream_set_field((uint32_t *)dcb, 231, 25, 0x20); + } + bkn_dnx_bitstream_set_field((uint32_t *)dcb, 112, 16, packet_info.ftmh.src_sys_port); + bkn_dnx_bitstream_set_field((uint32_t *)dcb, 296, 12, packet_info.internal.vsi); + bkn_dnx_bitstream_set_field((uint32_t *)dcb, 64, 32, (packet_info.internal.trap_id << 16 | packet_info.internal.trap_qualifier)); + pkt += packet_info.ntwrk_header_ptr; + pktlen -= packet_info.ntwrk_header_ptr; + bkn_dump_pkt(pkt, 32, XGS_DMA_RX_CHAN); + /* check if vlan tag exists */ + tpid = (uint16_t)((pkt[12] << 8) | pkt[13]); + vid = (uint16_t)(packet_info.internal.vsi & 0xfff); + if (packet_is_untagged(tpid)) { + if ((pktlen + 4) < rx_buffer_size) { + DBG_DUNE(("add vlan tag (%d) to untagged packets\n", vid)); + for (idx = (pktlen-1); idx >= 12; idx--) { + pkt[idx+4] = pkt[idx]; + } + pkt[12] = 0x81; + pkt[13] = 0x00; + pkt[14] = (vid >> 8); + pkt[15] = (vid & 0xff); + /* reset packet length in DCB */ + pktlen += 4; + dcb[sinfo->dcb_wsize-1] &= ~SOC_DCB_KNET_COUNT_MASK; + dcb[sinfo->dcb_wsize-1] |= ((pktlen + packet_info.ntwrk_header_ptr) & SOC_DCB_KNET_COUNT_MASK); + bkn_dump_pkt(pkt, 32, XGS_DMA_RX_CHAN); + } + } + } + } + filter = bkn_match_rx_pkt(sinfo, dcb, pkt, chan, &cbf); + if ((dcb[sinfo->dcb_wsize-1] & 0x70000) != 0x30000) { + /* Fragment or error */ + if (filter && filter->kf.mask.w[sinfo->dcb_wsize-1] == 0) { + /* Drop unless DCB status is part of filter */ + filter = NULL; + } + } + drop_api = 1; + if (filter) { + DBG_FLTR(("Match filter ID %d\n", filter->kf.id)); + switch (filter->kf.dest_type) { + case KCOM_DEST_T_API: + DBG_FLTR(("Send to Rx API\n")); + sinfo->rx[chan].pkts_f_api++; + drop_api = 0; + break; + case KCOM_DEST_T_NETIF: + priv = bkn_netif_lookup(sinfo, filter->kf.dest_id); + if (priv) { + /* Check that software link is up */ + if (!netif_carrier_ok(priv->dev)) { + sinfo->rx[chan].pkts_d_no_link++; + break; + } + + /* Add 2 bytes for IP header alignment (see below) */ + skb = dev_alloc_skb(pktlen + RCPU_RX_ENCAP_SIZE + 2); + if (skb == NULL) { + sinfo->rx[chan].pkts_d_no_skb++; + break; + } + skb_reserve(skb, RCPU_RX_ENCAP_SIZE); + + DBG_FLTR(("Send to netif %d (%s)\n", + priv->id, priv->dev->name)); + sinfo->rx[chan].pkts_f_netif++; + skb->dev = priv->dev; + skb_reserve(skb, 2); /* 16 byte align the IP fields. */ + + /* Save for RCPU before stripping tag */ + ethertype = (pkt[16] << 8) | pkt[17]; + if ((priv->flags & KCOM_NETIF_F_KEEP_RX_TAG) == 0) { + if (filter->kf.flags & KCOM_FILTER_F_STRIP_TAG) { + /* Strip the VLAN tag */ + uint16_t vlan_proto = (uint16_t)((pkt[12] << 8) | pkt[13]); + if (vlan_proto == 0x8100 || vlan_proto == 0x88a8) { + DBG_FLTR(("Strip VLAN tag\n")); + for (idx = 11; idx >= 0; idx--) { + pkt[idx+4] = pkt[idx]; + } + pktlen -= 4; + pkt += 4; + } + } + } + + skb_copy_to_linear_data(skb, pkt, pktlen); + if (device_is_dune(sinfo)) { + /* CRC has been stripped */ + skb_put(skb, pktlen); + } else { + skb_put(skb, pktlen - 4); /* Strip CRC */ + } + priv->stats.rx_packets++; + priv->stats.rx_bytes += pktlen; + + /* Optional SKB updates */ + if (knet_rx_cb != NULL) { + KNET_SKB_CB(skb)->netif_user_data = priv->cb_user_data; + KNET_SKB_CB(skb)->filter_user_data = filter->kf.cb_user_data; + KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF; + skb = knet_rx_cb(skb, sinfo->dev_no, dcb); + if (skb == NULL) { + /* Consumed by call-back */ + sinfo->rx[chan].pkts_d_callback++; + break; + } + } + + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { + bkn_add_rcpu_encap(sinfo, skb, dcb); + } + skb->protocol = eth_type_trans(skb, skb->dev); + if (filter->kf.dest_proto) { + skb->protocol = filter->kf.dest_proto; + } + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { + bkn_eth_type_update(skb, ethertype); + } + DBG_DUNE(("skb protocol 0x%04x\n",skb->protocol)); + + /* Unlock while calling up network stack */ + spin_unlock(&sinfo->lock); + if (use_napi) { + netif_receive_skb(skb); + } else { + netif_rx(skb); + } + spin_lock(&sinfo->lock); + + if (filter->kf.mirror_type == KCOM_DEST_T_API || + dbg_pkt_enable) { + DBG_FLTR(("Mirror to Rx API\n")); + sinfo->rx[chan].pkts_m_api++; + drop_api = 0; + } + } else { + DBG_FLTR(("Unknown netif %d\n", + filter->kf.dest_id)); + sinfo->rx[chan].pkts_d_unkn_netif++; + } + break; + default: + /* Drop packet */ + DBG_FLTR(("Unknown dest type %d\n", + filter->kf.dest_type)); + sinfo->rx[chan].pkts_d_unkn_dest++; + break; + } + } + if (drop_api) { + /* If count is zero, the DCB will just be recycled */ + dcb[sinfo->dcb_wsize-1] &= ~SOC_DCB_KNET_COUNT_MASK; + } + dcb[sinfo->dcb_wsize-1] |= SOC_DCB_KNET_DONE; + dcb_chain->dcb_cur++; + dcbs_done++; + } + + return dcbs_done; +} + +static int +bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget) +{ + bkn_priv_t *priv; + bkn_desc_info_t *desc; + struct sk_buff *skb; + bkn_filter_t cbf; + bkn_filter_t *filter; + uint32_t *dcb; + int ethertype; + int dcbs_done; + int pktlen; + bkn_dnx_packet_info packet_info = {0}; + int idx; + + dcbs_done = 0; + + if (!sinfo->rx[chan].running) { + /* Rx not ready */ + return 0; + } + + while (dcbs_done < budget) { + char str[32]; + sprintf(str, "Rx DCB (%d)", sinfo->rx[chan].dirty); + desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty]; + dcb = desc->dcb_mem; + bkn_dump_dcb(str, dcb, sinfo->dcb_wsize, XGS_DMA_RX_CHAN); + if ((dcb[sinfo->dcb_wsize-1] & (1 << 31)) == 0) { + break; + } + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + /* DMA run to the new halt location */ + bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, desc->dcb_dma); + } + if ((dcb[1] & (1 << 16)) == 0) { + sinfo->rx[chan].chain_complete = 1; + /* Request one extra poll to check for chain done interrupt */ + if (sinfo->napi_poll_mode) { + sinfo->napi_poll_again = 1; + } + } + sinfo->rx[chan].pkts++; + pktlen = dcb[sinfo->dcb_wsize-1] & 0xffff; + priv = netdev_priv(sinfo->dev); + skb = desc->skb; + DBG_DCB_RX(("Rx%d SKB DMA done (%d).\n", chan, sinfo->rx[chan].dirty)); + DMA_UNMAP_SINGLE(sinfo->dma_dev, + desc->skb_dma, desc->dma_size, + DMA_FROMDEV); + desc->skb_dma = 0; + bkn_dump_pkt(skb->data, 32, XGS_DMA_RX_CHAN); + if (device_is_dune(sinfo)) { + uint16_t tpid = 0; + uint16_t vid = 0; + uint8_t *pkt = skb->data; + int res = 0; + + memset(&packet_info, 0, sizeof(bkn_dnx_packet_info)); + res = bkn_dnx_packet_header_parse(pkt, (uint32_t)pktlen, &packet_info); + if (res == 0) { + if (packet_info.ftmh.action_type == 0x2) { + bkn_dnx_bitstream_set_field((uint32_t *)dcb, 192, 32, 0x8); + } else if (packet_info.ftmh.action_type == 0x1) { + bkn_dnx_bitstream_set_field((uint32_t *)dcb, 231, 25, 0x20); + } + bkn_dnx_bitstream_set_field((uint32_t *)dcb, 112, 16, packet_info.ftmh.src_sys_port); + bkn_dnx_bitstream_set_field((uint32_t *)dcb, 296, 12, packet_info.internal.vsi); + bkn_dnx_bitstream_set_field((uint32_t *)dcb, 64, 32, (packet_info.internal.trap_id << 16 | packet_info.internal.trap_qualifier)); + pkt = skb->data + packet_info.ntwrk_header_ptr; + /* check if vlan tag exists */ + tpid = (uint16_t)((pkt[12] << 8) | pkt[13]); + vid = (uint16_t)(packet_info.internal.vsi & 0xfff); + if (packet_is_untagged(tpid)) { + if ((pktlen + 4) < rx_buffer_size) { + DBG_DUNE(("add vlan tag to untagged packets\n")); + for (idx = (pktlen-packet_info.ntwrk_header_ptr-1); idx >= 12; idx--) { + pkt[idx+4] = pkt[idx]; + } + pkt[12] = 0x81; + pkt[13] = 0x00; + pkt[14] = (vid >> 8); + pkt[15] = (vid & 0xff); + pktlen += 4; + /* reset packet length in DCB */ + dcb[sinfo->dcb_wsize-1] &= ~SOC_DCB_KNET_COUNT_MASK; + dcb[sinfo->dcb_wsize-1] |= (pktlen & SOC_DCB_KNET_COUNT_MASK); + bkn_dump_pkt(pkt, 32, XGS_DMA_RX_CHAN); + } + } + } + } + if (device_is_dune(sinfo)) { + filter = bkn_match_rx_pkt(sinfo, dcb, (skb->data + packet_info.ntwrk_header_ptr), chan, &cbf); + } else { + filter = bkn_match_rx_pkt(sinfo, dcb, skb->data, chan, &cbf); + } + if ((dcb[sinfo->dcb_wsize-1] & 0x70000) == 0x30000) { + DBG_PKT(("Rx packet (%d bytes).\n", pktlen)); + } else { + /* Fragment or error */ + priv->stats.rx_errors++; + if (filter && filter->kf.mask.w[sinfo->dcb_wsize-1] == 0) { + /* Drop unless DCB status is part of filter */ + filter = NULL; + } + } + if (filter) { + DBG_FLTR(("Match filter ID %d\n", filter->kf.id)); + switch (filter->kf.dest_type) { + case KCOM_DEST_T_API: + DBG_FLTR(("Send to Rx API\n")); + sinfo->rx[chan].pkts_f_api++; + bkn_api_rx_copy_from_skb(sinfo, chan, desc); + break; + case KCOM_DEST_T_NETIF: + priv = bkn_netif_lookup(sinfo, filter->kf.dest_id); + if (priv) { + /* Check that software link is up */ + if (!netif_carrier_ok(priv->dev)) { + sinfo->rx[chan].pkts_d_no_link++; + break; + } + DBG_FLTR(("Send to netif %d (%s)\n", + priv->id, priv->dev->name)); + sinfo->rx[chan].pkts_f_netif++; + + if (device_is_dune(sinfo)) { + if (filter->kf.mirror_type == KCOM_DEST_T_API) { + sinfo->rx[chan].pkts_m_api++; + bkn_api_rx_copy_from_skb(sinfo, chan, desc); + } + /* Strip Dune headers */ + skb->data += packet_info.ntwrk_header_ptr; + pktlen -= packet_info.ntwrk_header_ptr; + bkn_dump_pkt(skb->data, 32, XGS_DMA_RX_CHAN); + /* CRC has been stripped on Dune*/ + skb_put(skb, pktlen); + } else { + skb_put(skb, pktlen - 4); /* Strip CRC */ + } + + /* Save for RCPU before stripping tag */ + ethertype = (skb->data[16] << 8) | skb->data[17]; + + if ((priv->flags & KCOM_NETIF_F_KEEP_RX_TAG) == 0) { + if (filter->kf.flags & KCOM_FILTER_F_STRIP_TAG) { + /* Strip VLAN tag */ + uint16_t vlan_proto = (uint16_t)((skb->data[12] << 8) | skb->data[13]); + if (vlan_proto == 0x8100 || vlan_proto == 0x88a8) { + DBG_FLTR(("Strip VLAN tag\n")); + ((u32*)skb->data)[3] = ((u32*)skb->data)[2]; + ((u32*)skb->data)[2] = ((u32*)skb->data)[1]; + ((u32*)skb->data)[1] = ((u32*)skb->data)[0]; + skb_pull(skb, 4); + pktlen -= 4; + } + } + } + priv->stats.rx_packets++; + priv->stats.rx_bytes += pktlen; + skb->dev = priv->dev; + + /* Optional SKB updates */ + if (knet_rx_cb != NULL) { + KNET_SKB_CB(skb)->netif_user_data = priv->cb_user_data; + KNET_SKB_CB(skb)->filter_user_data = filter->kf.cb_user_data; + KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF; + skb = knet_rx_cb(skb, sinfo->dev_no, dcb); + if (skb == NULL) { + /* Consumed by call-back */ + sinfo->rx[chan].pkts_d_callback++; + priv->stats.rx_dropped++; + desc->skb = NULL; + desc->skb_dma = 0; + break; + } + } + + if (((filter->kf.mirror_type == KCOM_DEST_T_API) && + (!device_is_dune(sinfo))) || dbg_pkt_enable) { + sinfo->rx[chan].pkts_m_api++; + bkn_api_rx_copy_from_skb(sinfo, chan, desc); + } + + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { + bkn_add_rcpu_encap(sinfo, skb, dcb); + } + skb->protocol = eth_type_trans(skb, skb->dev); + if (filter->kf.dest_proto) { + skb->protocol = filter->kf.dest_proto; + } + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { + bkn_eth_type_update(skb, ethertype); + } + DBG_DUNE(("skb protocol 0x%04x\n",skb->protocol)); + if (filter->kf.mirror_type == KCOM_DEST_T_NETIF) { + bkn_priv_t *mpriv; + struct sk_buff *mskb; + mpriv = bkn_netif_lookup(sinfo, filter->kf.mirror_id); + if (mpriv && netif_carrier_ok(mpriv->dev)) { + mskb = skb_clone(skb, GFP_ATOMIC); + if (mskb == NULL) { + sinfo->rx[chan].pkts_d_no_skb++; + } else { + sinfo->rx[chan].pkts_m_netif++; + mpriv->stats.rx_packets++; + mpriv->stats.rx_bytes += pktlen; + skb->dev = mpriv->dev; + if (filter->kf.mirror_proto) { + skb->protocol = filter->kf.mirror_proto; + } + /* Unlock while calling up network stack */ + spin_unlock(&sinfo->lock); + if (use_napi) { + netif_receive_skb(mskb); + } else { + netif_rx(mskb); + } + spin_lock(&sinfo->lock); + } + } + } + + /* Unlock while calling up network stack */ + spin_unlock(&sinfo->lock); + if (use_napi) { + netif_receive_skb(skb); + } else { + netif_rx(skb); + } + spin_lock(&sinfo->lock); + + /* Ensure that we reallocate SKB for this DCB */ + desc->skb = NULL; + desc->skb_dma = 0; + } else { + DBG_FLTR(("Unknown netif %d\n", + filter->kf.dest_id)); + sinfo->rx[chan].pkts_d_unkn_netif++; + } + } + } else { + DBG_PKT(("Rx packet dropped.\n")); + sinfo->rx[chan].pkts_d_no_match++; + priv->stats.rx_dropped++; + } + dcb[sinfo->dcb_wsize-1] = 0; + if (++sinfo->rx[chan].dirty >= MAX_RX_DCBS) { + sinfo->rx[chan].dirty = 0; + } + sinfo->rx[chan].free--; + dcbs_done++; + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + /* Right now refill for Continuous DMA mode */ + bkn_rx_refill(sinfo, chan); + if (sinfo->rx[chan].tokens < MAX_RX_DCBS) { + break; + } + } + } + + return dcbs_done; +} + +static int +bkn_do_rx(bkn_switch_info_t *sinfo, int chan, int budget) +{ + if (sinfo->rx[chan].use_rx_skb == 0) { + /* Rx buffers are provided by BCM Rx API */ + return bkn_do_api_rx(sinfo, chan, budget); + } else { + /* Rx buffers are provided by Linux kernel */ + return bkn_do_skb_rx(sinfo, chan, budget); + } +} + +static void +bkn_rx_desc_done(bkn_switch_info_t *sinfo, int chan) +{ + bkn_evt_resource_t *evt; + evt = &_bkn_evt[sinfo->evt_idx]; + DBG_IRQ(("Rx%d desc done\n", chan)); + + if (sinfo->rx[chan].use_rx_skb == 0) { + sinfo->dma_events |= KCOM_DMA_INFO_F_RX_DONE; + evt->evt_wq_put++; + wake_up_interruptible(&evt->evt_wq); + } +} + +static void +bkn_rx_chain_done(bkn_switch_info_t *sinfo, int chan) +{ + DBG_IRQ(("Rx%d chain done\n", chan)); + + if (sinfo->rx[chan].chain_complete == 0) { + /* + * In certain environments the DCB memory is updated after + * the corresponding interrupt has been received. + * The following code will ensure that this situation is + * handled properly. + */ + int maxloop = 0; + while (sinfo->rx[chan].chain_complete == 0) { + sinfo->rx[chan].sync_retry++; + if (maxloop == 0) { + sinfo->rx[chan].sync_err++; + } + if (maxloop > sinfo->rx[chan].sync_maxloop) { + sinfo->rx[chan].sync_maxloop = maxloop; + } + if (bkn_do_rx(sinfo, chan, MAX_RX_DCBS) > 0) { + bkn_rx_desc_done(sinfo, chan); + } + if (++maxloop > rx_sync_retry) { + gprintk("Fatal error: Incomplete chain\n"); + sinfo->rx[chan].chain_complete = 1; + break; + } + } + } + + sinfo->rx[chan].running = 0; + + if (sinfo->rx[chan].use_rx_skb == 0) { + bkn_api_rx_chain_done(sinfo, chan); + } else { + bkn_rx_refill(sinfo, chan); + + if (bkn_rx_restart(sinfo, chan) != 0) { + /* Presumably out of resources */ + sinfo->timer.expires = jiffies + 1; + if (!sinfo->timer_queued) { + sinfo->timer_queued = 1; + add_timer(&sinfo->timer); + } + } + } +} + +static void +bkn_suspend_tx(bkn_switch_info_t *sinfo) +{ + struct list_head *list; + bkn_priv_t *priv = netdev_priv(sinfo->dev); + + /* Stop main device */ + netif_stop_queue(priv->dev); + sinfo->tx.suspends++; + /* Stop associated virtual devices */ + list_for_each(list, &sinfo->ndev_list) { + priv = (bkn_priv_t *)list; + netif_stop_queue(priv->dev); + } +} + +static void +bkn_resume_tx(bkn_switch_info_t *sinfo) +{ + struct list_head *list; + bkn_priv_t *priv = netdev_priv(sinfo->dev); + + /* Check main device */ + if (netif_queue_stopped(priv->dev) && sinfo->tx.free > 1) { + netif_wake_queue(priv->dev); + } + /* Check associated virtual devices */ + list_for_each(list, &sinfo->ndev_list) { + priv = (bkn_priv_t *)list; + if (netif_queue_stopped(priv->dev) && sinfo->tx.free > 1) { + netif_wake_queue(priv->dev); + } + } +} + +static int +bkn_do_tx(bkn_switch_info_t *sinfo) +{ + bkn_desc_info_t *desc; + int dcbs_done = 0; + + if (!CDMA_CH(sinfo, XGS_DMA_TX_CHAN) && sinfo->tx.api_active) { + return dcbs_done; + } + + while (dcbs_done < MAX_TX_DCBS) { + char str[32]; + if (sinfo->tx.free == MAX_TX_DCBS) { + break; + } + sprintf(str, "Tx DCB (%d)", sinfo->tx.dirty); + desc = &sinfo->tx.desc[sinfo->tx.dirty]; + bkn_dump_dcb(str, desc->dcb_mem, sinfo->dcb_wsize, XGS_DMA_TX_CHAN); + if ((desc->dcb_mem[sinfo->dcb_wsize-1] & (1 << 31)) == 0) { + break; + } + if (desc->skb) { + DBG_DCB_TX(("Tx SKB DMA done (%d).\n", sinfo->tx.dirty)); + DMA_UNMAP_SINGLE(sinfo->dma_dev, + desc->skb_dma, desc->dma_size, + DMA_TODEV); + dev_kfree_skb_any(desc->skb); + desc->skb = NULL; + desc->skb_dma = 0; + } + desc->dcb_mem[sinfo->dcb_wsize-1] = 0; + if (++sinfo->tx.dirty >= MAX_TX_DCBS) { + sinfo->tx.dirty = 0; + } + if (++sinfo->tx.free > MAX_TX_DCBS) { + gprintk("Too many free Tx DCBs(%d).\n", sinfo->tx.free); + } + dcbs_done++; + } + + return dcbs_done; +} + +static void +bkn_tx_cdma_chain_switch(bkn_switch_info_t *sinfo) +{ + bkn_dcb_chain_t *dcb_chain = sinfo->tx.api_dcb_chain; + uint32_t *dcb_mem; + dma_addr_t dcb_dma; + int woffset; + + /* Switch between SKB Tx and API Tx for Continuous DMA mode */ + if (!sinfo->tx.api_active) { + /* + * Set the current SKB DCB as reload DCB and the last DCB of + * the pending API chain as the new halt location. + */ + sinfo->tx.api_active = 1; + dcb_mem = sinfo->tx.desc[sinfo->tx.cur].dcb_mem; + memset(dcb_mem, 0, sinfo->dcb_wsize * sizeof(uint32_t)); + dcb_mem[0] = dcb_chain->dcb_dma; + dcb_mem[1] |= (1 << 24) | (1 << 18) | (1 << 16); + if (++sinfo->tx.cur >= MAX_TX_DCBS) { + sinfo->tx.cur = 0; + } + sinfo->tx.free--; + woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize; + dcb_dma = dcb_chain->dcb_dma + woffset * sizeof(uint32_t); + /* DMA run to the new halt location */ + bkn_cdma_goto(sinfo, XGS_DMA_TX_CHAN, dcb_dma); + } else { + /* Only need to set the current SKB DCB as the new halt location */ + sinfo->tx.api_active = 0; + woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize; + dcb_mem = &dcb_chain->dcb_mem[woffset]; + dcb_mem[0] = sinfo->tx.desc[sinfo->tx.dirty].dcb_dma; + dcb_dma = sinfo->tx.desc[sinfo->tx.cur].dcb_dma; + /* DMA run to the new halt location */ + bkn_cdma_goto(sinfo, XGS_DMA_TX_CHAN, dcb_dma); + } +} + +static void +bkn_skb_tx(bkn_switch_info_t *sinfo) +{ + if (sinfo->tx.api_active) { + /* Switch from API Tx to SKB Tx */ + bkn_tx_cdma_chain_switch(sinfo); + } +} + +static void +bkn_api_tx(bkn_switch_info_t *sinfo) +{ + bkn_dcb_chain_t *dcb_chain; + + /* Assume that driver lock is held */ + if (list_empty(&sinfo->tx.api_dcb_list)) { + sinfo->tx.api_active = 0; + } else { + sinfo->tx.pkts++; + dcb_chain = list_entry(sinfo->tx.api_dcb_list.next, + bkn_dcb_chain_t, list); + DBG_DCB_TX(("Start API Tx DMA, first DCB @ 0x%08x (%d DCBs).\n", + (uint32_t)dcb_chain->dcb_dma, dcb_chain->dcb_cnt)); + + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) { + sinfo->tx.api_dcb_chain = dcb_chain; + if (!sinfo->tx.api_active) { + /* Switch from SKB Tx to API Tx */ + bkn_tx_cdma_chain_switch(sinfo); + } + list_del(&dcb_chain->list); + } else { + sinfo->tx.api_active = 1; + dev_dma_chan_clear(sinfo, XGS_DMA_TX_CHAN); + dev_irq_mask_enable(sinfo, XGS_DMA_TX_CHAN, 1); + dev_dma_chan_start(sinfo, XGS_DMA_TX_CHAN, + dcb_chain->dcb_dma); + list_del(&dcb_chain->list); + kfree(dcb_chain); + } + } +} + +static void +bkn_tx_cdma_chain_done(bkn_switch_info_t *sinfo, int done) +{ + int woffset; + int dcbs_done = 0; + bkn_evt_resource_t *evt; + + evt = &_bkn_evt[sinfo->evt_idx]; + if (sinfo->tx.api_active) { + sinfo->dma_events |= KCOM_DMA_INFO_F_TX_DONE; + evt->evt_wq_put++; + wake_up_interruptible(&evt->evt_wq); + /* Drain API Tx chains */ + while (sinfo->tx.api_dcb_chain != sinfo->tx.api_dcb_chain_end) { + woffset = sinfo->tx.api_dcb_chain->dcb_cnt * sinfo->dcb_wsize - 1; + if (!(sinfo->tx.api_dcb_chain->dcb_mem[woffset] & (1 << 31))) { + return; + } + kfree(sinfo->tx.api_dcb_chain); + bkn_api_tx(sinfo); + if ((++dcbs_done + done) >= MAX_TX_DCBS) { + if (sinfo->napi_poll_mode) { + /* Request one extra poll to reschedule Tx */ + sinfo->napi_poll_again = 1; + } else { + /* Request to yield for Continuous DMA mode */ + sinfo->tx_yield = 1; + } + return; + } + } + woffset = (sinfo->tx.api_dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize - 1; + if (!(sinfo->tx.api_dcb_chain->dcb_mem[woffset] & (1 << 31))) { + return; + } + /* Try and park at SKB Tx if API Tx done */ + bkn_skb_tx(sinfo); + kfree(sinfo->tx.api_dcb_chain); + sinfo->tx.api_dcb_chain = NULL; + sinfo->tx.api_dcb_chain_end = NULL; + if (!sinfo->napi_poll_mode) { + /* Not need to yield for Continuous DMA mode */ + sinfo->tx_yield = 0; + } + } else { + if (sinfo->tx.free == MAX_TX_DCBS) { + /* Try API Tx if SKB Tx done */ + bkn_api_tx(sinfo); + if (sinfo->tx.api_active) { + return; + } + } + } + + /* Resume if netif Tx resources available and API Tx not active */ + bkn_resume_tx(sinfo); +} + +static void +bkn_tx_chain_done(bkn_switch_info_t *sinfo, int done) +{ + bkn_desc_info_t *desc; + int idx, pending; + bkn_evt_resource_t *evt; + + evt = &_bkn_evt[sinfo->evt_idx]; + + DBG_IRQ(("Tx chain done (%d/%d)\n", sinfo->tx.cur, sinfo->tx.dirty)); + + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) { + return bkn_tx_cdma_chain_done(sinfo, done); + } + + dev_irq_mask_disable(sinfo, XGS_DMA_TX_CHAN, 0); + + if (sinfo->tx.api_active) { + sinfo->dma_events |= KCOM_DMA_INFO_F_TX_DONE; + evt->evt_wq_put++; + wake_up_interruptible(&evt->evt_wq); + /* Check if BCM API has more to send */ + bkn_api_tx(sinfo); + if (sinfo->tx.api_active) { + return; + } + } + + if (sinfo->tx.free == MAX_TX_DCBS) { + /* If netif Tx is idle then allow BCM API to send */ + bkn_api_tx(sinfo); + if (sinfo->tx.api_active) { + return; + } + } else { + /* If two or more DCBs are pending, chain them */ + pending = MAX_TX_DCBS - sinfo->tx.free; + idx = sinfo->tx.dirty; + while (--pending && idx < (MAX_TX_DCBS - 1)) { + sinfo->tx.desc[idx++].dcb_mem[1] |= (1 << 16); + DBG_DCB_TX(("Chain Tx DCB %d (%d)\n", idx, pending)); + } + /* Restart DMA from where we stopped */ + desc = &sinfo->tx.desc[sinfo->tx.dirty]; + DBG_DCB_TX(("Restart Tx DMA, DCB @ 0x%08x (%d).\n", + (uint32_t)desc->dcb_dma, sinfo->tx.dirty)); + dev_dma_chan_clear(sinfo, XGS_DMA_TX_CHAN); + dev_irq_mask_enable(sinfo, XGS_DMA_TX_CHAN, 0); + dev_dma_chan_start(sinfo, XGS_DMA_TX_CHAN, desc->dcb_dma); + } + + /* Resume if netif Tx resources available and API Tx not active */ + bkn_resume_tx(sinfo); +} + +static void +bkn_schedule_napi_poll(bkn_switch_info_t *sinfo) +{ + /* Schedule NAPI poll */ + DBG_NAPI(("Schedule NAPI poll on %s.\n", sinfo->dev->name)); + /* Disable interrupts until poll job is complete */ + sinfo->napi_poll_mode = 1; + /* Unlock while calling up network stack */ + spin_unlock(&sinfo->lock); + if (bkn_napi_schedule_prep(sinfo->dev, &sinfo->napi)) { + __bkn_napi_schedule(sinfo->dev, &sinfo->napi); + DBG_NAPI(("Schedule prep OK on %s.\n", sinfo->dev->name)); + } else { + /* Most likely the base device is has not been opened */ + gprintk("Warning: Unable to schedule NAPI - base device not up?\n"); + } + spin_lock(&sinfo->lock); +} + +static void +bkn_napi_poll_complete(bkn_switch_info_t *sinfo) +{ + /* Unlock while calling up network stack */ + spin_unlock(&sinfo->lock); + bkn_napi_complete(sinfo->dev, &sinfo->napi); + spin_lock(&sinfo->lock); + /* Re-enable interrupts */ + sinfo->napi_poll_mode = 0; + dev_irq_mask_set(sinfo, sinfo->irq_mask); +} + +static int +xgs_do_dma(bkn_switch_info_t *sinfo, int budget) +{ + int rx_dcbs_done = 0, tx_dcbs_done = 0; + uint32_t dma_stat; + int chan; + + DEV_READ32(sinfo, CMIC_DMA_STATr, &dma_stat); + + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + if (dma_stat & DS_DESC_DONE_TST(XGS_DMA_RX_CHAN + chan)) { + xgs_dma_desc_clear(sinfo, XGS_DMA_RX_CHAN + chan); + rx_dcbs_done += bkn_do_rx(sinfo, chan, budget - rx_dcbs_done); + bkn_rx_desc_done(sinfo, chan); + } + + if (dma_stat & DS_CHAIN_DONE_TST(XGS_DMA_RX_CHAN + chan)) { + xgs_dma_chain_clear(sinfo, XGS_DMA_RX_CHAN + chan); + bkn_rx_chain_done(sinfo, chan); + } + } + + if (dma_stat & DS_CHAIN_DONE_TST(XGS_DMA_TX_CHAN)) { + xgs_dma_chain_clear(sinfo, XGS_DMA_TX_CHAN); + tx_dcbs_done = bkn_do_tx(sinfo); + bkn_tx_chain_done(sinfo, tx_dcbs_done); + } + + return rx_dcbs_done; +} + +static int +xgsm_do_dma(bkn_switch_info_t *sinfo, int budget) +{ + int rx_dcbs_done = 0, tx_dcbs_done = 0; + uint32_t dma_stat, irq_stat = 0; + int chan; + + /* Get Controlled interrupt states for Continuous DMA mode */ + if (sinfo->cdma_channels) { + DEV_READ32(sinfo, CMICM_IRQ_STATr, &irq_stat); + } + + DEV_READ32(sinfo, CMICM_DMA_STATr, &dma_stat); + + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + if (dma_stat & (0x10 << (XGS_DMA_RX_CHAN + chan)) || + irq_stat & (0x08000000 << (XGS_DMA_RX_CHAN + chan))) { + xgsm_dma_desc_clear(sinfo, XGS_DMA_RX_CHAN + chan); + rx_dcbs_done += bkn_do_rx(sinfo, chan, budget - rx_dcbs_done); + bkn_rx_desc_done(sinfo, chan); + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + continue; + } + } + + if (dma_stat & (0x1 << (XGS_DMA_RX_CHAN + chan))) { + xgsm_dma_chain_clear(sinfo, XGS_DMA_RX_CHAN + chan); + bkn_rx_chain_done(sinfo, chan); + } + } + + if (dma_stat & (0x1 << XGS_DMA_TX_CHAN) || + irq_stat & (0x08000000 << XGS_DMA_TX_CHAN)) { + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) { + xgsm_dma_desc_clear(sinfo, XGS_DMA_TX_CHAN); + } else { + xgsm_dma_chain_clear(sinfo, XGS_DMA_TX_CHAN); + } + tx_dcbs_done = bkn_do_tx(sinfo); + bkn_tx_chain_done(sinfo, tx_dcbs_done); + } + + return rx_dcbs_done; +} + +static int +dev_do_dma(bkn_switch_info_t *sinfo, int budget) +{ + if (DEV_HAS_CMICM(sinfo)) { + return xgsm_do_dma(sinfo, budget); + } else { + return xgs_do_dma(sinfo, budget); + } +} + +static void +xgs_isr(bkn_switch_info_t *sinfo) +{ + uint32_t irq_stat; + int rx_dcbs_done; + + DEV_READ32(sinfo, CMIC_IRQ_STATr, &irq_stat); + if ((irq_stat & sinfo->irq_mask) == 0) { + /* Not ours */ + return; + } + sinfo->interrupts++; + + DBG_IRQ(("Got interrupt on device %d (0x%08x)\n", + sinfo->dev_no, irq_stat)); + + if (use_napi) { + bkn_schedule_napi_poll(sinfo); + } else { + xgs_irq_mask_set(sinfo, 0); + do { + rx_dcbs_done = xgs_do_dma(sinfo, MAX_RX_DCBS); + } while (rx_dcbs_done); + } + + xgs_irq_mask_set(sinfo, sinfo->irq_mask); +} + +static void +xgsm_isr(bkn_switch_info_t *sinfo) +{ + uint32_t irq_stat; + int rx_dcbs_done; + + DEV_READ32(sinfo, CMICM_IRQ_STATr, &irq_stat); + if ((irq_stat & sinfo->irq_mask) == 0) { + /* Not ours */ + return; + } + sinfo->interrupts++; + + DBG_IRQ(("Got interrupt on device %d (0x%08x)\n", + sinfo->dev_no, irq_stat)); + + if (use_napi) { + bkn_schedule_napi_poll(sinfo); + } else { + xgsm_irq_mask_set(sinfo, 0); + do { + rx_dcbs_done = xgsm_do_dma(sinfo, MAX_RX_DCBS); + if (sinfo->cdma_channels) { + if (rx_dcbs_done >= MAX_RX_DCBS || sinfo->tx_yield) { + /* Continuous DMA mode requires to yield timely */ + break; + } + } + } while (rx_dcbs_done); + } + + xgsm_irq_mask_set(sinfo, sinfo->irq_mask); +} + +static void +bkn_isr(void *isr_data) +{ + bkn_switch_info_t *sinfo = isr_data; + + /* Safe exit on SMP systems */ + if (!module_initialized) { + return; + } + + /* Ensure that we do not touch registers during device reset */ + if (sinfo->irq_mask == 0) { + /* Not ours */ + return; + } + + spin_lock(&sinfo->lock); + + if (sinfo->napi_poll_mode) { + /* Not ours */ + spin_unlock(&sinfo->lock); + return; + } + + if (DEV_HAS_CMICM(sinfo)) { + xgsm_isr(sinfo); + } else { + xgs_isr(sinfo); + } + + spin_unlock(&sinfo->lock); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void +bkn_poll_controller(struct net_device *dev) +{ + bkn_priv_t *priv = netdev_priv(dev); + + disable_irq(dev->irq); + bkn_isr(priv->sinfo); + enable_irq(dev->irq); +} +#endif + +static void +bkn_resume_rx(bkn_switch_info_t *sinfo) +{ + bkn_desc_info_t *desc; + bkn_dcb_chain_t *dcb_chain; + dma_addr_t cur_halt, last_dcb, dcb_dma; + int woffset, chan, cdma_running; + + /* Resume Rx DMA on all channels */ + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + if (sinfo->rx[chan].use_rx_skb) { + cdma_running = 0; + bkn_api_rx_restart(sinfo); + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + cur_halt = sinfo->halt_addr[XGS_DMA_RX_CHAN + chan]; + last_dcb = sinfo->rx[chan].desc[MAX_RX_DCBS].dcb_dma; + if (cur_halt != last_dcb) { + desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty + 1]; + bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, + desc->dcb_dma); + cdma_running = 1; + } + } + if (!cdma_running) { + bkn_rx_restart(sinfo, chan); + } + } else { + cdma_running = 0; + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + if (sinfo->rx[chan].api_active) { + dcb_chain = sinfo->rx[chan].api_dcb_chain_end; + woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize; + dcb_dma = dcb_chain->dcb_dma + woffset * sizeof(uint32_t); + bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, dcb_dma); + cdma_running = 1; + } + } + if (!cdma_running) { + bkn_api_rx_restart(sinfo); + } + } + } +} + +static int +bkn_open(struct net_device *dev) +{ + bkn_priv_t *priv = netdev_priv(dev); + bkn_switch_info_t *sinfo = priv->sinfo; + unsigned long flags; + + /* Check if base device */ + if (priv->id <= 0) { + /* NAPI used only on base device */ + if (use_napi) { + bkn_napi_enable(dev, &sinfo->napi); + } + + /* Start DMA when base device is started */ + if (sinfo->basedev_suspended) { + spin_lock_irqsave(&sinfo->lock, flags); + dev_do_dma(sinfo, MAX_RX_DCBS); + sinfo->basedev_suspended = 0; + bkn_api_tx(sinfo); + if (!sinfo->tx.api_active) { + bkn_resume_tx(sinfo); + } + bkn_resume_rx(sinfo); + spin_unlock_irqrestore(&sinfo->lock, flags); + } + } + + if (!sinfo->basedev_suspended) { + netif_start_queue(dev); + } + + return 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) +static int +bkn_set_mac_address(struct net_device *dev, void *addr) +{ + if (!is_valid_ether_addr(((struct sockaddr *)addr)->sa_data)) { + return -EINVAL; + } + memcpy(dev->dev_addr, ((struct sockaddr *)addr)->sa_data, dev->addr_len); + return 0; +} +#endif + +static int +bkn_change_mtu(struct net_device *dev, int new_mtu) +{ + if (new_mtu < 68 || new_mtu > rx_buffer_size) { + return -EINVAL; + } + dev->mtu = new_mtu; + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) +static int +bkn_poll(struct net_device *dev, int *budget) +{ + bkn_priv_t *priv = netdev_priv(dev); + bkn_switch_info_t *sinfo = priv->sinfo; + int cur_budget = *budget; + int poll_again = 0; + int rx_dcbs_done; + unsigned long flags; + + spin_lock_irqsave(&sinfo->lock, flags); + + DBG_NAPI(("NAPI poll on %s.\n", dev->name)); + + sinfo->napi_poll_again = 0; + + if (cur_budget > dev->quota) { + cur_budget = dev->quota; + } + + rx_dcbs_done = dev_do_dma(sinfo, cur_budget); + + *budget -= rx_dcbs_done; + cur_budget -= rx_dcbs_done; + dev->quota -= rx_dcbs_done; + + if (sinfo->napi_poll_again || cur_budget <= 0) { + poll_again = 1; + sinfo->napi_not_done++; + } else { + bkn_napi_poll_complete(sinfo); + } + + spin_unlock_irqrestore(&sinfo->lock, flags); + + return poll_again; +} +#else +static int +bkn_poll(struct napi_struct *napi, int budget) +{ + bkn_switch_info_t *sinfo = container_of(napi, bkn_switch_info_t, napi); + int rx_dcbs_done; + unsigned long flags; + + spin_lock_irqsave(&sinfo->lock, flags); + + DBG_NAPI(("NAPI poll on %s.\n", sinfo->dev->name)); + + sinfo->napi_poll_again = 0; + + rx_dcbs_done = dev_do_dma(sinfo, budget); + + if (sinfo->napi_poll_again || rx_dcbs_done >= budget) { + /* Force poll again */ + rx_dcbs_done = budget; + sinfo->napi_not_done++; + } else { + bkn_napi_poll_complete(sinfo); + } + + spin_unlock_irqrestore(&sinfo->lock, flags); + + return rx_dcbs_done; +} +#endif + +static int +bkn_stop(struct net_device *dev) +{ + bkn_priv_t *priv = netdev_priv(dev); + bkn_switch_info_t *sinfo = priv->sinfo; + unsigned long flags; + + netif_stop_queue(dev); + + /* Check if base device */ + if (priv->id <= 0) { + /* NAPI used only on base device */ + if (use_napi) { + bkn_napi_disable(dev, &sinfo->napi); + } + /* Suspend all devices if base device is stopped */ + if (basedev_suspend) { + spin_lock_irqsave(&sinfo->lock, flags); + bkn_suspend_tx(sinfo); + sinfo->basedev_suspended = 1; + spin_unlock_irqrestore(&sinfo->lock, flags); + } + } + + return 0; +} + +/* + * Network Device Statistics. + * Cleared at init time. + */ +static struct net_device_stats * +bkn_get_stats(struct net_device *dev) +{ + bkn_priv_t *priv = netdev_priv(dev); + + return &priv->stats; +} + +/* Fake multicast ability */ +static void +bkn_set_multicast_list(struct net_device *dev) +{ +} + +static int +bkn_tx(struct sk_buff *skb, struct net_device *dev) +{ + bkn_priv_t *priv = netdev_priv(dev); + bkn_switch_info_t *sinfo = priv->sinfo; + struct sk_buff *new_skb; + unsigned char *pktdata; + int pktlen; + int taglen; + int rcpulen; + int metalen; + int sop; + int idx; + uint16_t tpid; + uint32_t *metadata; + unsigned long flags; + + DBG_VERB(("Netif Tx: Len=%d\n", skb->len)); + + if (priv->id <= 0) { + /* Do not transmit on base device */ + priv->stats.tx_dropped++; + dev_kfree_skb_any(skb); + return 0; + } + + if (!netif_carrier_ok(dev)) { + DBG_WARN(("Tx drop: Invalid RCPU encapsulation\n")); + priv->stats.tx_dropped++; + sinfo->tx.pkts_d_no_link++; + dev_kfree_skb_any(skb); + return 0; + } + + spin_lock_irqsave(&sinfo->lock, flags); + + if (sinfo->tx.free > 1) { + bkn_desc_info_t *desc = &sinfo->tx.desc[sinfo->tx.cur]; + uint32_t *dcb; + + pktdata = skb->data; + pktlen = skb->len + 4; + rcpulen = 0; + sop = 0; + + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { + rcpulen = RCPU_HDR_SIZE; + if (skb->len < (rcpulen + 14)) { + DBG_WARN(("Tx drop: Invalid RCPU encapsulation\n")); + priv->stats.tx_dropped++; + sinfo->tx.pkts_d_rcpu_encap++; + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&sinfo->lock, flags); + return 0; + } + if (check_rcpu_signature && + ((skb->data[18] << 8) | skb->data[19]) != sinfo->rcpu_sig) { + DBG_WARN(("Tx drop: Invalid RCPU signature\n")); + priv->stats.tx_dropped++; + sinfo->tx.pkts_d_rcpu_sig++; + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&sinfo->lock, flags); + return 0; + } + if (skb->data[21] & RCPU_F_MODHDR) { + rcpulen += RCPU_TX_META_SIZE; + sop = skb->data[RCPU_HDR_SIZE]; + switch (sop) { + case 0xff: + case 0x81: + case 0xfb: + case 0xfc: + break; + default: + DBG_WARN(("Tx drop: Invalid RCPU meta data\n")); + priv->stats.tx_dropped++; + sinfo->tx.pkts_d_rcpu_meta++; + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&sinfo->lock, flags); + return 0; + } + } + /* Skip over RCPU encapsulation */ + pktdata = &skb->data[rcpulen]; + pktlen -= rcpulen; + + /* CPU packets require tag */ + if (sop == 0) { + tpid = (pktdata[12] << 8) | pktdata[13]; + if (tpid != 0x8100) { + if (skb_header_cloned(skb)) { + /* Current SKB cannot be modified */ + DBG_SKB(("Realloc Tx SKB\n")); + new_skb = dev_alloc_skb(pktlen + 4); + if (new_skb == NULL) { + DBG_WARN(("Tx drop: No SKB memory\n")); + priv->stats.tx_dropped++; + sinfo->tx.pkts_d_no_skb++; + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&sinfo->lock, flags); + return 0; + } + memcpy(new_skb->data, pktdata, 12); + memcpy(&new_skb->data[16], &pktdata[12], pktlen - 12); + skb_put(new_skb, pktlen + 4); + dev_kfree_skb_any(skb); + skb = new_skb; + pktdata = skb->data; + } else { + /* Add tag to existing buffer */ + DBG_SKB(("Expand into unused RCPU header\n")); + pktdata = &skb->data[rcpulen-4]; + for (idx = 0; idx < 12; idx++) { + pktdata[idx] = pktdata[idx+4]; + } + } + pktdata[12] = 0x81; + pktdata[13] = 0x00; + pktdata[14] = (priv->vlan >> 8) & 0xf; + pktdata[15] = priv->vlan & 0xff; + pktlen += 4; + } + } + } else if (priv->port < 0 || (priv->flags & KCOM_NETIF_F_ADD_TAG)) { + /* Need to add VLAN tag if packet is untagged */ + tpid = (skb->data[12] << 8) | skb->data[13]; + if (tpid != 0x8100) { + if (skb_header_cloned(skb) || skb_headroom(skb) < 4) { + /* Current SKB cannot be modified */ + DBG_SKB(("Realloc Tx SKB\n")); + new_skb = dev_alloc_skb(pktlen + 4); + if (new_skb == NULL) { + DBG_WARN(("Tx drop: No SKB memory\n")); + priv->stats.tx_dropped++; + sinfo->tx.pkts_d_no_skb++; + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&sinfo->lock, flags); + return 0; + } + memcpy(new_skb->data, skb->data, 12); + memcpy(&new_skb->data[16], &skb->data[12], pktlen - 12); + skb_put(new_skb, pktlen + 4); + dev_kfree_skb_any(skb); + skb = new_skb; + } else { + /* Add tag to existing buffer */ + DBG_SKB(("Expand Tx SKB\n")); + skb_push(skb, 4); + for (idx = 0; idx < 12; idx++) { + skb->data[idx] = skb->data[idx+4]; + } + } + pktdata = skb->data; + pktdata[12] = 0x81; + pktdata[13] = 0x00; + pktdata[14] = (priv->vlan >> 8) & 0xf; + pktdata[15] = priv->vlan & 0xff; + pktlen += 4; + } + } + + /* Pad packet if needed */ + taglen = 0; + tpid = (pktdata[12] << 8) | pktdata[13]; + if (tpid == 0x8100) { + taglen = 4; + } + if (pktlen < (64 + taglen)) { + pktlen = (64 + taglen); + /* Pad runt packets accounting for skipped RCPU header if needed */ + if (SKB_PADTO(skb, pktlen + rcpulen) != 0) { + DBG_WARN(("Tx drop: skb_padto failed\n")); + priv->stats.tx_dropped++; + sinfo->tx.pkts_d_pad_fail++; + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&sinfo->lock, flags); + return 0; + } + /* skb_padto may update the skb->data pointer */ + pktdata = &skb->data[rcpulen]; + DBG_SKB(("Packet padded to %d bytes\n", pktlen)); + } + + if (pktlen > SOC_DCB_KNET_COUNT_MASK) { + DBG_WARN(("Tx drop: size of pkt (%d) is out of range(%d)\n", + pktlen, SOC_DCB_KNET_COUNT_MASK)); + sinfo->tx.pkts_d_over_limit++; + priv->stats.tx_dropped++; + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&sinfo->lock, flags); + return 0; + } + + dcb = desc->dcb_mem; + memset(dcb, 0, sizeof(uint32_t) * sinfo->dcb_wsize); + dcb[1] = pktlen; + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { + /* If module header SOP is non-zero, use RCPU meta data */ + if (sop != 0) { + metalen = (sinfo->dcb_wsize - 3) * sizeof(uint32_t); + if (metalen > RCPU_TX_META_SIZE) { + metalen = RCPU_TX_META_SIZE; + } + metadata = (uint32_t *)&skb->data[RCPU_HDR_SIZE]; + for (idx = 0; idx < BYTES2WORDS(metalen); idx++) { + dcb[idx+2] = ntohl(metadata[idx]); + } + dcb[1] |= (1 << 19); + } + bkn_dump_dcb("Tx RCPU", dcb, sinfo->dcb_wsize, XGS_DMA_TX_CHAN); + } else if (priv->port >= 0) { + /* Send to physical port */ + dcb[1] |= (1 << 19); + switch (sinfo->dcb_type) { + case 23: + case 26: + case 30: + case 31: + case 34: + case 37: + dcb[2] = 0x81000000; + dcb[3] = priv->port; + dcb[3] |= (priv->qnum & 0xc00) << 20; + dcb[4] = 0x00040000; + dcb[4] |= (priv->qnum & 0x3ff) << 8; + break; + case 32: + dcb[2] = 0x81000000; + dcb[3] = priv->port; + dcb[4] = 0x4000; + /* according to format of register SOBMH in bcm56960_a0 */ + dcb[4] |= (priv->qnum & 0x3f) << 8; + break; + case 33: + dcb[2] = 0x81000000; + dcb[3] = (priv->port) << 2; + dcb[4] = 0x00100000; + dcb[4] |= (priv->qnum & 0xfff) << 8; + break; + case 35: + dcb[2] = 0x81000000; + dcb[3] = (priv->port) << 4; + dcb[4] = 0x00400000; + dcb[4] |= (priv->qnum & 0x3fff) << 8; + break; + case 24: + dcb[2] = 0xff000000; + dcb[3] = 0x00000100; + dcb[4] = priv->port; + dcb[4] |= (priv->qnum & 0xfff) << 14; + break; + case 28: + { + if (priv->type == KCOM_NETIF_T_PORT) { + /* add PTCH ITMH header */ + if (skb_header_cloned(skb) || skb_headroom(skb) < 4) { + /* Current SKB cannot be modified */ + DBG_SKB(("Realloc Tx SKB for DNX ITMH header\n")); + new_skb = dev_alloc_skb(pktlen + 4 + 2); + if (new_skb == NULL) { + DBG_WARN(("Tx drop: No SKB memory for DNX ITMH header\n")); + priv->stats.tx_dropped++; + sinfo->tx.pkts_d_no_skb++; + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&sinfo->lock, flags); + return 0; + } + memcpy(&new_skb->data[6], skb->data, pktlen); + skb_put(new_skb, pktlen + 6); + dev_kfree_skb_any(skb); + skb = new_skb; + } else { + /* Add tag to existing buffer */ + DBG_SKB(("Expand Tx SKB for DNX ITMH header\n")); + skb_push(skb, 6); + } + pktdata = skb->data; + pktdata[0] = 0x50; + pktdata[1] = 0x00; + memcpy(&pktdata[2], priv->itmh, 4); + pktlen += 6; + } + else if (priv->type == KCOM_NETIF_T_VLAN) { + /* add PTCH header */ + if (skb_header_cloned(skb) || skb_headroom(skb) < 4) { + /* Current SKB cannot be modified */ + DBG_SKB(("Realloc Tx SKB for DNX header\n")); + new_skb = dev_alloc_skb(pktlen + 2); + if (new_skb == NULL) { + DBG_WARN(("Tx drop: No SKB memory for DNX header\n")); + priv->stats.tx_dropped++; + sinfo->tx.pkts_d_no_skb++; + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&sinfo->lock, flags); + return 0; + } + memcpy(&new_skb->data[2], skb->data, pktlen); + skb_put(new_skb, pktlen + 2); + dev_kfree_skb_any(skb); + skb = new_skb; + } else { + /* Add tag to existing buffer */ + DBG_SKB(("Expand Tx SKB for DNX header\n")); + skb_push(skb, 2); + } + pktdata = skb->data; + pktdata[0] = 0xd0; + pktdata[1] = priv->port; + pktlen += 2; + } + dcb[1] = pktlen; + break; + } + case 29: + dcb[2] = 0x81000000; + dcb[3] = priv->port; + dcb[4] = 0x00100000; + dcb[4] |= (priv->qnum & 0xfff) << 8; + break; + default: + dcb[2] = 0xff000000; + dcb[3] = 0x00000100; + dcb[4] = priv->port; + break; + } + } + + /* Optional SKB updates */ + if (knet_tx_cb != NULL) { + skb = knet_tx_cb(skb, sinfo->dev_no, dcb); + if (skb == NULL) { + /* Consumed by call-back */ + DBG_WARN(("Tx drop: Consumed by call-back\n")); + priv->stats.tx_dropped++; + sinfo->tx.pkts_d_callback++; + spin_unlock_irqrestore(&sinfo->lock, flags); + return 0; + } + /* Restore (possibly) altered packet variables + * bit0 -bit15 of dcb[1] is used to save requested byte count + */ + if ((skb->len + 4) <= SOC_DCB_KNET_COUNT_MASK) { + pktdata = skb->data; + pktlen = skb->len + 4; + if (pktlen < (64 + taglen)) { + pktlen = (64 + taglen); + if (SKB_PADTO(skb, pktlen) != 0) { + DBG_WARN(("Tx drop: skb_padto failed\n")); + priv->stats.tx_dropped++; + sinfo->tx.pkts_d_pad_fail++; + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&sinfo->lock, flags); + return 0; + } + DBG_SKB(("Packet padded to %d bytes after tx callback\n", pktlen)); + } + } else { + DBG_WARN(("Tx drop: size of pkt (%d) is out of range(%d)\n", + pktlen, SOC_DCB_KNET_COUNT_MASK)); + sinfo->tx.pkts_d_over_limit++; + priv->stats.tx_dropped++; + sinfo->tx.pkts_d_callback++; + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&sinfo->lock, flags); + return 0; + } + } + /* Prepare for DMA */ + desc->skb = skb; + desc->dma_size = pktlen; + desc->skb_dma = DMA_MAP_SINGLE(sinfo->dma_dev, + pktdata, desc->dma_size, + DMA_TODEV); + dcb[0] = desc->skb_dma; + dcb[1] &= ~SOC_DCB_KNET_COUNT_MASK; + dcb[1] |= pktlen; + + DBG_DCB_TX(("Add Tx DCB @ 0x%08x (%d) [%d free] (%d bytes).\n", + (uint32_t)desc->dcb_dma, sinfo->tx.cur, + sinfo->tx.free, pktlen)); + bkn_dump_pkt(pktdata, skb->len - rcpulen, XGS_DMA_TX_CHAN); + + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) { + dcb[1] |= (1 << 24) | (1 << 16); + } else { + bkn_tx_dma_start(sinfo); + } + if (++sinfo->tx.cur >= MAX_TX_DCBS) { + sinfo->tx.cur = 0; + } + sinfo->tx.free--; + + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN) && !sinfo->tx.api_active) { + /* DMA run to the new halt location */ + bkn_cdma_goto(sinfo, XGS_DMA_TX_CHAN, + sinfo->tx.desc[sinfo->tx.cur].dcb_dma); + } + + priv->stats.tx_packets++; + priv->stats.tx_bytes += pktlen; + sinfo->tx.pkts++; + } + else { + DBG_WARN(("Tx drop: No DMA resources\n")); + priv->stats.tx_dropped++; + sinfo->tx.pkts_d_dma_resrc++; + dev_kfree_skb_any(skb); + } + + /* Check our Tx resources */ + if (sinfo->tx.free <= 1) { + bkn_suspend_tx(sinfo); + } + + netif_trans_update(dev); + + spin_unlock_irqrestore(&sinfo->lock, flags); + + return 0; +} + +static void +bkn_timer(unsigned long context) +{ + bkn_switch_info_t *sinfo = (bkn_switch_info_t *)context; + unsigned long flags; + int chan; + int restart_timer; + + spin_lock_irqsave(&sinfo->lock, flags); + + sinfo->timer_runs++; + + restart_timer = 0; + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + /* Restart channel if not running */ + if (sinfo->rx[chan].running == 0) { + bkn_rx_refill(sinfo, chan); + if (bkn_rx_restart(sinfo, chan) != 0) { + restart_timer = 1; + } + } + } + + if (restart_timer) { + /* Presumably still out of memory */ + sinfo->timer.expires = jiffies + 1; + add_timer(&sinfo->timer); + } else { + sinfo->timer_queued = 0; + } + + spin_unlock_irqrestore(&sinfo->lock, flags); +} + +static void +bkn_rx_add_tokens(bkn_switch_info_t *sinfo, int chan) +{ + unsigned long cur_jif, ticks; + uint32_t tokens_per_tick; + + tokens_per_tick = sinfo->rx[chan].rate_max / HZ; + cur_jif = jiffies; + ticks = cur_jif - sinfo->rx[chan].tok_jif; + sinfo->rx[chan].tokens += ticks * tokens_per_tick; + sinfo->rx[chan].tok_jif = cur_jif; + if (sinfo->rx[chan].tokens > sinfo->rx[chan].burst_max) { + sinfo->rx[chan].tokens = sinfo->rx[chan].burst_max; + } + + /* Restart channel if not running */ + if (sinfo->rx[chan].running == 0) { + bkn_rx_refill(sinfo, chan); + bkn_rx_restart(sinfo, chan); + } +} + +static void +bkn_rxtick(unsigned long context) +{ + bkn_switch_info_t *sinfo = (bkn_switch_info_t *)context; + unsigned long flags; + unsigned long cur_jif, ticks; + uint32_t pkt_diff; + int chan; + + spin_lock_irqsave(&sinfo->lock, flags); + + sinfo->rxtick.expires = jiffies + sinfo->rxtick_jiffies; + + /* For debug purposes we maintain a rough actual packet rate */ + if (++sinfo->rxticks >= sinfo->rxticks_per_sec) { + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + pkt_diff = sinfo->rx[chan].pkts - sinfo->rx[chan].pkts_ref; + cur_jif = jiffies; + ticks = cur_jif - sinfo->rx[chan].rate_jif; + sinfo->rx[chan].rate = (pkt_diff * HZ) / ticks; + sinfo->rx[chan].rate_jif = cur_jif; + sinfo->rx[chan].pkts_ref = sinfo->rx[chan].pkts; + } + sinfo->rxticks = 0; + } + + /* Update tokens for Rx rate control */ + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + if (sinfo->rx[chan].tokens < sinfo->rx[chan].burst_max) { + bkn_rx_add_tokens(sinfo, chan); + } + } + + spin_unlock_irqrestore(&sinfo->lock, flags); + + add_timer(&sinfo->rxtick); +} + +static void +bkn_rx_rate_config(bkn_switch_info_t *sinfo) +{ + unsigned long flags; + int chan; + uint32_t rxticks_per_sec, rps; + uint32_t jiffies_per_rxtick; + uint32_t tokens_per_rxtick; + + spin_lock_irqsave(&sinfo->lock, flags); + + /* Calculate the minimum update frequency across all channels */ + rxticks_per_sec = 1; + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + if (sinfo->rx[chan].burst_max == 0) { + sinfo->rx[chan].burst_max = sinfo->rx[chan].rate_max / 10; + } + rps = sinfo->rx[chan].rate_max / sinfo->rx[chan].burst_max; + if (rxticks_per_sec < rps) { + rxticks_per_sec = rps; + } + } + + /* Convert update frequency to system ticks */ + jiffies_per_rxtick = HZ / rxticks_per_sec; + if (jiffies_per_rxtick == 0) { + jiffies_per_rxtick = 1; + } + rxticks_per_sec = HZ / jiffies_per_rxtick; + + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + /* Ensure that burst size satifies overall rate */ + tokens_per_rxtick = sinfo->rx[chan].rate_max / rxticks_per_sec; + if (sinfo->rx[chan].burst_max < tokens_per_rxtick) { + sinfo->rx[chan].burst_max = tokens_per_rxtick; + } + /* Ensure that rate has a sane value */ + if (sinfo->rx[chan].rate_max != 0) { + if (sinfo->rx[chan].rate_max < rxticks_per_sec) { + sinfo->rx[chan].rate_max = rxticks_per_sec; + } + } + sinfo->rx[chan].tokens = sinfo->rx[chan].burst_max; + } + + /* Update timer controls */ + sinfo->rxticks_per_sec = rxticks_per_sec; + sinfo->rxtick_jiffies = jiffies_per_rxtick; + + spin_unlock_irqrestore(&sinfo->lock, flags); +} + +static void +bkn_destroy_sinfo(bkn_switch_info_t *sinfo) +{ + list_del(&sinfo->list); + bkn_free_dcbs(sinfo); + kfree(sinfo); +} + +static bkn_switch_info_t * +bkn_create_sinfo(int dev_no) +{ + bkn_switch_info_t *sinfo; + uint32_t val; + int chan; + + if ((sinfo = kmalloc(sizeof(*sinfo), GFP_KERNEL)) == NULL) { + return NULL; + } + memset(sinfo, 0, sizeof(*sinfo)); + INIT_LIST_HEAD(&sinfo->ndev_list); + INIT_LIST_HEAD(&sinfo->rxpf_list); + sinfo->base_addr = lkbde_get_dev_virt(dev_no); + sinfo->dma_dev = lkbde_get_dma_dev(dev_no); + sinfo->pdev = lkbde_get_hw_dev(dev_no); + sinfo->dev_no = dev_no; + sinfo->evt_idx = -1; + + spin_lock_init(&sinfo->lock); + + init_timer(&sinfo->timer); + sinfo->timer.expires = jiffies + 1; + sinfo->timer.data = (unsigned long)sinfo; + sinfo->timer.function = bkn_timer; + + INIT_LIST_HEAD(&sinfo->tx.api_dcb_list); + + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + INIT_LIST_HEAD(&sinfo->rx[chan].api_dcb_list); + sinfo->rx[chan].use_rx_skb = use_rx_skb; + } + + /* + * Check for dual DMA mode where Rx DMA channel 0 uses DMA buffers + * provided by the BCM API, and the remaining Rx DMA channel(s) + * use socket buffers (SKB) provided by the Linux kernel. + */ + if (use_rx_skb == 2) { + sinfo->rx[0].use_rx_skb = 0; + } + + init_timer(&sinfo->rxtick); + sinfo->rxtick.expires = jiffies + 1; + sinfo->rxtick.data = (unsigned long)sinfo; + sinfo->rxtick.function = bkn_rxtick; + + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + sinfo->rx[chan].rate_max = rx_rate[chan]; + sinfo->rx[chan].burst_max = rx_burst[chan]; + } + bkn_rx_rate_config(sinfo); + + add_timer(&sinfo->rxtick); + + list_add_tail(&sinfo->list, &_sinfo_list); + + sinfo->cmic_type = 'e'; + DEV_READ32(sinfo, CMIC_DEV_REV_IDr, &val); + if (val == 0) { + sinfo->cmic_type = 'm'; + DEV_READ32(sinfo, CMICM_DEV_REV_IDr, &val); + } + + DBG_VERB(("Check dev/rev: 0x%08x\n", val)); + + return sinfo; +} + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) +static const struct net_device_ops bkn_netdev_ops = { + .ndo_open = bkn_open, + .ndo_stop = bkn_stop, + .ndo_start_xmit = bkn_tx, + .ndo_get_stats = bkn_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_rx_mode = bkn_set_multicast_list, + .ndo_set_mac_address = bkn_set_mac_address, + .ndo_do_ioctl = NULL, + .ndo_tx_timeout = NULL, + .ndo_change_mtu = bkn_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = bkn_poll_controller, +#endif +}; +#endif + +static struct net_device * +bkn_init_ndev(u8 *mac, char *name) +{ + struct net_device *dev; + + /* Create Ethernet device */ + dev = alloc_etherdev(sizeof(bkn_priv_t)); + + if (dev == NULL) { + DBG_WARN(("Error allocating Ethernet device.\n")); + return NULL; + } +#ifdef SET_MODULE_OWNER + SET_MODULE_OWNER(dev); +#endif + + /* Set the device MAC address */ + memcpy(dev->dev_addr, mac, 6); + + /* Device information -- not available right now */ + dev->irq = 0; + dev->base_addr = 0; + + /* Default MTU should not exceed MTU of switch front-panel ports */ + dev->mtu = default_mtu; + if (dev->mtu == 0) { + dev->mtu = rx_buffer_size; + } + + /* Device vectors */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) + dev->netdev_ops = &bkn_netdev_ops; +#else + dev->open = bkn_open; + dev->hard_start_xmit = bkn_tx; + dev->stop = bkn_stop; + dev->set_multicast_list = bkn_set_multicast_list; + dev->do_ioctl = NULL; + dev->get_stats = bkn_get_stats; + dev->change_mtu = bkn_change_mtu; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = bkn_poll_controller; +#endif +#endif + if (name && *name) { + strncpy(dev->name, name, IFNAMSIZ-1); + } + + /* Register the kernel Ethernet device */ + if (register_netdev(dev)) { + DBG_WARN(("Error registering Ethernet device.\n")); + free_netdev(dev); + return NULL; + } + DBG_VERB(("Created Ethernet device %s.\n", dev->name)); + + return dev; +} + +/* + * Device Link Control Proc Read Entry + */ +static int +bkn_proc_link_show(struct seq_file *m, void *v) +{ + struct list_head *slist, *dlist; + struct net_device *dev; + bkn_priv_t *priv; + bkn_switch_info_t *sinfo; + unsigned long flags; + + seq_printf(m, "Software link status:\n"); + list_for_each(slist, &_sinfo_list) { + sinfo = (bkn_switch_info_t *)slist; + spin_lock_irqsave(&sinfo->lock, flags); + list_for_each(dlist, &sinfo->ndev_list) { + priv = (bkn_priv_t *)dlist; + dev = priv->dev; + if (dev) { + seq_printf(m, " %-14s %s\n", dev->name, + netif_carrier_ok(dev) ? "up" : "down"); + } + } + spin_unlock_irqrestore(&sinfo->lock, flags); + } + return 0; +} + +static int +bkn_proc_link_open(struct inode * inode, struct file * file) +{ + return single_open(file, bkn_proc_link_show, NULL); +} + +/* + * Device Link Control Proc Write Entry + * + * Syntax: + * =up|down + * + * Where is a virtual network interface name. + * + * Examples: + * eth4=up + * eth4=down + */ +static ssize_t +bkn_proc_link_write(struct file *file, const char *buf, + size_t count, loff_t *loff) +{ + struct list_head *slist, *dlist; + struct net_device *dev; + bkn_priv_t *priv; + bkn_switch_info_t *sinfo; + unsigned long flags; + char link_str[40]; + char *ptr; + char *newline; + + if (count >= sizeof(link_str)) { + count = sizeof(link_str) - 1; + } + if (copy_from_user(link_str, buf, count)) { + return -EFAULT; + } + link_str[count] = 0; + newline = strchr(link_str, '\n'); + if (newline) { + /* Chop off the trailing newline */ + *newline = '\0'; + } + + if ((ptr = strchr(link_str, '=')) == NULL && + (ptr = strchr(link_str, ':')) == NULL) { + gprintk("Error: link syntax not recognized: '%s'\n", link_str); + return count; + } + *ptr++ = 0; + + dev = NULL; + list_for_each(slist, &_sinfo_list) { + sinfo = (bkn_switch_info_t *)slist; + spin_lock_irqsave(&sinfo->lock, flags); + list_for_each(dlist, &sinfo->ndev_list) { + priv = (bkn_priv_t *)dlist; + if (priv->dev) { + if (strcmp(priv->dev->name, link_str) == 0) { + dev = priv->dev; + break; + } + } + } + if (dev) { + if (strcmp(ptr, "up") == 0) { + netif_carrier_on(dev); + } else if (strcmp(ptr, "down") == 0) { + netif_carrier_off(dev); + } else { + gprintk("Warning: unknown link state setting: '%s'\n", ptr); + } + spin_unlock_irqrestore(&sinfo->lock, flags); + return count; + } + spin_unlock_irqrestore(&sinfo->lock, flags); + } + + gprintk("Warning: unknown network interface: '%s'\n", link_str); + + return count; +} + +struct file_operations bkn_proc_link_file_ops = { + owner: THIS_MODULE, + open: bkn_proc_link_open, + read: seq_read, + llseek: seq_lseek, + write: bkn_proc_link_write, + release: single_release, +}; + +/* + * Device Rate Control Proc Read Entry + */ +static int +bkn_proc_rate_show(struct seq_file *m, void *v){ + int unit = 0; + struct list_head *list; + bkn_switch_info_t *sinfo; + int chan; + + list_for_each(list, &_sinfo_list) { + sinfo = (bkn_switch_info_t *)list; + + seq_printf(m, "Rate control (unit %d):\n", unit); + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + seq_printf(m, " Rx%d max rate %8u\n", + chan, sinfo->rx[chan].rate_max); + seq_printf(m, " Rx%d max burst %8u\n", + chan, sinfo->rx[chan].burst_max); + seq_printf(m, " Rx%d rate %8u\n", + chan, sinfo->rx[chan].rate); + seq_printf(m, " Rx%d tokens %8u\n", + chan, sinfo->rx[chan].tokens); + } + + unit++; + } + return 0; +} + +static int +bkn_proc_rate_open(struct inode * inode, struct file * file) { + return single_open(file, bkn_proc_rate_show, NULL); +} + +/* + * Device Rate Control Proc Write Entry + * + * Syntax: + * [:]rx_rate=[,[, is packets/sec for the first Rx DMA channel, + * is packets/sec for the second Rx DMA channel, etc. + * + * Examples: + * rx_rate=5000 + * 0:rx_rate=10000,10000 + * 1:rx_rate=10000,5000 + */ +static ssize_t +bkn_proc_rate_write(struct file *file, const char *buf, + size_t count, loff_t *loff) +{ + bkn_switch_info_t *sinfo; + char rate_str[40]; + char *ptr; + int unit, chan; + + if (count >= sizeof(rate_str)) { + count = sizeof(rate_str) - 1; + } + if (copy_from_user(rate_str, buf, count)) { + return -EFAULT; + } + + unit = simple_strtol(rate_str, NULL, 10); + sinfo = bkn_sinfo_from_unit(unit); + if (sinfo == NULL) { + gprintk("Warning: unknown unit\n"); + return count; + } + + + if ((ptr = strstr(rate_str, "rx_rate=")) != NULL) { + ptr += 7; + chan = 0; + do { + ptr++; + sinfo->rx[chan].rate_max = simple_strtol(ptr, NULL, 10); + } + while ((ptr = strchr(ptr, ',')) != NULL && ++chan < NUM_RX_CHAN); + bkn_rx_rate_config(sinfo); + } else if ((ptr = strstr(rate_str, "rx_burst=")) != NULL) { + ptr += 8; + chan = 0; + do { + ptr++; + sinfo->rx[chan].burst_max = simple_strtol(ptr, NULL, 10); + } + while ((ptr = strchr(ptr, ',')) != NULL && ++chan < NUM_RX_CHAN); + bkn_rx_rate_config(sinfo); + } else { + gprintk("Warning: unknown configuration setting\n"); + } + + return count; +} + +struct file_operations bkn_proc_rate_file_ops = { + owner: THIS_MODULE, + open: bkn_proc_rate_open, + read: seq_read, + llseek: seq_lseek, + write: bkn_proc_rate_write, + release: single_release, +}; + +/* + * Driver DMA Proc Entry + * + * This output can be rather large (> PAGE_SIZE) so we use the + * seq_file interface to do the output. Special header records + * are indicated by a negative DCB index. + */ +typedef struct { + int dev_no; /* Current unit */ + int rx_dma; /* 0: Tx DMA, 1: Rx DMA*/ + int ch_no; /* DMA channel no. (Rx only) */ + int idx; /* DCB index */ +} bkn_seq_dma_iter_t; + +/* From current record, move forward 'pos' records */ +static int +bkn_seq_dma_next_pos(bkn_seq_dma_iter_t *iter, loff_t pos) +{ + while (pos) { + if (iter->rx_dma) { + if (++iter->idx >= MAX_RX_DCBS) { + iter->idx = -1; + if (++iter->ch_no >= NUM_RX_CHAN) { + iter->rx_dma = 0; + iter->ch_no = 0; + iter->dev_no++; + if (bkn_sinfo_from_unit(iter->dev_no) == NULL) { + return -1; + } + } + } + } else { + if (++iter->idx >= MAX_TX_DCBS) { + iter->idx = -1; + iter->rx_dma = 1; + } + } + pos--; + } + return 0; +} + +/* Initialize private data and move to requested start record */ +static void * +bkn_seq_dma_start(struct seq_file *s, loff_t *pos) +{ + bkn_seq_dma_iter_t *iter; + + iter = kmalloc(sizeof(bkn_seq_dma_iter_t), GFP_KERNEL); + if (!iter) { + return NULL; + } + memset(iter, 0, sizeof(*iter)); + iter->idx = -2; + if (bkn_seq_dma_next_pos(iter, *pos) < 0) { + kfree(iter); + return NULL; + } + return iter; +} + +/* Move to next record */ +static void * +bkn_seq_dma_next(struct seq_file *s, void *v, loff_t *pos) +{ + bkn_seq_dma_iter_t *iter = (bkn_seq_dma_iter_t *)v; + void *rv = iter; + + if (bkn_seq_dma_next_pos(iter, 1) < 0) { + return NULL; + } + (*pos)++; + return rv; +} + +/* Release private data */ +static void +bkn_seq_dma_stop(struct seq_file *s, void *v) +{ + if (v) { + kfree(v); + } +} + +/* Print current record */ +static int +bkn_seq_dma_show(struct seq_file *s, void *v) +{ + bkn_seq_dma_iter_t *iter = (bkn_seq_dma_iter_t *)v; + bkn_switch_info_t *sinfo; + uint32_t *dcb = NULL; + int chan; + + sinfo = bkn_sinfo_from_unit(iter->dev_no); + if (sinfo == NULL) { + /* Should not happen */ + return 0; + } + + if (iter->rx_dma == 0) { + if (iter->idx == -2) { + seq_printf(s, "Pending events: 0x%x\n", sinfo->dma_events); + } else if (iter->idx == -1) { + seq_printf(s, + "Tx DCB info (unit %d):\n" + " api: %d\n" + " dirty: %d\n" + " cur: %d\n" + " free: %d\n" + " pause: %s\n", + iter->dev_no, + sinfo->tx.api_active, + sinfo->tx.dirty, + sinfo->tx.cur, + sinfo->tx.free, + netif_queue_stopped(sinfo->dev) ? "yes" : "no"); + } else { + dcb = sinfo->tx.desc[iter->idx].dcb_mem; + } + } else { + if (iter->idx == -1) { + chan = iter->ch_no; + seq_printf(s, + "Rx%d DCB info (unit %d):\n" + " api: %d\n" + " dirty: %d\n" + " cur: %d\n" + " free: %d\n" + " run: %d\n", + chan, iter->dev_no, + sinfo->rx[chan].api_active, + sinfo->rx[chan].dirty, + sinfo->rx[chan].cur, + sinfo->rx[chan].free, + sinfo->rx[chan].running); + } else if (sinfo->rx[iter->ch_no].use_rx_skb) { + dcb = sinfo->rx[iter->ch_no].desc[iter->idx].dcb_mem; + } + } + if (dcb) { + seq_printf(s, " DCB %2d: 0x%08x 0x%08x ... 0x%08x\n", iter->idx, + dcb[0], dcb[1], dcb[sinfo->dcb_wsize - 1]); + } + return 0; +} + +static struct seq_operations bkn_seq_dma_ops = { + .start = bkn_seq_dma_start, + .next = bkn_seq_dma_next, + .stop = bkn_seq_dma_stop, + .show = bkn_seq_dma_show +}; + +static int +bkn_seq_dma_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &bkn_seq_dma_ops); +}; + +static struct file_operations bkn_seq_dma_file_ops = { + .owner = THIS_MODULE, + .open = bkn_seq_dma_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + +/* + * Device Debug Control Proc Write Entry + * + * Syntax: + * [:]debug= + * + * Where corresponds to the debug module parameter. + * + * Examples: + * debug=0xffff + * 0:debug-0x2000 + */ +static ssize_t +bkn_proc_debug_write(struct file *file, const char *buf, + size_t count, loff_t *loff) +{ + bkn_switch_info_t *sinfo; + char debug_str[40]; + char *ptr; + int unit; + + if (count >= sizeof(debug_str)) { + count = sizeof(debug_str) - 1; + } + if (copy_from_user(debug_str, buf, count)) { + return -EFAULT; + } + + unit = simple_strtol(debug_str, NULL, 10); + sinfo = bkn_sinfo_from_unit(unit); + if (sinfo == NULL) { + gprintk("Warning: unknown unit\n"); + return count; + } + + if ((ptr = strstr(debug_str, "debug=")) != NULL) { + ptr += 6; + debug = simple_strtol(ptr, NULL, 0); + } else { + gprintk("Warning: unknown configuration setting\n"); + } + + return count; +} + +/* + * Driver Debug Proc Entry + */ +static int +bkn_proc_debug_show(struct seq_file *m, void *v){ + int unit = 0; + struct list_head *list; + bkn_switch_info_t *sinfo; + + seq_printf(m, "Configuration:\n"); + seq_printf(m, " debug: 0x%x\n", debug); + seq_printf(m, " mac_addr: %02x:%02x:%02x:%02x:%02x:%02x\n", + bkn_dev_mac[0], bkn_dev_mac[1], bkn_dev_mac[2], + bkn_dev_mac[3], bkn_dev_mac[4], bkn_dev_mac[5]); + seq_printf(m, " rx_buffer_size: %d (0x%x)\n", + rx_buffer_size, rx_buffer_size); + seq_printf(m, " rcpu_mode: %d\n", rcpu_mode); + seq_printf(m, " rcpu_dmac: %02x:%02x:%02x:%02x:%02x:%02x\n", + bkn_rcpu_dmac[0], bkn_rcpu_dmac[1], bkn_rcpu_dmac[2], + bkn_rcpu_dmac[3], bkn_rcpu_dmac[4], bkn_rcpu_dmac[5]); + seq_printf(m, " rcpu_smac: %02x:%02x:%02x:%02x:%02x:%02x\n", + bkn_rcpu_smac[0], bkn_rcpu_smac[1], bkn_rcpu_smac[2], + bkn_rcpu_smac[3], bkn_rcpu_smac[4], bkn_rcpu_smac[5]); + seq_printf(m, " rcpu_ethertype: 0x%x\n", rcpu_ethertype); + seq_printf(m, " rcpu_signature: 0x%x\n", rcpu_signature); + seq_printf(m, " rcpu_vlan: %d\n", rcpu_vlan); + seq_printf(m, " use_rx_skb: %d\n", use_rx_skb); + seq_printf(m, " num_rx_prio: %d\n", num_rx_prio); + seq_printf(m, " check_rcpu_sig: %d\n", check_rcpu_signature); + seq_printf(m, " default_mtu: %d\n", default_mtu); + seq_printf(m, " rx_sync_retry: %d\n", rx_sync_retry); + seq_printf(m, " use_napi: %d\n", use_napi); + seq_printf(m, " napi_weight: %d\n", napi_weight); + seq_printf(m, " basedev_susp: %d\n", basedev_suspend); + seq_printf(m, "Thread states:\n"); + seq_printf(m, " Command thread: %d\n", bkn_cmd_ctrl.state); + seq_printf(m, " Event thread: %d\n", bkn_evt_ctrl.state); + seq_printf(m, "Active IOCTLs:\n"); + seq_printf(m, " Command: %d\n", ioctl_cmd); + seq_printf(m, " Event: %d\n", ioctl_evt); + + list_for_each(list, &_sinfo_list) { + sinfo = (bkn_switch_info_t *)list; + + seq_printf(m, "Device %d:\n", unit); + seq_printf(m, " base_addr: 0x%p\n", sinfo->base_addr); + seq_printf(m, " dev_no: %d\n", sinfo->dev_no); + seq_printf(m, " dcb_type: %d\n", sinfo->dcb_type); + seq_printf(m, " dcb_wsize: %d\n", sinfo->dcb_wsize); + seq_printf(m, " cmic_type: %c\n", sinfo->cmic_type); + seq_printf(m, " irq_mask: 0x%x\n", sinfo->irq_mask); + seq_printf(m, " dma_events: 0x%x\n", sinfo->dma_events); + seq_printf(m, " dcb_dma: 0x%p\n", (void *)sinfo->dcb_dma); + seq_printf(m, " dcb_mem_size: 0x%x\n", sinfo->dcb_mem_size); + seq_printf(m, " rcpu_sig: 0x%x\n", sinfo->rcpu_sig); + seq_printf(m, " napi_poll_mode: %d\n", sinfo->napi_poll_mode); + seq_printf(m, " inst_id: 0x%x\n", sinfo->inst_id); + seq_printf(m, " evt_queue: %d\n", sinfo->evt_idx); + + unit++; + } + + return 0; +} + +static int bkn_proc_debug_open(struct inode * inode, struct file * file) { + return single_open(file, bkn_proc_debug_show, NULL); +} + +struct file_operations bkn_proc_debug_file_ops = { + owner: THIS_MODULE, + open: bkn_proc_debug_open, + read: seq_read, + llseek: seq_lseek, + write: bkn_proc_debug_write, + release: single_release, +}; + +/* + * Device Statistics Proc Entry + */ +static int +bkn_proc_stats_show(struct seq_file *m, void *v){ + int unit = 0; + struct list_head *list, *flist; + bkn_switch_info_t *sinfo; + bkn_filter_t *filter; + int chan; + + + list_for_each(list, &_sinfo_list) { + sinfo = (bkn_switch_info_t *)list; + + seq_printf(m, "Device stats (unit %d):\n", unit); + seq_printf(m, " Interrupts %10u\n", sinfo->interrupts); + seq_printf(m, " Tx packets %10u\n", sinfo->tx.pkts); + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + seq_printf(m, " Rx%d packets %10u\n", + chan, sinfo->rx[chan].pkts); + } + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + if (sinfo->interrupts == 0) { + /* Avoid divide-by-zero */ + seq_printf(m, " Rx%d pkts/intr -\n", chan); + } else { + seq_printf(m, " Rx%d pkts/intr %8u\n", + chan, sinfo->rx[chan].pkts / sinfo->interrupts); + } + } + seq_printf(m, " Timer runs %10u\n", sinfo->timer_runs); + seq_printf(m, " NAPI reruns %10u\n", sinfo->napi_not_done); + + list_for_each(flist, &sinfo->rxpf_list) { + filter = (bkn_filter_t *)flist; + + seq_printf(m, " Filter %d stats:\n", filter->kf.id); + seq_printf(m, " Hits %10lu\n", filter->hits); + } + + unit++; + } + return 0; +} + +static int bkn_proc_stats_open(struct inode * inode, struct file * file) { + return single_open(file, bkn_proc_stats_show, NULL); +} + +/* + * Device Statistics Proc Write Entry + * + * Syntax: + * [:]clear[=all] + * + * Where corresponds to the debug module parameter. + * + * Examples: + * clear + * 0:clear=all + */ +static ssize_t +bkn_proc_stats_write(struct file *file, const char *buf, + size_t count, loff_t *loff) +{ + bkn_switch_info_t *sinfo; + struct list_head *flist; + bkn_filter_t *filter; + char debug_str[40]; + char *ptr; + int unit; + int clear_mask; + int chan; + + if (count >= sizeof(debug_str)) { + count = sizeof(debug_str) - 1; + } + if (copy_from_user(debug_str, buf, count)) { + return -EFAULT; + } + + unit = simple_strtol(debug_str, NULL, 10); + sinfo = bkn_sinfo_from_unit(unit); + if (sinfo == NULL) { + gprintk("Warning: unknown unit\n"); + return count; + } + + clear_mask = 0; + if ((ptr = strstr(debug_str, "clear=")) != NULL) { + ptr += 6; + if (strncmp(ptr, "all", 3) == 0) { + clear_mask = ~0; + } + } else if ((ptr = strstr(debug_str, "clear")) != NULL) { + clear_mask = ~0; + } else { + gprintk("Warning: unknown configuration setting\n"); + } + + if (clear_mask) { + sinfo->tx.pkts = 0; + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + sinfo->rx[chan].pkts = 0; + } + sinfo->interrupts = 0; + sinfo->timer_runs = 0; + sinfo->napi_not_done = 0; + list_for_each(flist, &sinfo->rxpf_list) { + filter = (bkn_filter_t *)flist; + filter->hits = 0; + } + } + + return count; +} + +struct file_operations bkn_proc_stats_file_ops = { + owner: THIS_MODULE, + open: bkn_proc_stats_open, + read: seq_read, + llseek: seq_lseek, + write: bkn_proc_stats_write, + release: single_release, +}; + +/* + * Device Debug Statistics Proc Entry + */ +static int +bkn_proc_dstats_show(struct seq_file *m, void *v){ + int unit = 0; + struct list_head *list; + bkn_switch_info_t *sinfo; + int chan; + + list_for_each(list, &_sinfo_list) { + sinfo = (bkn_switch_info_t *)list; + + seq_printf(m, "Device debug stats (unit %d):\n", unit); + seq_printf(m, " Tx drop no skb %10u\n", + sinfo->tx.pkts_d_no_skb); + seq_printf(m, " Tx drop rcpu encap %10u\n", + sinfo->tx.pkts_d_rcpu_encap); + seq_printf(m, " Tx drop rcpu sig %10u\n", + sinfo->tx.pkts_d_rcpu_sig); + seq_printf(m, " Tx drop rcpu meta %10u\n", + sinfo->tx.pkts_d_rcpu_meta); + seq_printf(m, " Tx drop pad failed %10u\n", + sinfo->tx.pkts_d_pad_fail); + seq_printf(m, " Tx drop no resource %10u\n", + sinfo->tx.pkts_d_dma_resrc); + seq_printf(m, " Tx drop callback %10u\n", + sinfo->tx.pkts_d_callback); + seq_printf(m, " Tx drop no link %10u\n", + sinfo->tx.pkts_d_no_link); + seq_printf(m, " Tx drop oversized %10u\n", + sinfo->tx.pkts_d_over_limit); + seq_printf(m, " Tx suspends %10u\n", + sinfo->tx.suspends); + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + seq_printf(m, " Rx%d filter to api %10u\n", + chan, sinfo->rx[chan].pkts_f_api); + seq_printf(m, " Rx%d filter to netif %10u\n", + chan, sinfo->rx[chan].pkts_f_netif); + seq_printf(m, " Rx%d mirror to api %10u\n", + chan, sinfo->rx[chan].pkts_m_api); + seq_printf(m, " Rx%d mirror to netif %10u\n", + chan, sinfo->rx[chan].pkts_m_netif); + seq_printf(m, " Rx%d drop no skb %10u\n", + chan, sinfo->rx[chan].pkts_d_no_skb); + seq_printf(m, " Rx%d drop no match %10u\n", + chan, sinfo->rx[chan].pkts_d_no_match); + seq_printf(m, " Rx%d drop unkn netif %10u\n", + chan, sinfo->rx[chan].pkts_d_unkn_netif); + seq_printf(m, " Rx%d drop unkn dest %10u\n", + chan, sinfo->rx[chan].pkts_d_unkn_dest); + seq_printf(m, " Rx%d drop callback %10u\n", + chan, sinfo->rx[chan].pkts_d_callback); + seq_printf(m, " Rx%d drop no link %10u\n", + chan, sinfo->rx[chan].pkts_d_no_link); + seq_printf(m, " Rx%d sync error %10u\n", + chan, sinfo->rx[chan].sync_err); + seq_printf(m, " Rx%d sync retry %10u\n", + chan, sinfo->rx[chan].sync_retry); + seq_printf(m, " Rx%d sync maxloop %10u\n", + chan, sinfo->rx[chan].sync_maxloop); + seq_printf(m, " Rx%d drop no buffer %10u\n", + chan, sinfo->rx[chan].pkts_d_no_api_buf); + } + unit++; + } + return 0; +} + +static int bkn_proc_dstats_open(struct inode * inode, struct file * file) { + return single_open(file, bkn_proc_dstats_show, NULL); +} + +/* + * Device Debug Statistics Proc Write Entry + * + * Syntax: + * [:]clear[=all|tx|rx[]] + * + * Where corresponds to the debug module parameter. + * + * Examples: + * clear + * 0:clear=rx1 + */ +static ssize_t +bkn_proc_dstats_write(struct file *file, const char *buf, + size_t count, loff_t *loff) +{ + bkn_switch_info_t *sinfo; + char debug_str[40]; + char *ptr; + int unit; + int clear_mask; + int chan; + + if (count >= sizeof(debug_str)) { + count = sizeof(debug_str) - 1; + } + if (copy_from_user(debug_str, buf, count)) { + return -EFAULT; + } + + unit = simple_strtol(debug_str, NULL, 10); + sinfo = bkn_sinfo_from_unit(unit); + if (sinfo == NULL) { + gprintk("Warning: unknown unit\n"); + return count; + } + + clear_mask = 0; + if ((ptr = strstr(debug_str, "clear=")) != NULL) { + ptr += 6; + if (strncmp(ptr, "all", 3) == 0) { + clear_mask = ~0; + } else if (strncmp(ptr, "dev", 3) == 0) { + clear_mask = 0x20; + } else if (strncmp(ptr, "tx", 2) == 0) { + clear_mask = 0x10; + } else if (strncmp(ptr, "rx0", 3) == 0) { + clear_mask = (1 << 0); + } else if (strncmp(ptr, "rx1", 3) == 0) { + clear_mask = (1 << 1); + } else if (strncmp(ptr, "rx", 2) == 0) { + clear_mask = 0xf; + } + } else if ((ptr = strstr(debug_str, "clear")) != NULL) { + clear_mask = ~0; + } else { + gprintk("Warning: unknown configuration setting\n"); + } + + /* Tx counters */ + if (clear_mask & 0x10) { + sinfo->tx.pkts_d_no_skb = 0; + sinfo->tx.pkts_d_rcpu_encap = 0; + sinfo->tx.pkts_d_rcpu_sig = 0; + sinfo->tx.pkts_d_rcpu_meta = 0; + sinfo->tx.pkts_d_pad_fail = 0; + sinfo->tx.pkts_d_over_limit = 0; + sinfo->tx.pkts_d_dma_resrc = 0; + sinfo->tx.suspends = 0; + } + /* Rx counters */ + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + if (clear_mask & (1 << chan)) { + sinfo->rx[chan].pkts_f_api = 0; + sinfo->rx[chan].pkts_f_netif = 0; + sinfo->rx[chan].pkts_m_api = 0; + sinfo->rx[chan].pkts_m_netif = 0; + sinfo->rx[chan].pkts_d_no_skb = 0; + sinfo->rx[chan].pkts_d_no_match = 0; + sinfo->rx[chan].pkts_d_unkn_netif = 0; + sinfo->rx[chan].pkts_d_unkn_dest = 0; + sinfo->rx[chan].pkts_d_no_api_buf = 0; + sinfo->rx[chan].sync_err = 0; + sinfo->rx[chan].sync_retry = 0; + sinfo->rx[chan].sync_maxloop = 0; + } + } + + return count; +} + +struct file_operations bkn_proc_dstats_file_ops = { + owner: THIS_MODULE, + open: bkn_proc_dstats_open, + read: seq_read, + llseek: seq_lseek, + write: bkn_proc_dstats_write, + release: single_release, +}; + +static int +bkn_proc_init(void) +{ + struct proc_dir_entry *entry; + + PROC_CREATE(entry, "link", 0666, bkn_proc_root, &bkn_proc_link_file_ops); + if (entry == NULL) { + return -1; + } + PROC_CREATE(entry, "rate", 0666, bkn_proc_root, &bkn_proc_rate_file_ops); + if (entry == NULL) { + return -1; + } + PROC_CREATE(entry, "dma", 0, bkn_proc_root, &bkn_seq_dma_file_ops); + if (entry == NULL) { + return -1; + } + PROC_CREATE(entry, "debug", 0666, bkn_proc_root, &bkn_proc_debug_file_ops); + if (entry == NULL) { + return -1; + } + PROC_CREATE(entry, "stats", 0666, bkn_proc_root, &bkn_proc_stats_file_ops); + if (entry == NULL) { + return -1; + } + PROC_CREATE(entry, "dstats", 0666, bkn_proc_root, &bkn_proc_dstats_file_ops); + if (entry == NULL) { + return -1; + } + + return 0; +} + +static int +bkn_proc_cleanup(void) +{ + remove_proc_entry("link", bkn_proc_root); + remove_proc_entry("rate", bkn_proc_root); + remove_proc_entry("dma", bkn_proc_root); + remove_proc_entry("debug", bkn_proc_root); + remove_proc_entry("stats", bkn_proc_root); + remove_proc_entry("dstats", bkn_proc_root); + return 0; +} + +/* + * Generic module functions + */ + +static int +_pprint(void) +{ + pprintf("Broadcom BCM KNET Linux Network Driver\n"); + + return 0; +} + +static int +bkn_knet_dma_info(kcom_msg_dma_info_t *kmsg, int len) +{ + bkn_switch_info_t *sinfo; + bkn_dcb_chain_t *dcb_chain, *dcb_chain_end; + unsigned long flags; + int chan = API_RX_CHAN; + dma_addr_t dcb_dma; + int woffset; + + kmsg->hdr.type = KCOM_MSG_TYPE_RSP; + + sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit); + if (sinfo == NULL) { + kmsg->hdr.status = KCOM_E_PARAM; + return sizeof(kcom_msg_hdr_t); + } + + dcb_chain = kmalloc(sizeof(*dcb_chain), GFP_KERNEL); + if (dcb_chain == NULL) { + gprintk("Fatal error: No memory for dcb_chain\n"); + kmsg->hdr.status = KCOM_E_RESOURCE; + return sizeof(kcom_msg_hdr_t); + } + memset(dcb_chain, 0, sizeof(*dcb_chain)); + dcb_chain->dcb_cnt = kmsg->dma_info.cnt; + dcb_chain->dcb_dma = kmsg->dma_info.data.dcb_start; + dcb_chain->dcb_mem = kernel_bde->p2l(sinfo->dev_no, + dcb_chain->dcb_dma); + + if (kmsg->dma_info.type == KCOM_DMA_INFO_T_TX_DCB) { + + spin_lock_irqsave(&sinfo->lock, flags); + + /* Hold back packets from kernel */ + bkn_suspend_tx(sinfo); + + list_add_tail(&dcb_chain->list, &sinfo->tx.api_dcb_list); + + /* Handle for Continuous DMA mode */ + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) { + woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize + 1; + if ((dcb_chain->dcb_mem[woffset] & ((1 << 18) | (1 << 16))) != 0x50000) { + gprintk("No suitable API DCB chain for Continuous DMA mode\n"); + kfree(dcb_chain); + kmsg->hdr.status = KCOM_E_PARAM; + spin_unlock_irqrestore(&sinfo->lock, flags); + return sizeof(kcom_msg_hdr_t); + } + dcb_chain_end = sinfo->tx.api_dcb_chain_end; + if (dcb_chain_end != NULL) { + /* Stitch this chain */ + woffset = (dcb_chain_end->dcb_cnt - 1) * sinfo->dcb_wsize; + dcb_chain_end->dcb_mem[woffset] = dcb_chain->dcb_dma; + } + sinfo->tx.api_dcb_chain_end = dcb_chain; + if (sinfo->tx.api_active) { + /* Set new halt location */ + woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize; + dcb_dma = dcb_chain->dcb_dma + woffset * sizeof(uint32_t); + /* DMA run to the new halt location */ + bkn_cdma_goto(sinfo, XGS_DMA_TX_CHAN, dcb_dma); + } + } + + if (sinfo->tx.free == MAX_TX_DCBS && + !sinfo->tx.api_active && + !sinfo->basedev_suspended) { + bkn_api_tx(sinfo); + } + + spin_unlock_irqrestore(&sinfo->lock, flags); + + } else if (kmsg->dma_info.type == KCOM_DMA_INFO_T_RX_DCB) { + + spin_lock_irqsave(&sinfo->lock, flags); + + list_add_tail(&dcb_chain->list, &sinfo->rx[chan].api_dcb_list); + + /* Handle for Continuous DMA mode */ + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize + 1; + if ((dcb_chain->dcb_mem[woffset] & ((1 << 18) | (1 << 16))) != 0x50000) { + gprintk("No suitable API DCB chain for Continuous DMA mode\n"); + kfree(dcb_chain); + kmsg->hdr.status = KCOM_E_PARAM; + spin_unlock_irqrestore(&sinfo->lock, flags); + return sizeof(kcom_msg_hdr_t); + } + dcb_chain_end = sinfo->rx[chan].api_dcb_chain_end; + if (dcb_chain_end != NULL) { + /* Stitch this chain */ + woffset = (dcb_chain_end->dcb_cnt - 1) * sinfo->dcb_wsize; + dcb_chain_end->dcb_mem[woffset] = dcb_chain->dcb_dma; + } + sinfo->rx[chan].api_dcb_chain_end = dcb_chain; + if (!sinfo->rx[chan].use_rx_skb) { + /* Set new halt location */ + woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize; + dcb_dma = dcb_chain->dcb_dma + woffset * sizeof(uint32_t); + /* DMA run to the new halt location */ + bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, dcb_dma); + } + } + + if (sinfo->rx[chan].api_active == 0) { + bkn_api_rx_restart(sinfo); + } + + spin_unlock_irqrestore(&sinfo->lock, flags); + + } else { + DBG_DCB(("Unknown DCB_INFO type (%d).\n", kmsg->dma_info.type)); + kfree(dcb_chain); + kmsg->hdr.status = KCOM_E_PARAM; + } + + return sizeof(kcom_msg_hdr_t); +} + +static int +bkn_create_inst(uint32 inst_id) +{ + bkn_switch_info_t *sinfo; + bkn_evt_resource_t *evt; + unsigned long flags; + int i, evt_idx = -1; + + /* multiple instance mode */ + for (i = 0; i < kernel_bde->num_devices(BDE_ALL_DEVICES); i ++) { + evt = &_bkn_evt[i]; + if (evt->inst_id == inst_id) { + evt_idx = i; + DBG_INST(("%s evt_idx %d inst_id 0x%x\n",__FUNCTION__, i, inst_id)); + break; + } + if ((_bkn_multi_inst == 0) || (evt->inst_id == 0)) { + _bkn_multi_inst ++; + evt_idx = i; + init_waitqueue_head(&evt->evt_wq); + evt->inst_id = inst_id; + DBG_INST(("%s evt_idx %d inst_id 0x%x\n",__FUNCTION__, i, inst_id)); + break; + } + } + + if (evt_idx == -1) { + DBG_WARN(("Run out the event queue resource !\n")); + return -1; + } + for (i = 0; i < kernel_bde->num_devices(BDE_ALL_DEVICES); i ++) { + if (inst_id & (1 << i)) { + sinfo = bkn_sinfo_from_unit(i); + spin_lock_irqsave(&sinfo->lock, flags); + sinfo->evt_idx = evt_idx; + spin_unlock_irqrestore(&sinfo->lock, flags); + DBG_INST(("%s d(%d) evt_idx %d \n",__FUNCTION__, i, evt_idx)); + } + } + return 0; +} + +/* + * Device reprobe driven by application to check if new device is probed or + * existed device is changed after inserting KNET module. + */ +static int +bkn_knet_dev_reprobe(void) +{ + bkn_switch_info_t *sinfo; + int i; + for (i = 0; i < kernel_bde->num_devices(BDE_ALL_DEVICES); i++) { + sinfo = bkn_sinfo_from_unit(i); + if (sinfo == NULL ) { + /* New device found after re-probe. */ + if (bkn_knet_dev_init(i) < 0) { + return -1; + } + } else { + /* Existed device reinit after re-probe. */ + if (bkn_knet_dev_reinit(i) < 0) { + return -1; + } + } + } + return 0; +} + +/* Assign the inst_id and evt_idx */ +static int +bkn_knet_dev_inst_set(kcom_msg_version_t *kmsg) +{ + bkn_switch_info_t *sinfo; + int d = kmsg->hdr.unit; + uint32 inst = 0; + unsigned long flags; + struct list_head *list; + + sinfo = bkn_sinfo_from_unit(d); + lkbde_dev_instid_get(d, &inst); + + spin_lock_irqsave(&sinfo->lock, flags); + if (sinfo->inst_id != inst) { + /* Instance database changed, reinit the inst_id */ + sinfo->inst_id = 0; + sinfo->evt_idx = -1; + } + spin_unlock_irqrestore(&sinfo->lock, flags); + + if (inst) { + if (sinfo->inst_id == 0){ + if (bkn_create_inst(inst) != 0) { + return -1; + } + } + spin_lock_irqsave(&sinfo->lock, flags); + sinfo->inst_id = inst; + spin_unlock_irqrestore(&sinfo->lock, flags); + } else { + /* legacy mode */ + list_for_each(list, &_sinfo_list) { + sinfo = (bkn_switch_info_t *)list; + spin_lock_irqsave(&sinfo->lock, flags); + sinfo->evt_idx = 0; + sinfo->inst_id = 0; + spin_unlock_irqrestore(&sinfo->lock, flags); + } + } + return 0; +} + +static int +bkn_knet_version(kcom_msg_version_t *kmsg, int len) +{ + /* Support pci hot plug and multiple instance */ + if ((bkn_knet_dev_reprobe() < 0) || + (bkn_knet_dev_inst_set(kmsg) < 0)){ + kmsg->hdr.status = KCOM_E_RESOURCE; + return sizeof(kcom_msg_version_t); + } + + kmsg->hdr.type = KCOM_MSG_TYPE_RSP; + kmsg->version = KCOM_VERSION; + kmsg->netif_max = KCOM_NETIF_MAX; + kmsg->filter_max = KCOM_FILTER_MAX; + + return sizeof(kcom_msg_version_t); +} + +static int +bkn_knet_hw_reset(kcom_msg_hw_reset_t *kmsg, int len) +{ + bkn_switch_info_t *sinfo; + unsigned long flags; + int chan; + + kmsg->hdr.type = KCOM_MSG_TYPE_RSP; + + sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit); + if (sinfo == NULL) { + kmsg->hdr.status = KCOM_E_PARAM; + return sizeof(kcom_msg_hdr_t); + } + + spin_lock_irqsave(&sinfo->lock, flags); + + if (kmsg->channels == 0) { + /* Clean all if no channels specified */ + bkn_dma_abort(sinfo); + bkn_clean_dcbs(sinfo); + } else { + if (kmsg->channels & (1 << XGS_DMA_TX_CHAN)) { + bkn_dma_abort_tx(sinfo); + bkn_clean_tx_dcbs(sinfo); + } + for (chan = 0; chan < NUM_RX_CHAN; chan++) { + if (kmsg->channels & (1 << (XGS_DMA_RX_CHAN + chan))) { + bkn_dma_abort_rx(sinfo, chan); + bkn_clean_rx_dcbs(sinfo, chan); + } + } + } + + spin_unlock_irqrestore(&sinfo->lock, flags); + + return sizeof(kcom_msg_hdr_t); +} + +static int +bkn_knet_hw_init(kcom_msg_hw_init_t *kmsg, int len) +{ + bkn_switch_info_t *sinfo; + unsigned long flags; + + kmsg->hdr.type = KCOM_MSG_TYPE_RSP; + + DBG_DCB(("DCB size %d, type %d\n", kmsg->dcb_size, kmsg->dcb_type)); + + sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit); + if (sinfo == NULL) { + kmsg->hdr.status = KCOM_E_PARAM; + return sizeof(kcom_msg_hdr_t); + } + + spin_lock_irqsave(&sinfo->lock, flags); + + /* Config Continuous DMA mode */ + sinfo->cdma_channels = kmsg->cdma_channels; + + /* First time called we need to allocate DCBs */ + sinfo->dcb_type = kmsg->dcb_type; + sinfo->dcb_wsize = BYTES2WORDS(kmsg->dcb_size); + if (sinfo->dcb_mem == NULL) { + if (bkn_alloc_dcbs(sinfo) < 0) { + kmsg->hdr.status = KCOM_E_RESOURCE; + return sizeof(kcom_msg_hdr_t); + } + bkn_init_dcbs(sinfo); + } + + /* Ensure that we restart properly */ + bkn_dma_abort(sinfo); + bkn_clean_dcbs(sinfo); + + if (basedev_suspend) { + if (!netif_running(sinfo->dev)) { + sinfo->basedev_suspended = 1; + } + } + + bkn_dma_init(sinfo); + + spin_unlock_irqrestore(&sinfo->lock, flags); + + return sizeof(kcom_msg_hdr_t); +} + +static int +bkn_knet_detach(kcom_msg_detach_t *kmsg, int len) +{ + bkn_switch_info_t *sinfo; + unsigned long flags; + bkn_evt_resource_t *evt; + + kmsg->hdr.type = KCOM_MSG_TYPE_RSP; + sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit); + if (sinfo == NULL) { + kmsg->hdr.status = KCOM_E_PARAM; + return sizeof(kcom_msg_hdr_t); + } + + spin_lock_irqsave(&sinfo->lock, flags); + + /* Create dummy event to unblock pending IOCTL */ + sinfo->dma_events |= KCOM_DMA_INFO_F_TX_DONE; + evt = &_bkn_evt[sinfo->evt_idx]; + evt->evt_wq_put++; + wake_up_interruptible(&evt->evt_wq); + + spin_unlock_irqrestore(&sinfo->lock, flags); + + /* Ensure that we return a valid unit number */ + kmsg->hdr.unit = sinfo->dev_no; + + return sizeof(kcom_msg_detach_t); +} + +static int +bkn_knet_netif_create(kcom_msg_netif_create_t *kmsg, int len) +{ + bkn_switch_info_t *sinfo; + struct net_device *dev; + struct list_head *list; + bkn_priv_t *priv, *lpriv; + unsigned long flags; + int found, id; + uint8 *ma; + + kmsg->hdr.type = KCOM_MSG_TYPE_RSP; + + switch (kmsg->netif.type) { + case KCOM_NETIF_T_VLAN: + case KCOM_NETIF_T_PORT: + case KCOM_NETIF_T_META: + break; + default: + kmsg->hdr.status = KCOM_E_PARAM; + return sizeof(kcom_msg_hdr_t); + } + sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit); + if (sinfo == NULL) { + kmsg->hdr.status = KCOM_E_PARAM; + return sizeof(kcom_msg_hdr_t); + } + ma = kmsg->netif.macaddr; + if ((ma[0] | ma[1] | ma[2] | ma[3] | ma[4] | ma[5]) == 0) { + bkn_dev_mac[5]++; + ma = bkn_dev_mac; + } + if ((dev = bkn_init_ndev(ma, kmsg->netif.name)) == NULL) { + kmsg->hdr.status = KCOM_E_RESOURCE; + return sizeof(kcom_msg_hdr_t); + } + priv = netdev_priv(dev); + priv->dev = dev; + priv->sinfo = sinfo; + priv->type = kmsg->netif.type; + priv->vlan = kmsg->netif.vlan; + if (priv->type == KCOM_NETIF_T_PORT) { + priv->port = kmsg->netif.port; + memcpy(priv->itmh, kmsg->netif.itmh, 4); + priv->qnum = kmsg->netif.qnum; + } else { + if ((device_is_dune(sinfo)) && (priv->type == KCOM_NETIF_T_VLAN)) { + /* set port as SSP to PTCH */ + priv->port = kmsg->netif.port; + priv->qnum = kmsg->netif.qnum; + } + else { + priv->port = -1; + } + } + priv->flags = kmsg->netif.flags; + priv->cb_user_data = kmsg->netif.cb_user_data; + + /* Force RCPU encapsulation if rcpu_mode */ + if (rcpu_mode) { + priv->flags |= KCOM_NETIF_F_RCPU_ENCAP; + DBG_RCPU(("RCPU auto-enabled\n")); + } + + /* Prevent (incorrect) compiler warning */ + lpriv = NULL; + + spin_lock_irqsave(&sinfo->lock, flags); + + /* + * We insert network interfaces sorted by ID. + * In case an interface is destroyed, we reuse the ID + * the next time an interface is created. + */ + found = 0; + id = 1; + list_for_each(list, &sinfo->ndev_list) { + lpriv = (bkn_priv_t *)list; + if (id < lpriv->id) { + found = 1; + break; + } + id = lpriv->id + 1; + } + priv->id = id; + if (found) { + /* Replace previously removed interface */ + list_add_tail(&priv->list, &lpriv->list); + } else { + /* No holes - add to end of list */ + list_add_tail(&priv->list, &sinfo->ndev_list); + } + + if (id < sinfo->ndev_max) { + DBG_NDEV(("Add netif ID %d to table\n", id)); + sinfo->ndevs[id] = dev; + } else { + int ndev_max = sinfo->ndev_max + NDEVS_CHUNK; + int size = ndev_max * sizeof(struct net_device *); + void *ndevs = kmalloc(size, GFP_ATOMIC); + if (ndevs != NULL) { + DBG_NDEV(("Reallocate netif table for ID %d\n", id)); + memset(ndevs, 0, size); + if (sinfo->ndevs != NULL) { + size = sinfo->ndev_max * sizeof(struct net_device *); + memcpy(ndevs, sinfo->ndevs, size); + kfree(sinfo->ndevs); + } + sinfo->ndevs = ndevs; + sinfo->ndev_max = ndev_max; + sinfo->ndevs[id] = dev; + } + } + + spin_unlock_irqrestore(&sinfo->lock, flags); + + DBG_VERB(("Assigned ID %d to Ethernet device %s\n", + priv->id, dev->name)); + + kmsg->netif.id = priv->id; + memcpy(kmsg->netif.macaddr, dev->dev_addr, 6); + memcpy(kmsg->netif.name, dev->name, KCOM_NETIF_NAME_MAX - 1); + + return sizeof(*kmsg); +} + +static int +bkn_knet_netif_destroy(kcom_msg_netif_destroy_t *kmsg, int len) +{ + bkn_switch_info_t *sinfo; + struct net_device *dev; + bkn_priv_t *priv; + struct list_head *list; + unsigned long flags; + int found; + + kmsg->hdr.type = KCOM_MSG_TYPE_RSP; + + sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit); + if (sinfo == NULL) { + kmsg->hdr.status = KCOM_E_PARAM; + return sizeof(kcom_msg_hdr_t); + } + + spin_lock_irqsave(&sinfo->lock, flags); + + found = 0; + list_for_each(list, &sinfo->ndev_list) { + priv = (bkn_priv_t *)list; + if (kmsg->hdr.id == priv->id) { + found = 1; + break; + } + } + + if (!found) { + spin_unlock_irqrestore(&sinfo->lock, flags); + kmsg->hdr.status = KCOM_E_NOT_FOUND; + return sizeof(kcom_msg_hdr_t); + } + + list_del(&priv->list); + + if (priv->id < sinfo->ndev_max) { + sinfo->ndevs[priv->id] = NULL; + } + + spin_unlock_irqrestore(&sinfo->lock, flags); + + dev = priv->dev; + DBG_VERB(("Removing virtual Ethernet device %s (%d).\n", + dev->name, priv->id)); + unregister_netdev(dev); + free_netdev(dev); + + return sizeof(kcom_msg_hdr_t); +} + +static int +bkn_knet_netif_list(kcom_msg_netif_list_t *kmsg, int len) +{ + bkn_switch_info_t *sinfo; + bkn_priv_t *priv; + struct list_head *list; + unsigned long flags; + int idx; + + kmsg->hdr.type = KCOM_MSG_TYPE_RSP; + + sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit); + if (sinfo == NULL) { + kmsg->hdr.status = KCOM_E_PARAM; + return sizeof(kcom_msg_hdr_t); + } + + spin_lock_irqsave(&sinfo->lock, flags); + + idx = 0; + list_for_each(list, &sinfo->ndev_list) { + if (idx >= KCOM_NETIF_MAX) { + DBG_WARN(("Too many network interfaces to list (max %d).\n", + KCOM_NETIF_MAX)); + break; + } + priv = (bkn_priv_t *)list; + kmsg->id[idx] = priv->id; + idx++; + } + kmsg->ifcnt = idx; + + spin_unlock_irqrestore(&sinfo->lock, flags); + + return sizeof(*kmsg) - sizeof(kmsg->id) + (idx * sizeof(kmsg->id[0])); +} + +static int +bkn_knet_netif_get(kcom_msg_netif_get_t *kmsg, int len) +{ + bkn_switch_info_t *sinfo; + bkn_priv_t *priv; + unsigned long flags; + + kmsg->hdr.type = KCOM_MSG_TYPE_RSP; + + sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit); + if (sinfo == NULL) { + kmsg->hdr.status = KCOM_E_PARAM; + return sizeof(kcom_msg_hdr_t); + } + + spin_lock_irqsave(&sinfo->lock, flags); + + priv = bkn_netif_lookup(sinfo, kmsg->hdr.id); + + if (priv == NULL) { + spin_unlock_irqrestore(&sinfo->lock, flags); + kmsg->hdr.status = KCOM_E_NOT_FOUND; + return sizeof(kcom_msg_hdr_t); + } + + memcpy(kmsg->netif.macaddr, priv->dev->dev_addr, 6); + memcpy(kmsg->netif.name, priv->dev->name, KCOM_NETIF_NAME_MAX - 1); + kmsg->netif.vlan = priv->vlan; + kmsg->netif.type = priv->type; + kmsg->netif.id = priv->id; + kmsg->netif.flags = priv->flags; + + if (priv->port < 0) { + kmsg->netif.port = 0; + } else { + kmsg->netif.port = priv->port; + } + kmsg->netif.qnum = priv->qnum; + + spin_unlock_irqrestore(&sinfo->lock, flags); + + return sizeof(*kmsg); +} + +static int +bkn_knet_filter_create(kcom_msg_filter_create_t *kmsg, int len) +{ + bkn_switch_info_t *sinfo; + struct list_head *list; + bkn_filter_t *filter, *lfilter; + unsigned long flags; + int found, id; + + kmsg->hdr.type = KCOM_MSG_TYPE_RSP; + + sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit); + if (sinfo == NULL) { + kmsg->hdr.status = KCOM_E_PARAM; + return sizeof(kcom_msg_hdr_t); + } + + switch (kmsg->filter.type) { + case KCOM_FILTER_T_RX_PKT: + break; + default: + kmsg->hdr.status = KCOM_E_PARAM; + return sizeof(kcom_msg_hdr_t); + } + + spin_lock_irqsave(&sinfo->lock, flags); + + /* + * Find available ID + */ + found = 1; + id = 0; + while (found && ++id < KCOM_FILTER_MAX) { + found = 0; + list_for_each(list, &sinfo->rxpf_list) { + lfilter = (bkn_filter_t *)list; + if (id == lfilter->kf.id) { + found = 1; + break; + } + } + } + if (found) { + /* Too many filters */ + spin_unlock_irqrestore(&sinfo->lock, flags); + kmsg->hdr.status = KCOM_E_RESOURCE; + return sizeof(kcom_msg_hdr_t); + } + + filter = kmalloc(sizeof(*filter), GFP_ATOMIC); + if (filter == NULL) { + spin_unlock_irqrestore(&sinfo->lock, flags); + kmsg->hdr.status = KCOM_E_PARAM; + return sizeof(kcom_msg_hdr_t); + } + memset(filter, 0, sizeof(*filter)); + memcpy(&filter->kf, &kmsg->filter, sizeof(filter->kf)); + filter->kf.id = id; + + /* Add according to priority */ + found = 0; + list_for_each(list, &sinfo->rxpf_list) { + lfilter = (bkn_filter_t *)list; + if (filter->kf.priority < lfilter->kf.priority) { + list_add_tail(&filter->list, &lfilter->list); + found = 1; + break; + } + } + if (!found) { + list_add_tail(&filter->list, &sinfo->rxpf_list); + } + + kmsg->filter.id = filter->kf.id; + + spin_unlock_irqrestore(&sinfo->lock, flags); + + DBG_VERB(("Created filter ID %d (%s).\n", + filter->kf.id, filter->kf.desc)); + + return len; +} + +static int +bkn_knet_filter_destroy(kcom_msg_filter_destroy_t *kmsg, int len) +{ + bkn_switch_info_t *sinfo; + bkn_filter_t *filter; + struct list_head *list; + unsigned long flags; + int found; + + kmsg->hdr.type = KCOM_MSG_TYPE_RSP; + + sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit); + if (sinfo == NULL) { + kmsg->hdr.status = KCOM_E_PARAM; + return sizeof(kcom_msg_hdr_t); + } + + spin_lock_irqsave(&sinfo->lock, flags); + + found = 0; + list_for_each(list, &sinfo->rxpf_list) { + filter = (bkn_filter_t *)list; + if (kmsg->hdr.id == filter->kf.id) { + found = 1; + break; + } + } + + if (!found) { + spin_unlock_irqrestore(&sinfo->lock, flags); + kmsg->hdr.status = KCOM_E_NOT_FOUND; + return sizeof(kcom_msg_hdr_t); + } + + list_del(&filter->list); + + spin_unlock_irqrestore(&sinfo->lock, flags); + + DBG_VERB(("Removing filter ID %d.\n", filter->kf.id)); + kfree(filter); + + return sizeof(kcom_msg_hdr_t); +} + +static int +bkn_knet_filter_list(kcom_msg_filter_list_t *kmsg, int len) +{ + bkn_switch_info_t *sinfo; + bkn_filter_t *filter; + struct list_head *list; + unsigned long flags; + int idx; + + kmsg->hdr.type = KCOM_MSG_TYPE_RSP; + + sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit); + if (sinfo == NULL) { + kmsg->hdr.status = KCOM_E_PARAM; + return sizeof(kcom_msg_hdr_t); + } + + spin_lock_irqsave(&sinfo->lock, flags); + + idx = 0; + list_for_each(list, &sinfo->rxpf_list) { + if (idx >= KCOM_FILTER_MAX) { + DBG_WARN(("Too many filters to list (max %d).\n", + KCOM_FILTER_MAX)); + break; + } + filter = (bkn_filter_t *)list; + kmsg->id[idx] = filter->kf.id; + idx++; + } + kmsg->fcnt = idx; + + spin_unlock_irqrestore(&sinfo->lock, flags); + + return sizeof(*kmsg) - sizeof(kmsg->id) + (idx * sizeof(kmsg->id[0])); +} + +static int +bkn_knet_filter_get(kcom_msg_filter_get_t *kmsg, int len) +{ + bkn_switch_info_t *sinfo; + bkn_filter_t *filter; + struct list_head *list; + unsigned long flags; + int found; + + kmsg->hdr.type = KCOM_MSG_TYPE_RSP; + + sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit); + if (sinfo == NULL) { + kmsg->hdr.status = KCOM_E_PARAM; + return sizeof(kcom_msg_hdr_t); + } + + spin_lock_irqsave(&sinfo->lock, flags); + + found = 0; + list_for_each(list, &sinfo->rxpf_list) { + filter = (bkn_filter_t *)list; + if (kmsg->hdr.id == filter->kf.id) { + found = 1; + break; + } + } + + if (!found) { + spin_unlock_irqrestore(&sinfo->lock, flags); + kmsg->hdr.status = KCOM_E_NOT_FOUND; + return sizeof(kcom_msg_hdr_t); + } + + memcpy(&kmsg->filter, &filter->kf, sizeof(kmsg->filter)); + + spin_unlock_irqrestore(&sinfo->lock, flags); + + return sizeof(*kmsg); +} + +static int +bkn_knet_dbg_pkt_set(kcom_msg_dbg_pkt_set_t *kmsg, int len) +{ + dbg_pkt_enable = kmsg->enable; + return sizeof(kcom_msg_dbg_pkt_set_t); +} + +static int +bkn_knet_dbg_pkt_get(kcom_msg_dbg_pkt_get_t *kmsg, int len) +{ + kmsg->value = dbg_pkt_enable; + return sizeof(kcom_msg_dbg_pkt_get_t); +} + +static int +bkn_handle_cmd_req(kcom_msg_t *kmsg, int len) +{ + /* Silently drop events and unrecognized message types */ + if (kmsg->hdr.type != KCOM_MSG_TYPE_CMD) { + if (kmsg->hdr.opcode == KCOM_M_STRING) { + DBG_VERB(("Debug string: '%s'\n", kmsg->string.val)); + return 0; + } + DBG_WARN(("Unsupported message (type=%d, opcode=%d)\n", + kmsg->hdr.type, kmsg->hdr.opcode)); + return 0; + } + + switch (kmsg->hdr.opcode) { + case KCOM_M_DMA_INFO: + DBG_CMD(("KCOM_M_DMA_INFO\n")); + /* Packet buffer */ + len = bkn_knet_dma_info(&kmsg->dma_info, len); + break; + case KCOM_M_VERSION: + DBG_CMD(("KCOM_M_VERSION\n")); + /* Return procotol version */ + len = bkn_knet_version(&kmsg->version, len); + break; + case KCOM_M_HW_RESET: + DBG_CMD(("KCOM_M_HW_RESET\n")); + /* Shut down DMA and release buffers */ + len = bkn_knet_hw_reset(&kmsg->hw_reset, len); + break; + case KCOM_M_HW_INIT: + DBG_CMD(("KCOM_M_HW_INIT\n")); + /* Initialize DMA */ + len = bkn_knet_hw_init(&kmsg->hw_init, len); + break; + case KCOM_M_DETACH: + DBG_CMD(("KCOM_M_DETACH\n")); + /* Detach kernel module */ + len = bkn_knet_detach(&kmsg->detach, len); + break; + case KCOM_M_NETIF_CREATE: + DBG_CMD(("KCOM_M_NETIF_CREATE\n")); + /* Create network interface */ + len = bkn_knet_netif_create(&kmsg->netif_create, len); + break; + case KCOM_M_NETIF_DESTROY: + DBG_CMD(("KCOM_M_NETIF_DESTROY\n")); + /* Destroy network interface */ + len = bkn_knet_netif_destroy(&kmsg->netif_destroy, len); + break; + case KCOM_M_NETIF_LIST: + DBG_CMD(("KCOM_M_NETIF_LIST\n")); + /* Return list of IDs of installed network interfaces */ + len = bkn_knet_netif_list(&kmsg->netif_list, len); + break; + case KCOM_M_NETIF_GET: + DBG_CMD(("KCOM_M_NETIF_GET\n")); + /* Return network interface info */ + len = bkn_knet_netif_get(&kmsg->netif_get, len); + break; + case KCOM_M_FILTER_CREATE: + DBG_CMD(("KCOM_M_FILTER_CREATE\n")); + /* Create packet filter */ + len = bkn_knet_filter_create(&kmsg->filter_create, len); + break; + case KCOM_M_FILTER_DESTROY: + DBG_CMD(("KCOM_M_FILTER_DESTROY\n")); + /* Destroy packet filter */ + len = bkn_knet_filter_destroy(&kmsg->filter_destroy, len); + break; + case KCOM_M_FILTER_LIST: + DBG_CMD(("KCOM_M_FILTER_LIST\n")); + /* Return list of IDs of installed packet filters */ + len = bkn_knet_filter_list(&kmsg->filter_list, len); + break; + case KCOM_M_FILTER_GET: + DBG_CMD(("KCOM_M_FILTER_GET\n")); + /* Return packet filter info */ + len = bkn_knet_filter_get(&kmsg->filter_get, len); + break; + case KCOM_M_DBGPKT_SET: + DBG_CMD(("KCOM_M_DBGPKT_SET\n")); + /* Set debugging packet function */ + len = bkn_knet_dbg_pkt_set(&kmsg->dbg_pkt_set, len); + break; + case KCOM_M_DBGPKT_GET: + DBG_CMD(("KCOM_M_DBGPKT_GET\n")); + /* Get debugging packet function info */ + len = bkn_knet_dbg_pkt_get(&kmsg->dbg_pkt_get, len); + break; + default: + DBG_WARN(("Unsupported command (type=%d, opcode=%d)\n", + kmsg->hdr.type, kmsg->hdr.opcode)); + kmsg->hdr.opcode = 0; + len = sizeof(kcom_msg_hdr_t); + break; + } + return len; +} + +static int +bkn_cmd_thread(void *context) +{ + bkn_thread_ctrl_t *tc = (bkn_thread_ctrl_t *)context; + kcom_msg_t kmsg; + unsigned int len, rlen; + + bkn_thread_boot(tc); + + DBG_VERB(("Command thread starting\n")); + tc->state = 1; + while (!bkn_thread_should_stop(tc)) { + len = sizeof(kmsg); + tc->state = 2; + if (PROXY_RECV(KCOM_CHAN_KNET, &kmsg, &len) >= 0) { + DBG_VERB(("Received %d bytes from KCOM_CHAN_CMD\n", len)); + tc->state = 3; + rlen = bkn_handle_cmd_req(&kmsg, len); + tc->state = 4; + if (rlen > 0) { + PROXY_SEND(KCOM_CHAN_KNET, &kmsg, rlen); + } + } else { + /* Thread interrupted */ + bkn_sleep(1); + } + } + DBG_VERB(("Command thread done\n")); + + bkn_thread_exit(tc); + return 0; +} + +static int +bkn_get_next_dma_event(kcom_msg_dma_info_t *kmsg) +{ + static int last_dev_no = 0; + bkn_switch_info_t *sinfo; + unsigned long flags; + int dev_no, dev_evt; + bkn_evt_resource_t *evt; + + dev_evt = kmsg->hdr.unit; + sinfo = bkn_sinfo_from_unit(dev_evt); + if (sinfo == NULL) { + /* The device is not probed or initialized yet.*/ + return 0; + } + if (sinfo->evt_idx == -1) { + /* Event queue is not ready yet */ + return 0; + } + + DBG_INST(("%s dev %d evt_idx %d\n",__FUNCTION__, dev_evt, sinfo->evt_idx)); + evt = &_bkn_evt[sinfo->evt_idx]; + dev_no = last_dev_no = dev_evt; + while (1) { + dev_no++; + sinfo = bkn_sinfo_from_unit(dev_no); + if (sinfo == NULL) { + dev_no = 0; + sinfo = bkn_sinfo_from_unit(dev_no); + } + + if (sinfo && (sinfo->inst_id != 0) && + ((sinfo->inst_id & (1 << dev_evt)) == 0)) { + DBG_INST((" %s skip dev(%d)\n",__FUNCTION__,dev_evt)); + continue; + } + + if (sinfo && sinfo->dma_events) { + DBG_EVT(("Next DMA events (0x%08x)\n", sinfo->dma_events)); + kmsg->hdr.unit = sinfo->dev_no; + + spin_lock_irqsave(&sinfo->lock, flags); + kmsg->dma_info.flags = sinfo->dma_events; + sinfo->dma_events = 0; + spin_unlock_irqrestore(&sinfo->lock, flags); + + last_dev_no = dev_no; + break; + } + + if (dev_no == last_dev_no) { + DBG_INST(("wait queue index %d\n",sinfo->evt_idx)); + wait_event_interruptible(evt->evt_wq, + evt->evt_wq_get != evt->evt_wq_put); + DBG_VERB(("Event thread wakeup\n")); + + /* Thread interrupted */ + if (signal_pending(current)) { + return 0; + } + + evt->evt_wq_get = evt->evt_wq_put; + } + } + return sizeof(*kmsg); +} + +static int +bkn_evt_thread(void *context) +{ + bkn_thread_ctrl_t *tc = (bkn_thread_ctrl_t *)context; + kcom_msg_dma_info_t kmsg; + int len; + + bkn_thread_boot(tc); + + memset(&kmsg, 0, sizeof(kmsg)); + kmsg.hdr.type = KCOM_MSG_TYPE_EVT; + kmsg.hdr.opcode = KCOM_M_DMA_INFO; + + DBG_VERB(("Event thread starting\n")); + tc->state = 1; + while (!bkn_thread_should_stop(tc)) { + tc->state = 2; + len = bkn_get_next_dma_event(&kmsg); + tc->state = 3; + if (len) { + PROXY_SEND(KCOM_CHAN_KNET, &kmsg, len); + } else { + /* Thread interrupted */ + bkn_sleep(1); + } + } + DBG_VERB(("Event thread done\n")); + + bkn_thread_exit(tc); + return 0; +} + +static int +_cleanup(void) +{ + struct list_head *list; + struct net_device *dev; + bkn_filter_t *filter; + bkn_priv_t *priv; + bkn_switch_info_t *sinfo; + unsigned long flags; + + /* Inidicate that we are shutting down */ + module_initialized = 0; + + /* Shut down event thread */ + bkn_thread_stop(&bkn_evt_ctrl); + + /* Shut down command thread */ + bkn_thread_stop(&bkn_cmd_ctrl); + + /* Remove KCOM channel */ + PROXY_SERVICE_DESTROY(KCOM_CHAN_KNET); + + bkn_proc_cleanup(); + remove_proc_entry("bcm/knet", NULL); + remove_proc_entry("bcm", NULL); + + list_for_each(list, &_sinfo_list) { + sinfo = (bkn_switch_info_t *)list; + + del_timer_sync(&sinfo->timer); + del_timer_sync(&sinfo->rxtick); + + spin_lock_irqsave(&sinfo->lock, flags); + bkn_dma_abort(sinfo); + dev_irq_mask_set(sinfo, 0); + spin_unlock_irqrestore(&sinfo->lock, flags); + + DBG_IRQ(("Unregister ISR.\n")); + kernel_bde->interrupt_disconnect(sinfo->dev_no | LKBDE_ISR2_DEV); + + if (use_napi) { + while (sinfo->napi_poll_mode) { + bkn_sleep(1); + } + } + + spin_lock_irqsave(&sinfo->lock, flags); + bkn_clean_dcbs(sinfo); + spin_unlock_irqrestore(&sinfo->lock, flags); + } + + /* Destroy all switch devices */ + while (!list_empty(&_sinfo_list)) { + sinfo = list_entry(_sinfo_list.next, bkn_switch_info_t, list); + + /* Destroy all associated Rx packet filters */ + while (!list_empty(&sinfo->rxpf_list)) { + filter = list_entry(sinfo->rxpf_list.next, bkn_filter_t, list); + list_del(&filter->list); + DBG_VERB(("Removing filter ID %d.\n", filter->kf.id)); + kfree(filter); + } + + /* Destroy all associated virtual net devices */ + while (!list_empty(&sinfo->ndev_list)) { + priv = list_entry(sinfo->ndev_list.next, bkn_priv_t, list); + list_del(&priv->list); + dev = priv->dev; + DBG_VERB(("Removing virtual Ethernet device %s.\n", dev->name)); + unregister_netdev(dev); + free_netdev(dev); + } + if (sinfo->ndevs != NULL) { + kfree(sinfo->ndevs); + } + + /* Destroy base net device */ + if (sinfo->dev) { + DBG_VERB(("Removing Ethernet device %s.\n", sinfo->dev->name)); + unregister_netdev(sinfo->dev); + free_netdev(sinfo->dev); + } + + DBG_VERB(("Removing switch device.\n")); + bkn_destroy_sinfo(sinfo); + } + + return 0; +} + +static int +bkn_knet_dev_reinit(int d) +{ + bkn_switch_info_t *sinfo; + uint32 dev_state; + uint32_t dev_type; + unsigned long flags; + + if (lkbde_dev_state_get(d, &dev_state) < 0) { + return -1; + } + DBG_VERB(("%s dev %d dev_state %d\n",__FUNCTION__, d, dev_state)); + if (dev_state == BDE_DEV_STATE_CHANGED) { + sinfo = bkn_sinfo_from_unit(d); + spin_lock_irqsave(&sinfo->lock, flags); + sinfo->base_addr = lkbde_get_dev_virt(d); + sinfo->dma_dev = lkbde_get_dma_dev(d); + sinfo->pdev = lkbde_get_hw_dev(d); + + dev_type = kernel_bde->get_dev_type(d); + /* Ensure 32-bit PCI DMA is mapped properly on 64-bit platforms */ + if (dev_type & BDE_PCI_DEV_TYPE) { + if (pci_set_dma_mask(sinfo->pdev, 0xffffffff)) { + gprintk("No suitable DMA available for SKBs\n"); + _cleanup(); + return -1; + } + } + dev_irq_mask_set(sinfo, 0); + spin_unlock_irqrestore(&sinfo->lock, flags); + + gprintk("Unregister ISR.\n"); + kernel_bde->interrupt_disconnect(sinfo->dev_no | LKBDE_ISR2_DEV); + + /* Register interrupt handler */ + kernel_bde->interrupt_connect(sinfo->dev_no | LKBDE_ISR2_DEV, + bkn_isr, sinfo); + + dev_state = 0; + lkbde_dev_state_set(d, dev_state); + } + return 0; +} + +static int +bkn_knet_dev_init(int d) +{ + uint32_t dev_type; + struct net_device *dev; + bkn_switch_info_t *sinfo; + bkn_priv_t *priv; + char *bdev_name; + const ibde_dev_t *bde_dev; + + DBG_VERB(("%s dev %d\n",__FUNCTION__, d)); + /* Base network device name */ + bdev_name = "bcm%d"; + if (base_dev_name) { + if (strlen(base_dev_name) < IFNAMSIZ) { + bdev_name = base_dev_name; + } else { + DBG_WARN(("Base device name too long\n")); + } + } + + dev_type = kernel_bde->get_dev_type(d); + DBG_VERB(("Found device type 0x%x\n", dev_type)); + if ((dev_type & BDE_SWITCH_DEV_TYPE) == 0) { + DBG_WARN(("Not switch device - skipping\n")); + return 0; + } + switch (dev_type & BDE_DEV_BUS_TYPE_MASK) { + case BDE_PCI_DEV_TYPE: + case BDE_ICS_DEV_TYPE: + case BDE_AXI_DEV_TYPE: + break; + default: + DBG_WARN(("Not PCI/ICS/AXI device - skipping\n")); + return 0; + } + + if ((sinfo = bkn_create_sinfo(d)) == NULL) { + _cleanup(); + return -ENOMEM; + } + /* Ensure 32-bit PCI DMA is mapped properly on 64-bit platforms */ + if (dev_type & BDE_PCI_DEV_TYPE) { + if (pci_set_dma_mask(sinfo->pdev, 0xffffffff)) { + gprintk("No suitable DMA available for SKBs\n"); + _cleanup(); + return -EIO; + } + } + /* Initialize the cpu_no.*/ + if (dev_type & BDE_AXI_DEV_TYPE) { + /* AXI device type implies the activated iProc iHost */ + sinfo->cpu_no = 1; + } + /* Initialize default RCPU signature */ + if ((bde_dev = kernel_bde->get_dev(d)) != NULL) { + sinfo->rcpu_sig = bde_dev->device & ~0xf; + } + /* Check for override */ + if (rcpu_signature) { + sinfo->rcpu_sig = rcpu_signature; + } + + /* Ensure all interrupts are disabled, e.g. if warmbooting */ + dev_irq_mask_set(sinfo, 0); + + /* Register interrupt handler */ + kernel_bde->interrupt_connect(sinfo->dev_no | LKBDE_ISR2_DEV, + bkn_isr, sinfo); + + /* Create base virtual net device */ + bkn_dev_mac[5]++; + if ((dev = bkn_init_ndev(bkn_dev_mac, bdev_name)) == NULL) { + _cleanup(); + return -ENOMEM; + } else { + sinfo->dev = dev; + priv = netdev_priv(dev); + priv->dev = dev; + priv->sinfo = sinfo; + priv->vlan = 1; + priv->port = -1; + memset(priv->itmh, 0, sizeof(priv->itmh)); + priv->id = -1; + } + + if (use_napi) { + netif_napi_add(dev, &sinfo->napi, bkn_poll, napi_weight); + } + return 0; +} + +static int +_init(void) +{ + int idx; + int num_dev; + int rv; + bkn_evt_resource_t *evt; + + /* Connect to the kernel bde */ + if ((linux_bde_create(NULL, &kernel_bde) < 0) || kernel_bde == NULL) { + return -ENODEV; + } + + /* Randomize Lower 3 bytes of the MAC address (TESTING ONLY) */ + get_random_bytes(&bkn_dev_mac[3], 3); + + /* Check for user-supplied MAC address (recommended) */ + if (mac_addr != NULL && strlen(mac_addr) == 17) { + for (idx = 0; idx < 6; idx++) { + bkn_dev_mac[idx] = simple_strtoul(&mac_addr[idx*3], NULL, 16); + } + /* Do not allow multicast address */ + bkn_dev_mac[0] &= ~0x01; + } + + /* Optional RCPU MAC addresses */ + if (rcpu_dmac != NULL && strlen(rcpu_dmac) == 17) { + for (idx = 0; idx < 6; idx++) { + bkn_rcpu_dmac[idx] = simple_strtoul(&rcpu_dmac[idx*3], NULL, 16); + } + } + if (rcpu_smac != NULL && strlen(rcpu_smac) == 17) { + for (idx = 0; idx < 6; idx++) { + bkn_rcpu_smac[idx] = simple_strtoul(&rcpu_smac[idx*3], NULL, 16); + } + } + + /* NAPI implies that base device must be up before we can pass traffic */ + if (use_napi) { + basedev_suspend = 1; + } + + num_dev = kernel_bde->num_devices(BDE_ALL_DEVICES); + for (idx = 0; idx < num_dev; idx++) { + rv = bkn_knet_dev_init(idx); + if (rv) { + return rv; + } + } + + /* Initialize proc files */ + proc_mkdir("bcm", NULL); + bkn_proc_root = proc_mkdir("bcm/knet", NULL); + + bkn_proc_init(); + + /* Initialize event queue */ + for (idx = 0; idx < LINUX_BDE_MAX_DEVICES; idx++) { + memset(&_bkn_evt[idx], 0, sizeof(bkn_evt_resource_t)); + } + evt = &_bkn_evt[0]; + init_waitqueue_head(&evt->evt_wq); + + if (use_proxy) { + PROXY_SERVICE_CREATE(KCOM_CHAN_KNET, 1, 0); + + DBG_VERB(("Starting command thread\n")); + bkn_thread_start(&bkn_cmd_ctrl, "bkncmd", bkn_cmd_thread); + + DBG_VERB(("Starting event thread\n")); + bkn_thread_start(&bkn_evt_ctrl, "bknevt", bkn_evt_thread); + } + + module_initialized = 1; + + return 0; +} + +static int +_ioctl(unsigned int cmd, unsigned long arg) +{ + bkn_ioctl_t io; + kcom_msg_t kmsg; + + if (!module_initialized) { + return -EFAULT; + } + + if (copy_from_user(&io, (void*)arg, sizeof(io))) { + return -EFAULT; + } + + if (io.len > sizeof(kmsg)) { + return -EINVAL; + } + + io.rc = 0; + + switch(cmd) { + case 0: + if (io.len > 0) { + if (copy_from_user(&kmsg, (void *)(unsigned long)io.buf, io.len)) { + return -EFAULT; + } + ioctl_cmd++; + io.len = bkn_handle_cmd_req(&kmsg, io.len); + ioctl_cmd--; + } else { + memset(&kmsg, 0, sizeof(kcom_msg_dma_info_t)); + /* + * Retrive the kmsg.hdr.unit from user space. The dma event queue + * selection is based the instance derived from unit. + */ + if (copy_from_user(&kmsg, (void *)(unsigned long)io.buf, sizeof(kmsg))) { + return -EFAULT; + } + kmsg.hdr.type = KCOM_MSG_TYPE_EVT; + kmsg.hdr.opcode = KCOM_M_DMA_INFO; + ioctl_evt++; + io.len = bkn_get_next_dma_event((kcom_msg_dma_info_t *)&kmsg); + ioctl_evt--; + } + if (io.len > 0) { + if (copy_to_user((void *)(unsigned long)io.buf, &kmsg, io.len)) { + return -EFAULT; + } + } + break; + default: + gprintk("Invalid IOCTL"); + io.rc = -1; + break; + } + + if (copy_to_user((void*)arg, &io, sizeof(io))) { + return -EFAULT; + } + + return 0; +} + +static gmodule_t _gmodule = { + name: MODULE_NAME, + major: MODULE_MAJOR, + init: _init, + cleanup: _cleanup, + pprint: _pprint, + ioctl: _ioctl, + open: NULL, + close: NULL, +}; + +gmodule_t* +gmodule_get(void) +{ + EXPORT_NO_SYMBOLS; + return &_gmodule; +} + +/* + * Call-back interfaces for other Linux kernel drivers. + * + * The Rx call-back allows an external module to modify SKB contents + * before it is handed off to the Linux network stack. + * + * The Tx call-back allows an external module to modify SKB contents + * before it is injected inot the switch. + */ + +int +bkn_rx_skb_cb_register(knet_skb_cb_f rx_cb) +{ + if (knet_rx_cb != NULL) { + return -1; + } + knet_rx_cb = rx_cb; + return 0; +} + +int +bkn_rx_skb_cb_unregister(knet_skb_cb_f rx_cb) +{ + if (rx_cb != NULL && knet_rx_cb != rx_cb) { + return -1; + } + knet_rx_cb = NULL; + return 0; +} + +int +bkn_tx_skb_cb_register(knet_skb_cb_f tx_cb) +{ + if (knet_tx_cb != NULL) { + return -1; + } + knet_tx_cb = tx_cb; + return 0; +} + +int +bkn_tx_skb_cb_unregister(knet_skb_cb_f tx_cb) +{ + if (tx_cb != NULL && knet_tx_cb != tx_cb) { + return -1; + } + knet_tx_cb = NULL; + return 0; +} + +int +bkn_filter_cb_register(knet_filter_cb_f filter_cb) +{ + if (knet_filter_cb != NULL) { + return -1; + } + knet_filter_cb = filter_cb; + return 0; +} + +int +bkn_filter_cb_unregister(knet_filter_cb_f filter_cb) +{ + if (filter_cb != NULL && knet_filter_cb != filter_cb) { + return -1; + } + knet_filter_cb = NULL; + return 0; +} + +LKM_EXPORT_SYM(bkn_rx_skb_cb_register); +LKM_EXPORT_SYM(bkn_rx_skb_cb_unregister); +LKM_EXPORT_SYM(bkn_tx_skb_cb_register); +LKM_EXPORT_SYM(bkn_tx_skb_cb_unregister); +LKM_EXPORT_SYM(bkn_filter_cb_register); +LKM_EXPORT_SYM(bkn_filter_cb_unregister); diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/bcm-knet.h b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/bcm-knet.h new file mode 100644 index 0000000000..277ea74152 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/bcm-knet.h @@ -0,0 +1,79 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: bcm-knet.h,v 1.4 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ +#ifndef __LINUX_BCM_KNET_H__ +#define __LINUX_BCM_KNET_H__ + +#ifndef __KERNEL__ +#include +#endif + +typedef struct { + int rc; + int len; + int bufsz; + int reserved; + uint64_t buf; +} bkn_ioctl_t; + +#ifdef __KERNEL__ + +/* + * Call-back interfaces for other Linux kernel drivers. + */ +#include + +typedef struct { + uint32 netif_user_data; + uint32 filter_user_data; + uint16 dcb_type; +} knet_skb_cb_t; + +#define KNET_SKB_CB(__skb) ((knet_skb_cb_t *)&((__skb)->cb[0])) + +typedef struct sk_buff * +(*knet_skb_cb_f)(struct sk_buff *skb, int dev_no, void *meta); + +typedef int +(*knet_filter_cb_f)(uint8_t *pkt, int size, int dev_no, void *meta, + int chan, kcom_filter_t *filter); + +extern int +bkn_rx_skb_cb_register(knet_skb_cb_f rx_cb); + +extern int +bkn_rx_skb_cb_unregister(knet_skb_cb_f rx_cb); + +extern int +bkn_tx_skb_cb_register(knet_skb_cb_f tx_cb); + +extern int +bkn_tx_skb_cb_unregister(knet_skb_cb_f tx_cb); + +extern int +bkn_filter_cb_register(knet_filter_cb_f filter_cb); + +extern int +bkn_filter_cb_unregister(knet_filter_cb_f filter_cb); + +#endif + +#endif /* __LINUX_BCM_KNET_H__ */ diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/gmodule.h b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/gmodule.h new file mode 100644 index 0000000000..a0deac1bae --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/gmodule.h @@ -0,0 +1,66 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: gmodule.h,v 1.9 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ + +#ifndef __COMMON_LINUX_KRN_GMODULE_H__ +#define __COMMON_LINUX_KRN_GMODULE_H__ + +#include + +typedef struct gmodule_s { + + const char* name; + int major; + int minor; + + int (*init)(void); + int (*cleanup)(void); + + int (*pprint)(void); + + int (*open)(void); + int (*ioctl)(unsigned int cmd, unsigned long arg); + int (*close)(void); + int (*mmap) (struct file *filp, struct vm_area_struct *vma); + +} gmodule_t; + + +/* The framework will ask for your module definition */ +extern gmodule_t* gmodule_get(void); + + +/* Proc Filesystem information */ +extern int pprintf(const char* fmt, ...) + __attribute__ ((format (printf, 1, 2))); +extern int gmodule_vpprintf(char** page, const char* fmt, va_list args) + __attribute__ ((format (printf, 2, 0))); +extern int gmodule_pprintf(char** page, const char* fmt, ...) + __attribute__ ((format (printf, 2, 3))); + +extern int gprintk(const char* fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +extern int gdbg(const char* fmt, ...) + __attribute__ ((format (printf, 1, 2))); +#define GDBG gdbg + +#endif /* __COMMON_LINUX_KRN_GMODULE_H__ */ diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/lkm.h b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/lkm.h new file mode 100644 index 0000000000..eb0077f257 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/lkm.h @@ -0,0 +1,180 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: lkm.h,v 1.22 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ + +#ifndef __COMMON_LINUX_KRN_LKM_H__ +#define __COMMON_LINUX_KRN_LKM_H__ + +#ifndef __KERNEL__ +# define __KERNEL__ +#endif +#ifndef MODULE +# define MODULE +#endif + +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#include +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) +#include +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) +#include +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) +#include +#endif +#include + +/* Helper defines for multi-version kernel support */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#define LKM_2_4 +#else +#define LKM_2_6 +#endif + +#include /* printk() */ +#include /* everything... */ +#include /* error codes */ +#include /* size_t */ +#include +#include /* O_ACCMODE */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_DEVFS_FS +#include +#endif + +#define PROC_INTERFACE_KERN_VER_3_10 (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) + +/* Compatibility Macros */ + +#ifdef LKM_2_4 + +#include +#include +#define LKM_MOD_PARAM(n,ot,nt,d) MODULE_PARM(n,ot) +#define LKM_MOD_PARAM_ARRAY(n,ot,nt,c,d) MODULE_PARM(n,ot) +#define LKM_EXPORT_SYM(s) +#define _free_netdev kfree + +#else /* LKM_2_6 */ + +#define LKM_MOD_PARAM(n,ot,nt,d) module_param(n,nt,d) +#define LKM_MOD_PARAM_ARRAY(n,ot,nt,c,d) module_param_array(n,nt,c,d) +#define LKM_EXPORT_SYM(s) EXPORT_SYMBOL(s) +#define _free_netdev free_netdev + +#endif /* LKM_2_x */ + +#ifndef list_for_each_safe +#define list_for_each_safe(l,t,i) t = 0; list_for_each((l),(i)) +#endif + +#ifndef reparent_to_init +#define reparent_to_init() +#endif + +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(str) +#endif + +#ifndef EXPORT_NO_SYMBOLS +#define EXPORT_NO_SYMBOLS +#endif + +#ifndef DEFINE_SPINLOCK +#define DEFINE_SPINLOCK(_lock) spinlock_t _lock = SPIN_LOCK_UNLOCKED +#endif + +#ifndef __SPIN_LOCK_UNLOCKED +#define __SPIN_LOCK_UNLOCKED(_lock) SPIN_LOCK_UNLOCKED +#endif + +#ifndef lock_kernel +#ifdef preempt_disable +#define lock_kernel() preempt_disable() +#else +#define lock_kernel() +#endif +#endif + +#ifndef unlock_kernel +#ifdef preempt_enable +#define unlock_kernel() preempt_enable() +#else +#define unlock_kernel() +#endif +#endif + +#ifndef init_MUTEX_LOCKED +#define init_MUTEX_LOCKED(_sem) sema_init(_sem, 0) +#endif + +#ifdef CONFIG_BCM98245 +#define CONFIG_BMW +#endif + +#if PROC_INTERFACE_KERN_VER_3_10 +#define PROC_CREATE(_entry, _name, _acc, _path, _fops) \ + do { \ + _entry = proc_create(_name, _acc, _path, _fops); \ + } while (0) + +#define PROC_CREATE_DATA(_entry, _name, _acc, _path, _fops, _data) \ + do { \ + _entry = proc_create_data(_name, _acc, _path, _fops, _data); \ + } while (0) + +#define PROC_PDE_DATA(_node) PDE_DATA(_node) + +#else +#define PROC_CREATE(_entry, _name, _acc, _path, _fops) \ + do { \ + _entry = create_proc_entry(_name, _acc, _path); \ + if (_entry) { \ + _entry->proc_fops = _fops; \ + } \ + } while (0) + +#define PROC_CREATE_DATA(_entry, _name, _acc, _path, _fops, _data) \ + do { \ + _entry = create_proc_entry(_name, _acc, _path); \ + if (_entry) { \ + _entry->proc_fops = _fops; \ + _entry->data=_data; \ + } \ + } while (0) + +#define PROC_PDE_DATA(_node) PROC_I(_node)->pde->data +#endif + +#endif /* __COMMON_LINUX_KRN_LKM_H__ */ diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/Makefile b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/Makefile new file mode 100644 index 0000000000..ecabf0ae8e --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/Makefile @@ -0,0 +1,65 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# -*- Makefile -*- +# $Id: +# $Copyright: (c) 2017 Broadcom Corp. +# All Rights Reserved.$ +# +LOCALDIR = systems/linux/kernel/modules/knet-cb + +include ${SDK}/make/Make.config + +LIBS = $(LIBDIR)/libkern.a + +ifeq ($(kernel_version),2_4) +MODULE = $(LIBDIR)/linux-knet-cb.o +else +KERNEL_MODULE_DIR = kernel_module + +THIS_MOD_NAME := linux-knet-cb +MODULE = $(LIBDIR)/$(THIS_MOD_NAME).o +KMODULE = $(LIBDIR)/$(THIS_MOD_NAME).ko + +build: $(MODULE) $(KMODULE) +endif + +KBUILD_EXTRA_SYMBOLS := ${BLDDIR}/../bcm-knet/kernel_module/Module.symvers + +# BCM Network Device + +$(MODULE): $(BLDDIR)/.tree $(BOBJS) $(LIBS) + $(LD) $(MODULE_LDFLAGS) -r -d $(BOBJS) $(LIBS) -o $@ +ifneq ($(kernel_version),2_4) +$(KMODULE): $(MODULE) + rm -fr $(BLDDIR)/$(KERNEL_MODULE_DIR) + mkdir $(BLDDIR)/$(KERNEL_MODULE_DIR) + cp ${SDK}/make/Makefile.linux-kmodule $(BLDDIR)/$(KERNEL_MODULE_DIR)/Makefile + cat ${KBUILD_EXTRA_SYMBOLS} > $(BLDDIR)/$(KERNEL_MODULE_DIR)/Module.symvers + MOD_NAME=$(THIS_MOD_NAME) $(MAKE) -C $(BLDDIR)/$(KERNEL_MODULE_DIR) $(THIS_MOD_NAME).ko +endif + +# Make.depend is before clean:: so that Make.depend's clean:: runs first. + +include ${SDK}/make/Make.depend + +clean:: + $(RM) $(BLDDIR)/version.c $(BLDDIR)/version.o + $(RM) $(BOBJS) $(MODULE) + +ifneq ($(kernel_version),2_4) +.PHONY: build +endif diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c new file mode 100644 index 0000000000..30fba8750e --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c @@ -0,0 +1,276 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: + * $Copyright: (c) 2017 Broadcom Corp. + * All Rights Reserved.$ + */ + +/* + * Driver for call-back functions for Linux KNET driver. + * + * This is sample code that demonstrates how to selectively strip VLAN tags + * from an incoming packet based on tag information in the DMA control block + * (DCB). The switch will automatically add a VLAN tag to packets that ingress + * without an outer VLAN tag. Outer tagged and double tagged packets are + * not modified. The call back defined here determines which packets have + * had tags added by those and strips only those tags from the packet. + * + * This is sample code, the customer is responsible for maintaining and + * modifying this code as necessary. + * + * The module can be built from the standard Linux user mode target + * directories using the following command (assuming bash), e.g. + * + * cd $SDK/systems/linux/user/ + * make BUILD_KNET_CB=1 + * + */ + +#include /* Must be included first */ +#include +#include +#include + +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_DESCRIPTION("Broadcom Linux KNET Call-Back Driver"); +MODULE_LICENSE("GPL"); + +/* Module Information */ +#define MODULE_MAJOR 121 +#define MODULE_NAME "linux-knet-cb" + +/* set KNET_CB_DEBUG for debug info */ +#define KNET_CB_DEBUG + +/* Maintain tag strip statistics */ +struct strip_stats_s { + unsigned long stripped; /* Number of packets that have been stripped */ + unsigned long checked; + unsigned long skipped; +}; + +static struct strip_stats_s strip_stats; + +/* Local function prototypes */ +static void strip_vlan_tag(struct sk_buff *skb); +static int get_tag_status(int dcb_type, void *meta); +static struct sk_buff *strip_tag_rx_cb(struct sk_buff *skb, int dev_no, void *meta); +static struct sk_buff *strip_tag_tx_cb(struct sk_buff *skb, int dev_no, void *meta); +static int strip_tag_filter_cb(uint8_t * pkt, int size, int dev_no, void *meta, + int chan, kcom_filter_t * kf); +static int _pprint(void); +static int _cleanup(void); +static int _init(void); + +/* Remove VLAN tag for select TPIDs */ +static void +strip_vlan_tag(struct sk_buff *skb) +{ + uint16_t vlan_proto = (uint16_t) ((skb->data[12] << 8) | skb->data[13]); + if ((vlan_proto == 0x8100) || (vlan_proto == 0x88a8) || (vlan_proto == 0x9100)) { + /* Move first 12 bytes of packet back by 4 */ + ((u32 *) skb->data)[3] = ((u32 *) skb->data)[2]; + ((u32 *) skb->data)[2] = ((u32 *) skb->data)[1]; + ((u32 *) skb->data)[1] = ((u32 *) skb->data)[0]; + skb_pull(skb, 4); /* Remove 4 bytes from start of buffer */ + } +} + +/* + * Location of tagging status in select DCB types found below: + * + * DCB type 14: word 12, bits 10.11 + * DCB type 19, 20, 21, 22, 30: word 12, bits 10..11 + * DCB type 23, 29: word 13, bits 0..1 + * DCB type 31, 34, 37: word 13, bits 0..1 + * DCB type 26, 32, 33, 35: word 13, bits 0..1 + * + * The function get_tag_status() returns the tag status for known DCB types. + * 0 = Untagged + * 1 = Single inner-tag + * 2 = Single outer-tag + * 3 = Double tagged. + * -1 = Unsupported DCB type + */ +static int +get_tag_status(int dcb_type, void *meta) +{ + uint32 *dcb = (uint32 *) meta; + int tag_status; + switch (dcb_type) { + case 14: + case 19: + case 20: + case 21: + case 22: + case 30: + tag_status = (dcb[12] > 10) & 0x3; + break; + case 23: + case 29: + case 31: + case 34: + case 37: + case 26: + case 32: + case 33: + case 35: + tag_status = dcb[13] & 0x3; + break; + default: + tag_status = -1; + break; + } + return tag_status; +} + +/* + * SDK-134189 added the ability to pass two 4 byte unsigned values to the + * KNET callback function, one from the matching filter and one from the + * network interface. The usage of this data is completely defined by the + * user. In this case, if bit 0 of the interface value is set, tag stripping + * is enabled for that interface. When creating the interface and filter, + * something like the following is necessary: "netif.cb_user_data = uflags". + */ +#define NETIF_UNTAGGED_STRIP (1 << 0) + +/* Rx packet callback function */ +static struct sk_buff * +strip_tag_rx_cb(struct sk_buff *skb, int dev_no, void *meta) +{ + unsigned netif_flags = KNET_SKB_CB(skb)->netif_user_data; + unsigned dcb_type; + int tag_status; + /* Currently not using filter flags: + * unsigned filter_flags = KNET_SKB_CB(skb)->filter_user_data; + */ + +#ifdef KNET_CB_DEBUG + gprintk("%s Enter; Flags: %08X\n", __func__, netif_flags); +#endif + + if ((netif_flags & NETIF_UNTAGGED_STRIP) == 0) { + /* Untagged stripping not enabled on this netif */ + strip_stats.skipped++; + return skb; + } + + /* Get DCB type for this packet, passed by KNET driver */ + dcb_type = KNET_SKB_CB(skb)->dcb_type; + + /* Get tag status from DCB */ + tag_status = get_tag_status(dcb_type, meta); + +#ifdef KNET_CB_DEBUG + gprintk("%s; DCB Type: %d; tag status: %d\n", __func__, dcb_type, tag_status); +#endif + + if (tag_status < 0) { + /* Unsupported DCB type */ + return skb; + } + + strip_stats.checked++; + /* + * Untagged and inner tagged packet will get a new tag from the switch + * device, we need to strip this off. + */ + if (tag_status < 2) { +#ifdef KNET_CB_DEBUG + gprintk("%s; Stripping VLAN\n", __func__); +#endif + strip_stats.stripped++; + strip_vlan_tag(skb); + } +#ifdef KNET_CB_DEBUG + else { + gprintk("%s; Preserve VLAN\n", __func__); + } +#endif + return skb; +} + +/* Tx callback not used */ +static struct sk_buff * +strip_tag_tx_cb(struct sk_buff *skb, int dev_no, void *meta) +{ + /* Pass through for now */ + return skb; +} + +/* Filter callback not used */ +static int +strip_tag_filter_cb(uint8_t * pkt, int size, int dev_no, void *meta, + int chan, kcom_filter_t *kf) +{ + /* Pass through for now */ + return 0; +} + +/* + * Get statistics. + * % cat /proc/linux-knet-cb + */ +static int +_pprint(void) +{ + pprintf("Broadcom Linux KNET Call-Back: Untagged VLAN Stripper\n"); + pprintf(" %lu stripped packets\n", strip_stats.stripped); + pprintf(" %lu packets checked\n", strip_stats.checked); + pprintf(" %lu packets skipped\n", strip_stats.skipped); + + return 0; +} + +static int +_cleanup(void) +{ + bkn_rx_skb_cb_unregister(strip_tag_rx_cb); + bkn_tx_skb_cb_unregister(strip_tag_tx_cb); + bkn_filter_cb_unregister(strip_tag_filter_cb); + + return 0; +} + +static int +_init(void) +{ + bkn_rx_skb_cb_register(strip_tag_rx_cb); + bkn_tx_skb_cb_register(strip_tag_tx_cb); + bkn_filter_cb_register(strip_tag_filter_cb); + + return 0; +} + +static gmodule_t _gmodule = { + name: MODULE_NAME, + major: MODULE_MAJOR, + init: _init, + cleanup: _cleanup, + pprint: _pprint, + ioctl: NULL, + open: NULL, + close: NULL, +}; + +gmodule_t* +gmodule_get(void) +{ + EXPORT_NO_SYMBOLS; + return &_gmodule; +} diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/Makefile b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/Makefile new file mode 100644 index 0000000000..4c420c07ec --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/Makefile @@ -0,0 +1,30 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# -*- Makefile -*- +# $Id: Makefile,v 1.2 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ +# +LOCALDIR = systems/linux/kernel/modules/shared + +include ${SDK}/make/Make.config + +lib = libkern + +include ${SDK}/make/Make.kernlib + +include ${SDK}/make/Make.depend diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/gmodule.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/gmodule.c new file mode 100644 index 0000000000..a72a54ef1c --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/gmodule.c @@ -0,0 +1,428 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: gmodule.c,v 1.20 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + * + * Generic Linux Module Framework + * + * Hooks up your driver to the kernel + */ + +#include +#include +#include +#include + +/* Module Vector Table */ +static gmodule_t* _gmodule = NULL; + + +/* Allow DEVFS Support on 2.4 Kernels */ +#if defined(LKM_2_4) && defined(CONFIG_DEVFS_FS) +#define GMODULE_CONFIG_DEVFS_FS +#endif + + +#ifdef GMODULE_CONFIG_DEVFS_FS +devfs_handle_t devfs_handle = NULL; +#endif + +/* FIXME: support dynamic debugging */ + +static int _dbg_enable = 0; + +static int +gvprintk(const char* fmt, va_list args) + __attribute__ ((format (printf, 1, 0))); + +static int +gvprintk(const char* fmt, va_list args) +{ + static char _buf[256]; + + strcpy(_buf, ""); + sprintf(_buf, "%s (%d): ", _gmodule->name, current->pid); + vsprintf(_buf+strlen(_buf), fmt, args); + printk("%s",_buf); + + return 0; +} + +int +gprintk(const char* fmt, ...) +{ + int rv; + + va_list args; + va_start(args, fmt); + rv = gvprintk(fmt, args); + va_end(args); + return rv; +} + +int +gdbg(const char* fmt, ...) +{ + int rv = 0; + + va_list args; + va_start(args, fmt); + if(_dbg_enable) { + rv = gvprintk(fmt, args); + } + va_end(args); + return rv; +} + + +/* + * Proc FS Utilities + */ +#if PROC_INTERFACE_KERN_VER_3_10 +static struct seq_file* _proc_buf = NULL; + +int +pprintf(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + seq_vprintf(_proc_buf, fmt, args); + va_end(args); + return 0; +} + +static int _gmodule_proc_show(struct seq_file *m, void *v){ + _proc_buf = m; + _gmodule->pprint(); + return 0; +} + +static int +_gmodule_proc_open(struct inode * inode, struct file * file) { + if(_gmodule->open) { + _gmodule->open(); + } + + return single_open(file, _gmodule_proc_show, NULL); +} + +static ssize_t +_gmodule_proc_write(struct file *file, const char *buffer, + size_t count, loff_t *loff) +{ + /* Workaround to toggle debugging */ + if(count > 2) { + if(buffer[0] == 'd') { + _dbg_enable = buffer[1] - '0'; + GDBG("Debugging Enabled"); + } + } + return count; +} + +static int _gmodule_proc_release(struct inode * inode, struct file * file) { + if(_gmodule->close) { + _gmodule->close(); + } + + return single_release(inode, file); +} + +struct file_operations _gmodule_proc_fops = { + owner: THIS_MODULE, + open: _gmodule_proc_open, + read: seq_read, + llseek: seq_lseek, + write: _gmodule_proc_write, + release: _gmodule_proc_release, +}; +#else +int +gmodule_vpprintf(char** page_ptr, const char* fmt, va_list args) +{ + *page_ptr += vsprintf(*page_ptr, fmt, args); + return 0; +} + +int +gmodule_pprintf(char** page_ptr, const char* fmt, ...) +{ + int rv; + + va_list args; + va_start(args, fmt); + rv = gmodule_vpprintf(page_ptr, fmt, args); + va_end(args); + return rv; +} + +static char* _proc_buf = NULL; + +int +pprintf(const char* fmt, ...) +{ + int rv; + + va_list args; + va_start(args, fmt); + rv = gmodule_vpprintf(&_proc_buf, fmt, args); + va_end(args); + return rv; +} + +#define PSTART(b) _proc_buf = b +#define PPRINT proc_print +#define PEND(b) (_proc_buf-b) + +static int +_gmodule_pprint(char* buf) +{ + PSTART(buf); + _gmodule->pprint(); + return PEND(buf); +} + +static int +_gmodule_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + *eof = 1; + return _gmodule_pprint(page); +} + +static int +_gmodule_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + /* Workaround to toggle debugging */ + if(count > 2) { + if(buffer[0] == 'd') { + _dbg_enable = buffer[1] - '0'; + GDBG("Debugging Enabled"); + } + } + return count; +} +#endif + +static int +_gmodule_create_proc(void) +{ + struct proc_dir_entry* ent; +#if PROC_INTERFACE_KERN_VER_3_10 + if((ent = proc_create(_gmodule->name, + S_IRUGO | S_IWUGO, + NULL, + &_gmodule_proc_fops)) != NULL) { + return 0; + } +#else + if((ent = create_proc_entry(_gmodule->name, S_IRUGO | S_IWUGO, NULL)) != NULL) { + ent->read_proc = _gmodule_read_proc; + ent->write_proc = _gmodule_write_proc; + return 0; + } +#endif + return -1; +} + +static void +_gmodule_remove_proc(void) +{ + remove_proc_entry(_gmodule->name, NULL); +} + +static int +_gmodule_open(struct inode *inode, struct file *filp) +{ + if(_gmodule->open) { + _gmodule->open(); + } + return 0; +} + +static int +_gmodule_release(struct inode *inode, struct file *filp) +{ + if(_gmodule->close) { + _gmodule->close(); + } + return 0; +} + +#ifdef HAVE_UNLOCKED_IOCTL +static long +_gmodule_unlocked_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + if(_gmodule->ioctl) { + return _gmodule->ioctl(cmd, arg); + } else { + return -1; + } +} +#else +static int +_gmodule_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + if(_gmodule->ioctl) { + return _gmodule->ioctl(cmd, arg); + } else { + return -1; + } +} +#endif + +#ifdef HAVE_COMPAT_IOCTL +static long +_gmodule_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + if(_gmodule->ioctl) { + return _gmodule->ioctl(cmd, arg); + } else { + return -1; + } +} +#endif + + +static int +_gmodule_mmap(struct file *filp, struct vm_area_struct *vma) +{ + if (_gmodule->mmap) { + return _gmodule->mmap(filp, vma); + } +#ifdef BCM_PLX9656_LOCAL_BUS + vma->vm_flags |= VM_RESERVED | VM_IO; + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED; + + if (io_remap_pfn_range( vma, + vma->vm_start, + vma->vm_pgoff, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) { + return (-EAGAIN); + } + return (0); +#else/* BCM_PLX9656_LOCAL_BUS */ + return -EPERM; +#endif/* BCM_PLX9656_LOCAL_BUS */ +} + +/* FILE OPERATIONS */ + +struct file_operations _gmodule_fops = { +#ifdef HAVE_UNLOCKED_IOCTL + unlocked_ioctl: _gmodule_unlocked_ioctl, +#else + ioctl: _gmodule_ioctl, +#endif + open: _gmodule_open, + release: _gmodule_release, + mmap: _gmodule_mmap, +#ifdef HAVE_COMPAT_IOCTL + compat_ioctl: _gmodule_compat_ioctl, +#endif +}; + + +void __exit +cleanup_module(void) +{ + if(!_gmodule) return; + + /* Specific Cleanup */ + if(_gmodule->cleanup) { + _gmodule->cleanup(); + } + + /* Remove any proc entries */ + if(_gmodule->pprint) { + _gmodule_remove_proc(); + } + + /* Finally, remove ourselves from the universe */ +#ifdef GMODULE_CONFIG_DEVFS_FS + if(devfs_handle) devfs_unregister(devfs_handle); +#else + unregister_chrdev(_gmodule->major, _gmodule->name); +#endif +} + +int __init +init_module(void) +{ + int rc; + + /* Get our definition */ + _gmodule = gmodule_get(); + if(!_gmodule) return -ENODEV; + + + /* Register ourselves */ +#ifdef GMODULE_CONFIG_DEVFS_FS + devfs_handle = devfs_register(NULL, + _gmodule->name, + DEVFS_FL_NONE, + _gmodule->major, + _gmodule->minor, + S_IFCHR | S_IRUGO | S_IWUGO, + &_gmodule_fops, + NULL); + if(!devfs_handle) { + printk(KERN_WARNING "%s: can't register device with devfs", + _gmodule->name); + } + rc = 0; +#else + rc = register_chrdev(_gmodule->major, + _gmodule->name, + &_gmodule_fops); + if (rc < 0) { + printk(KERN_WARNING "%s: can't get major %d", + _gmodule->name, _gmodule->major); + return rc; + } + + if(_gmodule->major == 0) { + _gmodule->major = rc; + } +#endif + + /* Specific module Initialization */ + if(_gmodule->init) { + int rc; + if((rc = _gmodule->init()) < 0) { +#ifdef GMODULE_CONFIG_DEVFS_FS + if(devfs_handle) devfs_unregister(devfs_handle); +#else + unregister_chrdev(_gmodule->major, _gmodule->name); +#endif + return rc; + } + } + + /* Add a /proc entry, if valid */ + if(_gmodule->pprint) { + _gmodule_create_proc(); + } + + return 0; /* succeed */ +} diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/ksal.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/ksal.c new file mode 100644 index 0000000000..1ed0416f02 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/ksal.c @@ -0,0 +1,250 @@ +/* + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to + * you under the terms of the GNU General Public License version 2 (the + * "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + * with the following added to such license: + * + * As a special exception, the copyright holders of this software give + * you permission to link this software with independent modules, and to + * copy and distribute the resulting executable under terms of your + * choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from this + * software. The special exception does not apply to any modifications + * of the software. + */ +/* + * $Id: ksal.c,v 1.1 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ + +#include +#include + +#include "lkm.h" +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +#include +#else +#include +#endif +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) +#include +#endif +#include + +#ifdef MAX_USER_RT_PRIO +/* Assume 2.6 scheduler */ +#define SAL_YIELD(task) \ + yield() +#else +/* Assume 2.4 scheduler */ +#define SAL_YIELD(task) \ +do { \ + task->policy |= SCHED_YIELD; \ + schedule(); \ +} while (0) +#endif + +#define SECOND_USEC (1000000) +#define USECS_PER_JIFFY (SECOND_USEC / HZ) +#define USEC_TO_JIFFIES(usec) ((usec + (USECS_PER_JIFFY - 1)) / USECS_PER_JIFFY) + +#define sal_alloc(size, desc) kmalloc(size, GFP_KERNEL) +#define sal_free(ptr) kfree(ptr) + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12) +#define WQ_SLEEP(a, b) wait_event_interruptible_timeout(a, NULL, b) +#else +#define WQ_SLEEP(a, b) interruptible_sleep_on_timeout(&(a), b) +#endif +/* + * sem_ctrl_t + * + * The semaphore control type uses the binary property to implement + * timed semaphores with improved performance using wait queues. + */ + +typedef struct sem_ctrl_s { + struct semaphore sem; + int binary; + int cnt; + wait_queue_head_t wq; +} sem_ctrl_t; + +sal_sem_t +sal_sem_create(char *desc, int binary, int initial_count) +{ + sem_ctrl_t *s; + + if ((s = sal_alloc(sizeof(*s), desc)) != 0) { + sema_init(&s->sem, initial_count); + s->binary = binary; + if (s->binary) { + init_waitqueue_head(&s->wq); + } + } + + return (sal_sem_t) s; +} + +void +sal_sem_destroy(sal_sem_t b) +{ + sem_ctrl_t *s = (sem_ctrl_t *) b; + + if (s == NULL) { + return; + } + + /* + * the linux kernel does not have a sema_destroy(s) + */ + sal_free(s); +} + +int +sal_sem_take(sal_sem_t b, int usec) +{ + sem_ctrl_t *s = (sem_ctrl_t *) b; + int err; + + if (usec == sal_sem_FOREVER && !in_interrupt()) { + err = down_interruptible(&s->sem); + } else { + int time_wait = 1; + int cnt = s->cnt; + + for (;;) { + if (down_trylock(&s->sem) == 0) { + err = 0; + break; + } + + if (s->binary) { + + /* Wait for event or timeout */ + + if (time_wait > 1) { + err = 1; + break; + } + err = wait_event_interruptible_timeout(s->wq, cnt != s->cnt, + USEC_TO_JIFFIES(usec)); + if (err < 0) { + break; + } + time_wait++; + + } else { + + /* Retry algorithm with exponential backoff */ + + if (time_wait > usec) { + time_wait = usec; + } + + sal_usleep(time_wait); + + usec -= time_wait; + + if (usec == 0) { + err = ETIMEDOUT; + break; + } + + if ((time_wait *= 2) > 100000) { + time_wait = 100000; + } + } + } + } + return err ? -1 : 0; +} + +int +sal_sem_give(sal_sem_t b) +{ + sem_ctrl_t *s = (sem_ctrl_t *) b; + + up(&s->sem); + if (s->binary) { + s->cnt++; + wake_up_interruptible(&s->wq); + } + return 0; +} + +uint32 +sal_time_usecs(void) +{ + struct timeval ltv; + do_gettimeofday(<v); + return (ltv.tv_sec * SECOND_USEC + ltv.tv_usec); +} + +void +sal_usleep(uint32 usec) +{ + uint32 start_usec; + wait_queue_head_t queue; + + if (usec <= SECOND_USEC / HZ) { + start_usec = sal_time_usecs(); + do { + SAL_YIELD(current); + } while ((sal_time_usecs() - start_usec) < usec); + } else { + init_waitqueue_head(&queue); + WQ_SLEEP(queue, USEC_TO_JIFFIES(usec)); + } +} + +void +sal_udelay(uint32 usec) +{ + static volatile int _sal_udelay_counter; + static int loops = 0; + int ix, iy; + + if (loops == 0 || usec == 0) { /* Need calibration? */ + int max_loops; + int start = 0, stop = 0; + int mpt = USECS_PER_JIFFY; /* usec/tick */ + + for (loops = 1; loops < 0x1000 && stop == start; loops <<= 1) { + /* Wait for clock turn over */ + for (stop = start = jiffies; start == stop; start = jiffies) { + /* Empty */ + } + sal_udelay(mpt); /* Single recursion */ + stop = jiffies; + } + + max_loops = loops / 2; /* Loop above overshoots */ + + start = stop = 0; + + if (loops < 4) { + loops = 4; + } + + for (loops /= 4; loops < max_loops && stop == start; loops++) { + /* Wait for clock turn over */ + for (stop = start = jiffies; start == stop; start = jiffies) { + /* Empty */ + } + sal_udelay(mpt); /* Single recursion */ + stop = jiffies; + } + } + + for (iy = 0; iy < usec; iy++) { + for (ix = 0; ix < loops; ix++) { + _sal_udelay_counter++; /* Prevent optimizations */ + } + } +} diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/common/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/common/Makefile new file mode 100644 index 0000000000..f78ed606aa --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/user/common/Makefile @@ -0,0 +1,242 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# -*- Makefile -*- +# $Id: Makefile,v 1.4 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ +# + +SDK :=$(shell if [ -n "$$SDK" ] ; then\ + echo $$SDK;\ + else\ + cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \ + dir=`cd ../;pwd`; \ + if [ "$$dir" = "/" ] ; then \ + echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \ + exit 1; \ + fi ; \ + cd $$dir; \ + done ; \ + pwd; \ + fi) + +ifeq ($(SDK),) +$(error Please run this in a tree) +endif + +export SDK + +override-target=linux-$(platform) + +ifeq ($(LINUX_MAKE_SHARED_LIB),1) +libext = so.$(SHAREDLIBVER) +else +libext = a +endif + +ifeq (,$(platform)) +$(error Internal error: platform variable is not set) +endif + +include $(SDK)/make/Make.config +LOCALDIR=systems/linux/user/common +include $(SDK)/make/Make.depend +kernel-override=linux-$(platform) +ifdef BLDCONFIG +KERN_BLDROOT=${SDK}/${SDKBUILD}/${BLDCONFIG}/$(kernel-override)$(bldroot_suffix) +else +KERN_BLDROOT=${SDK}/${SDKBUILD}/$(kernel-override)$(bldroot_suffix) +endif + +ifeq (,$(kernel_version)) +kernel_version=2_4 +endif + +ifeq ($(kernel_version),2_6) +KOBJ=ko +else +KOBJ=o +endif + +ifneq (,$(TOOLS_DIR)) +override PATH := $(TOOLS_DIR):$(PATH) +endif + +ifeq ($(DEST_DIR),) +DEST_DIR=${BLDDIR} +endif + +KERNEL_BDE_LOCAL :=linux-kernel-bde.$(KOBJ) +KERNEL_BDE :=$(DEST_DIR)/$(KERNEL_BDE_LOCAL) + +USER_BDE_LOCAL :=linux-user-bde.$(KOBJ) +USER_BDE=$(DEST_DIR)/$(USER_BDE_LOCAL) + +BCM_KNET_LOCAL :=linux-bcm-knet.$(KOBJ) +BCM_KNET=$(DEST_DIR)/$(BCM_KNET_LOCAL) + +KNET_CB_LOCAL := linux-knet-cb.$(KOBJ) +KNET_CB := $(DEST_DIR)/$(KNET_CB_LOCAL) + +ifeq (,$(findstring DELIVER,$(MAKECMDGOALS))) +.DEFAULT_GOAL := all +all_targets := kernel_modules $(KERNEL_BDE) $(USER_BDE) + +LOCAL_TARGETS := + +ifeq ($(NO_LOCAL_TARGETS),) +LOCAL_TARGETS +=$(patsubst %,$(realpath ..)/$(platform)/%,$(KERNEL_BDE_LOCAL) $(USER_BDE_LOCAL)) + +all_targets +=$(LOCAL_TARGETS) +endif + +# Build all by default +ifndef BUILD_KNET +BUILD_KNET = 1 +endif + +ifeq ($(BUILD_KNET),1) +# Kernel network support +all_targets += $(BCM_KNET) + +ifeq ($(NO_LOCAL_TARGETS),) +LOCAL_TARGETS +=$(patsubst %,../$(platform)/%,$(BCM_KNET_LOCAL)) +all_targets +=$(LOCAL_TARGETS) +endif + +ADD_TO_CFLAGS += -I$(SDK)/systems/linux/kernel/modules/include +COND_KNET_LIBS = libuser.$(libext) + +ifeq ($(BUILD_KNET_CB),1) +# KNET callback module support +all_targets += $(KNET_CB) + +ifeq ($(NO_LOCAL_TARGETS),) +LOCAL_TARGETS +=$(patsubst %,../$(platform)/%,$(KNET_CB_LOCAL)) +all_targets +=$(LOCAL_TARGETS) +endif +endif + +endif + +#OPENNSL_FIXUP +.NOTPARALLEL: + +all: $(BLDDIR)/.tree $(all_targets) + +ifeq ($(NO_LOCAL_TARGETS),) +define LOCAL_TARGET_DEF +$(1) : $(DEST_DIR)/$(notdir $(1)) + cp $$? $$@ +endef +endif + +# User BDE libraries +ADD_TO_CFLAGS += -I$(SDK)/systems/bde/linux/include + +# Use raw IOCTL for KNET +ADD_TO_CFLAGS += -DPROXY_SUPPORT=0 + +CFLAGS += $(ADD_TO_CFLAGS) + +# Kernel network support +ifdef BUILD_KNET + +knet_subdirs = shared bcm-knet + +ifdef BUILD_KNET_CB +knet_subdirs += knet-cb +endif + +endif # BUILD_KNET + +kernel_modules: + $(MAKE) -C $(SDK)/systems/bde/linux/kernel kernel_version=$(kernel_version) + $(MAKE) -C $(SDK)/systems/bde/linux/user/kernel kernel_version=$(kernel_version) +ifeq ($(BUILD_KNET),1) + $(MAKE) -j1 -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \ + subdirs="$(knet_subdirs)" override-target=linux-$(platform) CFLAGS="$(CFLAGS)" +endif + +$(KERNEL_BDE): $(KERN_BLDROOT)/linux-kernel-bde.$(KOBJ) + mkdir -p $(@D) + $(OBJCOPY) --strip-debug $< $@ + +$(USER_BDE): $(KERN_BLDROOT)/linux-user-bde.$(KOBJ) + $(OBJCOPY) --strip-debug $< $@ + +$(BCM_KNET): $(KERN_BLDROOT)/linux-bcm-knet.$(KOBJ) + $(OBJCOPY) --strip-debug $< $@ + +$(KNET_CB): $(KERN_BLDROOT)/linux-knet-cb.$(KOBJ) + $(OBJCOPY) --strip-debug $< $@ + +ifeq ($(NO_LOCAL_TARGETS),) +$(foreach targ,$(LOCAL_TARGETS),$(eval $(call LOCAL_TARGET_DEF,$(targ)))) +endif + +clean:: + $(MAKE) -C $(SDK)/systems/bde/linux/kernel $@ + $(MAKE) -C $(SDK)/systems/bde/linux/user/kernel $@ + $(MAKE) -C $(SDK)/systems/linux/kernel/modules \ + subdirs="$(knet_subdirs)" \ + override-target=linux-$(platform) $@ + $(RM) $(KERNEL_BDE) $(USER_BDE) + $(RM) $(BCM_KNET) + $(RM) $(KNET_CB) + $(RM) $(KERN_BLDROOT)/linux-kernel-bde.$(KOBJ) + $(RM) $(KERN_BLDROOT)/linux-user-bde.$(KOBJ) + $(RM) $(KERN_BLDROOT)/linux-bcm-knet.$(KOBJ) + $(RM) $(LOCAL_TARGETS) + +distclean:: clean + +.PHONY: variable + +# +# Echo variable values used for configuration +# usage: make VAR=CC variable +# +variable:: + @echo $($(VAR)) + +else +ifndef DELIVERY +$(error DELIVERY required) +endif + +DELIVERABLES := $(KERNEL_BDE) $(USER_BDE) +# 1= source +define DELIVERY_RULE +_DEL_TARG += $(DELIVERY)/$(notdir $(1)) +$(DELIVERY)/$(notdir $(1)) : $(1) + @mkdir -p $(DELIVERY) +ifeq ($(filter $(notdir $(BCM)) $(notdir $(BCM).dbg),$(notdir $1)),) + $(OBJCOPY) --strip-debug $$< $$@ +else + $(CP) -p $$< $$@ +endif +endef + +$(foreach f,$(DELIVERABLES),$(eval $(call DELIVERY_RULE,$(f)))) + +DELIVER: $(_DEL_TARG) +endif + +# Make.config defines remaining phony targets +.PHONY: build kernel_modules DELIVER + diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/gto-2_6/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/gto-2_6/Makefile new file mode 100644 index 0000000000..08f37e51c6 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/user/gto-2_6/Makefile @@ -0,0 +1,85 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# -*- Makefile -*- +# $Id: Makefile,v 1.9 Broadcom SDK $ +# $Copyright: (c) 2007 Broadcom Corp. +# All Rights Reserved.$ + +# +# This make job requires the following environment variables to be set: +# +# SDK - path to StrataXGS SDK root directory +# +# Optionally the following environment variables can be set to +# override the default build server configuration: +# +# PPC_TOOLS_DIR - path to build tools (if not in PATH already) +# PPC_CROSS_COMPILE - cross compile tools prefix +# LINUX_INCLUDE - path to Linux kernel include directory +# + +SDK :=$(shell if [ -n "$$SDK" ] ; then\ + echo $$SDK;\ + else\ + cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \ + dir=`cd ../;pwd`; \ + if [ "$$dir" = "/" ] ; then \ + echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \ + exit 1; \ + fi ; \ + cd $$dir; \ + done ; \ + pwd; \ + fi) + +ifeq ($(SDK),) +$(error Please run this in a tree) +endif + +export SDK + +override kernel_version=2_6 +platform=gto-$(kernel_version) +LINUX_MAKE_USER=1 +export LINKER_RELAX=1 + +# Select the build environment +#BUILD_PLATFORM=ELDK +#BUILD_PLATFORM=WR_LINUX + +#Select the LINUX KERNEL VERSION +#KERN_VER = 2.6.21.7 +#KERN_VER = 2.6.24.4 +#KERN_VER = 2.6.25 + + +# Select the ELDK version +#ELDK_VERSION=4.1 +#ELDK_VERSION=4.0 + +#Select WRS Linux version +#WRS_LINUX_VERSION=2.0 +#WRS_LINUX_VERSION=3.0 + + +export KERN_VER +export ELDK_VERSION +export BUILD_PLATFORM +export WRS_LINUX_VERSION + +include ${SDK}/make/Make.linux + diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/gto/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/gto/Makefile new file mode 100644 index 0000000000..8e3422cd18 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/user/gto/Makefile @@ -0,0 +1,61 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# -*- Makefile -*- +# $Id: Makefile,v 1.9 Broadcom SDK $ +# $Copyright: (c) 2015 Broadcom Corp. +# All Rights Reserved.$ + +# +# This make job requires the following environment variables to be set: +# +# SDK - path to StrataXGS SDK root directory +# +# Optionally the following environment variables can be set to +# override the default build server configuration: +# +# PPC_TOOLS_DIR - path to build tools (if not in PATH already) +# PPC_CROSS_COMPILE - cross compile tools prefix +# LINUX_INCLUDE - path to Linux kernel include directory +# + +SDK :=$(shell if [ -n "$$SDK" ] ; then\ + echo $$SDK;\ + else\ + cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \ + dir=`cd ../;pwd`; \ + if [ "$$dir" = "/" ] ; then \ + echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \ + exit 1; \ + fi ; \ + cd $$dir; \ + done ; \ + pwd; \ + fi) + +ifeq ($(SDK),) +$(error Please run this in a tree) +endif + +export SDK + +override kernel_version=4_4 +platform=gto +LINUX_MAKE_USER=1 +export LINKER_RELAX=1 + +include ${SDK}/make/Make.linux + diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/iproc-3_14/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/iproc-3_14/Makefile new file mode 100644 index 0000000000..c2081e42dc --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/user/iproc-3_14/Makefile @@ -0,0 +1,66 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# -*- Makefile -*- +# $Id: Makefile,v 1.7 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ + +# +# This make job requires the following environment variables to be set: +# +# SDK - path to StrataXGS SDK root directory +# +# Optionally the following environment variables can be set to +# override the default build server configuration: +# +# MIPS_TOOLS_DIR - path to build tools (if not in PATH already) +# MIPS_CROSS_COMPILE - cross compile tools prefix +# LINUX_INCLUDE - path to Linux kernel include directory +# + +SDK :=$(shell if [ -n "$$SDK" ] ; then\ + echo $$SDK;\ + else\ + cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \ + dir=`cd ../;pwd`; \ + if [ "$$dir" = "/" ] ; then \ + echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \ + exit 1; \ + fi ; \ + cd $$dir; \ + done ; \ + pwd; \ + fi) + +ifeq ($(SDK),) +$(error Please run this in a tree) +endif + +export SDK + +override kernel_version=3_14 +platform=iproc-$(kernel_version) + +IPROC_BUILD=1 +export IPROC_BUILD +export BUILD_PLATFORM +export ARM_LINUX_VERSION + +LINUX_MAKE_USER=1 +export ADD_TO_CFLAGS + +include ${SDK}/make/Make.linux diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/iproc/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/iproc/Makefile new file mode 100644 index 0000000000..7eef55d448 --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/user/iproc/Makefile @@ -0,0 +1,60 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# -*- Makefile -*- +# $Id: Makefile,v 1.7 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ + +# +# This make job requires the following environment variables to be set: +# +# SDK - path to StrataXGS SDK root directory +# + +SDK :=$(shell if [ -n "$$SDK" ] ; then\ + echo $$SDK;\ + else\ + cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \ + dir=`cd ../;pwd`; \ + if [ "$$dir" = "/" ] ; then \ + echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \ + exit 1; \ + fi ; \ + cd $$dir; \ + done ; \ + pwd; \ + fi) + +ifeq ($(SDK),) +$(error Please run this in a tree) +endif + +export SDK + +override kernel_version=4_4 +platform=iproc + +IPROC_BUILD=1 +export IPROC_BUILD +export BUILD_PLATFORM +export ARM_LINUX_VERSION + +LINUX_MAKE_USER=1 +export ADD_TO_CFLAGS +export BR_NO_CCACHE + +include ${SDK}/make/Make.linux diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile new file mode 100644 index 0000000000..bb5408536a --- /dev/null +++ b/platform/broadcom/saibcm-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile @@ -0,0 +1,46 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# -*- Makefile -*- +# $Id: Makefile,v 1.2 Broadcom SDK $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ + +SDK :=$(shell if [ -n "$$SDK" ] ; then\ + echo $$SDK;\ + else\ + cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \ + dir=`cd ../;pwd`; \ + if [ "$$dir" = "/" ] ; then \ + echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \ + exit 1; \ + fi ; \ + cd $$dir; \ + done ; \ + pwd; \ + fi) + +ifeq ($(SDK),) +$(error Please run this in a tree) +endif + +export SDK + +override kernel_version=2_6 +platform=x86-smp_generic_64-$(kernel_version) + +LINUX_MAKE_USER=1 +include ${SDK}/make/Make.linux diff --git a/platform/broadcom/saibcm-modules/tools/mktool.pl b/platform/broadcom/saibcm-modules/tools/mktool.pl new file mode 100644 index 0000000000..96bff14ecd --- /dev/null +++ b/platform/broadcom/saibcm-modules/tools/mktool.pl @@ -0,0 +1,293 @@ +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to +# you under the terms of the GNU General Public License version 2 (the +# "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, +# with the following added to such license: +# +# As a special exception, the copyright holders of this software give +# you permission to link this software with independent modules, and to +# copy and distribute the resulting executable under terms of your +# choice, provided that you also meet, for each linked independent +# module, the terms and conditions of the license of that module. An +# independent module is a module which is not derived from this +# software. The special exception does not apply to any modifications +# of the software. +# +# +# mktool.pl +# +# $Id: mktool.pl,v 1.5 Broadcom SDK $ +# +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved. $ + +use File::Path; +use File::Find; +use File::Copy; +use Cwd; + +($prog = $0) =~ s/.*\///; + +SWITCH: +{ + $op = shift; + + if ($op eq "-rm") { mktool_rm(@ARGV); last SWITCH; } + if ($op eq "-cp") { mktool_cp(@ARGV); last SWITCH; } + if ($op eq "-md") { mktool_md(@ARGV); last SWITCH; } + if ($op eq "-ln") { mktool_ln(@ARGV); last SWITCH; } + if ($op eq "-foreach") { mktool_foreach(@ARGV); last SWITCH; } + if ($op eq "-dep") { mktool_makedep(@ARGV); last SWITCH; } + if ($op eq "-echo") { mktool_echo(@ARGV); last SWITCH; } + if ($op eq "-beep") { mktool_beep(@ARGV); last SWITCH; } + die("$prog: unknown option '$op'\n"); +} + +exit 0; + + + + +# +# mktool_execute +# +# Executes a command, returns exist status. +# Performs token special translation before execution. +# + +sub mktool_execute +{ + my $token = shift; + my @cmds = @_; + +# printf("mktool_execute: token = '$token'\n"); + foreach $cmd (@cmds) + { + #printf("mktool_execute: cmd = '$cmd'\n"); + $cmd =~ s/\#\#/$token/g; + if($cmd =~ /^-p/) + { + $cmd =~ s/^-p//; + printf("$cmd\n"); + } + else + { + system($cmd); + my $excode = ($? >> 8); + exit $excode if $excode; + } + } +} + + +$find_regexp = ""; +@find_cmd; + +# +# mktool_foreach +# +sub mktool_foreach +{ + if($_[0] eq "-find") + { + shift; + $find_dir = shift; + $find_regexp = shift; + @find_cmds = @_; + + if(!($find_dir =~ /^\//)) + { + $find_dir = cwd() . "/" . $find_dir; + } + find(\&_mktool_foreach_find_wanted, $find_dir); + } + else + { + my $subdir = 0; + if($_[0] eq "-subdir") + { + $subdir = 1; + shift; + } + + my @thingies = split(' ', shift); + + foreach $thingy (@thingies) + { + chdir $thingy unless $subdir == 0; + mktool_execute($thingy, @_); + chdir ".." unless $subdir == 0; + } + } +} + + + +sub _mktool_foreach_find_wanted +{ + my $expr = "\$File::Find::name =~ /\^$find_regexp\$/"; + + if(eval($expr)) + { + mktool_execute($File::Find::name, @find_cmds); + exit $excode if $excode; + } +} + + +# +# rm +# +# Removes a list of objects +# +sub mktool_rm +{ + my($f); + + foreach $f (@_) { + eval { rmtree($f) }; + if ($@) { + die "$prog $op: failed to remove $f: $@\n"; + } + } +} + +# +# md +# +# Makes a list of directories +# +sub mktool_md +{ + my($dir); + + foreach $dir (@_) { + $dir =~ s!/+$!!; + eval { mkpath($dir) }; + if ($@) { + die "$prog $op: failed to make directory $dir: $@\n"; + } + } +} + + +sub mktool_cp +{ + my($from, $to) = @_; + + if (@_ != 2) { + die "$prog $op: must have two arguments\n"; + } + copy($from, $to) || + die "$prog $op: failed to copy $from to $to: $!\n"; +} + +sub mktool_ln +{ + my($old, $new) = @_; + + if (@_ != 2) { + die "$prog $op: must have two arguments\n"; + } + link ($old, $new) || + die "$prog $op: failed to link $new to $old: $!\n"; +} + + +# @echo "$@ \\" > ${BLDDIR}/$(notdir $@) +# @if ($(DEPEND)) >> $(BLDDIR)/$(notdir $@); then \ +# exit 0; \ +# else \ +# rm -f ${BLDDIR}/$(notdir $@); \ +# exit 1; \ +# fi + +# $(MAKEDEP) "$@" "$(BLDDIR)/$(notdir $@)" "$(DEPEND)" + +sub mktool_makedep +{ + my ($source, $target, $cmd, $curdir) = @_; + my @result = `$cmd`; + my $sdk = $ENV{'SDK'}; + my $count; + my $tmp; + local $resultant; + +## Comman $cmd +#Command $cmd +print <-1) & ($count < 20) ) + { + $line=~s/\/\w+\/\.\.//; + # if we hit a major recursion, revert the line, report + # this to the output and drop out of the loop, but do + # continue, this should not halt generation + if($count++>19) + { + print "mktool.pl: could not process $line \n\n"; + print ":: curdir $curdir\n"; + print ":: target $target\n"; + print ":: cmd $cmd\n"; + $line=$tmp; + } + } + + # set all the paths to use the $SDK variable + $line =~ s/$ENV{'SDK'}/\$\{SDK\}/g; + $resultant=$resultant . $line; + } + + # some compilers return extra newlines + $resultant=~s/\n//g; + + # now clean up the result + $resultant=~s/\\/\\\n/g; + + mktool_md($dirName) unless (-d $dirName); + open (TARGET, ">$target") || + die("$prog $op: cannot open '$target' for writing: $!\n"); + print TARGET "$resultant\n"; + close(TARGET); + } +} + +sub mktool_echo +{ + print "@_\n"; +} + +sub mktool_beep +{ + -t STDOUT && defined $ENV{MAKEBEEP} && print "\007"; +} diff --git a/platform/broadcom/sdk.mk b/platform/broadcom/sdk.mk deleted file mode 100644 index a74db331ab..0000000000 --- a/platform/broadcom/sdk.mk +++ /dev/null @@ -1,4 +0,0 @@ -BRCM_OPENNSL_KERNEL = opennsl-modules-4.9.0-5-amd64_3.4.1.11-1_amd64.deb -$(BRCM_OPENNSL_KERNEL)_URL = "https://sonicstorage.blob.core.windows.net/packages/opennsl-modules-4.9.0-5-amd64_3.4.1.11-1_amd64.deb?sv=2015-04-05&sr=b&sig=vdIqSXaJhvN7Blk08WyxWhfMxky0XBx37JYAmNozx3k%3D&se=2155-01-24T09%3A08%3A25Z&sp=r" - -SONIC_ONLINE_DEBS += $(BRCM_OPENNSL_KERNEL)