openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

commit a7e3aa032f0737b9ef4f408396a9e0c0f0e6c088
parent 158d1dd768be6a6d2a428b1e7c9d31c000d62b1b
Author: Broadcom SDK Release <sdk.releases@broadcom.com>
Date:   Wed, 12 Aug 2020 13:59:09 -0700

Added GPL modules

Diffstat:
Asdk-6.5.16/src/gpl-modules/RELEASE | 0
Asdk-6.5.16/src/gpl-modules/include/ibde.h | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/include/kcom.h | 567+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/include/sal/core/sync.h | 38++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/include/sal/core/thread.h | 30++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/include/sal/types.h | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/include/sdk_config.h | 45+++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/include/soc/cmic.h | 37+++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/include/soc/devids.h | 1826+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Make.config | 358+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Make.depend | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Make.kernlib | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Make.lib | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Make.linux | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Make.subdirs | 44++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Make.tools | 38++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Makefile.linux-iproc | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Makefile.linux-iproc-3_14 | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel-2_6 | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel-3_6 | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel-4_4 | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Makefile.linux-kmodule | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Makefile.linux-x86-common-2_6 | 44++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Makefile.linux-x86-generic-common-2_6 | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/make/Makefile.linux-x86-smp_generic_64-2_6 | 37+++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/linux/include/linux-bde.h | 278+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/linux/include/linux_dma.h | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/linux/include/mpool.h | 36++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/Makefile | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux-kernel-bde.c | 4361+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux_dma.c | 1007+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.c | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.h | 33+++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/linux/shared/mpool.c | 355+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/linux/user/kernel/Makefile | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.c | 1456+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.h | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde.h | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde_iproc.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde_mdio.h | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde_pci.h | 46++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/shared/shbde_iproc.c | 494+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/shared/shbde_mdio.c | 186+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/bde/shared/shbde_pci.c | 392+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/Makefile | 31+++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/Makefile | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c | 8947+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/include/bcm-knet.h | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/include/gmodule.h | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/include/lkm.h | 182+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/knet-cb/Makefile | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/shared/Makefile | 29+++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/shared/gmodule.c | 427+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/shared/ksal.c | 249+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/linux/user/common/Makefile | 229+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/linux/user/iproc-3_14/Makefile | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/linux/user/iproc/Makefile | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile | 45+++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.16/src/gpl-modules/tools/mktool.pl | 292+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/RELEASE | 0
Asdk-6.5.20/src/gpl-modules/include/ibde.h | 178+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/include/kcom.h | 598+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/include/sal/core/sync.h | 38++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/include/sal/core/thread.h | 30++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/include/sal/types.h | 164+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/include/sdk_config.h | 45+++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/include/soc/devids.h | 1988+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Make.config | 358+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Make.depend | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Make.kernlib | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Make.lib | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Make.linux | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Make.subdirs | 44++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Make.tools | 38++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Makefile.linux-gts | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc | 104+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc-3_14 | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc-4_4 | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc_64 | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel-2_6 | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel-3_6 | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel-4_4 | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Makefile.linux-kmodule | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Makefile.linux-slk | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Makefile.linux-x86-common-2_6 | 44++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Makefile.linux-x86-generic-common-2_6 | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Makefile.linux-x86-smp_generic_64-2_6 | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/make/Makefile.linux-xlr | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/linux/include/linux-bde.h | 271+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/linux/include/linux_dma.h | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/linux/include/mpool.h | 36++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/Makefile | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux-kernel-bde.c | 4530+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux_dma.c | 1026+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.c | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.h | 33+++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/linux/shared/mpool.c | 355+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/linux/user/kernel/Makefile | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.c | 1661+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.h | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde.h | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde_iproc.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde_mdio.h | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde_pci.h | 46++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/shared/shbde_iproc.c | 503+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/shared/shbde_mdio.c | 186+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/bde/shared/shbde_pci.c | 392+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/Makefile | 31+++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/Makefile | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c | 9034+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/include/bcm-knet.h | 141+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/include/gmodule.h | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/include/lkm.h | 188+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/knet-cb/Makefile | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/shared/Makefile | 29+++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/shared/gmodule.c | 427+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/shared/ksal.c | 249+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/user/common/Makefile | 229+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/user/gts/Makefile | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/user/iproc-3_14/Makefile | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/user/iproc-4_4/Makefile | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/user/iproc/Makefile | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/user/iproc_64/Makefile | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/user/slk/Makefile | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile | 45+++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/systems/linux/user/xlr/Makefile | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asdk-6.5.20/src/gpl-modules/tools/mktool.pl | 292+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
131 files changed, 51539 insertions(+), 0 deletions(-)

diff --git a/sdk-6.5.16/src/gpl-modules/RELEASE b/sdk-6.5.16/src/gpl-modules/RELEASE diff --git a/sdk-6.5.16/src/gpl-modules/include/ibde.h b/sdk-6.5.16/src/gpl-modules/include/ibde.h @@ -0,0 +1,172 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: ibde.h,v 1.27 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ + +#ifndef __IBDE_H__ +#define __IBDE_H__ + +#include <sal/types.h> + +/* + * 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_8MB_REG_SPACE 0x10000000 /* 8MB sized CMIC BAR */ +#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); + + /* + * I2C operations on the Device, assuming it is connected by I2C to the CPU. + */ + /* Read from the internal device Address space using I2C */ + int (*i2c_device_read)( + int dev, /* The device ID to access */ + uint32 addr, /* The address to access in the internal device address space */ + uint32 *value);/* the value to be read. */ + /* Write to the internal device Address space using I2C */ + int (*i2c_device_write)( + int dev, /* The device ID to access */ + uint32 addr, /* The address to access in the internal device address space */ + uint32 value); /* the value to be written. */ + +} ibde_t; + + +/* System BDE */ +extern ibde_t *bde; + + +#endif /* __IBDE_H__ */ diff --git a/sdk-6.5.16/src/gpl-modules/include/kcom.h b/sdk-6.5.16/src/gpl-modules/include/kcom.h @@ -0,0 +1,567 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <sal/types.h> + +#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_REPROBE 7 /* Reprobe device */ +#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_M_WB_CLEANUP 51 /* Clean up for warmbooting */ + +#define KCOM_VERSION 10 /* 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 + +/* + * Max size of Sand System Headers + * For DNX, Module Header(20B) + PTCH(2B) + ITMH(5B) + * For DPP, PTCH(2B) + ITMH(4B) + */ +#define KCOM_NETIF_SYSTEM_HEADERS_SIZE_MAX 27 + +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]; + uint8 system_headers[KCOM_NETIF_SYSTEM_HEADERS_SIZE_MAX]; + uint8 system_headers_size; + 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 <dest_id>. + * + * KCOM_DEST_T_API + * Packet is sent to Rx API through queue <dest_id>. + * + * 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; + /** Information to parse Dune system headers */ + uint32 ftmh_lb_key_ext_size; + uint32 ftmh_stacking_ext_size; + uint32 pph_base_size; + uint32 pph_lif_ext_size[8]; + uint8 udh_enable; + uint32 udh_length_type[4]; +} 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 { + uint64 dcb_start; + struct { + uint32 tx; + uint32 rx; + } seqno; + } data; + union { + void *p; + uint8 b[8]; + } cookie; + } 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; + uint8 cmic_type; + uint8 dcb_type; + uint8 dcb_size; + uint8 pkt_hdr_size; + uint32 dma_hi; + 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; + +/* + * Reprobe switch device. + */ +typedef struct kcom_msg_reprobe_s { + kcom_msg_hdr_t hdr; + uint32 flags; +} kcom_msg_reprobe_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; + +/* + * Clean up warmboot-related resources. + */ +typedef struct kcom_msg_wb_cleanup_s { + kcom_msg_hdr_t hdr; + uint32 flags; +} kcom_msg_wb_cleanup_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 +#define KCOM_FILTER_MAX 128 +#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_reprobe_t reprobe; + 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_wb_cleanup_t wb_cleanup; +} 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/sdk-6.5.16/src/gpl-modules/include/sal/core/sync.h b/sdk-6.5.16/src/gpl-modules/include/sal/core/sync.h @@ -0,0 +1,38 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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/sdk-6.5.16/src/gpl-modules/include/sal/core/thread.h b/sdk-6.5.16/src/gpl-modules/include/sal/core/thread.h @@ -0,0 +1,30 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <sal/types.h> + +void sal_usleep(uint32 usec); +void sal_udelay(uint32 usec); + +#endif /* !_SAL_THREAD_H */ diff --git a/sdk-6.5.16/src/gpl-modules/include/sal/types.h b/sdk-6.5.16/src/gpl-modules/include/sal/types.h @@ -0,0 +1,155 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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/sdk-6.5.16/src/gpl-modules/include/sdk_config.h b/sdk-6.5.16/src/gpl-modules/include/sdk_config.h @@ -0,0 +1,45 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <sdk_custom_config.h> +#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/sdk-6.5.16/src/gpl-modules/include/soc/cmic.h b/sdk-6.5.16/src/gpl-modules/include/soc/cmic.h @@ -0,0 +1,37 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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/sdk-6.5.16/src/gpl-modules/include/soc/devids.h b/sdk-6.5.16/src/gpl-modules/include/soc/devids.h @@ -0,0 +1,1826 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * Copyright: (c) 2019 Broadcom. + * 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 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 BCM56980_DEVICE_ID 0xb980 +#define BCM56980_A0_REV_ID 1 +#define BCM56980_B0_REV_ID 0x11 +#define BCM56981_DEVICE_ID 0xb981 +#define BCM56981_A0_REV_ID 1 +#define BCM56982_DEVICE_ID 0xb982 +#define BCM56982_A0_REV_ID 1 +#define BCM56982_B0_REV_ID 0x11 +#define BCM56983_DEVICE_ID 0xb983 +#define BCM56983_A0_REV_ID 1 +#define BCM56983_B0_REV_ID 0x11 +#define BCM56984_DEVICE_ID 0xb984 +#define BCM56984_A0_REV_ID 1 +#define BCM56984_B0_REV_ID 0x11 + +#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 BCM56561_DEVICE_ID 0xb561 +#define BCM56561_A0_REV_ID 1 +#define BCM56561_B0_REV_ID 0x11 + +#define BCM56562_DEVICE_ID 0xb562 +#define BCM56562_A0_REV_ID 1 +#define BCM56562_B0_REV_ID 0x11 + +#define BCM56670_DEVICE_ID 0xb670 +#define BCM56670_A0_REV_ID 1 +#define BCM56670_B0_REV_ID 0x11 + +#define BCM56671_DEVICE_ID 0xb671 +#define BCM56671_A0_REV_ID 1 +#define BCM56671_B0_REV_ID 0x11 + +#define BCM56672_DEVICE_ID 0xb672 +#define BCM56672_A0_REV_ID 1 +#define BCM56672_B0_REV_ID 0x11 + +#define BCM56675_DEVICE_ID 0xb675 +#define BCM56675_A0_REV_ID 1 +#define BCM56675_B0_REV_ID 0x11 + + +#define BCM56565_DEVICE_ID 0xb565 +#define BCM56565_A0_REV_ID 1 +#define BCM56565_B0_REV_ID 0x11 + +#define BCM56566_DEVICE_ID 0xb566 +#define BCM56566_A0_REV_ID 1 +#define BCM56566_B0_REV_ID 0x11 + +#define BCM56567_DEVICE_ID 0xb567 +#define BCM56567_A0_REV_ID 1 +#define BCM56567_B0_REV_ID 0x11 + +#define BCM56568_DEVICE_ID 0xb568 +#define BCM56568_A0_REV_ID 1 +#define BCM56568_B0_REV_ID 0x11 + +#define BCM56760_DEVICE_ID 0xb760 +#define BCM56760_A0_REV_ID 1 +#define BCM56760_A1_REV_ID 2 +#define BCM56760_B0_REV_ID 0x11 + +#define BCM56761_DEVICE_ID 0xb761 +#define BCM56761_A0_REV_ID 1 +#define BCM56761_B0_REV_ID 0x11 + +#define BCM56761_DEVICE_ID 0xb761 +#define BCM56761_A0_REV_ID 1 +#define BCM56761_A1_REV_ID 2 +#define BCM56761_B0_REV_ID 0x11 +#define BCM56761_B1_REV_ID 0x12 + +#define BCM56762_DEVICE_ID 0xb762 +#define BCM56762_A0_REV_ID 1 +#define BCM56762_B0_REV_ID 0x11 + +#define BCM56764_DEVICE_ID 0xb764 +#define BCM56764_A0_REV_ID 1 +#define BCM56764_B0_REV_ID 0x11 + +#define BCM56765_DEVICE_ID 0xb765 +#define BCM56765_A0_REV_ID 1 +#define BCM56765_B0_REV_ID 0x11 + +#define BCM56766_DEVICE_ID 0xb766 +#define BCM56766_A0_REV_ID 1 +#define BCM56766_B0_REV_ID 0x11 + +#define BCM56768_DEVICE_ID 0xb768 +#define BCM56768_A0_REV_ID 1 +#define BCM56768_B0_REV_ID 0x11 + +#define BCM56068_DEVICE_ID 0xb068 +#define BCM56068_A0_REV_ID 1 +#define BCM56068_B0_REV_ID 0x11 + +#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 BCM56170_DEVICE_ID 0xb170 +#define BCM56170_A0_REV_ID 1 +#define BCM56170_B0_REV_ID 0x11 +#define BCM56172_DEVICE_ID 0xb172 +#define BCM56172_A0_REV_ID 1 +#define BCM56172_B0_REV_ID 0x11 +#define BCM56174_DEVICE_ID 0xb174 +#define BCM56174_A0_REV_ID 1 +#define BCM56174_B0_REV_ID 0x11 + +#define BCM53570_DEVICE_ID 0x8570 +#define BCM53570_A0_REV_ID 1 +#define BCM53570_B0_REV_ID 0x11 +#define BCM53575_DEVICE_ID 0x8575 +#define BCM53575_A0_REV_ID 1 +#define BCM53575_B0_REV_ID 0x11 + + +#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 BCM56975_DEVICE_ID 0xb975 +#define BCM56975_A0_REV_ID 1 +#define BCM56975_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 BCM56370_DEVICE_ID 0xb370 +#define BCM56370_A0_REV_ID 1 +#define BCM56370_A1_REV_ID 0x02 + +#define BCM56371_DEVICE_ID 0xb371 +#define BCM56371_A0_REV_ID 1 +#define BCM56371_A1_REV_ID 0x02 + +#define BCM56372_DEVICE_ID 0xb372 +#define BCM56372_A0_REV_ID 1 +#define BCM56372_A1_REV_ID 0x02 + +#define BCM56374_DEVICE_ID 0xb374 +#define BCM56374_A0_REV_ID 1 +#define BCM56374_A1_REV_ID 0x02 + +#define BCM56375_DEVICE_ID 0xb375 +#define BCM56375_A0_REV_ID 1 +#define BCM56375_A1_REV_ID 0x02 + +#define BCM56376_DEVICE_ID 0xb376 +#define BCM56376_A0_REV_ID 1 +#define BCM56376_A1_REV_ID 0x02 + +#define BCM56377_DEVICE_ID 0xb377 +#define BCM56377_A0_REV_ID 1 +#define BCM56377_A1_REV_ID 0x02 + +#define BCM56577_DEVICE_ID 0xb577 +#define BCM56577_A0_REV_ID 1 +#define BCM56577_A1_REV_ID 0x02 + +#define BCM56578_DEVICE_ID 0xb578 +#define BCM56578_A0_REV_ID 1 +#define BCM56578_A1_REV_ID 0x02 + +#define BCM56579_DEVICE_ID 0xb579 +#define BCM56579_A0_REV_ID 1 +#define BCM56579_A1_REV_ID 0x02 + +#define BCM56770_DEVICE_ID 0xb770 +#define BCM56770_A0_REV_ID 1 + +#define BCM56771_DEVICE_ID 0xb771 +#define BCM56771_A0_REV_ID 1 + +#define BCM53540_DEVICE_ID 0x8540 +#define BCM53540_A0_REV_ID 1 +#define BCM53547_DEVICE_ID 0x8547 +#define BCM53547_A0_REV_ID 1 +#define BCM53548_DEVICE_ID 0x8548 +#define BCM53548_A0_REV_ID 1 +#define BCM53549_DEVICE_ID 0x8549 +#define BCM53549_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 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 DNXC_A0_REV_ID 0x0001 +#define DNXC_A1_REV_ID 0x0002 +#define DNXC_B0_REV_ID 0x0011 +#define DNXC_B1_REV_ID 0x0012 +#define BCM88790_DEVICE_ID 0x8790 +#define BCM88790_A0_REV_ID DNXC_A0_REV_ID +#define BCM88790_B0_REV_ID DNXC_B0_REV_ID +#define BCM88791_DEVICE_ID 0x8791 +#define BCM88792_DEVICE_ID 0x8792 +#define BCM88793_DEVICE_ID 0x8793 +#define BCM88794_DEVICE_ID 0x8794 +#define BCM88795_DEVICE_ID 0x8795 +#define BCM88796_DEVICE_ID 0x8796 +#define BCM88797_DEVICE_ID 0x8797 +#define BCM88798_DEVICE_ID 0x8798 +#define BCM88799_DEVICE_ID 0x8799 +#define BCM8879A_DEVICE_ID 0x879A +#define BCM8879B_DEVICE_ID 0x879B +#define BCM8879C_DEVICE_ID 0x879C +#define BCM8879D_DEVICE_ID 0x879D +#define BCM8879E_DEVICE_ID 0x879E +#define BCM8879F_DEVICE_ID 0x879F +#define BCM_DNXF_DEVID_MASK 0xFFF0 +#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 DNXC_A0_REV_ID +#define JERICHO_2_B0_REV_ID DNXC_B0_REV_ID +#define JERICHO_2_B1_REV_ID DNXC_B1_REV_ID +#define BCM88690_DEVICE_ID JERICHO_2_DEVICE_ID +#define BCM88690_A0_REV_ID JERICHO_2_A0_REV_ID +#define BCM88690_B0_REV_ID JERICHO_2_B0_REV_ID +#define BCM88690_B1_REV_ID JERICHO_2_B1_REV_ID +#define BCM88691_DEVICE_ID 0x8691 +#define BCM88692_DEVICE_ID 0x8692 +#define BCM88693_DEVICE_ID 0x8693 +#define BCM88694_DEVICE_ID 0x8694 +#define BCM88695_DEVICE_ID 0x8695 +#define BCM88696_DEVICE_ID 0x8696 +#define BCM88697_DEVICE_ID 0x8697 +#define BCM88698_DEVICE_ID 0x8698 +#define BCM88699_DEVICE_ID 0x8699 +#define BCM8869A_DEVICE_ID 0x869A +#define BCM8869B_DEVICE_ID 0x869B +#define BCM8869C_DEVICE_ID 0x869C +#define BCM8869D_DEVICE_ID 0x869D +#define BCM8869E_DEVICE_ID 0x869E +#define BCM8869F_DEVICE_ID 0x869F +#define BCM_JR2_DEVID_MASK 0xFFF0 + +#define J2C_DEVICE_ID 0x8800 +#define J2C_A0_REV_ID DNXC_A0_REV_ID +#define BCM88800_DEVICE_ID J2C_DEVICE_ID +#define BCM88800_A0_REV_ID J2C_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 BCM88274_DEVICE_ID 0x8274 +#define BCM88278_DEVICE_ID 0x8278 +#define BCM88279_DEVICE_ID 0x8279 + +#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 + +#define PLX9056_DEVICE_ID 0x9056 + +#endif + diff --git a/sdk-6.5.16/src/gpl-modules/make/Make.config b/sdk-6.5.16/src/gpl-modules/make/Make.config @@ -0,0 +1,358 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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 + ESW_CHIPS = 1 +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/sdk-6.5.16/src/gpl-modules/make/Make.depend b/sdk-6.5.16/src/gpl-modules/make/Make.depend @@ -0,0 +1,108 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.16/src/gpl-modules/make/Make.kernlib b/sdk-6.5.16/src/gpl-modules/make/Make.kernlib @@ -0,0 +1,69 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.16/src/gpl-modules/make/Make.lib b/sdk-6.5.16/src/gpl-modules/make/Make.lib @@ -0,0 +1,80 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.16/src/gpl-modules/make/Make.linux b/sdk-6.5.16/src/gpl-modules/make/Make.linux @@ -0,0 +1,97 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# +# $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/sdk-6.5.16/src/gpl-modules/make/Make.subdirs b/sdk-6.5.16/src/gpl-modules/make/Make.subdirs @@ -0,0 +1,44 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.16/src/gpl-modules/make/Make.tools b/sdk-6.5.16/src/gpl-modules/make/Make.tools @@ -0,0 +1,38 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-iproc b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-iproc @@ -0,0 +1,94 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/xldk50-be/XLDK32 +TARGET_ARCHITECTURE:=armeb-broadcom-linux-uclibcgnueabi +KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux +else +TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk50/XLDK32 +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 + +CFLAGS += -fno-aggressive-loop-optimizations + +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.4/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/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-iproc-3_14 b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-iproc-3_14 @@ -0,0 +1,103 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel @@ -0,0 +1,112 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel-2_6 b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel-2_6 @@ -0,0 +1,148 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel-3_6 b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel-3_6 @@ -0,0 +1,148 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel-4_4 b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel-4_4 @@ -0,0 +1,157 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kmodule b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kmodule @@ -0,0 +1,81 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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 + if [ ! -f $(KERNBLDDIR)/NO_SUPRESS ]; then echo "# suppress warning" > .$(PRE_COMPILED_OBJ).cmd; fi + $(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/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-x86-common-2_6 b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-x86-common-2_6 @@ -0,0 +1,44 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-x86-generic-common-2_6 b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-x86-generic-common-2_6 @@ -0,0 +1,51 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-x86-smp_generic_64-2_6 b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-x86-smp_generic_64-2_6 @@ -0,0 +1,37 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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 + + +LINUX_UAPI = $(LINUX_INCLUDE)/uapi +ifneq (,$(shell ls $(LINUX_UAPI) 2>/dev/null)) +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 +endif + +include ${SDK}/make/Makefile.linux-x86-common-2_6 diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/include/linux-bde.h b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/include/linux-bde.h @@ -0,0 +1,278 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/*********************************************************************** + * + * $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 <sal/types.h> + +#include <ibde.h> + + +/* + * 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 <linux/version.h> + +#ifdef __KERNEL__ +#include <linux/types.h> +/* 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); + +/* + * Backdoor to retrieve number of switch devices probed. + */ +extern int lkbde_get_num_devices(int type); + +/* + * 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); + +#ifdef BCM_SAND_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 +/* + * This flag should be OR'ed onto the device number when calling + * irq_mask_set functions from a secondary device driver if the + * mask register is iProc register. + */ +#define LKBDE_IPROC_REG 0x4000 + +#ifdef BCM_SAND_SUPPORT +#include <linux/version.h> +#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 +#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 for DMA pool */ +#ifndef USE_LINUX_BDE_MMAP +#define USE_LINUX_BDE_MMAP 1 +#endif + +#endif /* __KERNEL__ */ + +#endif /* __LINUX_BDE_H__ */ diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/include/linux_dma.h b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/include/linux_dma.h @@ -0,0 +1,75 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/*********************************************************************** + * + * $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 <sal/types.h> + +#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 dev_index); +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_mmap(struct file *filp, struct vm_area_struct *vma); + +#endif /* __KERNEL__ */ + +#endif /* __LINUX_DMA_H__ */ diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/include/mpool.h b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/include/mpool.h @@ -0,0 +1,36 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/Makefile b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/Makefile @@ -0,0 +1,92 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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 + +# need to add vpath sources +VPATH = ../shared + +# Add the srcs to be found by vpath +LSRCS += mpool.c + +# 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/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux-kernel-bde.c b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux-kernel-bde.c @@ -0,0 +1,4361 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: linux-kernel-bde.c,v 1.414 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + * + * Linux Kernel BDE + * + */ + +#include <gmodule.h> +#include <linux-bde.h> +#include <linux_dma.h> +#include <mpool.h> +#include <linux/delay.h> +#include <linux/types.h> +#include <sdk_config.h> +#include <soc/devids.h> +#include <soc/cmic.h> +#include <soc/drv.h> +#include <linux/version.h> + +#include "linux_shbde.h" + + +#ifdef __GNUC__ +#if __GNUC__ == 8 +/* + * Prevent gcc 8.1.10 using a compiler inline memcpy even if using -fno-builtin or + * -fno-builtin-memcpy . + * __inline_memcpy and __memcpy are kernel functions that may be used instead, + * for either an inline or non-inline implementations of the function + */ +#define MEMCPY __inline_memcpy +#else +#define MEMCPY memcpy +#endif /* __GNUC__ == 8 */ +#else /* ifdef __GNUC__ */ +#define MEMCPY memcpy +#endif /* ifdef __GNUC__ */ + +#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)"); + +int msixcnt = 1; + +/* + * 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 + +/* 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 + + +/* 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,30)) +#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 +typedef irqreturn_t (*irq_handler_t)(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; + +#define VALID_DEVICE(_n) ((_n >= 0) && (_n < _ndevices)) + +#if defined(IPROC_CMICD) && defined(CONFIG_OF) +#define ICFG_CHIP_ID_REG 0x10236000 +#define IHOST_CMICX_MAX_INTRS 128 +static uint32 iproc_cmicx_irqs[IHOST_CMICX_MAX_INTRS]; +#endif + +/* CPU MMIO area used with CPU cards provided on demo boards */ +#if defined(BCM_SAND_SUPPORT) && (defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__)) +static void *cpu_address = NULL; +#endif + + +/* 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 + +/* Default gicd address if not available in DTB */ +#define IHOST_GICD_REG_ADDR 0x10781100 +#define IHOST_GICD_REG_REMAP_LEN 0x100 + +#define IHOST_GICD_REG_ADDR_VALID(d, addr) \ + (_devices[d].bde_dev.base_address1 && \ + (addr & 0xFFFFFF00) == _devices[d].phys_address1) + +#define IHOST_GICD_REG_ADDR_REMAP(d, addr) \ + (void *)(_devices[d].bde_dev.base_address1 + (addr - _devices[d].phys_address1)) + +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 void +_bde_add_device(void) +{ + int add_switch_device = 0; + if (_devices[_ndevices].dev_type & BDE_SWITCH_DEV_TYPE) { + _switch_ndevices++; + add_switch_device = 1; + } else if (_devices[_ndevices].dev_type & BDE_ETHER_DEV_TYPE) { + _ether_ndevices++; + } else if (_devices[_ndevices].dev_type & BDE_CPU_DEV_TYPE) { + _cpu_ndevices++; + } else { + return; + } + _ndevices++; + + /* + * 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 (add_switch_device) { + 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; + } + + _dma_init(_switch_ndevices-1); + } + + /* Initialize device locks */ + spin_lock_init(&_devices[_ndevices-1].lock); +} + +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; + + 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); + + _bde_add_device(); + + return 0; +} + +#ifdef BCM_SAND_SUPPORT + +#include <soc/devids.h> + +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__ + 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; + } + +#ifndef __DUNE_LINUX_BCM_CPU_PCIE__ + _bde_add_device(); +#endif + + return 0; +} +#endif /* BCM_SAND_SUPPORT */ + +#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 <linux/platform_device.h> +#include <linux/of.h> + +extern int iproc_platform_driver_register(struct platform_driver *drv); +extern void iproc_platform_driver_unregister(struct platform_driver *drv); +extern int 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" +#define IPROC_CMICX_COMPATIBLE "brcm,iproc-cmicx" + +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; + + 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; + +#ifdef CONFIG_OF + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + uint32 *icfg_chip_id; + icfg_chip_id = (uint32 *)IOREMAP(ICFG_CHIP_ID_REG, 2 * sizeof(uint32)); + if (icfg_chip_id == NULL) { + gprintk("Error mapping ICFG_CHIP_ID_REG\n"); + return -1; + } + ctrl->bde_dev.device = readl(icfg_chip_id) & 0xffff; + ctrl->bde_dev.rev = readl(icfg_chip_id+1) & 0xff; + iounmap(icfg_chip_id); + /* Map GICD block in the AXI memory space into CPU address space */ + memres = iproc_platform_get_resource(pldev, IORESOURCE_MEM, 1); + if (memres) { + ctrl->bde_dev.base_address1 = (sal_vaddr_t)IOREMAP(memres->start, memres->end - memres->start + 1); + ctrl->phys_address1 = memres->start; + } else { + /* Use default address if not available in DTB */ + ctrl->bde_dev.base_address1 = (sal_vaddr_t)IOREMAP(IHOST_GICD_REG_ADDR, IHOST_GICD_REG_REMAP_LEN); + ctrl->phys_address1 = IHOST_GICD_REG_ADDR; + } + if (ctrl->bde_dev.base_address1) { + if (debug >= 1) { + gprintk("base_address1:0x%lx phys_address1:0x%lx\n", + (unsigned long)ctrl->bde_dev.base_address1, (unsigned long)ctrl->phys_address1); + } + } else { + gprintk("Error mapping ihost GICD registers\n"); + } + } else +#endif + { + /* Read switch device ID from CMIC */ + dev_rev_id = *((uint32 *)(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 + ctrl->bde_dev.base_address1 = 0; + } + +#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]); + } + +#ifdef CONFIG_OF + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + int i; + for (i = 0; i < IHOST_CMICX_MAX_INTRS; i++) { + irqres = iproc_platform_get_resource(pldev, IORESOURCE_IRQ, i); + iproc_cmicx_irqs[i] = irqres->start; + if (debug >= 1) { + gprintk("iproc_cmicx_irqs[%d] = %d\n", i, iproc_cmicx_irqs[i]); + } + } + ctrl->iLine = iproc_cmicx_irqs[0]; + } else +#endif + { + 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 */ + _bde_add_device(); + 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 = IPROC_CMICD_COMPATIBLE }, + { .compatible = IPROC_CMICX_COMPATIBLE }, + {}, +}; +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) { + 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=%lx, cmicd_mem.end=%lx\n", + found_cmicd_dev ? "EROM" : "Default", + (unsigned long)iproc_cmicd_resources[IPROC_CMICD_RES_MEM].start, + (unsigned long)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; + + 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); + _bde_add_device(); + } + + 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 const 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, 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, 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, BCM56975_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, BCM56670_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56671_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56672_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56675_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56568_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56670_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56760_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56761_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 }, + { 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, BCM88274_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88278_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88279_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, 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_DNX_SUPPORT + { BROADCOM_VENDOR_ID, BCM88690_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88690_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88691_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88692_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88693_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88694_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88695_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88696_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88697_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88698_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88699_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8869A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8869B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8869C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8869D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8869F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88800_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, +#endif /* BCM_DNX_SUPPORT */ +#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 }, + { BROADCOM_VENDOR_ID, BCM88791_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88792_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88793_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88794_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88795_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88796_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88797_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88798_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88799_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8879A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8879B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8879C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8879D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8879F_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, BCM56370_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56371_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56372_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56374_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56375_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56376_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56377_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56577_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56578_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56579_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56873_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56770_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56771_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56980_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56981_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56982_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56983_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56984_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53540_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53547_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53548_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53549_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { 0, 0, 0, 0 } +};; + +MODULE_DEVICE_TABLE(pci, _id_table); + +#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; + } + pci_disable_msix(dev); + 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), GFP_KERNEL); + + if (!ctrl->entries) { + goto er_intx; + } + /* Only one vector is mapped by default */ + /* May be more in future, can be controlled using module param */ + ctrl->msix_cnt = msixcnt; + 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; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) + ret = pci_enable_msix_range(ctrl->pci_device, + ctrl->entries, ctrl->msix_cnt, ctrl->msix_cnt); +#else + 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; + msixcnt = ret; + ret = pci_enable_msix(ctrl->pci_device, + ctrl->entries, ctrl->msix_cnt); + if (ret != 0) + goto er_intx_free; + } +#endif + if (ret < 0) { + /* Error */ + goto er_intx_free; + } else { + gprintk("Enabled MSI-X interrupts = %d\n", ctrl->msix_cnt); + return 0; + } + } +#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/MSIX 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) { + if (ctrl->msix_cnt) { + pci_disable_msix(ctrl->pci_device); + kfree(ctrl->entries); + ctrl->entries = NULL; + 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(struct pci_dev *dev, bde_ctrl_t *ctrl, int iproc) +{ +#ifdef CONFIG_PCI_MSI + int ret; + shbde_iproc_config_t icfg; + + /* Each device follows global policy by default */ + ctrl->use_msi = use_msi; + + if (unlikely(debug > 1)) + gprintk("%s: msi = %d\n", __func__, ctrl->use_msi); + + /* Check IPROC version for MSIX support */ + if (iproc && ctrl->bde_dev.base_address1 && + (ctrl->use_msi == PCI_USE_INT_MSIX)) { + if (shbde_pci_iproc_version_get(&ctrl->shbde, dev, &icfg.iproc_ver, + &icfg.cmic_ver, &icfg.cmic_rev)) { + if (icfg.iproc_ver < 0xe) { + gprintk("%s: MSI-X not supported, using MSI.\n", __func__); + ctrl->use_msi = PCI_USE_INT_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, using INTx.\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; + int plx_dev = 0; + int eth_dev = 0; + int cpu_dev = 0; + int update_devid = 0; + int paxb_core = 0; + int add_dev = 0, 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; + 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; + ctrl->dev_type |= BDE_ETHER_DEV_TYPE; + ctrl->iLine = dev->irq; + add_dev = 1; + 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; + ctrl->dev_type |= BDE_CPU_DEV_TYPE; + add_dev = 1; + 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; + 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; + add_dev = 1; + } + + /* 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) + /*All Ramon devices from 0x8790 to 0x879F*/ + if ((dev->device & BCM_DNXF_DEVID_MASK) == 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); + + } +#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); + } + } + + /* configure interrupt type */ + config_pci_intr_type(dev, ctrl, iproc); + + /* 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)); + + + 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) { + ctrl->dev_type |= BDE_256K_REG_SPACE; + if (debug >= 1) gprintk("PCI resource len 256K\n"); + } else if (bar_len == 0x800000) { + ctrl->dev_type |= BDE_256K_REG_SPACE | BDE_8MB_REG_SPACE; + if (debug >= 1) gprintk("PCI resource len 8MB\n"); + } + + +#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); + } + + if (add_dev) { + _bde_add_device(); + } + /* 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); + } + 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; + 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); + } + _bde_add_device(); +} +#endif /* BCM_ICS */ + + + + +#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; + + /* + * 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; + + _bde_add_device(); + return(ctrl); +} + +#define BME_REVISION_OFFSET (0x0) + +#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; + + /* + * 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); + + + _bde_add_device(); + + switch (ctrl->bde_dev.device) { + default: + 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 */ + + + + +/* + * 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 +#ifdef CONFIG_OF + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + iproc_platform_driver_register(&iproc_cmicd_driver); + } else +#endif + 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; + + + /* 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_msi = %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_SAND_SUPPORT + sand_device_create(); +#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,","); + } + } + + return 0; +} + +/* + * Function: _cleanup + * + * Purpose: + * Module cleanup function. + * Parameters: + * None + * Returns: + * Always 0 + */ +static int +_cleanup(void) +{ + int i; + + _dma_cleanup(); + +#ifdef IPROC_CMICD +#ifdef CONFIG_OF + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + iproc_platform_driver_unregister(&iproc_cmicd_driver); + } else +#endif + 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 + + 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_SAND_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 %02x:%02x.%x 0x%x:0x%x:%d:0x%.8lx:0x%.8lx:%d%s\n", + (unsigned int)ctrl->pci_device->bus->number, + PCI_SLOT(ctrl->pci_device->devfn), + PCI_FUNC(ctrl->pci_device->devfn), + 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; +} + +/* 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, + mmap: _dma_mmap, +}; + +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++) { + if (unlikely(debug >= 1)) { + gprintk("%s(%d):device# = %d, irq = %d\n", + __func__, __LINE__, d, ctrl->entries[i].vector); + } + ret = request_irq(ctrl->entries[i].vector, (irq_handler_t)_isr, 0, + LINUX_KERNEL_BDE_NAME, ctrl); + if (ret < 0) + break; + } + if (ret < 0) { + while (i >= 0) + free_irq(ctrl->entries[i--].vector, ctrl); + + goto err_disable_msi; + } + } + else +#endif + { +#if defined(IPROC_CMICD) && defined(CONFIG_OF) + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + int i, j; + for (i = 0; i < IHOST_CMICX_MAX_INTRS; i++) { + if (unlikely(debug >= 1)) + gprintk("%s(%d):device# = %d, request_irq(%d)\n", + __func__, __LINE__, d, iproc_cmicx_irqs[i]); + ret = request_irq(iproc_cmicx_irqs[i], (irq_handler_t)_isr, + irq_flags, LINUX_KERNEL_BDE_NAME, ctrl); + if (ret < 0) { + gprintk("request_irq(%d) failed(%d)\n", iproc_cmicx_irqs[i], ret); + break; + } + } + if (ret < 0) { + for (j = 0; j < i; j++) { + free_irq(iproc_cmicx_irqs[j], ctrl); + } + 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++) { + if (unlikely(debug > 1)) { + gprintk("%s(%d):device# = %d, irq = %d\n", + __func__, __LINE__, d, ctrl->entries[i].vector); + } + free_irq(ctrl->entries[i].vector, ctrl); + } + } + else +#endif +#if defined(IPROC_CMICD) && defined(CONFIG_OF) + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + int i; + for (i = 0; i < IHOST_CMICX_MAX_INTRS; i++) { + if (unlikely(debug > 1)) { + gprintk("%s(%d):device# = %d, free_irq(%d)\n", + __func__, __LINE__, d, iproc_cmicx_irqs[i]); + } + free_irq(iproc_cmicx_irqs[i], ctrl); + } + } 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) { + if (IHOST_GICD_REG_ADDR_VALID(d, addr)) { + return readl(IHOST_GICD_REG_ADDR_REMAP(d, addr)); + } + 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) { + if (IHOST_GICD_REG_ADDR_VALID(d, addr)) { + writel(data, IHOST_GICD_REG_ADDR_REMAP(d, addr)); + return 0; + } + 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_SAND_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 BCM88800_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 BCM88274_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; + } + +#ifdef BCM_DNX_SUPPORT + /*All Jericho 2 devices from 0x8690 to 0x869F*/ + if (SOC_IS_JERICHO_2_TYPE(ctrl->bde_dev.device)) { + /* 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); + } +#endif + + /* 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 /* BCM_SAND_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, + + NULL, + NULL, + 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, iproc_reg; + unsigned long flags; + + isr2_dev = d & LKBDE_ISR2_DEV; + iproc_reg = d & LKBDE_IPROC_REG; + d &= ~(LKBDE_ISR2_DEV | LKBDE_IPROC_REG); + + 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; + } + + if (iproc_reg) { + _iproc_write(d, addr, ctrl->imask | ctrl->imask2); + } else { + _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 | LKBDE_IPROC_REG); + + if (!VALID_DEVICE(d)) { + return -1; + } + + if (mask == NULL || fmask == NULL) { + return -1; + } + + ctrl = _devices + d; + + *fmask = ctrl->fmask; + *mask = ctrl->imask | ctrl->imask2; + + return 0; +} + +int +lkbde_get_num_devices(int type) +{ + return _num_devices(type); +} + +/* + * 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); +#ifdef BCM_SAND_SUPPORT +LKM_EXPORT_SYM(lkbde_cpu_write); +LKM_EXPORT_SYM(lkbde_cpu_read); +LKM_EXPORT_SYM(lkbde_cpu_pci_register); +#endif diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux_dma.c b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux_dma.c @@ -0,0 +1,1007 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <gmodule.h> +#include <linux-bde.h> +#include <linux_dma.h> +#include <mpool.h> +#include <sdk_config.h> + +#ifdef BCM_PLX9656_LOCAL_BUS +#include <asm/cacheflush.h> +#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 <linux/dma-mapping.h> +#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 +#if defined(__arm__) +#define USE_DMA_MMAP_COHERENT +#define _PGPROT_NONCACHED(x) x = pgprot_noncached((x)) +#elif defined(__aarch64__ ) +#define USE_DMA_MMAP_COHERENT +#define _PGPROT_NONCACHED(x) x = pgprot_writecombine((x)) +#endif +#else +#define ALLOC_METHOD_DEFAULT ALLOC_TYPE_CHUNK +#endif + +#ifndef _PGPROT_NONCACHED +#ifdef REMAP_DMA_NONCACHED +#define _PGPROT_NONCACHED(x) x = pgprot_noncached((x)) +#else +#define _PGPROT_NONCACHED(x) +#endif +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) +#include <linux/slab.h> +#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 + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) +#define DMA_MAPPING_ERROR(d, p) dma_mapping_error((d),(p)) +#else +#define DMA_MAPPING_ERROR(d, p) dma_mapping_error((p)) +#endif + +#ifndef KMALLOC_MAX_SIZE +#define KMALLOC_MAX_SIZE (1UL << (MAX_ORDER - 1 + PAGE_SHIFT)) +#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)"); + +/* Physical high memory address to use for DMA */ +static char *himemaddr = 0; +LKM_MOD_PARAM(himemaddr, "s", charp, 0); +MODULE_PARM_DESC(himemaddr, +"Physical address to use for high memory DMA"); + +/* DMA memory allocation */ + +#define ONE_KB 1024 +#define ONE_MB (1024*1024) +#define ONE_GB (1024*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 + +/* 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 unsigned long _himemaddr = 0; +static int _use_dma_mapping = 0; +static LIST_HEAD(_dma_seg); + +#define DMA_DEV_INDEX 0 /* Device index to allocate memory pool */ +#define DMA_DEV(n) lkbde_get_dma_dev(n) +#define BDE_NUM_DEVICES(t) lkbde_get_num_devices(t) + +/* + * 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; + for (i = 0; i < blks; 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[start + i] = addr; + ++dseg->blk_cnt; + } else { + gprintk("DMA allocation failed: allocated %d of %d " + "requested blocks\n", i, blks); + 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); + if (blk_ptr_size > KMALLOC_MAX_SIZE) { + blk_ptr_size = KMALLOC_MAX_SIZE; + dseg->blk_cnt_max = KMALLOC_MAX_SIZE / 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 */ + if (_alloc_dma_blocks(dseg, dseg->req_size / dseg->blk_size) != 0) { + gprintk("Failed to allocate minimum number of DMA blocks\n"); + /* + * _alloc_dma_blocks() returns -1 if it fails to allocate the requested + * number of blocks, but it may still have allocated something. Fall + * through and return dseg filled in with as much memory as we could + * allocate. + */ + } + /* 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 */ + gprintk("_pgalloc() failed to get requested size %zu: " + "only got %lu contiguous across %d blocks\n", + size, dseg->seg_size, dseg->blk_cnt); + _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(DMA_DEV_INDEX), _dma_mem_size, _dma_vbase, _dma_pbase); + } + break; +#endif /* _SIMPLE_MEMORY_ALLOCATION_ */ + + case ALLOC_TYPE_CHUNK: { + struct list_head *pos, *tmp; + int i, ndevices; + if (_use_dma_mapping) { + ndevices = BDE_NUM_DEVICES(BDE_SWITCH_DEVICES); + for (i = 0; i < ndevices && DMA_DEV(i); i ++) { + dma_unmap_single(DMA_DEV(i), (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 */ + if (_himemaddr) { + pbase = _himemaddr; + } else { + 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 */ + if (dma_debug >= 1) { + gprintk("Allocating DMA memory using method dmaalloc=%d\n", dmaalloc); + } + 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(DMA_DEV_INDEX), + alloc_size, &dma_handle, GFP_KERNEL)) || !dma_handle) { + gprintk("Failed to allocate coherent memory pool of size 0x%lx\n", (unsigned long)alloc_size); + return; + } + _cpu_pbase = pbase = dma_handle; + } + + if (alloc_size != size) { + gprintk("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_vbase) { + gprintk("Failed to allocate memory pool of size 0x%lx\n", (unsigned long)size); + return; + } + _cpu_pbase = virt_to_bus(_dma_vbase); + /* Use dma_map_single to obtain DMA bus address or IOVA if iommu is present. */ + if (DMA_DEV(DMA_DEV_INDEX)) { + pbase = dma_map_single(DMA_DEV(DMA_DEV_INDEX), _dma_vbase, size, DMA_BIDIRECTIONAL); + if (DMA_MAPPING_ERROR(DMA_DEV(DMA_DEV_INDEX), pbase)) { + gprintk("Failed to map memory at %p\n", _dma_vbase); + _pgcleanup(); + _dma_vbase = NULL; + return; + } + _use_dma_mapping = 1; + } else { + pbase = _cpu_pbase; + } + break; + default: + _dma_vbase = NULL; + gprintk("DMA memory allocation method dmaalloc=%d is not supported\n", dmaalloc); + return; + } + + 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; + } + + _dma_pbase = pbase; +#ifdef REMAP_DMA_NONCACHED + _dma_vbase = IOREMAP(_dma_pbase, size); +#endif + if (dma_debug >= 1) { + gprintk("_use_dma_mapping:%d _dma_vbase:%p _dma_pbase:%lx _cpu_pbase:%lx allocated:%lx dmaalloc:%d\n", + _use_dma_mapping, _dma_vbase, (unsigned long)_dma_pbase, + (unsigned long)_cpu_pbase, (unsigned long)size, dmaalloc); + } + } +} + +/* + * 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 dev_index) +{ + unsigned long pbase; + + if (dev_index > DMA_DEV_INDEX) { + if (_use_dma_mapping && DMA_DEV(dev_index) && _dma_vbase) { + pbase = dma_map_single(DMA_DEV(dev_index), _dma_vbase, _dma_mem_size, DMA_BIDIRECTIONAL); + if (DMA_MAPPING_ERROR(DMA_DEV(dev_index), pbase)) { + gprintk("Failed to map memory for device %d at %p\n", dev_index, _dma_vbase); + return; + } + if (pbase != (unsigned long)_dma_pbase) { + /* Bus address/IOVA must be identical for all devices. */ + gprintk("Device %d has different pbase: %lx (should be %lx)\n", + dev_index, pbase, (unsigned long)_dma_pbase); + } + } + return; + } + + /* 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; + } + } + + 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 (himemaddr && strlen(himemaddr) > 0) { + char suffix = (himemaddr[strlen(himemaddr)-1] & ~0x20); + _himemaddr = simple_strtoul(himemaddr, NULL, 0); + if (suffix == 'M') { + _himemaddr *= ONE_MB; + } else if (suffix == 'G') { + _himemaddr *= ONE_GB; + } else { + gprintk("DMA high memory address must be specified as e.g. himemaddr=8[MG]\n"); + } + } + + 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); + } + } +} + +/* + * Some kernels are configured to prevent mapping of kernel RAM memory + * into user space via the /dev/mem device. + * + * The function below provides a backdoor to mapping the DMA pool to + * user space via the BDE device file. + */ +int _dma_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 (phys_addr < (unsigned long )_cpu_pbase || + (phys_addr + size) > ((unsigned long )_cpu_pbase + _dma_mem_size)) { + gprintk("range 0x%lx-0x%lx outside DMA pool 0x%lx-0x%lx\n", + phys_addr, phys_addr + size, (unsigned long )_cpu_pbase, + (unsigned long )_cpu_pbase + _dma_mem_size); + return -EINVAL; + } + +#ifdef USE_DMA_MMAP_COHERENT + if (dmaalloc == ALLOC_TYPE_API) { + vma->vm_pgoff = 0; + return dma_mmap_coherent(DMA_DEV(DMA_DEV_INDEX), vma, (void *)_dma_vbase, phys_addr, size); + } +#endif + + _PGPROT_NONCACHED(vma->vm_page_prot); + + 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; +} + +/* + * 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/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.c b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.c @@ -0,0 +1,120 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#include <gmodule.h> +#include <shbde.h> +#include <shbde_iproc.h> +#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/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.h b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.h @@ -0,0 +1,33 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#ifndef __LINUX_SHBDE_H__ +#define __LINUX_SHBDE_H__ + +#include <shbde.h> +#include <shbde_pci.h> +#include <shbde_iproc.h> + +extern int +linux_shbde_hal_init(shbde_hal_t *shbde, shbde_log_func_t log_func); + +#endif /* __LINUX_SHBDE_H__ */ diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/shared/mpool.c b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/shared/mpool.c @@ -0,0 +1,355 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: mpool.c,v 1.18 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ + +#include <mpool.h> + +#ifdef __KERNEL__ + +/* + * Abstractions used when compiling for Linux kernel mode. + */ + +#include <lkm.h> + +/* + * 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 <stdlib.h> +#include <sal/core/sync.h> + +#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 + +#define MPOOL_BUF_SIZE 1024 +#define MPOOL_BUF_ALLOC_COUNT_MAX 16 + +typedef struct mpool_mem_s { + unsigned char *address; + int size; + struct mpool_mem_s *prev; + struct mpool_mem_s *next; +} mpool_mem_t; + +static int _buf_alloc_count; +static mpool_mem_t *mpool_buf[MPOOL_BUF_ALLOC_COUNT_MAX]; +static mpool_mem_t *free_list; + +#define ALLOC_INIT_MPOOL_BUF(ptr) \ + ptr = MALLOC((sizeof(mpool_mem_t) * MPOOL_BUF_SIZE)); \ + if (ptr) { \ + int i; \ + for (i = 0; i < MPOOL_BUF_SIZE - 1; i++) { \ + ptr[i].next = &ptr[i+1]; \ + } \ + ptr[MPOOL_BUF_SIZE - 1].next = NULL; \ + free_list = &ptr[0]; \ + } + +/* + * 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(); + + if (size < BCM_CACHE_LINE_BYTES) { + size = BCM_CACHE_LINE_BYTES; + } + + 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; + } + + if (!free_list) { + if (_buf_alloc_count == MPOOL_BUF_ALLOC_COUNT_MAX) { + MPOOL_UNLOCK(); + return NULL; + } + + ALLOC_INIT_MPOOL_BUF(mpool_buf[_buf_alloc_count]); + + if (mpool_buf[_buf_alloc_count] == NULL) { + MPOOL_UNLOCK(); + return NULL; + } + + _buf_alloc_count++; + } + + newptr = free_list; + free_list = free_list->next; + + newptr->address = ptr->address + ptr->size; + newptr->size = size; + newptr->next = ptr->next; + newptr->prev = ptr; + ptr->next->prev = newptr; + 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 *head = pool, *ptr = NULL; + + MPOOL_LOCK(); + + if (!(head && head->prev)) { + MPOOL_UNLOCK(); + return; + } + + ptr = head->prev->prev; + + while (ptr && (ptr != head)) { + if (ptr->address == address) { +#ifdef TRACK_DMA_USAGE + _dma_mem_used -= ptr->size; +#endif + ptr->prev->next = ptr->next; + ptr->next->prev = ptr->prev; + ptr->next = free_list; + free_list = ptr; + break; + } + ptr = ptr->prev; + } + + 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)); + int i; + + MPOOL_LOCK(); + + for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) { + mpool_buf[i] = NULL; + } + + _buf_alloc_count = 0; + + ALLOC_INIT_MPOOL_BUF(mpool_buf[_buf_alloc_count]); + + if (mpool_buf[_buf_alloc_count] == NULL) { + MPOOL_UNLOCK(); + return NULL; + } + + _buf_alloc_count++; + + 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 = free_list; + free_list = free_list->next; + tail = free_list; + free_list = free_list->next; + + head->size = tail->size = 0; + head->address = base_ptr; + tail->address = head->address + size; + head->prev = tail; + head->next = tail; + tail->prev = head; + 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) +{ + int i; + + MPOOL_LOCK(); + + if ((mpool_mem_t *)pool != mpool_buf[0]) { + MPOOL_UNLOCK(); + return 0; + } + + for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) { + if (mpool_buf[i]) { + FREE(mpool_buf[i]); + mpool_buf[i] = NULL; + } + } + + 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/sdk-6.5.16/src/gpl-modules/systems/bde/linux/user/kernel/Makefile b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/user/kernel/Makefile @@ -0,0 +1,70 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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/sdk-6.5.16/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.c b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.c @@ -0,0 +1,1456 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: linux-user-bde.c,v 1.80 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + * + * Linux User BDE Helper Module + */ +#include <gmodule.h> +#include <mpool.h> +#include <linux-bde.h> + +#include <sal/core/thread.h> +#include <sal/core/sync.h> +#include <soc/devids.h> +#include <soc/drv.h> + +#include "linux-user-bde.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) +#include <linux/uaccess.h> +#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_MASK5_OFFSET(x) (0x314c0 + (0x1000 * x)) +#define CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(x) (0x314c4 + (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) + +/* +TODO:HX5 +The INTR base address values are changed for HX5, +hence making new #defines so runtime decisions can +be made. +*/ + +#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 HX5_INTC_INTR_ENABLE_REG0 (0x102310f0) +#define HX5_INTC_INTR_STATUS_REG0 (0x10231190) +#define HX5_INTC_INTR_RAW_STATUS_REG0 (0x10231140) + +#define HX5_INTC_INTR_ENABLE_BASE (HX5_INTC_INTR_ENABLE_REG0) +#define HX5_INTC_INTR_STATUS_BASE (HX5_INTC_INTR_STATUS_REG0) +#define HX5_INTC_INTR_RAW_STATUS_BASE (HX5_INTC_INTR_RAW_STATUS_REG0) + +#define IOREMAP(addr, size) ioremap_nocache(addr, size) + +#define HX5_IHOST_GICD_ISENABLERN_0 (0x10781100) +#define HX5_IHOST_GICD_ISENABLERN_1 (0x10781104) +#define HX5_IHOST_GICD_ICENABLERN_1 (0x10781184) +#define HX5_IHOST_GICD_ICENABLERN_8 (0x107811a0) +/* Offset between ISENABLERN_1 and ICENABLERN_1 in 4-bytes */ +#define HX5_IHOST_IRQ_MASK_OFFSET 0x20 +#define HX5_IHOST_INTR_MAP_NUM (HX5_IHOST_GICD_ICENABLERN_8 - HX5_IHOST_GICD_ISENABLERN_0) +#define HX5_IHOST_INTR_STATUS_MAP_NUM (INTC_INTR_REG_NUM * (sizeof(uint32))) +#define IRQ_BIT(intr) (intr % (sizeof(uint32)*8)) +#define IRQ_MASK_INDEX(intr) (intr / (sizeof(uint32)*8)) +#define HX5_CHIP_INTR_LOW_PRIORITY 119 +#define INTR_LOW_PRIORITY_BITPOS (1 << IRQ_BIT(HX5_CHIP_INTR_LOW_PRIORITY)) +#define INTC_LOW_PRIORITY_INTR_REG_IND IRQ_MASK_INDEX(HX5_CHIP_INTR_LOW_PRIORITY) +#define INTC_PDMA_INTR_REG_IND 4 + +#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)) + +#define IHOST_READ_INTR(d, reg, v) \ + (v = readl((reg))) +#define IHOST_WRITE_INTR(d, reg, v) \ + (writel((v), (reg))) + +/* 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 uint32 *ihost_intr_status_base = NULL; +static uint32 *ihost_intr_enable_base = NULL; + +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, ind; + uint32 stat, iena, mask, fmask; + bde_inst_resource_t *res; + uint32 intc_intr_status_base = 0, intc_intr_enable_base = 0; + + d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t)); + res = &_bde_inst_resource[ctrl->inst]; + + lkbde_irq_mask_get(d, &mask, &fmask); + + if ((ctrl->dev_type & BDE_SWITCH_DEV_TYPE) && + ((user_bde->get_dev(d)->device == BCM56370_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56371_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56372_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56374_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56375_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56376_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56377_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56577_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56578_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56579_DEVICE_ID))) { + intc_intr_status_base = HX5_INTC_INTR_STATUS_BASE; + intc_intr_enable_base = HX5_INTC_INTR_ENABLE_BASE; + } else { + intc_intr_status_base = INTC_INTR_STATUS_BASE; + intc_intr_enable_base = INTC_INTR_ENABLE_BASE; + } + if (fmask) { + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + IHOST_READ_INTR(d, ihost_intr_status_base + INTC_PDMA_INTR_REG_IND, stat); + IHOST_READ_INTR(d, ihost_intr_enable_base + INTC_PDMA_INTR_REG_IND, iena); + } else { + READ_INTC_INTR(d, intc_intr_status_base + 4 * INTC_PDMA_INTR_REG_IND, stat); + READ_INTC_INTR(d, intc_intr_enable_base + 4 * INTC_PDMA_INTR_REG_IND, iena); + } + if (stat & iena) { + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + IHOST_WRITE_INTR(d, ihost_intr_enable_base + INTC_PDMA_INTR_REG_IND + + HX5_IHOST_IRQ_MASK_OFFSET, ~0); + } else { + WRITE_INTC_INTR(d, intc_intr_enable_base + 4 * INTC_PDMA_INTR_REG_IND, 0); + } + + for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) { + if (ind == INTC_PDMA_INTR_REG_IND) { + continue; + } + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + if (ind < INTC_LOW_PRIORITY_INTR_REG_IND) { + continue; + } + IHOST_READ_INTR(d, ihost_intr_status_base + ind, stat); + IHOST_READ_INTR(d, ihost_intr_enable_base + ind, iena); + if (ind == INTC_LOW_PRIORITY_INTR_REG_IND) { + stat &= INTR_LOW_PRIORITY_BITPOS; + } + } else { + READ_INTC_INTR(d, intc_intr_status_base + 4 * ind, stat); + READ_INTC_INTR(d, intc_intr_enable_base + 4 * ind, iena); + } + if (stat & iena) { + break; + } + } + + if (ind >= INTC_INTR_REG_NUM) { + return; + } + } + } + + /* 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 (ind = 0; ind < INTC_INTR_REG_NUM; ind++) { + if (fmask && ind == INTC_PDMA_INTR_REG_IND) { + continue; + } + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + if (ind < INTC_LOW_PRIORITY_INTR_REG_IND) { + continue; + } + if (ind == INTC_LOW_PRIORITY_INTR_REG_IND) { + IHOST_WRITE_INTR(d, ihost_intr_enable_base + INTC_LOW_PRIORITY_INTR_REG_IND + + HX5_IHOST_IRQ_MASK_OFFSET, INTR_LOW_PRIORITY_BITPOS); + } else { + IHOST_WRITE_INTR(d, ihost_intr_enable_base + ind + + HX5_IHOST_IRQ_MASK_OFFSET, ~0); + } + } else { + WRITE_INTC_INTR(d, intc_intr_enable_base + 4*ind, 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 +} + +/* some device has cmc0 only */ +static void +_cmicd_cmc0_interrupt(bde_ctrl_t *ctrl) +{ + int d; + int cmc = 0; + 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; + } + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT5_OFFSET(cmc)); + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(cmc)); + } else { + 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)); + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc)); + } else { + mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK6_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_MASK5_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc), 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_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 +_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)); + 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; + } + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT5_OFFSET(cmc)); + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(cmc)); + } else { + 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)); + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc)); + } else { + mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK6_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_MASK5_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK6_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_MASK5_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK6_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 +_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 +} + +/* The actual interrupt handler of ethernet devices */ +static void +_ether_interrupt(bde_ctrl_t *ctrl) +{ + 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)_cmicd_cmc0_interrupt, "CMICd CMC0" }, + { (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; + uint16 device_id_mask = 0xFFF0; + uint16 device_id; + uint32 state = 0; + + (void)lkbde_dev_state_get(d, &state); + if (state == BDE_DEV_STATE_REMOVED) { + return; + } + + 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 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; + case BCM53540_DEVICE_ID: + case BCM53547_DEVICE_ID: + case BCM53548_DEVICE_ID: + case BCM53549_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 BCM88800_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 BCM88274_DEVICE_ID: + case BCM88278_DEVICE_ID: + case BCM88279_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 BCM88772_DEVICE_ID: + case BCM88952_DEVICE_ID: + ctrl->isr = (isr_f)_cmicd_cmc0_interrupt; + break; + case BCM88790_DEVICE_ID: + ctrl->isr = (isr_f)_cmicx_interrupt; + break; + case BCM56370_DEVICE_ID: + case BCM56371_DEVICE_ID: + case BCM56372_DEVICE_ID: + case BCM56374_DEVICE_ID: + case BCM56375_DEVICE_ID: + case BCM56376_DEVICE_ID: + case BCM56377_DEVICE_ID: + case BCM56577_DEVICE_ID: + case BCM56578_DEVICE_ID: + case BCM56579_DEVICE_ID: + ctrl->isr = (isr_f)_cmicx_interrupt; + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + if (!ihost_intr_enable_base) { + ihost_intr_enable_base = (uint32_t *)IOREMAP(HX5_IHOST_GICD_ISENABLERN_1, + HX5_IHOST_INTR_MAP_NUM); + } + if (!ihost_intr_status_base) { + ihost_intr_status_base = (uint32_t *)IOREMAP(HX5_INTC_INTR_RAW_STATUS_REG0, + HX5_IHOST_INTR_STATUS_MAP_NUM); + } + } + break; + default: + /* Get CMIC version */ + if (user_bde->get_cmic_ver(d, &ver) != 0) { + ver = -1; + } + device_id = ctrl->devid & device_id_mask; + /* TH/TH+/TH2 should use cmicd interrupt handler */ + if (BCM56960_DEVICE_ID == device_id || + BCM56930_DEVICE_ID == device_id || + BCM56970_DEVICE_ID == device_id) { + ctrl->isr = (isr_f)_cmicd_interrupt; + } + /* check if version is CMICX */ + else 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; + } + +#ifdef BCM_DNX_SUPPORT + /*All Jericho 2 devices from 0x8690 to 0x869F*/ + if (SOC_IS_JERICHO_2_TYPE(user_bde->get_dev(d)->device)) { + ctrl->isr = (isr_f)_cmicx_interrupt; + } +#endif + + /*All Ramon devices from 0x8790 to 0x879F*/ + if ((user_bde->get_dev(d)->device & BCM88790_DEVICE_ID) == BCM88790_DEVICE_ID) { + ctrl->isr = (isr_f)_cmicx_interrupt; + } + 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); + + ihost_intr_enable_base = NULL; + ihost_intr_status_base = NULL; + + 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; + } + + if (ihost_intr_enable_base) { + iounmap(ihost_intr_enable_base); + ihost_intr_enable_base = NULL; + } + if (ihost_intr_status_base) { + iounmap(ihost_intr_status_base); + ihost_intr_status_base = 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; + uint32_t *mapaddr; + + 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: + case LUBDE_UDELAY: + case LUBDE_SEM_OP: + return -EINVAL; + 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; +#ifdef BCM_SAND_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: + if (!VALID_DEVICE(io.dev)) { + return -EINVAL; + } + if (_devices[io.dev].dev_type & BDE_AXI_DEV_TYPE) { + mapaddr = IOREMAP(io.d0, sizeof(uint32_t)); + if (mapaddr == NULL) { + io.rc = LUBDE_FAIL; + return -1; + } + io.d1 = readl(mapaddr); + iounmap(mapaddr); + } else { + 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; + case LUBDE_REPROBE: + io.rc = _device_reprobe(); + 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/sdk-6.5.16/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.h b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.h @@ -0,0 +1,114 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <linux/types.h> +#include <linux/ioctl.h> +#include <linux-bde.h> +#ifndef __KERNEL__ +#include <stdint.h> +#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_REPROBE _IO(LUBDE_MAGIC, 31) + +#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 + * 2: add LUBDE_REPROBE to support reprobe available devices + */ +#define KBDE_VERSION 2 + + +/* This is the signal that will be used + * when an interrupt occurs + */ + +#ifndef __KERNEL__ +#include <signal.h> +#endif + +#define LUBDE_INTERRUPT_SIGNAL SIGUSR1 +#define LUBDE_ETHER_INTERRUPT_SIGNAL SIGUSR2 + +#endif /* __LUBDE_H__ */ diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde.h b/sdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde.h @@ -0,0 +1,76 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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/sdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde_iproc.h b/sdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde_iproc.h @@ -0,0 +1,48 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#ifndef __SHBDE_IPROC_H__ +#define __SHBDE_IPROC_H__ + +#include <shbde.h> + +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/sdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde_mdio.h b/sdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde_mdio.h @@ -0,0 +1,59 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2015 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#ifndef __SHBDE_MDIO_H__ +#define __SHBDE_MDIO_H__ + +#include <shbde.h> + +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/sdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde_pci.h b/sdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde_pci.h @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#ifndef __SHBDE_PCI_H__ +#define __SHBDE_PCI_H__ + +#include <shbde.h> + +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/sdk-6.5.16/src/gpl-modules/systems/bde/shared/shbde_iproc.c b/sdk-6.5.16/src/gpl-modules/systems/bde/shared/shbde_iproc.c @@ -0,0 +1,494 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#include <shbde_iproc.h> +#include <shbde_mdio.h> +#include <shbde_pci.h> + +/* 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 PAXB_0_CMICD_TO_PCIE_INTR_EN 0x2380 + +#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 + +#define PAXB_0_FUNC0_IMAP1_3 0x2d88 + +/* 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 +#define PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT 20 + +/* 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 0xb670: /* MO */ + case 0xb760: /* Maverick */ + icfg->iproc_ver = 0xB; + break; + case 0xb160: /* Hurricane3 */ + case 0x8440: /* Buckhound2 */ + case 0x8430: /* Foxhound2 */ + case 0x8540: /* Wolfhound2 */ + 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); + } + } + + /* Configure MSIX interrupt page, only need for iproc ver == 0x10 */ + if ((icfg->use_msi == 2) && (icfg->iproc_ver == 0x10)) { + unsigned int mask = (0x1 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT) - 1; + reg = ROFFS(iproc_regs, PAXB_0_FUNC0_IMAP1_3); + data = iproc32_read(shbde, reg); + data &= mask; + data |= 0x410 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT; + iproc32_write(shbde, reg, data); + } + + /* Disable INTx interrupt if MSI/MSIX is selected */ + reg = ROFFS(iproc_regs, PAXB_0_CMICD_TO_PCIE_INTR_EN); + data = iproc32_read(shbde, reg); + if (icfg->use_msi) { + data &= ~0x1; + } else { + data |= 0x1; + } + iproc32_write(shbde, reg, data); + + 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 == 0x10231000) || (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 == 0x10231000) || (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/sdk-6.5.16/src/gpl-modules/systems/bde/shared/shbde_mdio.c b/sdk-6.5.16/src/gpl-modules/systems/bde/shared/shbde_mdio.c @@ -0,0 +1,186 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2015 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#include <shbde_mdio.h> + +/* 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/sdk-6.5.16/src/gpl-modules/systems/bde/shared/shbde_pci.c b/sdk-6.5.16/src/gpl-modules/systems/bde/shared/shbde_pci.c @@ -0,0 +1,392 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#include <shbde_pci.h> + +/* 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/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/Makefile b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/Makefile @@ -0,0 +1,31 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/Makefile b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/Makefile @@ -0,0 +1,67 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c @@ -0,0 +1,8947 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <gmodule.h> /* Must be included first */ +#include <linux-bde.h> +#include <kcom.h> +#include <bcm-knet.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/random.h> +#include <linux/seq_file.h> +#include <linux/if_vlan.h> + + +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[8] = { 100000, 100000, 100000, 100000, 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[8] = { 0, 0, 0, 0, 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)"); + +/* 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 <linux-uk-proxy.h> + +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(4,7,0)) +#define NETDEV_UPDATE_TRANS_START_TIME(dev) dev->trans_start = jiffies +#else +#define NETDEV_UPDATE_TRANS_START_TIME(dev) netif_trans_update(dev) +#endif + +#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) */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) +#define bkn_vlan_hwaccel_put_tag(_skb, _proto, _tci) \ + __vlan_hwaccel_put_tag(_skb, _tci) +#else +#define bkn_vlan_hwaccel_put_tag(_skb, _proto, _tci) \ + __vlan_hwaccel_put_tag(_skb, htons(_proto), _tci) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) +#define bkn_dma_mapping_error(d, a) \ + dma_mapping_error(a) +#define bkn_pci_dma_mapping_error(d, a) \ + pci_dma_mapping_error(a) +#else +#define bkn_dma_mapping_error(d, a) \ + dma_mapping_error(d, a) +#define bkn_pci_dma_mapping_error(d, a) \ + pci_dma_mapping_error(d, a) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) +enum { + SKBTX_HW_TSTAMP = 1 << 0, + SKBTX_SW_TSTAMP = 1 << 1, + SKBTX_IN_PROGRESS = 1 << 2, +}; +struct skb_shared_hwtstamps { + ktime_t hwtstamp; + ktime_t syststamp; +}; +struct bkn_skb_shared_info { + uint8_t tx_flags; + struct skb_shared_hwtstamps hwtstamps; +}; +#define bkn_skb_shinfo(_skb) ((struct bkn_skb_shared_info *)(unsigned char *)_skb->end) +#define bkn_skb_tx_flags(_skb) bkn_skb_shinfo(_skb)->tx_flags +static inline struct skb_shared_hwtstamps *skb_hwtstamps(struct sk_buff *skb) +{ + return &bkn_skb_shinfo(skb)->hwtstamps; +} +void skb_tstamp_tx(struct sk_buff *orig_skb, struct skb_shared_hwtstamps *hwtstamps) +{ +} +static inline void bkn_skb_tx_timestamp(struct sk_buff *skb) +{ +} +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) +static inline ktime_t ns_to_ktime(u64 ns) +{ + static const ktime_t ktime; + return ktime; +} +#endif +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +#include <linux/net_tstamp.h> +enum { + SKBTX_HW_TSTAMP = 1 << 0, + SKBTX_SW_TSTAMP = 1 << 1, + SKBTX_IN_PROGRESS = 1 << 2, +}; +#define bkn_skb_tx_flags(_skb) skb_shinfo(_skb)->tx_flags.flags +static inline void bkn_skb_tx_timestamp(struct sk_buff *skb) +{ +} +#else +#include <linux/net_tstamp.h> +#define bkn_skb_tx_flags(_skb) skb_shinfo(_skb)->tx_flags +static inline void bkn_skb_tx_timestamp(struct sk_buff *skb) +{ + return skb_tx_timestamp(skb); +} +#endif + +#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) +#define DMA_MAPPING_ERROR(d,a) bkn_dma_mapping_error(d,a) +#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) +#define DMA_MAPPING_ERROR(d,a) bkn_pci_dma_mapping_error(d,a) +#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) + +#define PKT_TX_HDR_SIZE 16 + +static volatile int module_initialized; + +static ibde_t *kernel_bde = NULL; + +/* Descriptor info */ +typedef struct bkn_desc_info_s { + uint32_t *dcb_mem; + uint64_t dcb_dma; + struct sk_buff *skb; + uint64_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; + uint64_t dcb_dma; +} bkn_dcb_chain_t; + +#define MAX_TX_DCBS 64 +#define MAX_RX_DCBS 64 + +#define NUM_DMA_CHAN 8 +#define NUM_RX_CHAN 7 +#define NUM_CMICX_RX_CHAN 7 +#define NUM_CMICM_RX_CHAN 3 + +#define FCS_SZ 4 +#define TAG_SZ 4 + +/* 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) */ + int pkt_hdr_size; /* Packet header size */ + uint32_t ftmh_lb_key_ext_size; /* FTMH LB-Key Extension existence/size */ + uint32_t ftmh_stacking_ext_size; /* FTMH Stacking extension existence/size */ + uint32_t pph_base_size; /* Size of PPH base */ + uint32_t pph_lif_ext_size[8]; /* Size of PPH Lif extension header */ + uint8_t udh_enable; /* Indicates UDH existence */ + uint32_t udh_length_type[4]; /* Size of UDH header per type */ + int rx_chans; /* Number of Rx channels */ + uint32_t dma_hi; /* DMA higher address */ + 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 */ + uint64_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 */ + uint64_t halt_addr[NUM_DMA_CHAN]; /* DMA halt address */ + uint32_t cdma_channels; /* Active channels for Continuous DMA mode */ + uint32_t poll_channels; /* Channels for polling */ + uint32_t inst_id; /* Instance id of this device */ + int evt_idx; /* Event queue index for this device*/ + int basedev_suspended; /* Base device suspended */ + int tx_hwts; /* HW timestamp for Tx */ + int rx_hwts; /* HW timestamp for Rx */ + struct sk_buff_head tx_ptp_queue; /* Tx PTP skb queue */ + struct work_struct tx_ptp_work; /* Tx PTP work */ + 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; + +/* PTCH_2 */ +#define BKN_DNX_PTCH_2_SIZE 2 +/* ITMH */ +#define BKN_DNX_ITMH_SIZE 5 +/* Modlue Header */ +#define BKN_DNX_MODULE_HEADER_SIZE 20 +/* FTMH */ +#define BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_MSB 17 +#define BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_NOF_BITS 16 +#define BKN_DNX_FTMH_PP_DSP_MSB 33 +#define BKN_DNX_FTMH_PP_DSP_NOF_BITS 8 +#define BKN_DNX_FTMH_ACTION_TYPE_MSB 43 +#define BKN_DNX_FTMH_ACTION_TYPE_NOF_BITS 2 +#define BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_MSB 73 +#define BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_NOF_BITS 1 +#define BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_MSB 74 +#define BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_NOF_BITS 1 +#define BKN_DNX_FTMH_TM_DST_EXT_PRESENT_MSB 75 +#define BKN_DNX_FTMH_TM_DST_EXT_PRESENT_NOF_BITS 1 +#define BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_MSB 76 +#define BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_NOF_BITS 1 +#define BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_MSB 77 +#define BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_NOF_BITS 1 +#define BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_MSB 78 +#define BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_NOF_BITS 1 +/* Fix Length for FTMH and Extension headers */ +#define BKN_DNX_FTMH_BASE_SIZE 10 +#define BKN_DNX_FTMH_BIER_BFR_EXT_SIZE 2 +#define BKN_DNX_FTMH_TM_DST_EXT_SIZE 3 +#define BKN_DNX_FTMH_FLOW_ID_EXT_SIZE 3 +#define BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE 6 +/* TSH */ +#define BKN_DNX_TSH_SIZE 4 +/* PPH */ +#define BKN_DNX_PPH_BASE_TYPE_9 9 +#define BKN_DNX_PPH_BASE_TYPE_10 10 +#define BKN_DNX_PPH_BASE_TYPE_12 12 +#define BKN_DNX_PPH_9_FORWARD_DOMAIN_MSB 5 +#define BKN_DNX_PPH_9_FORWARD_DOMAIN_NOF_BITS 16 +#define BKN_DNX_PPH_9_LEARN_EXT_PRESENT_MSB 53 +#define BKN_DNX_PPH_9_LEARN_EXT_PRESENT_NOF_BITS 1 +#define BKN_DNX_PPH_9_FHEI_SIZE_MSB 54 +#define BKN_DNX_PPH_9_FHEI_SIZE_NOF_BITS 2 +#define BKN_DNX_PPH_9_LIF_EXT_TYPE_MSB 56 +#define BKN_DNX_PPH_9_LIF_EXT_TYPE_NOF_BITS 3 +#define BKN_DNX_PPH_10_FORWARD_DOMAIN_MSB 9 +#define BKN_DNX_PPH_10_FORWARD_DOMAIN_NOF_BITS 16 +#define BKN_DNX_PPH_10_LEARN_EXT_PRESENT_MSB 61 +#define BKN_DNX_PPH_10_LEARN_EXT_PRESENT_NOF_BITS 1 +#define BKN_DNX_PPH_10_FHEI_SIZE_MSB 62 +#define BKN_DNX_PPH_10_FHEI_SIZE_NOF_BITS 2 +#define BKN_DNX_PPH_10_LIF_EXT_TYPE_MSB 64 +#define BKN_DNX_PPH_10_LIF_EXT_TYPE_NOF_BITS 3 +#define BKN_DNX_PPH_12_FORWARD_DOMAIN_MSB 21 +#define BKN_DNX_PPH_12_FORWARD_DOMAIN_NOF_BITS 18 +#define BKN_DNX_PPH_12_LEARN_EXT_PRESENT_MSB 77 +#define BKN_DNX_PPH_12_LEARN_EXT_PRESENT_NOF_BITS 1 +#define BKN_DNX_PPH_12_FHEI_SIZE_MSB 78 +#define BKN_DNX_PPH_12_FHEI_SIZE_NOF_BITS 2 +#define BKN_DNX_PPH_12_LIF_EXT_TYPE_MSB 80 +#define BKN_DNX_PPH_12_LIF_EXT_TYPE_NOF_BITS 3 +/* PPH.FHEI_TYPE */ +#define BKN_DNX_PPH_FHEI_TYPE_SZ0 1 +#define BKN_DNX_PPH_FHEI_TYPE_SZ1 2 +#define BKN_DNX_PPH_FHEI_TYPE_SZ2 3 +/* FHEI */ +#define BKN_DNX_PPH_FHEI_SZ0_SIZE 3 +#define BKN_DNX_PPH_FHEI_SZ1_SIZE 5 +#define BKN_DNX_PPH_FHEI_SZ2_SIZE 8 +#define BKN_DNX_PPH_FHEI_TRAP_5B_QUALIFIER_MSB 0 +#define BKN_DNX_PPH_FHEI_TRAP_5B_QUALIFIER_NOF_BITS 27 +#define BKN_DNX_PPH_FHEI_TRAP_5B_CODE_MSB 27 +#define BKN_DNX_PPH_FHEI_TRAP_5B_CODE_NOF_BITS 9 +#define BKN_DNX_PPH_FHEI_TRAP_5B_TYPE_MSB 36 +#define BKN_DNX_PPH_FHEI_TRAP_5B_TYPE_NOF_BITS 4 +/* PPH Extension */ +#define BKN_DNX_PPH_LEARN_EXT_SIZE 19 +/* UDH */ +#define BKN_DNX_UDH_DATA_TYPE_0_MSB 0 +#define BKN_DNX_UDH_DATA_TYPE_0_NOF_BITS 2 +#define BKN_DNX_UDH_DATA_TYPE_1_MSB 2 +#define BKN_DNX_UDH_DATA_TYPE_1_NOF_BITS 2 +#define BKN_DNX_UDH_DATA_TYPE_2_MSB 4 +#define BKN_DNX_UDH_DATA_TYPE_2_NOF_BITS 2 +#define BKN_DNX_UDH_DATA_TYPE_3_MSB 6 +#define BKN_DNX_UDH_DATA_TYPE_3_NOF_BITS 2 +#define BKN_DNX_UDH_BASE_SIZE 1 + +#define BKN_DPP_HDR_MAX_SIZE 40 +/* PTCH_2 */ +#define BKN_DPP_PTCH_2_SIZE 2 +/* ITMH */ +#define BKN_DPP_ITMH_SIZE 4 +/* FTMH */ +#define BKN_DPP_FTMH_LB_EXT_EN 0x1 +#define BKN_DPP_FTMH_STACKING_EXT_EN 0x2 +#define BKN_DPP_FTMH_SIZE_BYTE 9 +#define BKN_DPP_FTMH_LB_EXT_SIZE_BYTE 1 +#define BKN_DPP_FTMH_STACKING_SIZE_BYTE 2 +#define BKN_DPP_FTMH_DEST_EXT_SIZE_BYTE 2 +#define BKN_DPP_FTMH_LB_EXT_SIZE_BYTE 1 +#define BKN_DPP_FTMH_PKT_SIZE_MSB 0 +#define BKN_DPP_FTMH_PKT_SIZE_NOF_BITS 14 +#define BKN_DPP_FTMH_TC_MSB 14 +#define BKN_DPP_FTMH_TC_NOF_BITS 3 +#define BKN_DPP_FTMH_SRC_SYS_PORT_MSB 17 +#define BKN_DPP_FTMH_SRC_SYS_PORT_NOF_BITS 16 +#define BKN_DPP_FTMH_EXT_DSP_EXIST_MSB 68 +#define BKN_DPP_FTMH_EXT_DSP_EXIST_NOF_BITS 1 +#define BKN_DPP_FTMH_EXT_MSB 45 +#define BKN_DPP_FTMH_EXT_NOF_BITS 2 +#define BKN_DPP_FTMH_FIRST_EXT_MSB 72 +#define BKN_DPP_FTMH_ACTION_TYPE_MSB 43 +#define BKN_DPP_FTMH_ACTION_TYPE_NOF_BITS 2 +#define BKN_DPP_FTMH_PPH_TYPE_MSB 45 +#define BKN_DPP_FTMH_PPH_TYPE_NOF_BITS 2 + +/* PPH */ +#define BKN_DPP_PPH_SIZE_BYTE 7 +#define BKN_DPP_PPH_EEI_EXTENSION_PRESENT_MSB 0 +#define BKN_DPP_PPH_EEI_EXTENSION_PRESENT_NOF_BITS 1 +#define BKN_DPP_PPH_LEARN_EXENSION_PRESENT_MSB 1 +#define BKN_DPP_PPH_LEARN_EXENSION_PRESENT_NOF_BITS 1 +#define BKN_DPP_PPH_FHEI_SIZE_MSB 2 +#define BKN_DPP_PPH_FHEI_SIZE_NOF_BITS 2 +#define BKN_DPP_PPH_FORWARD_CODE_MSB 4 +#define BKN_DPP_PPH_FORWARD_CODE_NOF_BITS 4 +#define BKN_DPP_PPH_VSI_MSB 22 +#define BKN_DPP_PPH_VSI_NOF_BITS 16 +/* FHEI TRAP/SNOOP 3B */ +#define BKN_DPP_PPH_FHEI_3B_SIZE_BYTE 3 +#define BKN_DPP_PPH_FHEI_5B_SIZE_BYTE 5 +#define BKN_DPP_PPH_FHEI_8B_SIZE_BYTE 8 +#define BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_MSB 0 +#define BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_NOF_BITS 16 +#define BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_MSB 16 +#define BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_NOF_BITS 8 +/* PPH extension */ +#define BKN_DPP_PPH_EXPLICIT_EDITING_INFOMATION_EXTENSION_SIZE_BYTE 3 +#define BKN_DPP_PPH_LEARN_EXTENSION_SIZE_BYTE 5 + +/* ftmh action type. */ +typedef enum bkn_dpp_ftmh_action_type_e { + BKN_DPP_FTMH_ACTION_TYPE_FORWARD = 0, /* TM action is forward */ + BKN_DPP_FTMH_ACTION_TYPE_SNOOP = 1, /* TM action is snoop */ + BKN_DPP_FTMH_ACTION_TYPE_INBOUND_MIRROR = 2, /* TM action is inbound mirror. */ + BKN_DPP_FTMH_ACTION_TYPE_OUTBOUND_MIRROR = 3 /* TM action is outbound mirror. */ +}bkn_dpp_ftmh_action_type_t; + +/* ftmh dest extension. */ +typedef struct bkn_dpp_ftmh_dest_extension_s { + uint8 valid; /* Set if the extension is present */ + uint32_t dst_sys_port; /* Destination System Port */ +} bkn_dpp_ftmh_dest_extension_t; + +/* dnx packet */ +typedef struct bkn_dune_system_header_info_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; + uint32_t system_header_size; + uint32_t ftmh_spa; /* FTMH: Source-System-Port-Aggregate*/ + uint32_t pph_forward_domain; /* PPH: Forward-Domain*/ + uint32_t fhei_qualifier; /* FHEI: Qualifier */ + uint32_t fhei_code; /* FHEI: Code */ + uint32_t fhei_type; /* FHEI: Type */ +} bkn_dune_system_header_info_t; + +#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 smp_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; + uint8_t system_headers[27]; + uint32_t system_headers_size; +} 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; +static knet_hw_tstamp_enable_cb_f knet_hw_tstamp_enable_cb = NULL; +static knet_hw_tstamp_enable_cb_f knet_hw_tstamp_disable_cb = NULL; +static knet_hw_tstamp_tx_time_get_cb_f knet_hw_tstamp_tx_time_get_cb = NULL; +static knet_hw_tstamp_tx_meta_get_cb_f knet_hw_tstamp_tx_meta_get_cb = NULL; +static knet_hw_tstamp_ptp_clock_index_cb_f knet_hw_tstamp_ptp_clock_index_cb = NULL; +static knet_hw_tstamp_rx_time_upscale_cb_f knet_hw_tstamp_rx_time_upscale_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(&current->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 <linux/kthread.h> +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 + +/* CMICx registers */ +#define CMICX_CMC_BASE 0x00000000 +#define CMICX_DMA_CTRLr (CMICX_CMC_BASE + 0x00002100) +#define CMICX_DMA_STATr (CMICX_CMC_BASE + 0x00002114) +#define CMICX_DMA_DESC_HIr (CMICX_CMC_BASE + 0x00002108) +#define CMICX_DMA_DESC_LOr (CMICX_CMC_BASE + 0x00002104) +#define CMICX_DMA_HALT_HIr (CMICX_CMC_BASE + 0x00002110) +#define CMICX_DMA_HALT_LOr (CMICX_CMC_BASE + 0x0000210c) +#define CMICX_IRQ_STATr (CMICX_CMC_BASE + 0x0000106c) +#define CMICX_IRQ_STAT_CLRr (CMICX_CMC_BASE + 0x00001074) +#define CMICX_IRQ_ENABr 0x18013100 +#define IHOST_GIC_GIC400_GICD_ISENABLERN_5r 0x10781114 +#define IHOST_GIC_GIC400_GICD_ICENABLERN_5r 0x10781194 + +/* CMICx interrupts reserved for kernel handler */ +#define CMICX_TXRX_IRQ_MASK 0xffffffff + +#define DEV_IS_CMICX(_sinfo) ((_sinfo)->cmic_type == 'x') +#define DEV_IS_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)) + +#define CMICX_DS_CMC_DESC_DONE(ch) (0x00000001 << ((ch) * 4)) +#define CMICX_DS_CMC_CHAIN_DONE(ch) (0x00000002 << ((ch) * 4)) +#define CMICX_DS_CMC_CTRLD_INT(ch) (0x00000008 << ((ch) * 4)) +#define CMICX_DS_CMC_DMA_CHAIN_DONE (0x00000001) +#define CMICX_DS_CMC_DMA_ACTIVE (0x00000002) + +#define DMA_TO_BUS_HI(dma) ((dma) | sinfo->dma_hi) +#define BUS_TO_DMA_HI(bus) ((bus) & ~sinfo->dma_hi) + +/* + * 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) + +#define CMICX_DC_CMC_DIRECTION (0x00000001) +#define CMICX_DC_CMC_ENABLE (0x00000002) +#define CMICX_DC_CMC_ABORT (0x00000004) +#define CMICX_DC_CMC_CTRLD_INT (0x00000080) +#define CMICX_DC_CMC_CONTINUOUS (0x00000100) + +/* + * 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, uint64_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, uint64_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 +xgsx_dma_chain_clear(bkn_switch_info_t *sinfo, int chan) +{ + uint32_t ctrl, stat; + + /* Disabing DMA clears chain done */ + DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl); + ctrl &= ~(CMICX_DC_CMC_ENABLE | CMICX_DC_CMC_ABORT); + DEV_WRITE32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, ctrl); + + stat = CMICX_DS_CMC_CHAIN_DONE(chan); + DEV_WRITE32(sinfo, CMICX_IRQ_STAT_CLRr, stat); + + MEMORY_BARRIER; + + /* Flush write buffer */ + DEV_READ32(sinfo, CMICX_IRQ_STAT_CLRr, &stat); + + MEMORY_BARRIER; +} + +static inline void +xgsx_dma_desc_clear(bkn_switch_info_t *sinfo, int chan) +{ + uint32_t stat; + + if (CDMA_CH(sinfo, chan)) { + stat = CMICX_DS_CMC_CTRLD_INT(chan); + } else { + stat = CMICX_DS_CMC_DESC_DONE(chan); + } + DEV_WRITE32(sinfo, CMICX_IRQ_STAT_CLRr, stat); + + MEMORY_BARRIER; + + /* Flush write buffer */ + DEV_READ32(sinfo, CMICX_IRQ_STAT_CLRr, &stat); + + MEMORY_BARRIER; +} + +static int +xgsx_dma_chan_clear(bkn_switch_info_t *sinfo, int chan) +{ + xgsx_dma_chain_clear(sinfo, chan); + xgsx_dma_desc_clear(sinfo, chan); + + return 0; +} + +static inline void +xgsx_cdma_halt_set(bkn_switch_info_t *sinfo, int chan) +{ + DEV_WRITE32(sinfo, CMICX_DMA_HALT_LOr + 0x80 * chan, + sinfo->halt_addr[chan]); + DEV_WRITE32(sinfo, CMICX_DMA_HALT_HIr + 0x80 * chan, + DMA_TO_BUS_HI(sinfo->halt_addr[chan] >> 32)); + + MEMORY_BARRIER; +} + +static int +xgsx_dma_chan_init(bkn_switch_info_t *sinfo, int chan, int dir) +{ + uint32_t ctrl; + + DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl); + ctrl &= ~CMICX_DC_CMC_DIRECTION; + if (dir) { + ctrl |= CMICX_DC_CMC_DIRECTION; + } + if (CDMA_CH(sinfo, chan)) { + ctrl |= CMICX_DC_CMC_CONTINUOUS | CMICX_DC_CMC_CTRLD_INT; + xgsx_cdma_halt_set(sinfo, chan); + } + DEV_WRITE32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, ctrl); + + MEMORY_BARRIER; + + return 0; +} + +static int +xgsx_dma_chan_start(bkn_switch_info_t *sinfo, int chan, uint64_t dcb) +{ + uint32_t ctrl; + + /* Write the DCB address to the DESC address for this channel */ + DEV_WRITE32(sinfo, CMICX_DMA_DESC_LOr + 0x80 * chan, dcb); + DEV_WRITE32(sinfo, CMICX_DMA_DESC_HIr + 0x80 * chan, DMA_TO_BUS_HI(dcb >> 32)); + + MEMORY_BARRIER; + + /* Kick it off */ + DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl); + ctrl |= CMICX_DC_CMC_ENABLE; + DEV_WRITE32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, ctrl); + + MEMORY_BARRIER; + + return 0; +} + +static int +xgsx_dma_chan_abort(bkn_switch_info_t *sinfo, int chan, int polls) +{ + uint32_t ctrl, stat; + int p; + + /* Skip abort sequence if channel is not active */ + DEV_READ32(sinfo, CMICX_DMA_STATr + 0x80 * chan, &stat); + if (!(stat & CMICX_DS_CMC_DMA_ACTIVE)) { + return 0; + } + + /* Abort the channel */ + DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl); + ctrl |= CMICX_DC_CMC_ENABLE | CMICX_DC_CMC_ABORT; + DEV_WRITE32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, ctrl); + + MEMORY_BARRIER; + + /* Poll for abort completion */ + for (p = 0; p < polls; p++) { + DEV_READ32(sinfo, CMICX_DMA_STATr + 0x80 * chan, &stat); + if (!(stat & CMICX_DS_CMC_DMA_ACTIVE)) { + /* Clear up channel */ + xgsx_dma_chan_clear(sinfo, chan); + return polls; + } + } + + DBG_WARN(("DMA channel %d abort failed\n", chan)); + + return -1; +} + +static inline void +xgsx_irq_mask_set(bkn_switch_info_t *sinfo, uint32_t mask) +{ + uint32_t irq_mask_reg = CMICX_IRQ_ENABr; + uint32_t irq_mask, irq_fmask, disable_mask; + + if (sinfo->napi_poll_mode) { + mask = 0; + } + + if (sinfo->cpu_no == 1) { + lkbde_irq_mask_get(sinfo->dev_no, &irq_mask, &irq_fmask); + disable_mask = ~mask & (irq_mask & irq_fmask); + if (disable_mask) { + lkbde_irq_mask_set(sinfo->dev_no | LKBDE_ISR2_DEV | LKBDE_IPROC_REG, + IHOST_GIC_GIC400_GICD_ICENABLERN_5r, disable_mask, CMICX_TXRX_IRQ_MASK); + } + irq_mask_reg = IHOST_GIC_GIC400_GICD_ISENABLERN_5r; + } + + lkbde_irq_mask_set(sinfo->dev_no | LKBDE_ISR2_DEV | LKBDE_IPROC_REG, + irq_mask_reg, mask, CMICX_TXRX_IRQ_MASK); +} + +static inline void +xgsx_irq_mask_enable(bkn_switch_info_t *sinfo, int chan, int update_hw) +{ + uint32_t mask; + + if (CDMA_CH(sinfo, chan)) { + mask = CMICX_DS_CMC_CTRLD_INT(chan); + } else { + if (chan == XGS_DMA_TX_CHAN) { + mask = CMICX_DS_CMC_CHAIN_DONE(chan); + } else { + mask = CMICX_DS_CMC_DESC_DONE(chan) | + CMICX_DS_CMC_CHAIN_DONE(chan); + } + } + + sinfo->irq_mask |= mask; + + if (update_hw) { + xgsx_irq_mask_set(sinfo, sinfo->irq_mask); + } +} + +static inline void +xgsx_irq_mask_disable(bkn_switch_info_t *sinfo, int chan, int update_hw) +{ + uint32_t mask; + + if (CDMA_CH(sinfo, chan)) { + mask = CMICX_DS_CMC_CTRLD_INT(chan); + } else { + if (chan == XGS_DMA_TX_CHAN) { + mask = CMICX_DS_CMC_CHAIN_DONE(chan); + } else { + mask = CMICX_DS_CMC_DESC_DONE(chan) | + CMICX_DS_CMC_CHAIN_DONE(chan); + } + } + + sinfo->irq_mask &= ~mask; + + if (update_hw) { + xgsx_irq_mask_set(sinfo, sinfo->irq_mask); + } +} + +static inline void +dev_dma_chain_clear(bkn_switch_info_t *sinfo, int chan) +{ + if (DEV_IS_CMICX(sinfo)) { + xgsx_dma_chain_clear(sinfo, chan); + } else if (DEV_IS_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_IS_CMICX(sinfo)) { + xgsx_dma_desc_clear(sinfo, chan); + } else if (DEV_IS_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_IS_CMICX(sinfo)) { + return xgsx_dma_chan_clear(sinfo, chan); + } else if (DEV_IS_CMICM(sinfo)) { + return xgsm_dma_chan_clear(sinfo, chan); + } else { + return xgs_dma_chan_clear(sinfo, chan); + } +} + +static void +dev_cdma_halt_set(bkn_switch_info_t *sinfo, int chan) +{ + if (DEV_IS_CMICX(sinfo)) { + xgsx_cdma_halt_set(sinfo, chan); + } else if (DEV_IS_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_IS_CMICX(sinfo)) { + return xgsx_dma_chan_init(sinfo, chan, dir); + } else if (DEV_IS_CMICM(sinfo)) { + return xgsm_dma_chan_init(sinfo, chan, dir); + } else { + return xgs_dma_chan_init(sinfo, chan, dir); + } +} + +static int +dev_dma_chan_start(bkn_switch_info_t *sinfo, int chan, uint64_t dcb) +{ + if (DEV_IS_CMICX(sinfo)) { + return xgsx_dma_chan_start(sinfo, chan, dcb); + } else if (DEV_IS_CMICM(sinfo)) { + return xgsm_dma_chan_start(sinfo, chan, dcb); + } else { + 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_IS_CMICX(sinfo)) { + return xgsx_dma_chan_abort(sinfo, chan, polls); + } else if (DEV_IS_CMICM(sinfo)) { + return xgsm_dma_chan_abort(sinfo, chan, polls); + } else { + 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_IS_CMICX(sinfo)) { + xgsx_irq_mask_set(sinfo, mask); + } else if (DEV_IS_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_IS_CMICX(sinfo)) { + xgsx_irq_mask_enable(sinfo, chan, update_hw); + } else if (DEV_IS_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_IS_CMICX(sinfo)) { + xgsx_irq_mask_disable(sinfo, chan, update_hw); + } else if (DEV_IS_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; + dma_addr_t dcb_dma = 0; + + 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 * sinfo->rx_chans; + + sinfo->dcb_mem = DMA_ALLOC_COHERENT(sinfo->dma_dev, + sinfo->dcb_mem_size, + &dcb_dma); + if (sinfo->dcb_mem == NULL) { + gprintk("DCB memory allocation (%d bytes) failed.\n", + sinfo->dcb_mem_size); + return -ENOMEM; + } + sinfo->dcb_dma = (uint64_t)dcb_dma; + + 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, (dma_addr_t)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 < sinfo->rx_chans; chan++) { + bkn_clean_rx_dcbs(sinfo, chan); + } +} + +static void +bkn_init_dcbs(bkn_switch_info_t *sinfo) +{ + int dcb_size; + uint32_t *dcb_mem; + uint64_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)) { + if (sinfo->cmic_type == 'x') { + dcb_mem[2] |= 1 << 24 | 1 << 16; + } else { + dcb_mem[1] |= 1 << 24 | 1 << 16; + } + if (idx == MAX_TX_DCBS) { + if (sinfo->cmic_type == 'x') { + dcb_mem[0] = sinfo->tx.desc[0].dcb_dma; + dcb_mem[1] = DMA_TO_BUS_HI(sinfo->tx.desc[0].dcb_dma >> 32); + dcb_mem[2] |= 1 << 18; + } else { + dcb_mem[0] = sinfo->tx.desc[0].dcb_dma; + dcb_mem[1] |= 1 << 18; + } + } + } + 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; + sinfo->tx.cur = 0; + sinfo->tx.dirty = 0; + + DBG_DCB_TX(("Tx DCBs @ 0x%08x.\n", + (uint32_t)sinfo->tx.desc[0].dcb_dma)); + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + for (idx = 0; idx < (MAX_RX_DCBS + 1); idx++) { + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + if (sinfo->cmic_type == 'x') { + dcb_mem[2] |= 1 << 24 | 1 << 16; + } else { + dcb_mem[1] |= 1 << 24 | 1 << 16; + } + if (idx == MAX_RX_DCBS) { + if (sinfo->cmic_type == 'x') { + dcb_mem[0] = sinfo->rx[chan].desc[0].dcb_dma; + dcb_mem[1] = DMA_TO_BUS_HI(sinfo->rx[chan].desc[0].dcb_dma >> 32); + dcb_mem[2] |= 1 << 18; + } else { + dcb_mem[0] = sinfo->rx[chan].desc[0].dcb_dma; + dcb_mem[1] |= 1 << 18; + } + } + } + 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; + sinfo->rx[chan].cur = 0; + sinfo->rx[chan].dirty = 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) { + if (wsize > 4) { + 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_TX(("%s: 0x%08x 0x%08x 0x%08x 0x%08x\n", + prefix, dcb[0], dcb[1], dcb[2], dcb[3])); + } + } else { + if (wsize > 4) { + 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])); + } else { + DBG_DCB_RX(("%s: 0x%08x 0x%08x 0x%08x 0x%08x\n", + prefix, dcb[0], dcb[1], dcb[2], dcb[3])); + } + } +} + +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; + } + + 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_cdma_goto(bkn_switch_info_t *sinfo, int chan, uint64_t dcb) +{ + if (sinfo->basedev_suspended) { + return; + } + + /* Set the new halt location */ + sinfo->halt_addr[chan] = dcb; + dev_cdma_halt_set(sinfo, chan); +} + +static void +bkn_api_rx_restart(bkn_switch_info_t *sinfo, int chan) +{ + bkn_dcb_chain_t *dcb_chain; + 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, chan); +} + +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; + uint64_t pkt_dma; + 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 ((sinfo->cmic_type == 'x' && (dcb[2] & 0xffff) < pktlen) || + (sinfo->cmic_type != 'x' && (dcb[1] & 0xffff) < pktlen)) { + DBG_WARN(("Rx API buffer too small\n")); + return -1; + } + if (sinfo->cmic_type == 'x') { + pkt_dma = BUS_TO_DMA_HI(dcb[1]); + pkt_dma = pkt_dma << 32 | dcb[0]; + } else { + pkt_dma = dcb[0]; + } + pkt = (uint8_t *)kernel_bde->p2l(sinfo->dev_no, (sal_paddr_t)pkt_dma); + 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 */ + if (sinfo->cmic_type != 'x') { + 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; + MEMORY_BARRIER; + + 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 ((sinfo->cmic_type == 'x' && dcb[2] & (1 << 18)) || + (sinfo->cmic_type != 'x' && dcb[1] & (1 << 18))) { + /* Get the next chain if reload done */ + dcb[sinfo->dcb_wsize-1] |= 1 << 31 | SOC_DCB_KNET_DONE; + MEMORY_BARRIER; + 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 ((sinfo->cmic_type == 'x' && (dcb[2] & (1 << 16)) == 0) || + (sinfo->cmic_type != 'x' && (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; + uint32_t resv_size = sinfo->cmic_type == 'x' ? RCPU_HDR_SIZE : RCPU_RX_ENCAP_SIZE; + uint32_t meta_size = sinfo->cmic_type == 'x' ? RCPU_RX_META_SIZE : 0; + 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, resv_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 + meta_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); + if (DMA_MAPPING_ERROR(sinfo->dma_dev, desc->skb_dma)) { + dev_kfree_skb_any(skb); + desc->skb = NULL; + break; + } + 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; + dcb[0] = desc->skb_dma; + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + if (sinfo->cmic_type == 'x') { + dcb[2] |= 1 << 24 | 1 << 16; + } else { + dcb[1] |= 1 << 24 | 1 << 16; + } + } else { + prev = PREV_IDX(sinfo->rx[chan].cur, MAX_RX_DCBS); + if (prev < (MAX_RX_DCBS - 1)) { + if (sinfo->cmic_type == 'x') { + sinfo->rx[chan].desc[prev].dcb_mem[2] |= 1 << 16; + } else { + sinfo->rx[chan].desc[prev].dcb_mem[1] |= 1 << 16; + } + } + } + if (sinfo->cmic_type == 'x') { + dcb[1] = DMA_TO_BUS_HI(desc->skb_dma >> 32); + dcb[2] |= rx_buffer_size + meta_size; + } else { + dcb[1] |= rx_buffer_size; + } + + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) && + sinfo->rx[chan].tokens > MAX_RX_DCBS) { + /* DMA run to the new halt location */ + bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, desc->dcb_dma); + } + + 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 < sinfo->rx_chans; 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 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 < sinfo->rx_chans; chan++) { + bkn_dma_abort_rx(sinfo, chan); + } + + return 0; +} + +static int +device_is_dpp(bkn_switch_info_t *sinfo) +{ + int is_dpp = 0; + + is_dpp = (sinfo->dcb_type == 28) ? 1 : 0; + return is_dpp; +} + +static int +device_is_dnx(bkn_switch_info_t *sinfo) +{ + int is_dnx = 0; + + /* No EP_TO_CPU header for DNX(JR2) */ + is_dnx = ((sinfo->cmic_type == 'x') && (sinfo->pkt_hdr_size ==0)) ? 1 : 0; + return is_dnx; +} + +/* is DPP or is DNX*/ +static int +device_is_sand(bkn_switch_info_t *sinfo) +{ + int is_sand = 0; + + if (device_is_dpp(sinfo) || device_is_dnx(sinfo)) { + is_sand = 1; + } + return is_sand; +} + +static bkn_filter_t * +bkn_match_rx_pkt(bkn_switch_info_t *sinfo, uint8_t *pkt, int pktlen, + void *meta, int chan, bkn_filter_t *cbf) +{ + struct list_head *list; + bkn_filter_t *filter; + kcom_filter_t scratch, *kf; + uint8_t *oob = (uint8_t *)meta; + 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])); + + if (device_is_dnx(sinfo)) { + DBG_DUNE(("Filter: size = %d (wsize %d)\n", size, wsize)); + for (idx = 0; idx < wsize; idx++) + { + DBG_DUNE(("OOB[%d]: 0x%08x [0x%08x]\n", idx, kf->data.w[idx], kf->mask.w[idx])); + } + DBG_DUNE(("Meta Data [+ Selected Raw packet data]\n")); + for (idx = 0; idx < wsize; idx++) + { + DBG_DUNE(("Scratch[%d]: 0x%08x\n", idx, scratch.data.w[idx])); + } + } + + match = 1; + if (match) { + if (device_is_sand(sinfo)) + { + /** priority 0 means no priority check */ + if (kf->priority && (kf->priority < (num_rx_prio * sinfo->rx_chans))) { + if (kf->priority < (num_rx_prio * chan) || + kf->priority >= (num_rx_prio * (chan + 1))) { + match = 0; + } + } + } + else { + if (kf->priority < (num_rx_prio * sinfo->rx_chans)) { + 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) { + memset(cbf, 0, sizeof(*cbf)); + memcpy(&cbf->kf, kf, sizeof(cbf->kf)); + if (knet_filter_cb(pkt, pktlen, sinfo->dev_no, + meta, 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_hw_tstamp_rx_set(bkn_switch_info_t *sinfo, struct sk_buff *skb, uint32 *meta) +{ + struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); + uint32_t *md = meta; + uint64_t ts = 0; + + switch (sinfo->dcb_type) { + case 26: + case 32: + case 33: + ts = md[14]; + ts = ts << 32 | md[12]; + break; + case 36: + ts = md[10]; + break; + case 38: + ts = md[4] & 0xffff; + ts = ts << 32 | md[5]; + break; + default: + return -1; + } + + if (knet_hw_tstamp_rx_time_upscale_cb) { + if (knet_hw_tstamp_rx_time_upscale_cb(sinfo->dev_no, &ts) < 0) { + return -1; + } + } + + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); + shhwtstamps->hwtstamp = ns_to_ktime(be64_to_cpu(ts)); + + return 0; +} + +static int +bkn_add_rcpu_encap(bkn_switch_info_t *sinfo, struct sk_buff *skb, void *meta) +{ + int pktlen = skb->len; + uint32_t *dmeta, *smeta, wsize, psize; + int idx; + + /* Add and clear RCPU encapsulation */ + if (sinfo->cmic_type == 'x') { + psize = RCPU_HDR_SIZE + sinfo->pkt_hdr_size; + skb_push(skb, psize); + memset(skb->data, 0, RCPU_HDR_SIZE); + } else { + psize = RCPU_RX_ENCAP_SIZE; + skb_push(skb, psize); + memset(skb->data, 0, RCPU_RX_ENCAP_SIZE); + } + + /* RCPU Header */ + memcpy(skb->data, &skb->data[psize], 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 */ + dmeta = (uint32_t *)&skb->data[RCPU_HDR_SIZE]; + smeta = sinfo->cmic_type == 'x' ? (uint32_t *)meta : (uint32_t *)meta + 2; + wsize = sinfo->cmic_type == 'x' ? sinfo->pkt_hdr_size / 4 : sinfo->dcb_wsize - 3; + for (idx = 0; idx < wsize; idx++) { + dmeta[idx] = htonl(smeta[idx]); + } + + 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 +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_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_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_dpp_packet_parse_ftmh(bkn_switch_info_t *sinfo, uint8_t hdr_buff[], bkn_dune_system_header_info_t *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_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DPP_FTMH_PKT_SIZE_MSB, + BKN_DPP_FTMH_PKT_SIZE_NOF_BITS, + &fld_val); + packet_info->ftmh.packet_size = fld_val; + /* Traffic-class */ + bkn_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DPP_FTMH_TC_MSB, + BKN_DPP_FTMH_TC_NOF_BITS, + &fld_val); + packet_info->ftmh.prio = fld_val; + /* Source-system-port-aggregate */ + bkn_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DPP_FTMH_SRC_SYS_PORT_MSB, + BKN_DPP_FTMH_SRC_SYS_PORT_NOF_BITS, + &fld_val); + packet_info->ftmh.src_sys_port = fld_val; + /* TM-action-type */ + bkn_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DPP_FTMH_ACTION_TYPE_MSB, + BKN_DPP_FTMH_ACTION_TYPE_NOF_BITS, + &fld_val); + packet_info->ftmh.action_type = fld_val; + /* PPH-type */ + bkn_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DPP_FTMH_PPH_TYPE_MSB, + BKN_DPP_FTMH_PPH_TYPE_NOF_BITS, + &fld_val); + packet_info->ftmh.pph_type = fld_val; + + packet_info->ntwrk_header_ptr += BKN_DPP_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 ((sinfo->pkt_hdr_size & BKN_DPP_FTMH_LB_EXT_EN) == BKN_DPP_FTMH_LB_EXT_EN) + { + packet_info->ntwrk_header_ptr += BKN_DPP_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_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DPP_FTMH_EXT_DSP_EXIST_MSB, + BKN_DPP_FTMH_EXT_DSP_EXIST_NOF_BITS, + &dsp_ext_exist); + if (dsp_ext_exist) + { + packet_info->ntwrk_header_ptr += BKN_DPP_FTMH_DEST_EXT_SIZE_BYTE; + DBG_DUNE(("FTMH(%d) DSP-extension-present 1\n", packet_info->ntwrk_header_ptr)); + } + + /* stacking ext */ + if ((sinfo->pkt_hdr_size & BKN_DPP_FTMH_STACKING_EXT_EN) == BKN_DPP_FTMH_STACKING_EXT_EN) + { + packet_info->ntwrk_header_ptr += BKN_DPP_FTMH_STACKING_SIZE_BYTE; + DBG_DUNE(("FTMH(%d) FTMH Stacking Extension is present\n", packet_info->ntwrk_header_ptr)); + } + return; +} + +static void +bkn_dpp_packet_parse_internal(bkn_switch_info_t *sinfo, uint8_t hdr_buff[], bkn_dune_system_header_info_t *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_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DPP_PPH_EEI_EXTENSION_PRESENT_MSB, + BKN_DPP_PPH_EEI_EXTENSION_PRESENT_NOF_BITS, + &eei_extension_present); + bkn_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DPP_PPH_LEARN_EXENSION_PRESENT_MSB, + BKN_DPP_PPH_LEARN_EXENSION_PRESENT_NOF_BITS, + &learn_extension_present); + bkn_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DPP_PPH_FHEI_SIZE_MSB, + BKN_DPP_PPH_FHEI_SIZE_NOF_BITS, + &fhei_size); + bkn_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DPP_PPH_FORWARD_CODE_MSB, + BKN_DPP_PPH_FORWARD_CODE_NOF_BITS, + &forward_code); + /* 7: CPU-Trap */ + is_trapped = (uint8_t)(forward_code == 7); + + bkn_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DPP_PPH_VSI_MSB, + BKN_DPP_PPH_VSI_NOF_BITS, + &fld_val); + packet_info->internal.vsi = fld_val; + + /* size of PPH base is 7 */ + packet_info->ntwrk_header_ptr += BKN_DPP_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_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_MSB, + BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_NOF_BITS, + &fld_val); + packet_info->internal.trap_qualifier = fld_val; + /* CPU trap code */ + bkn_bitstream_get_field( + &hdr_buff[header_ptr], + BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_MSB, + BKN_DPP_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_DPP_PPH_FHEI_3B_SIZE_BYTE; + break; + case 2: + packet_info->ntwrk_header_ptr += BKN_DPP_PPH_FHEI_5B_SIZE_BYTE; + break; + case 3: + packet_info->ntwrk_header_ptr += BKN_DPP_PPH_FHEI_8B_SIZE_BYTE; + break; + default: + break; + } + if (eei_extension_present) { + packet_info->ntwrk_header_ptr += BKN_DPP_PPH_EXPLICIT_EDITING_INFOMATION_EXTENSION_SIZE_BYTE; + } + if (learn_extension_present) { + packet_info->ntwrk_header_ptr += BKN_DPP_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_dpp_packet_header_parse(bkn_switch_info_t *sinfo, uint8 *buff, uint32_t buff_len, bkn_dune_system_header_info_t *packet_info) +{ + uint8_t hdr_buff[BKN_DPP_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_DPP_HDR_MAX_SIZE ? buff_len: BKN_DPP_HDR_MAX_SIZE; + memcpy(hdr_buff, buff, hdr_size); + + /* FTMH */ + bkn_dpp_packet_parse_ftmh(sinfo, 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_dune_system_header_info_t)); + 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_dpp_packet_parse_internal(sinfo, &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_dnx_packet_header_parse(bkn_switch_info_t *sinfo, uint8 *buf, uint32_t buf_len, bkn_dune_system_header_info_t *packet_info) +{ + uint32_t fld_val; + uint32_t hdr_size = 0; + uint32_t pkt_offset_ingress_untrapped =0; + uint8_t tm_dst_ext_present = 0; + uint8_t app_specific_ext_size = 0; + uint8_t flow_id_ext_size = 0; + uint8_t bier_bfr_ext_size = 0; + uint8_t is_pph_en = 0; + uint8_t is_tsh_en = 0; + + if ((buf == NULL) || (packet_info == NULL)) { + return -1; + } + + /* FTMH: Source-System-Port-Aggregate */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_MSB, + BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_NOF_BITS, + &fld_val); + packet_info->ftmh_spa = fld_val; + /* FTMH: PPH-Type TSH */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_MSB, + BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_NOF_BITS, + &fld_val); + is_tsh_en = fld_val; + /* FTMH: PPH-Type PPH base */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_MSB, + BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_NOF_BITS, + &fld_val); + is_pph_en = fld_val; + /* FTMH: TM-Destination-Extension-Present */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_FTMH_TM_DST_EXT_PRESENT_MSB, + BKN_DNX_FTMH_TM_DST_EXT_PRESENT_NOF_BITS, + &fld_val); + tm_dst_ext_present = fld_val; + /* FTMH: Application-Specific-Extension-Size */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_MSB, + BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_NOF_BITS, + &fld_val); + app_specific_ext_size = fld_val; + /* FTMH: Flow-ID-Extension-Size */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_MSB, + BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_NOF_BITS, + &fld_val); + flow_id_ext_size = fld_val; + /* FTMH: BIER-BFR-Extension-Size */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_MSB, + BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_NOF_BITS, + &fld_val); + bier_bfr_ext_size = fld_val; + + hdr_size = BKN_DNX_FTMH_BASE_SIZE; + pkt_offset_ingress_untrapped = BKN_DNX_FTMH_BASE_SIZE; + + DBG_DUNE(("FTMH(%d) source-system-port 0x%x is_tsh_en %d is_pph_en %d\n", + hdr_size, packet_info->ftmh_spa, is_tsh_en, is_pph_en)); + + /* FTMH LB-Key Extension */ + if (sinfo->ftmh_lb_key_ext_size > 0) + { + hdr_size += sinfo->ftmh_lb_key_ext_size; + DBG_DUNE(("FTMH LB-Key Extension(%d) is present\n", sinfo->ftmh_lb_key_ext_size)); + } + /* FTMH Stacking Extension */ + if (sinfo->ftmh_stacking_ext_size > 0) + { + hdr_size += sinfo->ftmh_stacking_ext_size; + DBG_DUNE(("FTMH Stacking Extension(%d) is present\n", sinfo->ftmh_stacking_ext_size)); + } + /* FTMH BIER BFR Extension */ + if (bier_bfr_ext_size > 0) + { + hdr_size += BKN_DNX_FTMH_BIER_BFR_EXT_SIZE; + DBG_DUNE(("FTMH BIER BFR Extension(2) is present\n")); + } + /* FTMH TM Destination Extension */ + if (tm_dst_ext_present > 0) + { + hdr_size += BKN_DNX_FTMH_TM_DST_EXT_SIZE; + DBG_DUNE(("FTMH TM Destination Extension(3) is present\n")); + } + /* FTMH Application Specific Extension */ + if (app_specific_ext_size > 0) + { + hdr_size += BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE; + DBG_DUNE(("FTMH Application Specific Extension(6) is present\n")); + } + /* FTMH Flow-ID Extension */ + if (flow_id_ext_size > 0) + { + hdr_size += BKN_DNX_FTMH_FLOW_ID_EXT_SIZE; + DBG_DUNE(("FTMH Flow-ID Extension(3) is present\n")); + } + + /* Given the packet is trapped to CPU */ + + /* Time-Stamp Header */ + if (is_tsh_en == TRUE) + { + hdr_size += BKN_DNX_TSH_SIZE; + DBG_DUNE(("Time-Stamp Header(4) is present\n")); + } + + /* Packet Processing Header */ + if (is_pph_en) + { + uint8_t learn_ext_present; + uint8_t fhei_size; + uint8_t lif_ext_type; + + switch (sinfo->pph_base_size) + { + case BKN_DNX_PPH_BASE_TYPE_9: + /* FTMH: Forward-Domain */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_9_FORWARD_DOMAIN_MSB, + BKN_DNX_PPH_9_FORWARD_DOMAIN_NOF_BITS, + &fld_val); + packet_info->pph_forward_domain = fld_val; + /* FTMH: Learn-Extension-Present */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_9_LEARN_EXT_PRESENT_MSB, + BKN_DNX_PPH_9_LEARN_EXT_PRESENT_NOF_BITS, + &fld_val); + learn_ext_present = fld_val; + /* FTMH: FHEI-Size */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_9_FHEI_SIZE_MSB, + BKN_DNX_PPH_9_FHEI_SIZE_NOF_BITS, + &fld_val); + fhei_size = fld_val; + /* FTMH: LIF-Extension-Type */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_9_LIF_EXT_TYPE_MSB, + BKN_DNX_PPH_9_LIF_EXT_TYPE_NOF_BITS, + &fld_val); + lif_ext_type = fld_val; + + hdr_size += BKN_DNX_PPH_BASE_TYPE_9; + DBG_DUNE(("PPH(10) FWD_DOMAIN %d, LEARN_EXT %d, FHEI_SIZE %d, LIF_EXT %d \n", + packet_info->pph_forward_domain, learn_ext_present, fhei_size, lif_ext_type)); + break; + case BKN_DNX_PPH_BASE_TYPE_10: + /* FTMH: Forward-Domain */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_10_FORWARD_DOMAIN_MSB, + BKN_DNX_PPH_10_FORWARD_DOMAIN_NOF_BITS, + &fld_val); + packet_info->pph_forward_domain = fld_val; + /* FTMH: Learn-Extension-Present */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_10_LEARN_EXT_PRESENT_MSB, + BKN_DNX_PPH_10_LEARN_EXT_PRESENT_NOF_BITS, + &fld_val); + learn_ext_present = fld_val; + /* FTMH: FHEI-Size */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_10_FHEI_SIZE_MSB, + BKN_DNX_PPH_10_FHEI_SIZE_NOF_BITS, + &fld_val); + fhei_size = fld_val; + /* FTMH: LIF-Extension-Type */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_10_LIF_EXT_TYPE_MSB, + BKN_DNX_PPH_10_LIF_EXT_TYPE_NOF_BITS, + &fld_val); + lif_ext_type = fld_val; + + hdr_size += BKN_DNX_PPH_BASE_TYPE_10; + DBG_DUNE(("PPH(10) FWD_DOMAIN %d, LEARN_EXT %d, FHEI_SIZE %d, LIF_EXT %d \n", + packet_info->pph_forward_domain, learn_ext_present, fhei_size, lif_ext_type)); + break; + case BKN_DNX_PPH_BASE_TYPE_12: + /* FTMH: Forward-Domain */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_12_FORWARD_DOMAIN_MSB, + BKN_DNX_PPH_12_FORWARD_DOMAIN_NOF_BITS, + &fld_val); + packet_info->pph_forward_domain = fld_val; + /* FTMH: Learn-Extension-Present */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_12_LEARN_EXT_PRESENT_MSB, + BKN_DNX_PPH_12_LEARN_EXT_PRESENT_NOF_BITS, + &fld_val); + learn_ext_present = fld_val; + /* FTMH: FHEI-Size */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_12_FHEI_SIZE_MSB, + BKN_DNX_PPH_12_FHEI_SIZE_NOF_BITS, + &fld_val); + fhei_size = fld_val; + /* FTMH: LIF-Extension-Type */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_12_LIF_EXT_TYPE_MSB, + BKN_DNX_PPH_12_LIF_EXT_TYPE_NOF_BITS, + &fld_val); + lif_ext_type = fld_val; + + hdr_size += BKN_DNX_PPH_BASE_TYPE_12; + DBG_DUNE(("PPH(12) FWD_DOMAIN %d, LEARN_EXT %d, FHEI_SIZE %d, LIF_EXT %d \n", + packet_info->pph_forward_domain, learn_ext_present, fhei_size, lif_ext_type)); + break; + default: + fhei_size = 0; + lif_ext_type = 0; + learn_ext_present = 0; + break; + } + if (fhei_size) + { + switch (fhei_size) + { + case BKN_DNX_PPH_FHEI_TYPE_SZ0: + hdr_size += BKN_DNX_PPH_FHEI_SZ0_SIZE; + DBG_DUNE(("FHEI(3) is present\n")); + break; + case BKN_DNX_PPH_FHEI_TYPE_SZ1: + /* FHEI: Code */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_FHEI_TRAP_5B_TYPE_MSB, + BKN_DNX_PPH_FHEI_TRAP_5B_TYPE_NOF_BITS, + &fld_val); + packet_info->fhei_type = fld_val; + /* FHEI-Size == 5B, FHEI-Type == Trap/Sniff */ + if (packet_info->fhei_type == 0x5) + { + /* FHEI: Qualifier */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_FHEI_TRAP_5B_QUALIFIER_MSB, + BKN_DNX_PPH_FHEI_TRAP_5B_QUALIFIER_NOF_BITS, + &fld_val); + packet_info->fhei_qualifier = fld_val; + /* FHEI: Code */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_FHEI_TRAP_5B_CODE_MSB, + BKN_DNX_PPH_FHEI_TRAP_5B_CODE_NOF_BITS, + &fld_val); + packet_info->fhei_code = fld_val; + } + hdr_size += BKN_DNX_PPH_FHEI_SZ1_SIZE; + DBG_DUNE(("FHEI(5) is present code 0x%x qualifier 0x%x\n", packet_info->fhei_code, packet_info->fhei_qualifier)); + break; + case BKN_DNX_PPH_FHEI_TYPE_SZ2: + hdr_size += BKN_DNX_PPH_FHEI_SZ1_SIZE; + DBG_DUNE(("FHEI(8) is present\n")); + break; + } + } + + /* PPH LIF Extension */ + if (lif_ext_type) + { + hdr_size += sinfo->pph_lif_ext_size[lif_ext_type]; + DBG_DUNE(("PPH LIF Extension(%d) is present\n", sinfo->pph_lif_ext_size[lif_ext_type])); + } + + /* PPH Learn Extension */ + if (learn_ext_present) + { + hdr_size += BKN_DNX_PPH_LEARN_EXT_SIZE; + DBG_DUNE(("PPH Learn Extension(19) is present\n")); + } + } + + /* UDH Header */ + if (sinfo->udh_enable) + { + uint8 data_type_0; + uint8 data_type_1; + uint8 data_type_2; + uint8 data_type_3; + + DBG_DUNE(("UDH base(1) is present\n")); + + /* UDH: UDH-Data-Type[0] */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_UDH_DATA_TYPE_0_MSB, + BKN_DNX_UDH_DATA_TYPE_0_NOF_BITS, + &fld_val); + data_type_0 = fld_val; + hdr_size += sinfo->udh_length_type[data_type_0]; + /* UDH: UDH-Data-Type[1] */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_UDH_DATA_TYPE_1_MSB, + BKN_DNX_UDH_DATA_TYPE_1_NOF_BITS, + &fld_val); + data_type_1 = fld_val; + hdr_size += sinfo->udh_length_type[data_type_1]; + /* UDH: UDH-Data-Type[2] */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_UDH_DATA_TYPE_2_MSB, + BKN_DNX_UDH_DATA_TYPE_2_NOF_BITS, + &fld_val); + data_type_2 = fld_val; + hdr_size += sinfo->udh_length_type[data_type_2]; + /* UDH: UDH-Data-Type[3] */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_UDH_DATA_TYPE_3_MSB, + BKN_DNX_UDH_DATA_TYPE_3_NOF_BITS, + &fld_val); + data_type_3 = fld_val; + hdr_size += sinfo->udh_length_type[data_type_3]; + hdr_size += BKN_DNX_UDH_BASE_SIZE; + } + + /* + * Check if fhei_type if of type trap + * There is a RISK that raw packet data is parsed and fhei_type is 0x5 by chance + */ + if (packet_info->fhei_type == 0x5) + { + /* Done for ingress trapped packets */ + packet_info->system_header_size = hdr_size; + DBG_DUNE(("Total Size of Headers is %d\n", packet_info->system_header_size)); + return 0; + } + else + { + /* New generated header will be FTMH(80b), TSH(32b), PPH(96b), FHEI(40b) */ + + /* Revert packet_info except info from FTHM base header */ + packet_info->fhei_qualifier = 0; + packet_info->fhei_code = 0; + packet_info->fhei_type = 0; + hdr_size = pkt_offset_ingress_untrapped; + + /* Time-Stamp Header */ + hdr_size += BKN_DNX_TSH_SIZE; + DBG_DUNE(("Time-Stamp Header(4) is present\n")); + + /** Packet Processing Header */ + bkn_bitstream_get_field( + &buf[hdr_size], + BKN_DNX_PPH_12_FORWARD_DOMAIN_MSB, + BKN_DNX_PPH_12_FORWARD_DOMAIN_NOF_BITS, + &fld_val); + packet_info->pph_forward_domain = fld_val; + hdr_size += BKN_DNX_PPH_BASE_TYPE_12; + DBG_DUNE(("PPH(12) is present\n")); + + /* + * FHEI(Trap,40) + * 5B-FHEI format for sys_hdr_generation_profile:J2-OAM + * 8b' 0 + * 19b'oam_id + * 9b' cpu_trap_code: INGRESS_TRAP_ID is always 0 here + * 4b' type(0x5): J2-Configuration FHEI Type for CPU trap + */ + hdr_size += BKN_DNX_PPH_FHEI_SZ1_SIZE; + DBG_DUNE(("FHEI(5) is present\n")); + } + packet_info->system_header_size = hdr_size; + DBG_DUNE(("Total Size of Headers is %d\n", packet_info->system_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 err_woff; + uint32_t *dcb, *meta; + uint8_t *pkt; + uint64_t pkt_dma; + int drop_api; + int ethertype; + int pktlen; + int idx; + int dcbs_done = 0; + bkn_dune_system_header_info_t packet_info = {0}; + uint32_t dnx_meta_data[3] = {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 ((sinfo->cmic_type == 'x' && dcb[2] & (1 << 18)) || + (sinfo->cmic_type != 'x' && 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 ((sinfo->cmic_type == 'x' && (dcb[2] & (1 << 16)) == 0) || + (sinfo->cmic_type != 'x' && (dcb[1] & (1 << 16)) == 0)) { + sinfo->rx[chan].chain_complete = 1; + } + sinfo->rx[chan].pkts++; + if (sinfo->cmic_type == 'x') { + pkt_dma = BUS_TO_DMA_HI(dcb[1]); + pkt_dma = pkt_dma << 32 | dcb[0]; + } else { + pkt_dma = dcb[0]; + } + pkt = (uint8_t *)kernel_bde->p2l(sinfo->dev_no, (sal_paddr_t)pkt_dma); + if (sinfo->cmic_type == 'x') { + if (device_is_dnx(sinfo)){ + meta = &dnx_meta_data[0]; + /* get error bit from last DCB words */ + err_woff = 2; + meta[err_woff] = dcb[sinfo->dcb_wsize-1]; + } else { + meta = (uint32_t *)pkt; + err_woff = sinfo->pkt_hdr_size / sizeof(uint32_t) - 1; + meta[err_woff] = dcb[sinfo->dcb_wsize-1]; + } + } else { + meta = dcb; + err_woff = sinfo->dcb_wsize - 1; + } + pktlen = dcb[sinfo->dcb_wsize-1] & SOC_DCB_KNET_COUNT_MASK; + bkn_dump_pkt(pkt, pktlen, XGS_DMA_RX_CHAN); + + if (device_is_dpp(sinfo)) { + uint16_t tpid = 0; + uint16_t vid = 0; + int res = -1; + + memset(&packet_info, 0, sizeof(bkn_dune_system_header_info_t)); + res = bkn_dpp_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info); + if (res == 0) { + if (packet_info.ftmh.action_type == 0x2) { + bkn_bitstream_set_field((uint32_t *)dcb, 192, 32, 0x8); + } else if (packet_info.ftmh.action_type == 0x1) { + bkn_bitstream_set_field((uint32_t *)dcb, 231, 25, 0x20); + } + bkn_bitstream_set_field((uint32_t *)dcb, 112, 16, packet_info.ftmh.src_sys_port); + bkn_bitstream_set_field((uint32_t *)dcb, 296, 12, packet_info.internal.vsi); + bkn_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); + } + } + } + } + else if (device_is_dnx(sinfo)) { + int res = -1; + res = bkn_dnx_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info); + if (res == 0) { + bkn_bitstream_set_field(meta, 0, 16, packet_info.fhei_code); + bkn_bitstream_set_field(meta, 16, 16, packet_info.fhei_qualifier); + bkn_bitstream_set_field(meta, 32, 16, packet_info.ftmh_spa); + bkn_bitstream_set_field(meta, 48, 16, (packet_info.pph_forward_domain & 0xffff)); + + pkt += packet_info.system_header_size; + pktlen -= packet_info.system_header_size; + bkn_dump_pkt(pkt, 32, XGS_DMA_RX_CHAN); + } + } + + if (device_is_dpp(sinfo)) { + filter = bkn_match_rx_pkt(sinfo, pkt, pktlen, dcb, chan, &cbf); + } else if (device_is_dnx(sinfo)) { + filter = bkn_match_rx_pkt(sinfo, pkt, pktlen, meta, chan, &cbf); + } else { + filter = bkn_match_rx_pkt(sinfo, pkt + sinfo->pkt_hdr_size, + pktlen - sinfo->pkt_hdr_size, meta, chan, &cbf); + } + if ((dcb[sinfo->dcb_wsize-1] & 0xf0000) != 0x30000) { + /* Fragment or error */ + if (filter && filter->kf.mask.w[err_woff] == 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; + } + + if (sinfo->cmic_type == 'x') { + pkt += sinfo->pkt_hdr_size; + pktlen -= sinfo->pkt_hdr_size; + } + + /* 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; + } + } else { + /* + * Mark packet as VLAN-tagged, otherwise newer + * kernels will strip the tag. + */ + uint16_t tci = (pkt[14] << 8) | pkt[15]; + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { + bkn_vlan_hwaccel_put_tag(skb, ETH_P_8021Q, tci); + } else { + bkn_vlan_hwaccel_put_tag(skb, + ((skb->data[12] << 8) | skb->data[13]), tci); + } + } + } + + skb_copy_to_linear_data(skb, pkt, pktlen); + if (device_is_sand(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 += skb->len; + + /* 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, meta); + if (skb == NULL) { + /* Consumed by call-back */ + sinfo->rx[chan].pkts_d_callback++; + break; + } + } + + /* Do Rx timestamping */ + if (sinfo->rx_hwts) { + bkn_hw_tstamp_rx_set(sinfo, skb, meta); + } + + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { + bkn_add_rcpu_encap(sinfo, skb, meta); + DBG_PDMP(("After add RCPU ENCAP\n")); + bkn_dump_pkt(skb->data, pktlen + RCPU_RX_ENCAP_SIZE, XGS_DMA_RX_CHAN); + } + 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; + } + } else { + DBG_PKT(("Rx packet dropped.\n")); + sinfo->rx[chan].pkts_d_no_match++; + } + 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 err_woff; + uint32_t *dcb, *meta; + int ethertype; + int pktlen; + int idx; + int dcbs_done = 0; + bkn_dune_system_header_info_t packet_info = {0}; + uint32_t dnx_meta_data[3] = {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 ((sinfo->cmic_type == 'x' && (dcb[2] & (1 << 16)) == 0) || + (sinfo->cmic_type != 'x' && (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++; + skb = desc->skb; + if (sinfo->cmic_type == 'x') { + if (device_is_dnx(sinfo)){ + meta = &dnx_meta_data[0]; + /* get error bit from last DCB words */ + err_woff = 2; + meta[err_woff] = dcb[sinfo->dcb_wsize-1]; + } else { + meta = (uint32_t *)skb->data; + err_woff = sinfo->pkt_hdr_size / sizeof(uint32_t) - 1; + meta[err_woff] = dcb[sinfo->dcb_wsize-1]; + } + } else { + meta = dcb; + err_woff = sinfo->dcb_wsize - 1; + } + pktlen = dcb[sinfo->dcb_wsize-1] & 0xffff; + priv = netdev_priv(sinfo->dev); + 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, pktlen, XGS_DMA_RX_CHAN); + + if (device_is_dpp(sinfo)) { + uint16_t tpid = 0; + uint16_t vid = 0; + uint8_t *pkt = skb->data; + int res = 0; + + memset(&packet_info, 0, sizeof(bkn_dune_system_header_info_t)); + res = bkn_dpp_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info); + if (res == 0) { + if (packet_info.ftmh.action_type == 0x2) { + bkn_bitstream_set_field((uint32_t *)dcb, 192, 32, 0x8); + } else if (packet_info.ftmh.action_type == 0x1) { + bkn_bitstream_set_field((uint32_t *)dcb, 231, 25, 0x20); + } + bkn_bitstream_set_field((uint32_t *)dcb, 112, 16, packet_info.ftmh.src_sys_port); + bkn_bitstream_set_field((uint32_t *)dcb, 296, 12, packet_info.internal.vsi); + bkn_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); + } + } + } + } + else if (device_is_dnx(sinfo)) { + uint8_t *pkt = skb->data; + int res = -1; + + res = bkn_dnx_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info); + if (res == 0) { + bkn_bitstream_set_field(meta, 0, 16, packet_info.fhei_code); + bkn_bitstream_set_field(meta, 16, 16, packet_info.fhei_qualifier); + bkn_bitstream_set_field(meta, 32, 16, packet_info.ftmh_spa); + bkn_bitstream_set_field(meta, 48, 16, (packet_info.pph_forward_domain & 0xffff)); + + pkt += packet_info.system_header_size; + pktlen -= packet_info.ntwrk_header_ptr; + bkn_dump_pkt(pkt, 32, XGS_DMA_RX_CHAN); + } + } + + if (device_is_dpp(sinfo)) { + filter = bkn_match_rx_pkt(sinfo, skb->data + packet_info.ntwrk_header_ptr, + pktlen, dcb, chan, &cbf); + } else if (device_is_dnx(sinfo)) { + filter = bkn_match_rx_pkt(sinfo, skb->data + packet_info.system_header_size, + pktlen, meta, chan, &cbf); + } else { + filter = bkn_match_rx_pkt(sinfo, skb->data + sinfo->pkt_hdr_size, + pktlen - sinfo->pkt_hdr_size, meta, chan, &cbf); + } + if ((dcb[sinfo->dcb_wsize-1] & 0xf0000) != 0x30000) { + /* Fragment or error */ + priv->stats.rx_errors++; + if (filter && filter->kf.mask.w[err_woff] == 0) { + /* Drop unless DCB status is part of filter */ + filter = NULL; + } + } + DBG_PKT(("Rx packet (%d bytes).\n", pktlen)); + 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 (((filter->kf.mirror_type == KCOM_DEST_T_API) && + (!device_is_sand(sinfo))) || dbg_pkt_enable) { + sinfo->rx[chan].pkts_m_api++; + bkn_api_rx_copy_from_skb(sinfo, chan, desc); + } + + if (device_is_dpp(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 if (device_is_dnx(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.system_header_size; + pktlen -= packet_info.system_header_size; + 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 */ + } + + if (sinfo->cmic_type == 'x' && !device_is_dnx(sinfo)) { + skb_pull(skb, sinfo->pkt_hdr_size); + } + + /* 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); + if (sinfo->cmic_type == 'x' && !device_is_dnx(sinfo)) { + for (idx = sinfo->pkt_hdr_size / sizeof(uint32_t); idx; idx--) { + meta[idx] = meta[idx - 1]; + } + meta++; + } + } + } else { + /* + * Mark packet as VLAN-tagged, otherwise newer + * kernels will strip the tag. + */ + uint16_t tci = (skb->data[14] << 8) | skb->data[15]; + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { + bkn_vlan_hwaccel_put_tag(skb, ETH_P_8021Q, tci); + } else { + bkn_vlan_hwaccel_put_tag(skb, + ((skb->data[12] << 8) | skb->data[13]), tci); + } + } + } + priv->stats.rx_packets++; + priv->stats.rx_bytes += skb->len; + 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, meta); + if (skb == NULL) { + /* Consumed by call-back */ + sinfo->rx[chan].pkts_d_callback++; + priv->stats.rx_dropped++; + desc->skb = NULL; + break; + } + } + + /* Do Rx timestamping */ + if (sinfo->rx_hwts) { + bkn_hw_tstamp_rx_set(sinfo, skb, meta); + } + + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { + bkn_add_rcpu_encap(sinfo, skb, meta); + DBG_PDMP(("After add RCPU ENCAP\n")); + bkn_dump_pkt(skb->data, pktlen + RCPU_RX_ENCAP_SIZE, XGS_DMA_RX_CHAN); + } + 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 += mskb->len; + 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; + } 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; + } + } else { + DBG_PKT(("Rx packet dropped.\n")); + sinfo->rx[chan].pkts_d_no_match++; + priv->stats.rx_dropped++; + } + dcb[sinfo->dcb_wsize-1] &= ~(1 << 31); + 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); + } + } + + 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_hw_tstamp_tx_set(bkn_switch_info_t *sinfo, struct sk_buff *skb) +{ + struct skb_shared_hwtstamps shhwtstamps; + uint64_t ts = 0; + uint32_t hdrlen = sinfo->cmic_type == 'x' ? PKT_TX_HDR_SIZE : 0; + int port; + + if (!knet_hw_tstamp_tx_time_get_cb) { + return -1; + } + + port = KNET_SKB_CB(skb)->port; + if (knet_hw_tstamp_tx_time_get_cb(sinfo->dev_no, port, skb->data + hdrlen, &ts) < 0) { + return -1; + } + + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); + shhwtstamps.hwtstamp = ns_to_ktime(be64_to_cpu(ts)); + skb_tstamp_tx(skb, &shhwtstamps); + + return 0; +} + +static void +bkn_hw_tstamp_tx_work(struct work_struct *work) +{ + bkn_switch_info_t *sinfo = container_of(work, bkn_switch_info_t, tx_ptp_work); + struct sk_buff *skb; + + while (skb_queue_len(&sinfo->tx_ptp_queue)) { + skb = skb_dequeue(&sinfo->tx_ptp_queue); + if (bkn_hw_tstamp_tx_set(sinfo, skb) < 0) { + gprintk("Timestamp has not been taken for the current skb.\n"); + } + dev_kfree_skb_any(skb); + } +} + +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); + if (bkn_skb_tx_flags(desc->skb) & SKBTX_IN_PROGRESS) { + skb_queue_tail(&sinfo->tx_ptp_queue, desc->skb); + schedule_work(&sinfo->tx_ptp_work); + } else { + dev_kfree_skb_any(desc->skb); + } + desc->skb = NULL; + desc->skb_dma = 0; + } + desc->dcb_mem[sinfo->dcb_wsize-1] &= ~(1 << 31); + 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; + uint64_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; + if (sinfo->cmic_type == 'x') { + dcb_mem[1] = DMA_TO_BUS_HI(dcb_chain->dcb_dma >> 32); + dcb_mem[2] |= 1 << 24 | 1 << 18 | 1 << 16; + } else { + 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; + if (sinfo->cmic_type == 'x') { + dcb_mem[1] = DMA_TO_BUS_HI(sinfo->tx.desc[sinfo->tx.dirty].dcb_dma >> 32); + } + 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; + uint64_t pkt_dma; + unsigned char *pktdata; + int pktlen; + int i; + + /* 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)); + for (i = 0; i < dcb_chain->dcb_cnt && debug & DBG_LVL_PDMP; i++) { + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN) && i == dcb_chain->dcb_cnt - 1) { + break; + } + if (sinfo->cmic_type == 'x') { + pkt_dma = BUS_TO_DMA_HI(dcb_chain->dcb_mem[sinfo->dcb_wsize * i + 1]); + pkt_dma = pkt_dma << 32 | dcb_chain->dcb_mem[sinfo->dcb_wsize * i]; + } else { + pkt_dma = dcb_chain->dcb_mem[sinfo->dcb_wsize * i]; + } + pktdata = kernel_bde->p2l(sinfo->dev_no, pkt_dma); + if (sinfo->cmic_type == 'x') { + pktlen = dcb_chain->dcb_mem[sinfo->dcb_wsize * i + 2] & 0xffff; + } else { + pktlen = dcb_chain->dcb_mem[sinfo->dcb_wsize * i + 1] & 0xffff; + } + bkn_dump_pkt(pktdata, pktlen, XGS_DMA_TX_CHAN); + } + + 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; + + DBG_IRQ(("Tx CDMA chain done \n")); + + evt = &_bkn_evt[sinfo->evt_idx]; + + if (sinfo->tx.api_active) { + /* 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; + } + sinfo->tx.api_dcb_chain->dcb_mem[woffset - sinfo->dcb_wsize] |= SOC_DCB_KNET_DONE; + sinfo->dma_events |= KCOM_DMA_INFO_F_TX_DONE; + evt->evt_wq_put++; + wake_up_interruptible(&evt->evt_wq); + kfree(sinfo->tx.api_dcb_chain); + sinfo->tx.api_dcb_chain = NULL; + 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; + } + sinfo->tx.api_dcb_chain->dcb_mem[woffset] |= SOC_DCB_KNET_DONE; + /* Try and park at SKB Tx if API Tx done */ + bkn_skb_tx(sinfo); + sinfo->dma_events |= KCOM_DMA_INFO_F_TX_DONE; + evt->evt_wq_put++; + wake_up_interruptible(&evt->evt_wq); + 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; + + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) { + return bkn_tx_cdma_chain_done(sinfo, done); + } + + DBG_IRQ(("Tx chain done (%d/%d)\n", sinfo->tx.cur, sinfo->tx.dirty)); + + dev_irq_mask_disable(sinfo, XGS_DMA_TX_CHAN, 0); + + 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); + /* 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)) { + if (sinfo->cmic_type == 'x') { + sinfo->tx.desc[idx++].dcb_mem[2] |= 1 << 16; + } else { + 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; + int chan_done, budget_chans = 0; + uint32_t dma_stat; + int chan; + + DEV_READ32(sinfo, CMIC_DMA_STATr, &dma_stat); + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (dma_stat & DS_DESC_DONE_TST(XGS_DMA_RX_CHAN + chan)) { + xgs_dma_desc_clear(sinfo, XGS_DMA_RX_CHAN + chan); + sinfo->poll_channels |= 1 << chan; + } + } + if (!sinfo->poll_channels) { + sinfo->poll_channels = (uint32_t)(1 << sinfo->rx_chans) - 1; + budget_chans = budget / sinfo->rx_chans; + } else { + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + budget_chans++; + } + } + budget_chans = budget / budget_chans; + } + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + chan_done = bkn_do_rx(sinfo, chan, budget_chans); + rx_dcbs_done += chan_done; + if (chan_done < budget_chans) { + sinfo->poll_channels &= ~(1 << chan); + } + 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 sinfo->poll_channels ? budget : rx_dcbs_done; +} + +static int +xgsm_do_dma(bkn_switch_info_t *sinfo, int budget) +{ + int rx_dcbs_done = 0, tx_dcbs_done = 0; + int chan_done, budget_chans = 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 < sinfo->rx_chans; 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); + sinfo->poll_channels |= 1 << chan; + } + } + if (!sinfo->poll_channels) { + sinfo->poll_channels = (uint32_t)(1 << sinfo->rx_chans) - 1; + budget_chans = budget / sinfo->rx_chans; + } else { + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + budget_chans++; + } + } + budget_chans = budget / budget_chans; + } + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + chan_done = bkn_do_rx(sinfo, chan, budget_chans); + rx_dcbs_done += chan_done; + if (chan_done < budget_chans) { + sinfo->poll_channels &= ~(1 << chan); + } + 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 sinfo->poll_channels ? budget : rx_dcbs_done; +} + +static int +xgsx_do_dma(bkn_switch_info_t *sinfo, int budget) +{ + int rx_dcbs_done = 0, tx_dcbs_done = 0; + int chan_done, budget_chans = 0; + uint32_t irq_stat, tx_dma_stat, rx_dma_stat[NUM_CMICX_RX_CHAN]; + int chan; + + DEV_READ32(sinfo, CMICX_IRQ_STATr, &irq_stat); + DEV_READ32(sinfo, CMICX_DMA_STATr + 0x80 * XGS_DMA_TX_CHAN, &tx_dma_stat); + for (chan = 0; chan < sinfo->rx_chans; chan++) { + DEV_READ32(sinfo, + CMICX_DMA_STATr + 0x80 * (XGS_DMA_RX_CHAN + chan), + &rx_dma_stat[chan]); + } + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if ((irq_stat & CMICX_DS_CMC_CTRLD_INT(XGS_DMA_RX_CHAN + chan)) || + (irq_stat & CMICX_DS_CMC_DESC_DONE(XGS_DMA_RX_CHAN + chan))) { + xgsx_dma_desc_clear(sinfo, XGS_DMA_RX_CHAN + chan); + sinfo->poll_channels |= 1 << chan; + } + } + if (!sinfo->poll_channels) { + sinfo->poll_channels = (uint32_t)(1 << sinfo->rx_chans) - 1; + budget_chans = budget / sinfo->rx_chans; + } else { + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + budget_chans++; + } + } + budget_chans = budget / budget_chans; + } + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + chan_done = bkn_do_rx(sinfo, chan, budget_chans); + rx_dcbs_done += chan_done; + if (chan_done < budget_chans) { + sinfo->poll_channels &= ~(1 << chan); + } + bkn_rx_desc_done(sinfo, chan); + } + + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + continue; + } + + if (rx_dma_stat[chan] & CMICX_DS_CMC_DMA_CHAIN_DONE) { + xgsx_dma_chain_clear(sinfo, XGS_DMA_RX_CHAN + chan); + bkn_rx_chain_done(sinfo, chan); + } + } + + if ((irq_stat & CMICX_DS_CMC_CTRLD_INT(XGS_DMA_TX_CHAN)) || + (tx_dma_stat & CMICX_DS_CMC_DMA_CHAIN_DONE)) { + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) { + xgsx_dma_desc_clear(sinfo, XGS_DMA_TX_CHAN); + } else { + xgsx_dma_chain_clear(sinfo, XGS_DMA_TX_CHAN); + } + tx_dcbs_done = bkn_do_tx(sinfo); + bkn_tx_chain_done(sinfo, tx_dcbs_done); + } + + return sinfo->poll_channels ? budget : rx_dcbs_done; +} + +static int +dev_do_dma(bkn_switch_info_t *sinfo, int budget) +{ + if (DEV_IS_CMICX(sinfo)) { + return xgsx_do_dma(sinfo, budget); + } else if (DEV_IS_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 +xgsx_isr(bkn_switch_info_t *sinfo) +{ + uint32_t irq_stat; + int rx_dcbs_done; + + DEV_READ32(sinfo, CMICX_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 { + xgsx_irq_mask_set(sinfo, 0); + do { + rx_dcbs_done = xgsx_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); + } + + xgsx_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_IS_CMICX(sinfo)) { + xgsx_isr(sinfo); + } else if (DEV_IS_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; + uint64_t cur_halt, last_dcb, dcb_dma; + int woffset, chan, cdma_running; + + /* Resume Rx DMA on all channels */ + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (sinfo->rx[chan].use_rx_skb) { + cdma_running = 0; + bkn_api_rx_restart(sinfo, chan); + 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, chan); + } + } + } +} + +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 + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) +static int +bkn_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + bkn_priv_t *priv = netdev_priv(dev); + bkn_switch_info_t *sinfo = priv->sinfo; + struct hwtstamp_config config; + + if (cmd == SIOCSHWTSTAMP) { + if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) { + return -EFAULT; + } + + if (!knet_hw_tstamp_enable_cb || !knet_hw_tstamp_disable_cb || + priv->type != KCOM_NETIF_T_PORT) { + return -ERANGE; + } + + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + knet_hw_tstamp_disable_cb(sinfo->dev_no, priv->port); + sinfo->tx_hwts = 0; + break; + case HWTSTAMP_TX_ON: + knet_hw_tstamp_enable_cb(sinfo->dev_no, priv->port); + sinfo->tx_hwts = 1; + break; + default: + return -ERANGE; + } + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + if (sinfo->rx_hwts) { + knet_hw_tstamp_disable_cb(sinfo->dev_no, priv->port); + sinfo->rx_hwts = 0; + } + break; + default: + if (!sinfo->rx_hwts) { + knet_hw_tstamp_enable_cb(sinfo->dev_no, priv->port); + sinfo->rx_hwts = 1; + } + config.rx_filter = HWTSTAMP_FILTER_ALL; + break; + } + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) + if (cmd == SIOCGHWTSTAMP) { + config.flags = 0; + config.tx_type = sinfo->tx_hwts ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; + config.rx_filter = sinfo->rx_hwts ? HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE; + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; + } +#endif + + return -EINVAL; +} +#endif + +static int +bkn_change_mtu(struct net_device *dev, int new_mtu) +{ + int max_size = new_mtu + ETH_HLEN + VLAN_HLEN + 4; + + if (new_mtu < 68 || max_size > 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_hw_tstamp_tx_config(bkn_switch_info_t *sinfo, struct sk_buff *skb, uint32_t *meta) +{ + uint32_t *md = NULL; + + if (!knet_hw_tstamp_tx_meta_get_cb) { + return -1; + } + + KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF; + knet_hw_tstamp_tx_meta_get_cb(sinfo->dev_no, skb, &md); + if (!md) { + return -1; + } + + switch (sinfo->dcb_type) { + case 26: + case 32: + case 33: + meta[2] |= md[0]; + meta[3] |= md[1]; + meta[4] |= md[2]; + meta[5] |= md[3]; + break; + case 36: + case 38: + meta[0] |= md[0]; + meta[1] |= md[1]; + meta[2] |= md[2]; + meta[3] |= md[3]; + break; + default: + return -1; + } + + return 0; +} + +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 = NULL; + unsigned char *pktdata; + int pktlen, hdrlen, taglen, rcpulen, metalen; + int sop, 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, *meta; + + pktdata = skb->data; + pktlen = skb->len; + hdrlen = (sinfo->cmic_type == 'x' ) ? ((device_is_dnx(sinfo)) ? priv->system_headers_size: PKT_TX_HDR_SIZE) : 0; + 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) { + 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; + } + if (sinfo->cmic_type != 'x') { + rcpulen += RCPU_TX_META_SIZE; + } + } + /* Skip over RCPU encapsulation */ + pktdata = &skb->data[rcpulen]; + pktlen -= rcpulen; + + /* CPU packets require tag */ + if (sop == 0) { + hdrlen = 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 + TAG_SZ + FCS_SZ); + 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 + TAG_SZ); + dev_kfree_skb_any(skb); + skb = new_skb; + pktdata = skb->data; + rcpulen = 0; + } else { + /* Add tag to RCPU header space */ + DBG_SKB(("Expand into unused RCPU header\n")); + rcpulen -= TAG_SZ; + pktdata = &skb->data[rcpulen]; + for (idx = 0; idx < 12; idx++) { + pktdata[idx] = pktdata[idx + TAG_SZ]; + } + } + pktdata[12] = 0x81; + pktdata[13] = 0x00; + pktdata[14] = (priv->vlan >> 8) & 0xf; + pktdata[15] = priv->vlan & 0xff; + pktlen += TAG_SZ; + } + } + } else { + if (sinfo->cmic_type == 'x' && priv->port >= 0) { + if (skb_header_cloned(skb) || skb_headroom(skb) < hdrlen + 4) { + /* Current SKB cannot be modified */ + DBG_SKB(("Realloc Tx SKB\n")); + new_skb = dev_alloc_skb(pktlen + hdrlen + 4 + FCS_SZ); + 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; + } + if (!device_is_dnx(sinfo)) + { + skb_reserve(new_skb, 4); + } + memcpy(new_skb->data + hdrlen, skb->data, pktlen); + skb_put(new_skb, pktlen + hdrlen); + dev_kfree_skb_any(skb); + skb = new_skb; + } else { + DBG_SKB(("Expand Tx SKB\n")); + skb_push(skb, hdrlen); + } + memset(skb->data, 0, hdrlen); + pktdata = skb->data; + pktlen += hdrlen; + } else { + hdrlen = 0; + } + + if (priv->port < 0 || (priv->flags & KCOM_NETIF_F_ADD_TAG)) { + DBG_DUNE(("ADD VLAN TAG\n")); + /* Need to add VLAN tag if packet is untagged */ + tpid = (skb->data[hdrlen + 12] << 8) | skb->data[hdrlen + 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 + TAG_SZ + FCS_SZ); + 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, hdrlen + 12); + memcpy(&new_skb->data[hdrlen + 16], &skb->data[hdrlen + 12], + pktlen - hdrlen - 12); + skb_put(new_skb, pktlen + TAG_SZ); + dev_kfree_skb_any(skb); + skb = new_skb; + } else { + /* Add tag to existing buffer */ + DBG_SKB(("Expand Tx SKB\n")); + skb_push(skb, TAG_SZ); + for (idx = 0; idx < hdrlen + 12; idx++) { + skb->data[idx] = skb->data[idx + TAG_SZ]; + } + } + pktdata = skb->data; + pktdata[hdrlen + 12] = 0x81; + pktdata[hdrlen + 13] = 0x00; + pktdata[hdrlen + 14] = (priv->vlan >> 8) & 0xf; + pktdata[hdrlen + 15] = priv->vlan & 0xff; + pktlen += TAG_SZ; + } + } + } + + /* Pad packet if needed */ + taglen = 0; + tpid = (pktdata[hdrlen + 12] << 8) | pktdata[hdrlen + 13]; + if (tpid == 0x8100) { + taglen = 4; + } + if (pktlen < (60 + taglen + hdrlen)) { + pktlen = (60 + taglen + hdrlen); + 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; + } + /* skb_padto may update the skb->data pointer */ + pktdata = &skb->data[rcpulen]; + } + + if ((pktlen + FCS_SZ) > SOC_DCB_KNET_COUNT_MASK) { + DBG_WARN(("Tx drop: size of pkt (%d) is out of range(%d)\n", + (pktlen + FCS_SZ), 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; + meta = (sinfo->cmic_type == 'x') ? (uint32_t *)pktdata : dcb; + memset(dcb, 0, sinfo->dcb_wsize * sizeof(uint32_t)); + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { + /* If module header SOP is non-zero, use RCPU meta data */ + if (sop != 0) { + if (sinfo->cmic_type == 'x') { + dcb[2] |= 1 << 19; + } else { + 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; + } + } + } else if (priv->port >= 0) { + /* Send to physical port */ + if (sinfo->cmic_type == 'x') { + dcb[2] |= 1 << 19; + } else { + 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 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 + FCS_SZ); + 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 + FCS_SZ); + 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; + case 32: + dcb[2] = 0x81000000; + dcb[3] = priv->port; + dcb[4] = 0x00004000; + 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 36: + if (sinfo->cmic_type == 'x') { + meta[0] = htonl(0x81000000); + meta[1] = htonl(priv->port); + meta[2] = htonl(0x00008000 | (priv->qnum & 0x3f) << 9); + } else { + dcb[2] = 0x81000000; + dcb[3] = priv->port; + dcb[4] = 0x00008000; + dcb[4] |= (priv->qnum & 0x3f) << 9; + } + break; + case 38: + if (sinfo->cmic_type == 'x') { + meta[0] = htonl(0x81000000); + meta[1] = htonl(priv->port); + meta[2] = htonl(0x00004000 | (priv->qnum & 0x3f) << 8); + } else { + dcb[2] = 0x81000000; + dcb[3] = priv->port; + dcb[4] = 0x00004000; + dcb[4] |= (priv->qnum & 0x3f) << 8; + } + break; + case 39: + if (device_is_dnx(sinfo)) { + /* + * if KCOM_NETIF_T_PORT, add MH+PTCH+ITMH header + * if KCOM_NETIF_T_VLAN, add MH+PTCH+header + */ + pktdata = skb->data; + memcpy(&pktdata[0], priv->system_headers, priv->system_headers_size); + } + break; + default: + dcb[2] = 0xff000000; + dcb[3] = 0x00000100; + dcb[4] = priv->port; + break; + } + } + + /* Optional SKB updates */ + if (knet_tx_cb != NULL) { + KNET_SKB_CB(skb)->netif_user_data = priv->cb_user_data; + KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF; + skb = knet_tx_cb(skb, sinfo->dev_no, meta); + 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 + FCS_SZ) <= SOC_DCB_KNET_COUNT_MASK) { + pktlen = skb->len; + if (pktlen < (60 + taglen + hdrlen)) { + pktlen = (60 + taglen + hdrlen); + 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)); + } + pktdata = skb->data; + if (sinfo->cmic_type == 'x') { + meta = (uint32_t *)pktdata; + } + } else { + DBG_WARN(("Tx drop: size of pkt (%d) is out of range(%d)\n", + (pktlen + FCS_SZ), 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; + } + } + + /* Do Tx timestamping */ + if (priv->port >= 0) { + if (bkn_skb_tx_flags(skb) & SKBTX_HW_TSTAMP && sinfo->tx_hwts) { + KNET_SKB_CB(skb)->port = priv->port; + bkn_hw_tstamp_tx_config(sinfo, skb, meta); + bkn_skb_tx_flags(skb) |= SKBTX_IN_PROGRESS; + } + bkn_skb_tx_timestamp(skb); + } + + /* Prepare for DMA */ + desc->skb = skb; + /* Add FCS bytes */ + pktlen = pktlen + FCS_SZ; + desc->dma_size = pktlen; + desc->skb_dma = DMA_MAP_SINGLE(sinfo->dma_dev, + pktdata, desc->dma_size, + DMA_TODEV); + if (DMA_MAPPING_ERROR(sinfo->dma_dev, desc->skb_dma)) { + priv->stats.tx_dropped++; + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&sinfo->lock, flags); + return 0; + } + dcb[0] = desc->skb_dma; + if (sinfo->cmic_type == 'x') { + dcb[1] = DMA_TO_BUS_HI(desc->skb_dma >> 32); + dcb[2] &= ~SOC_DCB_KNET_COUNT_MASK; + dcb[2] |= pktlen; + } else { + dcb[1] &= ~SOC_DCB_KNET_COUNT_MASK; + dcb[1] |= pktlen; + } + + bkn_dump_dcb("Tx RCPU", dcb, sinfo->dcb_wsize, XGS_DMA_TX_CHAN); + 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, pktlen, XGS_DMA_TX_CHAN); + + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) { + if (sinfo->cmic_type == 'x') { + dcb[2] |= 1 << 24 | 1 << 16; + } else { + 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); + } + + NETDEV_UPDATE_TRANS_START_TIME(dev); + + spin_unlock_irqrestore(&sinfo->lock, flags); + + return 0; +} + +static void +bkn_timer_func(bkn_switch_info_t *sinfo) +{ + unsigned long flags; + int chan; + int restart_timer; + + spin_lock_irqsave(&sinfo->lock, flags); + + sinfo->timer_runs++; + + restart_timer = 0; + for (chan = 0; chan < sinfo->rx_chans; 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); +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)) +static void +bkn_timer(unsigned long context) +{ + bkn_switch_info_t *sinfo = (bkn_switch_info_t *)context; + return bkn_timer_func(sinfo); +} +#else +static void +bkn_timer(struct timer_list *t) +{ + bkn_switch_info_t *sinfo = from_timer(sinfo, t, timer); + return bkn_timer_func(sinfo); +} +#endif + +static void +bkn_rx_add_tokens(bkn_switch_info_t *sinfo, int chan) +{ + unsigned long cur_jif, ticks; + uint32_t tokens_per_tick; + bkn_desc_info_t *desc; + + 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 Rx is suppressed */ + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + bkn_rx_refill(sinfo, chan); + desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty]; + if (desc->dcb_dma == sinfo->halt_addr[XGS_DMA_RX_CHAN + chan]) { + desc = &sinfo->rx[chan].desc[MAX_RX_DCBS]; + bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, desc->dcb_dma); + } + } else { + if (sinfo->rx[chan].running == 0) { + bkn_rx_refill(sinfo, chan); + bkn_rx_restart(sinfo, chan); + } + } +} + +static void +bkn_rxtick_func(bkn_switch_info_t *sinfo) +{ + 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 < sinfo->rx_chans; 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 < sinfo->rx_chans; 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); +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)) +static void +bkn_rxtick(unsigned long context) +{ + bkn_switch_info_t *sinfo = (bkn_switch_info_t *)context; + return bkn_rxtick_func(sinfo); +} +#else +static void +bkn_rxtick(struct timer_list *t) +{ + bkn_switch_info_t *sinfo = from_timer(sinfo, t, rxtick); + return bkn_rxtick_func(sinfo); +} +#endif + +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; + 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); + skb_queue_head_init(&sinfo->tx_ptp_queue); + INIT_WORK(&sinfo->tx_ptp_work, bkn_hw_tstamp_tx_work); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)) + init_timer(&sinfo->timer); + sinfo->timer.data = (unsigned long)sinfo; + sinfo->timer.function = bkn_timer; +#else + timer_setup(&sinfo->timer, bkn_timer, 0); +#endif + sinfo->timer.expires = jiffies + 1; + + 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; + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)) + init_timer(&sinfo->rxtick); + sinfo->rxtick.data = (unsigned long)sinfo; + sinfo->rxtick.function = bkn_rxtick; +#else + timer_setup(&sinfo->rxtick, bkn_rxtick, 0); +#endif + sinfo->rxtick.expires = jiffies + 1; + + 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); + + 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 = bkn_ioctl, + .ndo_tx_timeout = NULL, + .ndo_change_mtu = bkn_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = bkn_poll_controller, +#endif +}; +#endif + +static void +bkn_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) +{ + strlcpy(drvinfo->driver, "bcm-knet", sizeof(drvinfo->driver)); + snprintf(drvinfo->version, sizeof(drvinfo->version), "%d", KCOM_VERSION); + strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); + strlcpy(drvinfo->bus_info, "N/A", sizeof(drvinfo->bus_info)); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)) +static int +bkn_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) +{ + bkn_priv_t *priv = netdev_priv(dev); + bkn_switch_info_t *sinfo = priv->sinfo; + + switch (sinfo->dcb_type) { + case 26: + case 32: + case 33: + case 36: + case 38: + info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + info->tx_types = 1 << HWTSTAMP_TX_OFF | 1 << HWTSTAMP_TX_ON; + info->rx_filters = 1 << HWTSTAMP_FILTER_NONE | 1 << HWTSTAMP_FILTER_ALL; + if (knet_hw_tstamp_ptp_clock_index_cb) { + info->phc_index = knet_hw_tstamp_ptp_clock_index_cb(sinfo->dev_no); + } else { + info->phc_index = -1; + } + break; + default: + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE; + info->phc_index = -1; + break; + } + + return 0; +} +#endif + +static const struct ethtool_ops bkn_ethtool_ops = { + .get_drvinfo = bkn_get_drvinfo, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)) + .get_ts_info = bkn_get_ts_info, +#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 + dev->ethtool_ops = &bkn_ethtool_ops; + 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: + * <netif>=up|down + * + * Where <netif> 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; + link_str[count] = '\0'; + } + 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 < sinfo->rx_chans; 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: + * [<unit>:]rx_rate=<rate0>[,<rate1>[,<rate2]] + * + * Where <rate0> is packets/sec for the first Rx DMA channel, + * <rate1> 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[80]; + char *ptr; + int unit, chan; + + if (count > sizeof(rate_str)) { + count = sizeof(rate_str) - 1; + rate_str[count] = '\0'; + } + 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: %d\n", unit); + 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 < sinfo->rx_chans); + 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 < sinfo->rx_chans); + 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) +{ + bkn_switch_info_t *sinfo; + + sinfo = bkn_sinfo_from_unit(iter->dev_no); + while (pos) { + if (iter->rx_dma) { + if (++iter->idx >= MAX_RX_DCBS + 1) { + iter->idx = -1; + if (++iter->ch_no >= sinfo->rx_chans) { + iter->rx_dma = 0; + iter->ch_no = 0; + iter->dev_no++; + if ((sinfo = bkn_sinfo_from_unit(iter->dev_no)) == NULL) { + return -1; + } + } + } + } else { + if (++iter->idx >= MAX_TX_DCBS + 1) { + 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; + bkn_dcb_chain_t *dcb_chain = NULL; + struct list_head *curr, *next; + unsigned long flags; + int chan, cnt; + + 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) { + spin_lock_irqsave(&sinfo->lock, flags); + curr = &sinfo->tx.api_dcb_list; + dcb_chain = sinfo->tx.api_dcb_chain; + while (dcb_chain) { + seq_printf(s, " [0x%08lx]--->\n", (unsigned long)dcb_chain->dcb_dma); + for (cnt = 0; cnt < dcb_chain->dcb_cnt; cnt++) { + dcb = &dcb_chain->dcb_mem[sinfo->dcb_wsize * cnt]; + if (sinfo->cmic_type == 'x') { + seq_printf(s, " DCB %2d: 0x%08x 0x%08x 0x%08x 0x%08x\n", cnt, + dcb[0], dcb[1], dcb[2], dcb[sinfo->dcb_wsize-1]); + } else { + seq_printf(s, " DCB %2d: 0x%08x 0x%08x ... 0x%08x\n", cnt, + dcb[0], dcb[1], dcb[sinfo->dcb_wsize-1]); + } + } + next = curr->next; + if (next != &sinfo->tx.api_dcb_list) { + dcb_chain = list_entry(next, bkn_dcb_chain_t, list); + curr = next; + } else { + dcb_chain = NULL; + } + } + dcb = NULL; + spin_unlock_irqrestore(&sinfo->lock, flags); + 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"); + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) { + bkn_desc_info_t *desc = &sinfo->tx.desc[0]; + uint64_t halt = sinfo->halt_addr[XGS_DMA_TX_CHAN]; + seq_printf(s, + " halt: %d\n", + (int)((uint32_t)(halt - desc->dcb_dma) / (sinfo->dcb_wsize * sizeof(uint32_t)))); + } + } else { + dcb = sinfo->tx.desc[iter->idx].dcb_mem; + if (iter->idx == 0) { + seq_printf(s, " [0x%08lx]--->\n", (unsigned long)sinfo->tx.desc[0].dcb_dma); + } + } + } 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); + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) && sinfo->rx[chan].use_rx_skb) { + bkn_desc_info_t *desc = &sinfo->rx[chan].desc[0]; + uint64_t halt = sinfo->halt_addr[XGS_DMA_RX_CHAN + chan]; + seq_printf(s, + " halt: %d\n", + (int)((uint32_t)(halt - desc->dcb_dma) / (sinfo->dcb_wsize * sizeof(uint32_t)))); + } + } else if (sinfo->rx[iter->ch_no].use_rx_skb) { + dcb = sinfo->rx[iter->ch_no].desc[iter->idx].dcb_mem; + if (iter->idx == 0) { + seq_printf(s, " [0x%08lx]--->\n", (unsigned long)sinfo->rx[iter->ch_no].desc[0].dcb_dma); + } + } else if (!sinfo->rx[iter->ch_no].use_rx_skb && iter->idx == 0) { + spin_lock_irqsave(&sinfo->lock, flags); + curr = &sinfo->rx[iter->ch_no].api_dcb_list; + dcb_chain = sinfo->rx[iter->ch_no].api_dcb_chain; + while (dcb_chain) { + seq_printf(s, " [0x%08lx]--->\n", (unsigned long)dcb_chain->dcb_dma); + for (cnt = 0; cnt < dcb_chain->dcb_cnt; cnt++) { + dcb = &dcb_chain->dcb_mem[sinfo->dcb_wsize * cnt]; + if (sinfo->cmic_type == 'x') { + seq_printf(s, " DCB %2d: 0x%08x 0x%08x 0x%08x 0x%08x\n", cnt, + dcb[0], dcb[1], dcb[2], dcb[sinfo->dcb_wsize-1]); + } else { + seq_printf(s, " DCB %2d: 0x%08x 0x%08x ... 0x%08x\n", cnt, + dcb[0], dcb[1], dcb[sinfo->dcb_wsize-1]); + } + } + next = curr->next; + if (next != &sinfo->rx[iter->ch_no].api_dcb_list) { + dcb_chain = list_entry(next, bkn_dcb_chain_t, list); + curr = next; + } else { + dcb_chain = NULL; + } + } + dcb = NULL; + spin_unlock_irqrestore(&sinfo->lock, flags); + } + } + if (dcb) { + if (sinfo->cmic_type == 'x') { + seq_printf(s, " DCB %2d: 0x%08x 0x%08x 0x%08x 0x%08x\n", iter->idx, + dcb[0], dcb[1], dcb[2], dcb[sinfo->dcb_wsize-1]); + } else { + 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: + * [<unit>:]debug=<mask> + * + * Where <mask> 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; + debug_str[count] = '\0'; + } + 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: %d\n", unit); + 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, " cmic_type: %c\n", sinfo->cmic_type); + seq_printf(m, " dcb_type: %d\n", sinfo->dcb_type); + seq_printf(m, " dcb_wsize: %d\n", sinfo->dcb_wsize); + seq_printf(m, " pkt_hdr_size: %d\n", sinfo->pkt_hdr_size); + seq_printf(m, " rx_chans: %d\n", sinfo->rx_chans); + seq_printf(m, " cdma_chans: 0x%x\n", sinfo->cdma_channels); + 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 *)(sal_paddr_t)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 < sinfo->rx_chans; chan++) { + seq_printf(m, " Rx%d packets %10u\n", chan, sinfo->rx[chan].pkts); + } + for (chan = 0; chan < sinfo->rx_chans; 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: + * [<unit>:]clear[=all] + * + * Where <mask> 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; + debug_str[count] = '\0'; + } + 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: %d\n", unit); + 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 < sinfo->rx_chans; 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 < sinfo->rx_chans; 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: + * [<unit>:]clear[=all|tx|rx[<chan>]] + * + * Where <mask> 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; + debug_str[count] = '\0'; + } + 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: %d\n", unit); + 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 < sinfo->rx_chans; 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; + uint64_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, + (sal_paddr_t)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 (sinfo->cmic_type == 'x') { + woffset += 1; + } + if ((dcb_chain->dcb_mem[woffset] & ((1 << 18) | (1 << 16))) != 0x50000) { + gprintk("Not suitable API DCB chain for Continuous DMA mode\n"); + list_del(&dcb_chain->list); + 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; + if (sinfo->cmic_type == 'x') { + dcb_chain_end->dcb_mem[woffset + 1] = DMA_TO_BUS_HI(dcb_chain->dcb_dma >> 32); + } + MEMORY_BARRIER; + } + 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); + + chan = kmsg->dma_info.chan - 1; + if ((chan < 0) || (chan > sinfo->rx_chans)) { + gprintk("Invalid RX DMA channel specified: %d\n", + kmsg->dma_info.chan); + kmsg->hdr.status = KCOM_E_PARAM; + spin_unlock_irqrestore(&sinfo->lock, flags); + return sizeof(kcom_msg_hdr_t); + } + + 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 (sinfo->cmic_type == 'x') { + woffset += 1; + } + if ((dcb_chain->dcb_mem[woffset] & ((1 << 18) | (1 << 16))) != 0x50000) { + gprintk("Not suitable API DCB chain for Continuous DMA mode\n"); + list_del(&dcb_chain->list); + 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; + if (sinfo->cmic_type == 'x') { + dcb_chain_end->dcb_mem[woffset + 1] = DMA_TO_BUS_HI(dcb_chain->dcb_dma >> 32); + } + MEMORY_BARRIER; + } + 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, chan); + } + + 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_reprobe_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) +{ + 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); + skb_queue_purge(&sinfo->tx_ptp_queue); + } else { + if (kmsg->channels & (1 << XGS_DMA_TX_CHAN)) { + bkn_dma_abort_tx(sinfo); + bkn_clean_tx_dcbs(sinfo); + skb_queue_purge(&sinfo->tx_ptp_queue); + } + for (chan = 0; chan < sinfo->rx_chans; 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; + uint32_t dev_type; + 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); + + sinfo->cmic_type = kmsg->cmic_type; + sinfo->dcb_type = kmsg->dcb_type; + sinfo->dcb_wsize = BYTES2WORDS(kmsg->dcb_size); + sinfo->pkt_hdr_size = kmsg->pkt_hdr_size; + sinfo->dma_hi = kmsg->dma_hi; + sinfo->rx_chans = sinfo->cmic_type == 'x' ? NUM_CMICX_RX_CHAN : NUM_CMICM_RX_CHAN; + if (sinfo->rx_chans > NUM_RX_CHAN) { + sinfo->rx_chans = NUM_RX_CHAN; + } + + DBG_DUNE(("CMIC:%c DCB:%d WSIZE:%d DMA HI: 0x%08x HDR size: %d\n", + sinfo->cmic_type, sinfo->dcb_type, sinfo->dcb_wsize, + sinfo->dma_hi, sinfo->pkt_hdr_size)); + + /* Config Continuous DMA mode */ + sinfo->cdma_channels = kmsg->cdma_channels & ~(~0 << (sinfo->rx_chans + 1)); + + /* Ensure 32-bit PCI DMA is mapped properly on 64-bit platforms */ + dev_type = kernel_bde->get_dev_type(sinfo->dev_no); + if (dev_type & BDE_PCI_DEV_TYPE && sinfo->cmic_type != 'x') { + if (pci_set_dma_mask(sinfo->pdev, 0xffffffff)) { + spin_unlock_irqrestore(&sinfo->lock, flags); + gprintk("No suitable DMA available for SKBs\n"); + kmsg->hdr.status = KCOM_E_RESOURCE; + return sizeof(kcom_msg_hdr_t); + } + } + + /* First time called we need to allocate DCBs */ + if (sinfo->dcb_mem == NULL) { + if (bkn_alloc_dcbs(sinfo) < 0) { + spin_unlock_irqrestore(&sinfo->lock, flags); + kmsg->hdr.status = KCOM_E_RESOURCE; + return sizeof(kcom_msg_hdr_t); + } + } + + /* 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; + } + } + + /* 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); + + /* Init DCBs */ + bkn_init_dcbs(sinfo); + + 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_reprobe(kcom_msg_reprobe_t *kmsg, int len) +{ + kmsg->hdr.type = KCOM_MSG_TYPE_RSP; + + /* 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_reprobe_t); + } + + return sizeof(kcom_msg_reprobe_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; + if (device_is_dpp(sinfo)) { + memcpy(priv->itmh, kmsg->netif.itmh, 4); + } else if (device_is_dnx(sinfo)) { + memcpy(priv->system_headers, kmsg->netif.system_headers, kmsg->netif.system_headers_size); + priv->system_headers_size = kmsg->netif.system_headers_size; + } + priv->qnum = kmsg->netif.qnum; + } else { + if (device_is_sand(sinfo)) { + if (device_is_dpp(sinfo)) { + priv->port = kmsg->netif.port; + priv->qnum = kmsg->netif.qnum; + }else if (device_is_dnx(sinfo)) { + memcpy(priv->system_headers, kmsg->netif.system_headers, kmsg->netif.system_headers_size); + priv->system_headers_size = kmsg->netif.system_headers_size; + } + } + 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); + + if (device_is_dnx(sinfo)) { + int idx = 0; + for (idx = 0; idx < priv->system_headers_size; idx++) { + DBG_DUNE(("System Header[%d]: 0x%02x\n", idx, priv->system_headers[idx])); + } + } + + 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)); + + if (device_is_dnx(sinfo)) { + /* Information to parser Dune system headers */ + sinfo->ftmh_lb_key_ext_size = kmsg->filter.ftmh_lb_key_ext_size; + sinfo->ftmh_stacking_ext_size = kmsg->filter.ftmh_stacking_ext_size; + sinfo->pph_base_size = kmsg->filter.pph_base_size; + memcpy(sinfo->pph_lif_ext_size, kmsg->filter.pph_lif_ext_size, sizeof(sinfo->pph_lif_ext_size)); + sinfo->udh_enable = kmsg->filter.udh_enable; + memcpy(sinfo->udh_length_type, kmsg->filter.udh_length_type, sizeof(sinfo->udh_length_type)); + } + + 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)); + + if (device_is_dnx(sinfo)) { + int idx, wsize; + wsize = BYTES2WORDS(filter->kf.oob_data_size + filter->kf.pkt_data_size); + DBG_DUNE(("Filter: oob_data_size = %d pkt_data_size=%d wsize %d\n", filter->kf.oob_data_size, filter->kf.pkt_data_size, wsize)); + for (idx = 0; idx < wsize; idx++) + { + DBG_DUNE(("OOB[%d]: 0x%08x [0x%08x]\n", idx, filter->kf.data.w[idx], filter->kf.mask.w[idx])); + } + DBG_DUNE(("DNX system headers parameters:LB_KEY_EXT %d, STK_EXT %d, PPH_BASE %d, LIF_EXT %d %d %d, UDH_ENA %d, %d %d %d %d\n", + sinfo->ftmh_lb_key_ext_size, sinfo->ftmh_stacking_ext_size, sinfo->pph_base_size, + sinfo->pph_lif_ext_size[1],sinfo->pph_lif_ext_size[2], sinfo->pph_lif_ext_size[3], + sinfo->udh_enable, sinfo->udh_length_type[0], sinfo->udh_length_type[1], sinfo->udh_length_type[2], sinfo->udh_length_type[3])); + } + + 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_knet_wb_cleanup(kcom_msg_wb_cleanup_t *kmsg, int len) +{ + bkn_switch_info_t *sinfo; + bkn_dcb_chain_t *dcb_chain; + 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); + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + 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; + sinfo->rx[chan].api_active = 0; + } + + spin_unlock_irqrestore(&sinfo->lock, flags); + + return sizeof(kcom_msg_hdr_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_REPROBE: + DBG_CMD(("KCOM_M_REPROBE\n")); + /* Reprobe device */ + len = bkn_knet_reprobe(&kmsg->reprobe, 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; + case KCOM_M_WB_CLEANUP: + DBG_CMD(("KCOM_M_WB_CLEANUP\n")); + /* Clean up for warmbooting */ + len = bkn_knet_wb_cleanup(&kmsg->wb_cleanup, 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)); + dev_no = last_dev_no; + 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) { + evt = &_bkn_evt[sinfo->evt_idx]; + 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); + skb_queue_purge(&sinfo->tx_ptp_queue); + 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; + 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); + spin_unlock_irqrestore(&sinfo->lock, flags); + + 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; + } + + /* 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; + } + + /* 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. + * + * The HW timestamp callbacks invoke an external module to enable, disable + * HW timestamp on a specific port which is indicated while the netif is + * created through KNET API. KNET can also get device-specific SOBMH and + * timestamp for a Tx PTP packet through these callbacks. + */ + +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; +} + +int +bkn_hw_tstamp_enable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb) +{ + if (knet_hw_tstamp_enable_cb != NULL) { + return -1; + } + knet_hw_tstamp_enable_cb = hw_tstamp_enable_cb; + return 0; +} + +int +bkn_hw_tstamp_enable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb) +{ + if (hw_tstamp_enable_cb == NULL || + knet_hw_tstamp_enable_cb != hw_tstamp_enable_cb) { + return -1; + } + knet_hw_tstamp_enable_cb = NULL; + return 0; +} + +int +bkn_hw_tstamp_disable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb) +{ + if (knet_hw_tstamp_disable_cb != NULL) { + return -1; + } + knet_hw_tstamp_disable_cb = hw_tstamp_disable_cb; + return 0; +} + +int +bkn_hw_tstamp_disable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb) +{ + if (hw_tstamp_disable_cb == NULL || + knet_hw_tstamp_disable_cb != hw_tstamp_disable_cb) { + return -1; + } + knet_hw_tstamp_disable_cb = NULL; + return 0; +} + +int +bkn_hw_tstamp_tx_time_get_cb_register(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb) +{ + if (knet_hw_tstamp_tx_time_get_cb != NULL) { + return -1; + } + knet_hw_tstamp_tx_time_get_cb = hw_tstamp_tx_time_get_cb; + return 0; +} + +int +bkn_hw_tstamp_tx_time_get_cb_unregister(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb) +{ + if (hw_tstamp_tx_time_get_cb == NULL || + knet_hw_tstamp_tx_time_get_cb != hw_tstamp_tx_time_get_cb) { + return -1; + } + knet_hw_tstamp_tx_time_get_cb = NULL; + return 0; +} + +int +bkn_hw_tstamp_tx_meta_get_cb_register(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb) +{ + if (knet_hw_tstamp_tx_meta_get_cb != NULL) { + return -1; + } + knet_hw_tstamp_tx_meta_get_cb = hw_tstamp_tx_meta_get_cb; + return 0; +} + +int +bkn_hw_tstamp_tx_meta_get_cb_unregister(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb) +{ + if (hw_tstamp_tx_meta_get_cb == NULL || + knet_hw_tstamp_tx_meta_get_cb != hw_tstamp_tx_meta_get_cb) { + return -1; + } + knet_hw_tstamp_tx_meta_get_cb = NULL; + return 0; +} + +int +bkn_hw_tstamp_ptp_clock_index_cb_register(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb) +{ + if (knet_hw_tstamp_ptp_clock_index_cb != NULL) { + return -1; + } + knet_hw_tstamp_ptp_clock_index_cb = hw_tstamp_ptp_clock_index_cb; + return 0; +} + +int +bkn_hw_tstamp_ptp_clock_index_cb_unregister(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb) +{ + if (hw_tstamp_ptp_clock_index_cb == NULL || + knet_hw_tstamp_ptp_clock_index_cb != hw_tstamp_ptp_clock_index_cb) { + return -1; + } + knet_hw_tstamp_ptp_clock_index_cb = NULL; + return 0; +} + +int +bkn_hw_tstamp_rx_time_upscale_cb_register(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb) +{ + if (knet_hw_tstamp_rx_time_upscale_cb != NULL) { + return -1; + } + knet_hw_tstamp_rx_time_upscale_cb = hw_tstamp_rx_time_upscale_cb; + return 0; +} + +int +bkn_hw_tstamp_rx_time_upscale_cb_unregister(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb) +{ + if (hw_tstamp_rx_time_upscale_cb == NULL || + knet_hw_tstamp_rx_time_upscale_cb != hw_tstamp_rx_time_upscale_cb) { + return -1; + } + knet_hw_tstamp_rx_time_upscale_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); +LKM_EXPORT_SYM(bkn_hw_tstamp_enable_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_enable_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_disable_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_disable_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_tx_time_get_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_tx_time_get_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_tx_meta_get_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_tx_meta_get_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_ptp_clock_index_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_ptp_clock_index_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_rx_time_upscale_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_rx_time_upscale_cb_unregister); diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/include/bcm-knet.h b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/include/bcm-knet.h @@ -0,0 +1,130 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <stdint.h> +#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 <linux/skbuff.h> + +typedef struct { + uint32 netif_user_data; + uint32 filter_user_data; + uint16 dcb_type; + int port; +} knet_skb_cb_t; + +#define KNET_SKB_CB(_skb) ((knet_skb_cb_t *)_skb->cb) + +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); + +typedef int +(*knet_hw_tstamp_enable_cb_f)(int dev_no, int port); + +typedef int +(*knet_hw_tstamp_tx_time_get_cb_f)(int dev_no, int port, uint8_t *pkt, uint64_t *ts); + +typedef int +(*knet_hw_tstamp_tx_meta_get_cb_f)(int dev_no, struct sk_buff *skb, uint32_t **md); + +typedef int +(*knet_hw_tstamp_ptp_clock_index_cb_f)(int dev_no); + +typedef int +(*knet_hw_tstamp_rx_time_upscale_cb_f)(int dev_no, uint64_t *ts); + +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); + +extern int +bkn_hw_tstamp_enable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb); + +extern int +bkn_hw_tstamp_enable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb); + +extern int +bkn_hw_tstamp_disable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb); + +extern int +bkn_hw_tstamp_disable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb); + +extern int +bkn_hw_tstamp_tx_time_get_cb_register(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb); + +extern int +bkn_hw_tstamp_tx_time_get_cb_unregister(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb); + +extern int +bkn_hw_tstamp_tx_meta_get_cb_register(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb); + +extern int +bkn_hw_tstamp_tx_meta_get_cb_unregister(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb); + +extern int +bkn_hw_tstamp_ptp_clock_index_cb_register(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb); + +extern int +bkn_hw_tstamp_ptp_clock_index_cb_unregister(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb); + +extern int +bkn_hw_tstamp_rx_time_upscale_cb_register(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb); + +extern int +bkn_hw_tstamp_rx_time_upscale_cb_unregister(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb); + +#endif + +#endif /* __LINUX_BCM_KNET_H__ */ diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/include/gmodule.h b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/include/gmodule.h @@ -0,0 +1,65 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <lkm.h> + +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/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/include/lkm.h b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/include/lkm.h @@ -0,0 +1,182 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <linux/init.h> +#include <linux/version.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#include <linux/config.h> +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) +#include <linux/kconfig.h> +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) +#include <linux/slab.h> +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) +#include <linux/smp_lock.h> +#endif +#include <linux/module.h> + +/* 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 <linux/kernel.h> /* printk() */ +#include <linux/fs.h> /* everything... */ +#include <linux/errno.h> /* error codes */ +#include <linux/types.h> /* size_t */ +#include <linux/proc_fs.h> +#include <linux/fcntl.h> /* O_ACCMODE */ +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/stat.h> +#include <linux/sched.h> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0) +#include <linux/sched/signal.h> +#endif +#include <linux/delay.h> + +#include <asm/io.h> +#include <asm/hardirq.h> +#include <asm/uaccess.h> + +#ifdef CONFIG_DEVFS_FS +#include <linux/devfs_fs_kernel.h> +#endif + +#define PROC_INTERFACE_KERN_VER_3_10 (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) + +/* Compatibility Macros */ + +#ifdef LKM_2_4 + +#include <linux/compatmac.h> +#include <linux/wrapper.h> +#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/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/knet-cb/Makefile b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/knet-cb/Makefile @@ -0,0 +1,64 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- Makefile -*- +# $Id: Makefile,v 1.3 Broadcom SDK $ +# $Copyright: (c) 2005 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/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c @@ -0,0 +1,139 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + */ + +/* + * Test driver for call-back functions in Linux KNET driver. + * + * 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/gto-2_6 + * BUILD_KNET_CB=1 make -s mod + * + */ + +#include <gmodule.h> /* Must be included first */ +#include <kcom.h> +#include <bcm-knet.h> + +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" + +static void +show_mac(struct sk_buff *skb) +{ + printk("DMAC=%02X:%02X:%02X:%02X:%02X:%02X\n", + skb->data[0], skb->data[1], skb->data[2], + skb->data[3], skb->data[4], skb->data[5]); +} + +static struct sk_buff * +test_rx_cb(struct sk_buff *skb, int dev_no, void *meta) +{ + printk("rx_cb for dev %d\n", dev_no); + printk("netif user data 0x%x\n", KNET_SKB_CB(skb)->netif_user_data); + printk("filter user data 0x%x\n", KNET_SKB_CB(skb)->filter_user_data); + printk("dcb type 0x%x\n", KNET_SKB_CB(skb)->dcb_type); + if (skb->data[5] == 0x03) { + dev_kfree_skb(skb); + return NULL; + } + show_mac(skb); + return skb; +} + +static struct sk_buff * +test_tx_cb(struct sk_buff *skb, int dev_no, void *meta) +{ + printk("tx_cb for dev %d\n", dev_no); + show_mac(skb); + skb->data[5] += 1; + return skb; +} + +static int +test_filter_cb(uint8_t *pkt, int size, int dev_no, void *meta, + int chan, kcom_filter_t *kf) +{ + printk("filter_cb (%d) for dev %d\n", kf->dest_id, dev_no); + if (pkt[12] == 0x81 && pkt[13] == 0x00) { + printk(" VTAG %d\n", pkt[15]); + kf->dest_type = KCOM_DEST_T_NETIF; + kf->dest_id = pkt[15]; + return 1; + } + return 0; +} + +/* + * Generic module functions + */ + +static int +_pprint(void) +{ + pprintf("Broadcom Linux KNET Call-Back Driver\n"); + + return 0; +} + +static int +_cleanup(void) +{ + bkn_rx_skb_cb_unregister(test_rx_cb); + bkn_tx_skb_cb_unregister(test_tx_cb); + bkn_filter_cb_unregister(test_filter_cb); + + return 0; +} + +static int +_init(void) +{ + bkn_rx_skb_cb_register(test_rx_cb); + bkn_tx_skb_cb_register(test_tx_cb); + bkn_filter_cb_register(test_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/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/shared/Makefile b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/shared/Makefile @@ -0,0 +1,29 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/shared/gmodule.c b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/shared/gmodule.c @@ -0,0 +1,427 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <lkm.h> +#include <gmodule.h> +#include <linux/init.h> +#include <linux/seq_file.h> + +/* 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/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/shared/ksal.c b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/shared/ksal.c @@ -0,0 +1,249 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: ksal.c,v 1.1 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ + +#include <sal/core/sync.h> +#include <sal/core/thread.h> + +#include "lkm.h" +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +#include <linux/semaphore.h> +#else +#include <asm/semaphore.h> +#endif +#include <linux/interrupt.h> +#include <linux/sched.h> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) +#include <linux/sched/rt.h> +#endif +#include <linux/time.h> + +#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(&ltv); + 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/sdk-6.5.16/src/gpl-modules/systems/linux/user/common/Makefile b/sdk-6.5.16/src/gpl-modules/systems/linux/user/common/Makefile @@ -0,0 +1,229 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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) + +KNET_CB_LOCAL := linux-knet-cb.$(KOBJ) +KNET_CB := $(DEST_DIR)/$(KNET_CB_LOCAL) + +BCM_KNET_LOCAL :=linux-bcm-knet.$(KOBJ) +BCM_KNET=$(DEST_DIR)/$(BCM_KNET_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 + +ifdef BUILD_KNET_CB +all_targets += $(KNET_CB) + +ifeq ($(NO_LOCAL_TARGETS),) +LOCAL_TARGETS +=$(patsubst %,../$(platform)/%,$(KNET_CB_LOCAL)) +all_targets +=$(LOCAL_TARGETS) +endif +endif + +ADD_TO_CFLAGS += -I$(SDK)/systems/linux/kernel/modules/include +COND_KNET_LIBS = libuser.$(libext) +endif + +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_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) -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \ + subdirs="shared bcm-knet" override-target=linux-$(platform) CFLAGS="$(CFLAGS)" +ifdef BUILD_KNET_CB + $(MAKE) -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \ + subdirs="knet-cb" override-target=linux-$(platform) CFLAGS="$(CFLAGS)" +endif +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="shared bcm-knet knet-cb" \ + override-target=linux-$(platform) $@ + $(RM) $(KERNEL_BDE) $(USER_BDE) + $(RM) $(BCM_KNET) $(KNET_CB) + $(RM) $(KERN_BLDROOT)/linux-kernel-bde.$(KOBJ) + $(RM) $(KERN_BLDROOT)/linux-user-bde.$(KOBJ) + $(RM) $(KERN_BLDROOT)/linux-bcm-knet.$(KOBJ) + $(RM) $(KERN_BLDROOT)/linux-knet-cb.$(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/sdk-6.5.16/src/gpl-modules/systems/linux/user/iproc-3_14/Makefile b/sdk-6.5.16/src/gpl-modules/systems/linux/user/iproc-3_14/Makefile @@ -0,0 +1,65 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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/sdk-6.5.16/src/gpl-modules/systems/linux/user/iproc/Makefile b/sdk-6.5.16/src/gpl-modules/systems/linux/user/iproc/Makefile @@ -0,0 +1,59 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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_14 +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/sdk-6.5.16/src/gpl-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile b/sdk-6.5.16/src/gpl-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile @@ -0,0 +1,45 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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/sdk-6.5.16/src/gpl-modules/tools/mktool.pl b/sdk-6.5.16/src/gpl-modules/tools/mktool.pl @@ -0,0 +1,292 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# +# 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 <<MKTOOL; + +mktool.pl:: +curdir $curdir + +MKTOOL + + # derive the path to the target + $curdir = "$sdk/$curdir"; + + # save the basename + $dirName = substr($target,0,rindex($target,"\/")); + + # prepare the top line of the %.d file + $resultant="$source \\\n\${BLDDIR}/"; + if(!$?) + { + foreach $line (@result) + { + $line =~ s/^#.*\n//g; # some makedeps produce comments + $line =~ s/\n+$//; # toss trailing newlines + $line =~ s/(\s+)(\.\/)/ /g; # remove leading ./ + + # insert SDK path before ../ + $line =~ s/(\s+)(\.\.\/)/${1}$curdir\/${2}/g; + + # insert SDK path + $line =~ s/(\s+)(\w+)/${1}$curdir\/${2}/g; + + $count=0; + $tmp=$line; + while( (index($line,"..")>-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/sdk-6.5.20/src/gpl-modules/RELEASE b/sdk-6.5.20/src/gpl-modules/RELEASE diff --git a/sdk-6.5.20/src/gpl-modules/include/ibde.h b/sdk-6.5.20/src/gpl-modules/include/ibde.h @@ -0,0 +1,178 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: ibde.h,v 1.27 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ + +#ifndef __IBDE_H__ +#define __IBDE_H__ + +#include <sal/types.h> + +/* + * 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; + /* a unique number representing the specific device. + * Must be different for different devices. + * May be used to identify specific devices in the system. + * May be implemented as a full PCIe address, a persistent configurable user value, ... + * Possible implementation value stores in QSPI flash memory of the device. */ + uint32 dev_unique_id; +} 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_8MB_REG_SPACE 0x10000000 /* 8MB sized CMIC BAR */ +#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); + + /* + * I2C operations on the Device, assuming it is connected by I2C to the CPU. + */ + /* Read from the internal device Address space using I2C */ + int (*i2c_device_read)( + int dev, /* The device ID to access */ + uint32 addr, /* The address to access in the internal device address space */ + uint32 *value);/* the value to be read. */ + /* Write to the internal device Address space using I2C */ + int (*i2c_device_write)( + int dev, /* The device ID to access */ + uint32 addr, /* The address to access in the internal device address space */ + uint32 value); /* the value to be written. */ + +} ibde_t; + + +/* System BDE */ +extern ibde_t *bde; + + +#endif /* __IBDE_H__ */ diff --git a/sdk-6.5.20/src/gpl-modules/include/kcom.h b/sdk-6.5.20/src/gpl-modules/include/kcom.h @@ -0,0 +1,598 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <sal/types.h> + +#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_REPROBE 7 /* Reprobe device */ +#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_M_WB_CLEANUP 51 /* Clean up for warmbooting */ +#define KCOM_M_CLOCK_CMD 52 /* Clock Commands */ + +#define KCOM_VERSION 12 /* 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 + +/* + * Max size of Sand System Headers + * For DNX, Module Header(20B) + PTCH(2B) + ITMH(5B) + * For DPP, PTCH(2B) + ITMH(4B) + */ +#define KCOM_NETIF_SYSTEM_HEADERS_SIZE_MAX 27 + +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 system_headers[KCOM_NETIF_SYSTEM_HEADERS_SIZE_MAX]; + uint8 system_headers_size; + char name[KCOM_NETIF_NAME_MAX]; + uint8 phys_port; +} 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 <dest_id>. + * + * KCOM_DEST_T_API + * Packet is sent to Rx API through queue <dest_id>. + * + * 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; + /** Mark to match source modid and modport */ + uint8 is_src_modport; + uint8 spa_unit; +} 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 { + uint64 dcb_start; + struct { + uint32 tx; + uint32 rx; + } seqno; + } data; + union { + void *p; + uint8 b[8]; + } cookie; + } 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; + +/* + * Request KCOM interface clock info. + */ +#define KSYNC_M_HW_INIT 0 +#define KSYNC_M_HW_DEINIT 1 +#define KSYNC_M_VERSION 2 +#define KSYNC_M_HW_TS_DISABLE 3 + +typedef struct kcom_clock_info_s { + uint8 cmd; + int32 data[8]; +} kcom_clock_info_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; + uint8 cmic_type; + uint8 dcb_type; + uint8 dcb_size; + uint8 pkt_hdr_size; + uint32 dma_hi; + uint32 cdma_channels; + /* + * Information to parse Dune system headers + */ + uint32 ftmh_lb_key_ext_size; + uint32 ftmh_stacking_ext_size; + uint32 pph_base_size; + uint32 pph_lif_ext_size[8]; + uint32 udh_length_type[4]; + uint32 udh_size; + uint32 oamp_punted; + uint8 no_skip_udh_check; + uint8 system_headers_mode; + uint8 udh_enable; +} 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; + +/* + * Reprobe switch device. + */ +typedef struct kcom_msg_reprobe_s { + kcom_msg_hdr_t hdr; + uint32 flags; +} kcom_msg_reprobe_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; + +/* + * Clean up warmboot-related resources. + */ +typedef struct kcom_msg_wb_cleanup_s { + kcom_msg_hdr_t hdr; + uint32 flags; +} kcom_msg_wb_cleanup_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; + +/* + * Destroy system network interface. + */ +typedef struct kcom_msg_clock_s{ + kcom_msg_hdr_t hdr; + kcom_clock_info_t clock_info; +} kcom_msg_clock_cmd_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 +#define KCOM_FILTER_MAX 128 +#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_reprobe_t reprobe; + 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_wb_cleanup_t wb_cleanup; + kcom_msg_clock_cmd_t clock_cmd; +} 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/sdk-6.5.20/src/gpl-modules/include/sal/core/sync.h b/sdk-6.5.20/src/gpl-modules/include/sal/core/sync.h @@ -0,0 +1,38 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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/sdk-6.5.20/src/gpl-modules/include/sal/core/thread.h b/sdk-6.5.20/src/gpl-modules/include/sal/core/thread.h @@ -0,0 +1,30 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <sal/types.h> + +void sal_usleep(uint32 usec); +void sal_udelay(uint32 usec); + +#endif /* !_SAL_THREAD_H */ diff --git a/sdk-6.5.20/src/gpl-modules/include/sal/types.h b/sdk-6.5.20/src/gpl-modules/include/sal/types.h @@ -0,0 +1,164 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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]))) + +#ifdef PTRS_ARE_64BITS +typedef uint64 sal_vaddr_t; /* Virtual address (Host address) */ +typedef uint64 sal_paddr_t; /* Physical address (PCI address) */ +#define PTR_TO_INT(x) ((uint32)(((sal_vaddr_t)(x))&0xFFFFFFFF)) +#define PTR_HI_TO_INT(x) ((uint32)((((sal_vaddr_t)(x))>>32)&0xFFFFFFFF)) +#else +typedef uint32 sal_vaddr_t; /* Virtual address (Host address) */ +/* Physical address (PCI address) */ +#ifdef PHYS_ADDRS_ARE_64BITS +typedef uint64 sal_paddr_t; +#define PTR_HI_TO_INT(x) ((uint32)((((uint64)(x))>>32)&0xFFFFFFFF)) +#else +typedef uint32 sal_paddr_t; +#define PTR_HI_TO_INT(x) (0) +#endif +#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_COMPOSITE_DEV_TYPE 0x20000 /* Composite device, composed of sub-devices with buses */ +#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/sdk-6.5.20/src/gpl-modules/include/sdk_config.h b/sdk-6.5.20/src/gpl-modules/include/sdk_config.h @@ -0,0 +1,45 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <sdk_custom_config.h> +#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/sdk-6.5.20/src/gpl-modules/include/soc/devids.h b/sdk-6.5.20/src/gpl-modules/include/soc/devids.h @@ -0,0 +1,1988 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * Copyright: (c) 2020 Broadcom. + * 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 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 BCM56980_DEVICE_ID_MASK 0xFFF0 +#define BCM56980_DEVICE_ID 0xb980 +#define BCM56980_A0_REV_ID 1 +#define BCM56980_B0_REV_ID 0x11 +#define BCM56981_DEVICE_ID 0xb981 +#define BCM56981_A0_REV_ID 1 +#define BCM56981_B0_REV_ID 0x11 +#define BCM56982_DEVICE_ID 0xb982 +#define BCM56982_A0_REV_ID 1 +#define BCM56982_B0_REV_ID 0x11 +#define BCM56983_DEVICE_ID 0xb983 +#define BCM56983_A0_REV_ID 1 +#define BCM56983_B0_REV_ID 0x11 +#define BCM56984_DEVICE_ID 0xb984 +#define BCM56984_A0_REV_ID 1 +#define BCM56984_B0_REV_ID 0x11 + +#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 BCM56273_DEVICE_ID 0xb273 +#define BCM56273_A0_REV_ID 1 +#define BCM56273_A1_REV_ID 2 + +#define BCM56274_DEVICE_ID 0xb274 +#define BCM56274_A0_REV_ID 1 +#define BCM56274_A1_REV_ID 2 + +#define BCM56275_DEVICE_ID 0xb275 +#define BCM56275_A0_REV_ID 1 +#define BCM56275_A1_REV_ID 2 + +#define BCM56276_DEVICE_ID 0xb276 +#define BCM56276_A0_REV_ID 1 +#define BCM56276_A1_REV_ID 2 + +#define BCM56277_DEVICE_ID 0xb277 +#define BCM56277_A0_REV_ID 1 +#define BCM56277_A1_REV_ID 2 + +#define BCM56278_DEVICE_ID 0xb278 +#define BCM56278_A0_REV_ID 1 +#define BCM56278_A1_REV_ID 2 + +#define BCM56279_DEVICE_ID 0xb279 +#define BCM56279_A1_REV_ID 2 + +#define BCM56575_DEVICE_ID 0xb575 +#define BCM56575_A1_REV_ID 2 + +#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 BCM56561_DEVICE_ID 0xb561 +#define BCM56561_A0_REV_ID 1 +#define BCM56561_B0_REV_ID 0x11 + +#define BCM56562_DEVICE_ID 0xb562 +#define BCM56562_A0_REV_ID 1 +#define BCM56562_B0_REV_ID 0x11 + +#define BCM56670_DEVICE_ID 0xb670 +#define BCM56670_A0_REV_ID 1 +#define BCM56670_B0_REV_ID 0x11 +#define BCM56670_C0_REV_ID 0x21 + + +#define BCM56671_DEVICE_ID 0xb671 +#define BCM56671_A0_REV_ID 1 +#define BCM56671_B0_REV_ID 0x11 +#define BCM56671_C0_REV_ID 0x21 + +#define BCM56672_DEVICE_ID 0xb672 +#define BCM56672_A0_REV_ID 1 +#define BCM56672_B0_REV_ID 0x11 +#define BCM56672_C0_REV_ID 0x21 + +#define BCM56675_DEVICE_ID 0xb675 +#define BCM56675_A0_REV_ID 1 +#define BCM56675_B0_REV_ID 0x11 +#define BCM56675_C0_REV_ID 0x21 + + +#define BCM56565_DEVICE_ID 0xb565 +#define BCM56565_A0_REV_ID 1 +#define BCM56565_B0_REV_ID 0x11 + +#define BCM56566_DEVICE_ID 0xb566 +#define BCM56566_A0_REV_ID 1 +#define BCM56566_B0_REV_ID 0x11 + +#define BCM56567_DEVICE_ID 0xb567 +#define BCM56567_A0_REV_ID 1 +#define BCM56567_B0_REV_ID 0x11 + +#define BCM56568_DEVICE_ID 0xb568 +#define BCM56568_A0_REV_ID 1 +#define BCM56568_B0_REV_ID 0x11 + +#define BCM56760_DEVICE_ID 0xb760 +#define BCM56760_A0_REV_ID 1 +#define BCM56760_A1_REV_ID 2 +#define BCM56760_B0_REV_ID 0x11 + + +#define BCM56761_DEVICE_ID 0xb761 +#define BCM56761_A0_REV_ID 1 +#define BCM56761_A1_REV_ID 2 +#define BCM56761_B0_REV_ID 0x11 +#define BCM56761_B1_REV_ID 0x12 + +#define BCM56762_DEVICE_ID 0xb762 +#define BCM56762_A0_REV_ID 1 +#define BCM56762_B0_REV_ID 0x11 + +#define BCM56764_DEVICE_ID 0xb764 +#define BCM56764_A0_REV_ID 1 +#define BCM56764_B0_REV_ID 0x11 + +#define BCM56765_DEVICE_ID 0xb765 +#define BCM56765_A0_REV_ID 1 +#define BCM56765_B0_REV_ID 0x11 + +#define BCM56766_DEVICE_ID 0xb766 +#define BCM56766_A0_REV_ID 1 +#define BCM56766_B0_REV_ID 0x11 + +#define BCM56768_DEVICE_ID 0xb768 +#define BCM56768_A0_REV_ID 1 +#define BCM56768_B0_REV_ID 0x11 + +#define BCM56068_DEVICE_ID 0xb068 +#define BCM56068_A0_REV_ID 1 +#define BCM56068_B0_REV_ID 0x11 + +#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 BCM56170_DEVICE_ID 0xb170 +#define BCM56170_A0_REV_ID 1 +#define BCM56170_B0_REV_ID 0x11 +#define BCM56172_DEVICE_ID 0xb172 +#define BCM56172_A0_REV_ID 1 +#define BCM56172_B0_REV_ID 0x11 +#define BCM56174_DEVICE_ID 0xb174 +#define BCM56174_A0_REV_ID 1 +#define BCM56174_B0_REV_ID 0x11 + +#define BCM53570_DEVICE_ID 0x8570 +#define BCM53570_A0_REV_ID 1 +#define BCM53570_B0_REV_ID 0x11 +#define BCM53575_DEVICE_ID 0x8575 +#define BCM53575_A0_REV_ID 1 +#define BCM53575_B0_REV_ID 0x11 + +#define BCM56070_DEVICE_ID 0xb070 +#define BCM56070_A0_REV_ID 1 +#define BCM56071_DEVICE_ID 0xb071 +#define BCM56071_A0_REV_ID 1 +#define BCM56072_DEVICE_ID 0xb072 +#define BCM56072_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 BCM56975_DEVICE_ID 0xb975 +#define BCM56975_A0_REV_ID 1 +#define BCM56975_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 BCM56370_DEVICE_ID 0xb370 +#define BCM56370_A0_REV_ID 1 +#define BCM56370_A1_REV_ID 0x02 +#define BCM56370_A2_REV_ID 0x03 + +#define BCM56371_DEVICE_ID 0xb371 +#define BCM56371_A0_REV_ID 1 +#define BCM56371_A1_REV_ID 0x02 +#define BCM56371_A2_REV_ID 0x03 + +#define BCM56372_DEVICE_ID 0xb372 +#define BCM56372_A0_REV_ID 1 +#define BCM56372_A1_REV_ID 0x02 +#define BCM56372_A2_REV_ID 0x03 + +#define BCM56374_DEVICE_ID 0xb374 +#define BCM56374_A0_REV_ID 1 +#define BCM56374_A1_REV_ID 0x02 +#define BCM56374_A2_REV_ID 0x03 + +#define BCM56375_DEVICE_ID 0xb375 +#define BCM56375_A0_REV_ID 1 +#define BCM56375_A1_REV_ID 0x02 +#define BCM56375_A2_REV_ID 0x03 + +#define BCM56376_DEVICE_ID 0xb376 +#define BCM56376_A0_REV_ID 1 +#define BCM56376_A1_REV_ID 0x02 +#define BCM56376_A2_REV_ID 0x03 + +#define BCM56377_DEVICE_ID 0xb377 +#define BCM56377_A0_REV_ID 1 +#define BCM56377_A1_REV_ID 0x02 +#define BCM56377_A2_REV_ID 0x03 + +#define BCM56577_DEVICE_ID 0xb577 +#define BCM56577_A0_REV_ID 1 +#define BCM56577_A1_REV_ID 0x02 +#define BCM56577_A2_REV_ID 0x03 + +#define BCM56578_DEVICE_ID 0xb578 +#define BCM56578_A0_REV_ID 1 +#define BCM56578_A1_REV_ID 0x02 +#define BCM56578_A2_REV_ID 0x03 + +#define BCM56579_DEVICE_ID 0xb579 +#define BCM56579_A0_REV_ID 1 +#define BCM56579_A1_REV_ID 0x02 +#define BCM56579_A2_REV_ID 0x03 + +#define BCM56770_DEVICE_ID 0xb770 +#define BCM56770_A0_REV_ID 1 + +#define BCM56771_DEVICE_ID 0xb771 +#define BCM56771_A0_REV_ID 1 + +#define BCM56470_DEVICE_ID 0xb470 +#define BCM56470_A0_REV_ID 1 +#define BCM56471_DEVICE_ID 0xb471 +#define BCM56471_A0_REV_ID 1 +#define BCM56472_DEVICE_ID 0xb472 +#define BCM56472_A0_REV_ID 1 +#define BCM56475_DEVICE_ID 0xb475 +#define BCM56475_A0_REV_ID 1 + + +#define BCM53540_DEVICE_ID 0x8540 +#define BCM53540_A0_REV_ID 1 +#define BCM53547_DEVICE_ID 0x8547 +#define BCM53547_A0_REV_ID 1 +#define BCM53548_DEVICE_ID 0x8548 +#define BCM53548_A0_REV_ID 1 +#define BCM53549_DEVICE_ID 0x8549 +#define BCM53549_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 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 DNXC_A0_REV_ID 0x0001 +#define DNXC_A1_REV_ID 0x0002 +#define DNXC_B0_REV_ID 0x0011 +#define DNXC_B1_REV_ID 0x0012 +#define DNXC_DEVID_FAMILY_MASK 0xfff0 +#define BCM88790_DEVICE_ID 0x8790 +#define BCM88790_A0_REV_ID DNXC_A0_REV_ID +#define BCM88790_B0_REV_ID DNXC_B0_REV_ID +#define BCM88791_DEVICE_ID 0x8791 +#define BCM88792_DEVICE_ID 0x8792 +#define BCM88793_DEVICE_ID 0x8793 +#define BCM88794_DEVICE_ID 0x8794 +#define BCM88795_DEVICE_ID 0x8795 +#define BCM88796_DEVICE_ID 0x8796 +#define BCM88797_DEVICE_ID 0x8797 +#define BCM88798_DEVICE_ID 0x8798 +#define BCM88799_DEVICE_ID 0x8799 +#define BCM8879A_DEVICE_ID 0x879A +#define BCM8879B_DEVICE_ID 0x879B +#define BCM8879C_DEVICE_ID 0x879C +#define BCM8879D_DEVICE_ID 0x879D +#define BCM8879E_DEVICE_ID 0x879E +#define BCM8879F_DEVICE_ID 0x879F +#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 BCM88687_DEVICE_ID 0x8687 +#define BCM88687_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 JERICHO2_DEVICE_ID 0x8690 +#define JERICHO2_A0_REV_ID DNXC_A0_REV_ID +#define JERICHO2_B0_REV_ID DNXC_B0_REV_ID +#define JERICHO2_B1_REV_ID DNXC_B1_REV_ID +#define BCM88690_DEVICE_ID JERICHO2_DEVICE_ID +#define BCM88690_A0_REV_ID JERICHO2_A0_REV_ID +#define BCM88690_B0_REV_ID JERICHO2_B0_REV_ID +#define BCM88690_B1_REV_ID JERICHO2_B1_REV_ID +#define BCM88691_DEVICE_ID 0x8691 +#define BCM88692_DEVICE_ID 0x8692 +#define BCM88693_DEVICE_ID 0x8693 +#define BCM88694_DEVICE_ID 0x8694 +#define BCM88695_DEVICE_ID 0x8695 +#define BCM88696_DEVICE_ID 0x8696 +#define BCM88697_DEVICE_ID 0x8697 +#define BCM88698_DEVICE_ID 0x8698 +#define BCM88699_DEVICE_ID 0x8699 +#define BCM8869A_DEVICE_ID 0x869A +#define BCM8869B_DEVICE_ID 0x869B +#define BCM8869C_DEVICE_ID 0x869C +#define BCM8869D_DEVICE_ID 0x869D +#define BCM8869E_DEVICE_ID 0x869E +#define BCM8869F_DEVICE_ID 0x869F + +#define J2C_DEVICE_ID 0x8800 +#define J2C_2ND_DEVICE_ID 0x8820 +#define J2C_DEVID_FAMILY_MASK 0xffd0 +#define J2C_A0_REV_ID DNXC_A0_REV_ID +#define J2C_A1_REV_ID DNXC_A1_REV_ID +#define BCM88800_DEVICE_ID J2C_DEVICE_ID +#define BCM88820_DEVICE_ID J2C_2ND_DEVICE_ID +#define BCM88800_A0_REV_ID J2C_A0_REV_ID +#define BCM88800_A1_REV_ID J2C_A1_REV_ID +#define BCM88821_DEVICE_ID 0x8821 +#define BCM88826_DEVICE_ID 0x8826 +#define BCM88802_DEVICE_ID 0x8802 +#define BCM88803_DEVICE_ID 0x8803 +#define BCM88804_DEVICE_ID 0x8804 +#define BCM88805_DEVICE_ID 0x8805 +#define BCM88806_DEVICE_ID 0x8806 +#define BCM88822_DEVICE_ID 0x8822 +#define BCM88823_DEVICE_ID 0x8823 +#define BCM88824_DEVICE_ID 0x8824 +#define BCM88825_DEVICE_ID 0x8825 + +#define J2P_DEVICE_ID 0x8850 +#define J2P_A0_REV_ID DNXC_A0_REV_ID +#define BCM88850_DEVICE_ID J2P_DEVICE_ID +#define BCM88850_A0_REV_ID J2P_A0_REV_ID + +#define Q2A_DEVICE_ID 0x8480 +#define Q2A_A0_REV_ID DNXC_A0_REV_ID +#define Q2A_B0_REV_ID DNXC_B0_REV_ID +#define Q2A_B1_REV_ID DNXC_B1_REV_ID +#define BCM88480_DEVICE_ID Q2A_DEVICE_ID +#define BCM88480_A0_REV_ID Q2A_A0_REV_ID +#define BCM88480_B0_REV_ID Q2A_B0_REV_ID +#define BCM88480_B1_REV_ID Q2A_B1_REV_ID +#define BCM88481_DEVICE_ID 0x8481 +#define BCM88482_DEVICE_ID 0x8482 +#define BCM88483_DEVICE_ID 0x8483 +#define BCM88484_DEVICE_ID 0x8484 +#define BCM88485_DEVICE_ID 0x8485 +#define BCM88486_DEVICE_ID 0x8486 +#define BCM88487_DEVICE_ID 0x8487 +#define BCM88488_DEVICE_ID 0x8488 +#define BCM88489_DEVICE_ID 0x8489 +#define BCM8848A_DEVICE_ID 0x848A +#define BCM8848B_DEVICE_ID 0x848B +#define BCM8848C_DEVICE_ID 0x848C +#define BCM8848D_DEVICE_ID 0x848D +#define BCM8848E_DEVICE_ID 0x848E +#define BCM8848F_DEVICE_ID 0x848F + +#define Q2U_DEVICE_ID 0x8280 +#define BCM88280_DEVICE_ID Q2U_DEVICE_ID +#define BCM88281_DEVICE_ID 0x8281 +#define BCM88282_DEVICE_ID 0x8282 +#define BCM88283_DEVICE_ID 0x8283 +#define BCM88284_DEVICE_ID 0x8284 +#define BCM88285_DEVICE_ID 0x8285 +#define BCM88286_DEVICE_ID 0x8286 +#define BCM88287_DEVICE_ID 0x8287 +#define BCM88288_DEVICE_ID 0x8288 +#define BCM88289_DEVICE_ID 0x8289 +#define BCM8828A_DEVICE_ID 0x828A +#define BCM8828B_DEVICE_ID 0x828B +#define BCM8828C_DEVICE_ID 0x828C +#define BCM8828D_DEVICE_ID 0x828D +#define BCM8828E_DEVICE_ID 0x828E +#define BCM8828F_DEVICE_ID 0x828F + +#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 BCM88271_DEVICE_ID 0x8271 +#define BCM88272_DEVICE_ID 0x8272 +#define BCM88273_DEVICE_ID 0x8273 +#define BCM88274_DEVICE_ID 0x8274 +#define BCM88276_DEVICE_ID 0x8276 +#define BCM88278_DEVICE_ID 0x8278 +#define BCM88279_DEVICE_ID 0x8279 + +#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 + +#define PLX9056_DEVICE_ID 0x9056 + +#ifdef BCM_LTSW_SUPPORT +#define BCM56880_DEVICE_ID 0xb880 +#define BCM56880_A0_REV_ID 0x0001 +#define BCM56880_B0_REV_ID 0x0011 +#define BCM56881_DEVICE_ID 0xb881 +#define BCM56881_A0_REV_ID 0x0001 +#define BCM56881_B0_REV_ID 0x0011 +#define BCM56883_DEVICE_ID 0xb883 +#define BCM56883_A0_REV_ID 0x0001 +#define BCM56883_B0_REV_ID 0x0011 + +#define BCM56780_DEVICE_ID 0xb780 +#define BCM56780_A0_REV_ID 0x0001 +#define BCM56782_DEVICE_ID 0xb782 +#define BCM56782_A0_REV_ID 0x0001 +#define BCM56784_DEVICE_ID 0xb784 +#define BCM56784_A0_REV_ID 0x0001 +#define BCM56786_DEVICE_ID 0xb786 +#define BCM56786_A0_REV_ID 0x0001 +#define BCM56788_DEVICE_ID 0xb788 +#define BCM56788_A0_REV_ID 0x0001 + +#define BCM56990_DEVICE_ID 0xb990 +#define BCM56990_A0_REV_ID 0x0001 +#define BCM56990_B0_REV_ID 0x0011 +#define BCM56991_DEVICE_ID 0xb991 +#define BCM56991_A0_REV_ID 0x0001 +#define BCM56991_B0_REV_ID 0x0011 + +#define BCM56996_DEVICE_ID 0xb996 +#define BCM56996_A0_REV_ID 0x0001 +#define BCM56997_DEVICE_ID 0xb997 +#define BCM56997_A0_REV_ID 0x0001 +#endif +#endif + diff --git a/sdk-6.5.20/src/gpl-modules/make/Make.config b/sdk-6.5.20/src/gpl-modules/make/Make.config @@ -0,0 +1,358 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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 + ESW_CHIPS = 1 +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/sdk-6.5.20/src/gpl-modules/make/Make.depend b/sdk-6.5.20/src/gpl-modules/make/Make.depend @@ -0,0 +1,108 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.20/src/gpl-modules/make/Make.kernlib b/sdk-6.5.20/src/gpl-modules/make/Make.kernlib @@ -0,0 +1,69 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.20/src/gpl-modules/make/Make.lib b/sdk-6.5.20/src/gpl-modules/make/Make.lib @@ -0,0 +1,80 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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 + $(AR) ${ARFLAGS} $@ $(sort ${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/sdk-6.5.20/src/gpl-modules/make/Make.linux b/sdk-6.5.20/src/gpl-modules/make/Make.linux @@ -0,0 +1,97 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# +# $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 issu: + $(MAKE) $(CMD) $@ + +clean_d: clean + +distclean: + $(MAKE) $(CMD) $@ + +.PHONY: build clean distclean clean_d DELIVER variable mod bcm user issu + diff --git a/sdk-6.5.20/src/gpl-modules/make/Make.subdirs b/sdk-6.5.20/src/gpl-modules/make/Make.subdirs @@ -0,0 +1,44 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.20/src/gpl-modules/make/Make.tools b/sdk-6.5.20/src/gpl-modules/make/Make.tools @@ -0,0 +1,38 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-gts b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-gts @@ -0,0 +1,142 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $Id: Makefile.linux-xlr-4_19,v 0.1 Broadcom SDK $ +# $Copyright: (c) 2015 Broadcom Corp. +# All Rights Reserved.$ + +# +# XLR system make file. +# +# Most of this was taken from target x86-smp_generic_64-2_6. +# + + +############################################################################# +# this segment is custom and not sourced from any existing makefile # +# (base thanks to http:<slash><slash>confluence.broadcom.com/display/NTSWSW/X86+System) # +############################################################################# + +# set up a basic feature list. tcl, etc. # +#ifeq (,$(FEATURE_LIST)) +#FEATURE_LIST = TCL BFD PTP CINT L3 I2C MEM_SCAN EDITLINE BCM_SAL_PROFILE CUSTOMER TEST CHASSIS MSTP RCPU +#endif + +# some basic path variables for tools and kernel source, etc # +export XLR_TOOLS_BASE = /projects/ntsw-tools/linux/xlr-419 +TOOLCHAIN_DIR = $(XLR_TOOLS_BASE)/buildroot/host/usr +KERNDIR = $(XLR_TOOLS_BASE)/kernel/linux + +# set up cross compile prefix, tools dir variables. # +export CROSS_COMPILE := x86_64-broadcom-linux-gnu- +export TOOLS_DIR := $(TOOLCHAIN_DIR)/bin + +# architecture. # +ARCH = x86_64 +TARGET_ARCHITECTURE = x86_64-broadcom-linux-gnu + +# Noisy kernel build +KBUILD_VERBOSE = 1 + +export ARCH KBUILD_VERBOSE + +# set up paths. # +export LIBRARY_PATH := $(TOOLCHAIN_DIR)/lib:$(TOOLCHAIN_DIR)/lib64:$(LIBRARY_PATH) +export PATH := $(TOOLCHAIN_DIR)/bin:$(KERNDIR):$(PATH) + +# set up SYSINC path # +export SYSINC := $(XLR_TOOLS_BASE)/buildroot/host/usr/lib/gcc/$(TARGET_ARCHITECTURE)/5.4.0/include + + +# CFLAGS/CFGFLAGS # +CFLAGS += -DUSE_LINUX_BDE_MMAP=1 +#CFLAGS += -DBDE_LINUX_USE_MSI_INTERRUPT +CFLAGS += -Wno-error=unused-value +CFLAGS += -Wno-error=unused-but-set-variable +CFLAGS += -Wno-error=maybe-uninitialized +CFLAGS += -Wno-error=cpp +CFLAGS += -Wno-error=aggressive-loop-optimizations +CFLAGS += -Wno-error=array-bounds +CFLAGS += -Wno-error=strict-overflow +CFLAGS += -L$(TOOLCHAIN_DIR)/lib +CFLAGS += -L$(TOOLCHAIN_DIR)/lib64 +#CFLAGS += -Wl,--rpath=/lib64 # may need to set rpath and dynamic-linker path here (and possibly in KLFAGS below) in the future, # +#CFLAGS += -Wl,--dynamic-linker=/lib64/ld-linux-x86-64.so.2 # if we want to build the target executable to be used with shared libs # + +#XLDK-568 fix inline references +CFGFLAGS += -fgnu89-inline + + +# set up KFLAGS appropriately. # +ifeq (,$(KFLAGS)) +KFLAGS := -L$(TOOLCHAIN_DIR)/lib -L$(TOOLCHAIN_DIR)/lib64 -I$(KERNDIR) -lc -nostdinc -isystem $(SYSINC) -Iinclude -I$(KERNDIR)/arch/x86/include -I$(KERNDIR)/arch/x86/include/generated -I$(KERNDIR)/arch/x86/include/generated/uapi -I$(KERNDIR)/arch/x86/include/uapi -I$(KERNDIR)/include -I$(KERNDIR)/include/generated -I$(KERNDIR)/include/generated/uapi -I$(KERNDIR)/include/uapi -include $(KERNDIR)/include/generated/autoconf.h -D__KERNEL__ -DNDEBUG -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Wno-format-security -fno-delete-null-pointer-checks -O2 -m64 -mtune=generic -mno-red-zone -mcmodel=kernel -funit-at-a-time -maccumulate-outgoing-args -fstack-protector -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -Wframe-larger-than=1024 -fno-omit-frame-pointer -Wdeclaration-after-statement -Wno-pointer-sign -fno-dwarf2-cfi-asm -fconserve-stack +endif + + +###################################################################### +# this segment comes from make/Makefile.linux-x86-smp_generic_64-2_6 # +###################################################################### +CFGFLAGS += -DLONGS_ARE_64BITS +CFGFLAGS += -DPTRS_ARE_64BITS +CFGFLAGS += -DSAL_SPL_LOCK_ON_IRQ + + +############################################################## +# This segment comes from make/Makefile.linux-x86-common-2_6 # +############################################################## +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\" +CFGFLAGS += -DSAL_BDE_DMA_MEM_DEFAULT=32 + +# 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)))") + +ifdef LTSW_CHIPS +# Ensure we do not use an out-of-date libelf.so +ELFUTILS_MIN = 158 +ELFUTILS_DIR ?= /projects/ntsw-tools/lib + +# Default open source target build +OPENSRC_BUILD ?= fed21-x86_64 + +# Hardware interface (see $SDKLT/bcma/sys/probe directory) +SYSTEM_INTERFACE ?= ngbde + +# Turn on direct register access if running on real hardware. +ifeq (ngbde,$(SYSTEM_INTERFACE)) +LTSW_ADD_CPPFLAGS += -DBCMDRD_CONFIG_MEMMAP_DIRECT=1 +endif + +export SYSTEM_INTERFACE +endif + +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/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc @@ -0,0 +1,104 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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)) +#While BE mode is supported, it's use is very limited. We had a specific customer +#request for BE support but don't currently mainstream it. So a 5.1.0 version +#has not been built. Continue using 5.0.3 for any BE support +TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk50-be/XLDK32 +TARGET_ARCHITECTURE:=armeb-broadcom-linux-uclibcgnueabi +KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux +else +TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk51/XLDK32 +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 + +CROSS_GCC_VER ?= $(shell $(TOOLCHAIN_BIN_DIR)/$(CROSS_COMPILE)gcc -dumpversion) + +# 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 + +CFLAGS += -fno-aggressive-loop-optimizations +CFLAGS += -Wno-error=maybe-uninitialized +CFLAGS += -Wno-error=array-bounds +CFLAGS += -fgnu89-inline +ifeq "$(shell expr `echo $(CROSS_GCC_VER) | cut -f1 -d.` \>= 7)" "1" + CFLAGS += -Wno-error=bool-operation +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 ?= $(LD_LIBRARY_PATH)/gcc/$(TARGET_ARCHITECTURE)/$(CROSS_GCC_VER)/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/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc-3_14 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc-3_14 @@ -0,0 +1,103 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc-4_4 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc-4_4 @@ -0,0 +1,92 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/xldk40-be/XLDK +TARGET_ARCHITECTURE:=armeb-broadcom-linux-uclibcgnueabi +KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux +else +TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk40/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/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc_64 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc_64 @@ -0,0 +1,106 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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)) +#We've never actually built a 64 BE executable. Just here for any future +#customer requirements. +TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk51-be/XLDK64 +TARGET_ARCHITECTURE ?= aarch64_be-broadcom-linux-uclibc +KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux +else +TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk51/XLDK64 +TARGET_ARCHITECTURE ?= aarch64-broadcom-linux-uclibc +KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux +endif + +ifeq (,$(CROSS_COMPILE)) +CROSS_COMPILE:= $(TARGET_ARCHITECTURE)- +endif + +# A72 tools +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 + +CROSS_GCC_VER ?= $(shell $(TOOLCHAIN_BIN_DIR)/$(CROSS_COMPILE)gcc -dumpversion) + +# 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 + +CFLAGS += -DPTRS_ARE_64BITS -DLONGS_ARE_64BITS +CFLAGS += -DPHYS_ADDRS_ARE_64BITS +CFLAGS += -fno-aggressive-loop-optimizations -fno-strict-overflow +CFLAGS += -Wno-error=maybe-uninitialized +CFLAGS += -Wno-error=array-bounds +CFLAGS += -fgnu89-inline +ifeq "$(shell expr `echo $(CROSS_GCC_VER) | cut -f1 -d.` \>= 7)" "1" + CFLAGS += -Wno-error=bool-operation +endif + + +CFGFLAGS += -D$(ENDIAN) -DIPROC_CMICD +CFGFLAGS += -DBCM_PLATFORM_STRING=\"IPROC_CMICD\" +CFGFLAGS += -DSAL_BDE_DMA_MEM_DEFAULT=16 + +ARCH = arm64 +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 ?= $(LD_LIBRARY_PATH)/gcc/$(TARGET_ARCHITECTURE)/$(CROSS_GCC_VER)/include + +ifeq (,$(KFLAGS)) +KFLAGS := -D__LINUX_ARM_ARCH__=8 -D__KERNEL__ -DPTRS_ARE_64BITS -DLONGS_ARE_64BITS -nostdinc -isystem $(KFLAG_INCLD) -I$(LINUX_INCLUDE) -include $(LINUX_INCLUDE)/generated/autoconf.h -I$(KERNDIR)/arch/arm64/include -I$(KERNDIR)/arch/arm64/include/generated -I$(KERNDIR)/arch/arm64/include/generated/uapi -I$(KERNDIR)/arch/arm64/include/generated/asm -I$(KERNDIR)/include/uapi -I$(KERNDIR)/include/generated/uapi -I$(KERNDIR)/arch/arm64/include/uapi -Wall -Wstrict-prototypes -Wno-trigraphs -Os -fno-strict-aliasing -fno-common -fno-pic -pipe -ffreestanding -fomit-frame-pointer -g -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign -mcmodel=large +endif + +ifneq ($(targetplat),user) +include ${SDK}/make/Makefile.linux-kernel-3_6 +endif diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel @@ -0,0 +1,112 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel-2_6 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel-2_6 @@ -0,0 +1,148 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel-3_6 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel-3_6 @@ -0,0 +1,148 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel-4_4 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel-4_4 @@ -0,0 +1,157 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kmodule b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kmodule @@ -0,0 +1,81 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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 + if [ ! -f $(KERNBLDDIR)/NO_SUPRESS ]; then echo "# suppress warning" > .$(PRE_COMPILED_OBJ).cmd; fi + $(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/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-slk b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-slk @@ -0,0 +1,146 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $Id: Makefile.linux-slk-3_14,v 1.2 Broadcom SDK $ +# $Copyright: (c) 2013 Broadcom Corp. +# All Rights Reserved.$ +# Makefile for SLK(BCM957812) + +# User must select one platform from below.By default ARM_LINUX is selected. . +ifeq (,$(BUILD_PLATFORM)) +BUILD_PLATFORM=ARM_LINUX +endif + +# Toolchain base directory for NS2 XMC card +ifeq (BE,$(ENDIAN_MODE)) +TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/toolchains/slk/linaro-be +TARGET_ARCHITECTURE:=aarch64_be-linux-gnu +KERNDIR ?= /projects/ntsw-tools/linux/iproc_ldks/slk-be/poky/brcm-released-source/git +else +TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/toolchains/slk/linaro-le +# Compiler for target architecture +TARGET_ARCHITECTURE:= aarch64-linux-gnu +# Kernel directory +KERNDIR ?= /projects/ntsw-tools/linux/iproc_ldks/slk/poky/brcm-released-source/git +endif + +ifeq (,$(CROSS_COMPILE)) +CROSS_COMPILE:= $(TARGET_ARCHITECTURE)- +endif + +# armtools +TOOLCHAIN_BIN_DIR=$(TOOLCHAIN_BASE_DIR)/bin +override PATH:=$(TOOLCHAIN_BIN_DIR):$(PATH) +LD_LIBRARY_PATH=$(TOOLCHAIN_BASE_DIR)/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) -DBCM958525 +CFGFLAGS += -DBCM_PLATFORM_STRING=\"SLK_BCM957812\" +CFGFLAGS += -DSAL_BDE_DMA_MEM_DEFAULT=32 +ifeq (1,$(SLK_32BIT)) +CFGFLAGS += -DSAL_BDE_32BIT_USER_64BIT_KERNEL +else +CFGFLAGS += -DPTRS_ARE_64BITS -DLONGS_ARE_64BITS +endif +CFGFLAGS += -DPHYS_ADDRS_ARE_64BITS + +CFLAGS += -Wno-unused-value -Wno-unused-but-set-variable -Wno-sizeof-pointer-memaccess -fno-aggressive-loop-optimizations + +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_SLK_BCM_CPU__ -D__DUNE_LINUX_BCM_CPU_PCIE__ +endif + +# Enable cached DMA memory by default +ifeq (,$(SAL_BDE_USE_CACHED_DMA_MEM)) +SAL_BDE_USE_CACHED_DMA_MEM = 1 +endif +ifeq ($(SAL_BDE_USE_CACHED_DMA_MEM),1) +CFGFLAGS += -DSAL_BDE_CACHE_DMA_MEM +endif + +ifeq (1,$(SLK_32BIT)) +ARCH = arm +else +ARCH = arm64 +endif + +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)/lib/gcc/$(TARGET_ARCHITECTURE)/4.9.2/include + +ifeq (,$(KFLAGS)) +KFLAGS := -D__LINUX_ARM_ARCH__=8 -D__KERNEL__ -DPTRS_ARE_64BITS -DLONGS_ARE_64BITS -nostdinc -isystem $(KFLAG_INCLD) -I$(LINUX_INCLUDE) -include $(LINUX_INCLUDE)/generated/autoconf.h -I$(KERNDIR)/arch/arm64/include -I$(KERNDIR)/arch/arm64/include/generated -I$(KERNDIR)/arch/arm64/include/generated/asm -I$(KERNDIR)/include/uapi -I$(KERNDIR)/include/generated/uapi -I$(KERNDIR)/arch/arm64/include/uapi -Wall -Wstrict-prototypes -Wno-trigraphs -Os -fno-strict-aliasing -fno-common -fno-pic -pipe -ffreestanding -fomit-frame-pointer -g -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign +endif + +ifdef LTSW_CHIPS +# Default open source target build +ifeq (BE,$(ENDIAN_MODE)) +OPENSRC_BUILD ?= linaro_arm64_be +else +OPENSRC_BUILD ?= linaro_arm64_le +endif + +# Hardware interface (see $SDKLT/bcma/sys/probe directory) +SYSTEM_INTERFACE ?= ngbde + +# Turn on direct register access if running on real hardware. +ifeq (ngbde,$(SYSTEM_INTERFACE)) +LTSW_ADD_CPPFLAGS += -DBCMDRD_CONFIG_MEMMAP_DIRECT=1 +endif + +export SYSTEM_INTERFACE +endif + +ifneq ($(targetplat),user) +include ${SDK}/make/Makefile.linux-kernel-3_6 +endif diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-x86-common-2_6 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-x86-common-2_6 @@ -0,0 +1,44 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-x86-generic-common-2_6 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-x86-generic-common-2_6 @@ -0,0 +1,51 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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 $(CC) -print-search-dirs | grep install | cut -c 10-)include diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-x86-smp_generic_64-2_6 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-x86-smp_generic_64-2_6 @@ -0,0 +1,56 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $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 -fno-pie -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 + + +LINUX_UAPI = $(LINUX_INCLUDE)/uapi +ifneq (,$(shell ls $(LINUX_UAPI) 2>/dev/null)) +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 +endif + +ifdef LTSW_CHIPS +# Ensure we do not use an out-of-date libelf.so +ELFUTILS_MIN = 158 +ELFUTILS_DIR ?= /projects/ntsw-tools/lib + +# Default open source target build +OPENSRC_BUILD ?= x86_64 + +# Hardware interface (see $SDKLT/bcma/sys/probe directory) +SYSTEM_INTERFACE ?= ngbde + +# Turn on direct register access if running on real hardware. +ifeq (ngbde,$(SYSTEM_INTERFACE)) +LTSW_ADD_CPPFLAGS += -DBCMDRD_CONFIG_MEMMAP_DIRECT=1 +endif + +export SYSTEM_INTERFACE +endif + +include ${SDK}/make/Makefile.linux-x86-common-2_6 diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-xlr b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-xlr @@ -0,0 +1,142 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# $Id: Makefile.linux-xlr-4_19,v 0.1 Broadcom SDK $ +# $Copyright: (c) 2015 Broadcom Corp. +# All Rights Reserved.$ + +# +# XLR system make file. +# +# Most of this was taken from target x86-smp_generic_64-2_6. +# + + +############################################################################# +# this segment is custom and not sourced from any existing makefile # +# (base thanks to http:<slash><slash>confluence.broadcom.com/display/NTSWSW/X86+System) # +############################################################################# + +# set up a basic feature list. tcl, etc. # +#ifeq (,$(FEATURE_LIST)) +#FEATURE_LIST = TCL BFD PTP CINT L3 I2C MEM_SCAN EDITLINE BCM_SAL_PROFILE CUSTOMER TEST CHASSIS MSTP RCPU +#endif + +# some basic path variables for tools and kernel source, etc # +export XLR_TOOLS_BASE = /projects/ntsw-tools/linux/xlr-419 +TOOLCHAIN_DIR = $(XLR_TOOLS_BASE)/buildroot/host/usr +KERNDIR = $(XLR_TOOLS_BASE)/kernel/linux + +# set up cross compile prefix, tools dir variables. # +export CROSS_COMPILE := x86_64-broadcom-linux-gnu- +export TOOLS_DIR := $(TOOLCHAIN_DIR)/bin + +# architecture. # +ARCH = x86_64 +TARGET_ARCHITECTURE = x86_64-broadcom-linux-gnu + +# Noisy kernel build +KBUILD_VERBOSE = 1 + +export ARCH KBUILD_VERBOSE + +# set up paths. # +export LIBRARY_PATH := $(TOOLCHAIN_DIR)/lib:$(TOOLCHAIN_DIR)/lib64:$(LIBRARY_PATH) +export PATH := $(TOOLCHAIN_DIR)/bin:$(KERNDIR):$(PATH) + +# set up SYSINC path # +export SYSINC := $(XLR_TOOLS_BASE)/buildroot/host/usr/lib/gcc/$(TARGET_ARCHITECTURE)/5.4.0/include + + +# CFLAGS/CFGFLAGS # +CFLAGS += -DUSE_LINUX_BDE_MMAP=1 +#CFLAGS += -DBDE_LINUX_USE_MSI_INTERRUPT +CFLAGS += -Wno-error=unused-value +CFLAGS += -Wno-error=unused-but-set-variable +CFLAGS += -Wno-error=maybe-uninitialized +CFLAGS += -Wno-error=cpp +CFLAGS += -Wno-error=aggressive-loop-optimizations +CFLAGS += -Wno-error=array-bounds +CFLAGS += -Wno-error=strict-overflow +CFLAGS += -L$(TOOLCHAIN_DIR)/lib +CFLAGS += -L$(TOOLCHAIN_DIR)/lib64 +#CFLAGS += -Wl,--rpath=/lib64 # may need to set rpath and dynamic-linker path here (and possibly in KLFAGS below) in the future, # +#CFLAGS += -Wl,--dynamic-linker=/lib64/ld-linux-x86-64.so.2 # if we want to build the target executable to be used with shared libs # + +#XLDK-568 fix inline references +CFGFLAGS += -fgnu89-inline + + +# set up KFLAGS appropriately. # +ifeq (,$(KFLAGS)) +KFLAGS := -L$(TOOLCHAIN_DIR)/lib -L$(TOOLCHAIN_DIR)/lib64 -I$(KERNDIR) -lc -nostdinc -isystem $(SYSINC) -Iinclude -I$(KERNDIR)/arch/x86/include -I$(KERNDIR)/arch/x86/include/generated -I$(KERNDIR)/arch/x86/include/generated/uapi -I$(KERNDIR)/arch/x86/include/uapi -I$(KERNDIR)/include -I$(KERNDIR)/include/generated -I$(KERNDIR)/include/generated/uapi -I$(KERNDIR)/include/uapi -include $(KERNDIR)/include/generated/autoconf.h -D__KERNEL__ -DNDEBUG -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Wno-format-security -fno-delete-null-pointer-checks -O2 -m64 -mtune=generic -mno-red-zone -mcmodel=kernel -funit-at-a-time -maccumulate-outgoing-args -fstack-protector -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -Wframe-larger-than=1024 -fno-omit-frame-pointer -Wdeclaration-after-statement -Wno-pointer-sign -fno-dwarf2-cfi-asm -fconserve-stack +endif + + +###################################################################### +# this segment comes from make/Makefile.linux-x86-smp_generic_64-2_6 # +###################################################################### +CFGFLAGS += -DLONGS_ARE_64BITS +CFGFLAGS += -DPTRS_ARE_64BITS +CFGFLAGS += -DSAL_SPL_LOCK_ON_IRQ + + +############################################################## +# This segment comes from make/Makefile.linux-x86-common-2_6 # +############################################################## +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\" +CFGFLAGS += -DSAL_BDE_DMA_MEM_DEFAULT=32 + +# 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)))") + +ifdef LTSW_CHIPS +# Ensure we do not use an out-of-date libelf.so +ELFUTILS_MIN = 158 +ELFUTILS_DIR ?= /projects/ntsw-tools/lib + +# Default open source target build +OPENSRC_BUILD ?= fed21-x86_64 + +# Hardware interface (see $SDKLT/bcma/sys/probe directory) +SYSTEM_INTERFACE ?= ngbde + +# Turn on direct register access if running on real hardware. +ifeq (ngbde,$(SYSTEM_INTERFACE)) +LTSW_ADD_CPPFLAGS += -DBCMDRD_CONFIG_MEMMAP_DIRECT=1 +endif + +export SYSTEM_INTERFACE +endif + +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/sdk-6.5.20/src/gpl-modules/systems/bde/linux/include/linux-bde.h b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/include/linux-bde.h @@ -0,0 +1,271 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/*********************************************************************** + * + * $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 <sal/types.h> + +#include <ibde.h> + + +/* + * 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 <linux/version.h> + +#ifdef __KERNEL__ +#include <linux/types.h> +/* 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); + +/* + * Backdoor to retrieve number of switch devices probed. + */ +extern int lkbde_get_num_devices(int type); + +/* + * 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); + +#ifdef BCM_SAND_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 +/* + * This flag should be OR'ed onto the device number when calling + * irq_mask_set functions from a secondary device driver if the + * mask register is iProc register. + */ +#define LKBDE_IPROC_REG 0x4000 + +#ifdef BCM_SAND_SUPPORT +#include <linux/version.h> +#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 +#endif +#endif + +#if defined(IPROC_CMICD) && defined(CONFIG_CMA) +#ifndef _SIMPLE_MEMORY_ALLOCATION_ +#define _SIMPLE_MEMORY_ALLOCATION_ 1 +#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 for DMA pool */ +#ifndef USE_LINUX_BDE_MMAP +#define USE_LINUX_BDE_MMAP 1 +#endif + +#endif /* __KERNEL__ */ + +#endif /* __LINUX_BDE_H__ */ diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/linux/include/linux_dma.h b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/include/linux_dma.h @@ -0,0 +1,75 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/*********************************************************************** + * + * $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 <sal/types.h> + +#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 dev_index); +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_mmap(struct file *filp, struct vm_area_struct *vma); + +#endif /* __KERNEL__ */ + +#endif /* __LINUX_DMA_H__ */ diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/linux/include/mpool.h b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/include/mpool.h @@ -0,0 +1,36 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/Makefile b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/Makefile @@ -0,0 +1,94 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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 + +# need to add vpath sources +VPATH = ../shared + +# Add the srcs to be found by vpath +LSRCS += mpool.c + +# 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: kernel_libs $(MODULE) + +$(MODULE): $(BLDDIR)/.tree $(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/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux-kernel-bde.c b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux-kernel-bde.c @@ -0,0 +1,4530 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* + * Linux Kernel BDE + */ + +#include <gmodule.h> +#include <linux-bde.h> +#include <linux_dma.h> +#include <mpool.h> +#include <linux/delay.h> +#include <linux/types.h> +#include <sdk_config.h> +#include <soc/devids.h> +#include <linux/version.h> + +#include "linux_shbde.h" + +#define MEMCPY memcpy + +#ifdef CONFIG_X86_64 +#if (defined(__GNUC__) && (__GNUC__ == 8)) +/* + * Prevent gcc 8.1.10 using a compiler inline memcpy even if using -fno-builtin or + * -fno-builtin-memcpy . + * __inline_memcpy and __memcpy are kernel functions that may be used instead, + * for either an inline or non-inline implementations of the function + */ +#undef MEMCPY +#define MEMCPY __memcpy +#endif /* (defined(__GNUC__) && (__GNUC__ == 8)) */ +#endif /* CONFIG_X86_64 */ + + +#if defined(CMIC_SOFT_BYTE_SWAP) +#define CMIC_SWAP32(_x) ((((_x) & 0xff000000) >> 24) \ + | (((_x) & 0x00ff0000) >> 8) \ + | (((_x) & 0x0000ff00) << 8) \ + | (((_x) & 0x000000ff) << 24)) +#endif /* defined(CMIC_SOFT_BYTE_SWAP) */ + +#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 size in bytes. + * The default value if not specified to the kernel module by maxpayload is historically 256. + * The default value may be changed using the BDE_PCIE_MAXPAYLOAD_DEFAULT macro. + */ +#ifndef BDE_PCIE_MAXPAYLOAD_DEFAULT +#define BDE_PCIE_MAXPAYLOAD_DEFAULT 256 +#endif +int maxpayload = BDE_PCIE_MAXPAYLOAD_DEFAULT; +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)"); + +int msixcnt = 1; + +/* + * 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 + +/* 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 + + +/* 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,30)) +#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 +typedef irqreturn_t (*irq_handler_t)(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; +}; + +/* Maximum number of I/O windows supported per device. */ +#define BDE_NUM_IOWIN_MAX 3 + +/* I/O memory window definition. */ +struct memwin_s { + + /* Physical address of I/O window. */ + resource_size_t addr; + + /* Size of I/O window (in bytes). */ + resource_size_t size; +}; + +/* 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 + + struct memwin_s iowin[BDE_NUM_IOWIN_MAX]; + + /* 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; + +#define VALID_DEVICE(_n) ((_n >= 0) && (_n < _ndevices)) + +#if defined(IPROC_CMICD) && defined(CONFIG_OF) +#define ICFG_CHIP_ID_REG 0x10236000 +#define IHOST_CMICX_MAX_INTRS 129 +static uint32 iproc_cmicx_irqs[IHOST_CMICX_MAX_INTRS]; +#endif + +/* CPU MMIO area used with CPU cards provided on demo boards */ +#if defined(BCM_SAND_SUPPORT) && (defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__)) +static void *cpu_address = NULL; +#endif + + +/* 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 + +/* Default gicd address if not available in DTB */ +#define IHOST_GICD_REG_ADDR 0x10781100 +#define IHOST_GICD_REG_REMAP_LEN 0x100 + +#define IHOST_GICD_REG_ADDR_VALID(d, addr) \ + (_devices[d].bde_dev.base_address1 && \ + (addr & 0xFFFFFF00) == _devices[d].iowin[1].addr) + +#define IHOST_GICD_REG_ADDR_REMAP(d, addr) \ + (void *)(_devices[d].bde_dev.base_address1 + \ + (addr - ((sal_vaddr_t)_devices[d].iowin[1].addr))) + +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 void +_bde_add_device(void) +{ + int add_switch_device = 0; + if (_devices[_ndevices].dev_type & BDE_SWITCH_DEV_TYPE) { + _switch_ndevices++; + add_switch_device = 1; + } else if (_devices[_ndevices].dev_type & BDE_ETHER_DEV_TYPE) { + _ether_ndevices++; + } else if (_devices[_ndevices].dev_type & BDE_CPU_DEV_TYPE) { + _cpu_ndevices++; + } else { + return; + } + _ndevices++; + + /* + * 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 (add_switch_device) { + 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; + } + + _dma_init(_switch_ndevices-1); + } + + /* Initialize device locks */ + spin_lock_init(&_devices[_ndevices-1].lock); +} + +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; + + 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->iowin[0].addr = paddr; + ctrl->iowin[0].size = 0x10000; + + 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); + + _bde_add_device(); + + return 0; +} + +#ifdef BCM_SAND_SUPPORT + +#include <soc/devids.h> + +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__ + 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->iowin[0].addr = 0x40000000; + ctrl->iowin[0].size = 0x100000; + + 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; + } + +#ifndef __DUNE_LINUX_BCM_CPU_PCIE__ + _bde_add_device(); +#endif + + return 0; +} +#endif /* BCM_SAND_SUPPORT */ + +#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 <linux/platform_device.h> +#include <linux/of.h> + +extern int iproc_platform_driver_register(struct platform_driver *drv); +extern void iproc_platform_driver_unregister(struct platform_driver *drv); +extern int 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" +#define IPROC_CMICX_COMPATIBLE "brcm,iproc-cmicx" + +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; + + 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->iowin[0].addr = memres->start; + ctrl->iowin[0].size = size; + +#ifdef CONFIG_OF + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + uint32 *icfg_chip_id; + icfg_chip_id = (uint32 *)IOREMAP(ICFG_CHIP_ID_REG, 2 * sizeof(uint32)); + if (icfg_chip_id == NULL) { + gprintk("Error mapping ICFG_CHIP_ID_REG\n"); + return -1; + } + ctrl->bde_dev.device = readl(icfg_chip_id) & 0xffff; + ctrl->bde_dev.rev = readl(icfg_chip_id+1) & 0xff; + iounmap(icfg_chip_id); + /* Map GICD block in the AXI memory space into CPU address space */ + memres = iproc_platform_get_resource(pldev, IORESOURCE_MEM, 1); + if (memres) { + ctrl->bde_dev.base_address1 = (sal_vaddr_t)IOREMAP(memres->start, memres->end - memres->start + 1); + ctrl->iowin[1].addr = memres->start; + ctrl->iowin[1].size = memres->end - memres->start + 1; + } else { + /* Use default address if not available in DTB */ + ctrl->bde_dev.base_address1 = (sal_vaddr_t)IOREMAP(IHOST_GICD_REG_ADDR, IHOST_GICD_REG_REMAP_LEN); + ctrl->iowin[1].addr = IHOST_GICD_REG_ADDR; + ctrl->iowin[1].size = IHOST_GICD_REG_REMAP_LEN; + } + if (ctrl->bde_dev.base_address1) { + if (debug >= 1) { + gprintk("base_address1:0x%lx phys_address1:0x%lx\n", + (unsigned long)ctrl->bde_dev.base_address1, (unsigned long)ctrl->iowin[1].addr); + } + } else { + gprintk("Error mapping ihost GICD registers\n"); + } + } else +#endif + { + /* Read switch device ID from CMIC */ + dev_rev_id = *((uint32 *)(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 + ctrl->bde_dev.base_address1 = 0; + } + +#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]); + } + +#ifdef CONFIG_OF + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + int i; + memset(iproc_cmicx_irqs, 0, IHOST_CMICX_MAX_INTRS*sizeof(uint32_t)); + for (i = 0; i < IHOST_CMICX_MAX_INTRS; i++) { + irqres = iproc_platform_get_resource(pldev, IORESOURCE_IRQ, i); + if (irqres) { + iproc_cmicx_irqs[i] = irqres->start; + } + if (debug >= 1) { + gprintk("iproc_cmicx_irqs[%d] = %d\n", i, iproc_cmicx_irqs[i]); + } + } + ctrl->iLine = iproc_cmicx_irqs[0]; + } else +#endif + { + 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 */ + _bde_add_device(); + 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 = IPROC_CMICD_COMPATIBLE }, + { .compatible = IPROC_CMICX_COMPATIBLE }, + {}, +}; +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) { + 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=%lx, cmicd_mem.end=%lx\n", + found_cmicd_dev ? "EROM" : "Default", + (unsigned long)iproc_cmicd_resources[IPROC_CMICD_RES_MEM].start, + (unsigned long)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; + + 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->iowin[0].addr = paddr; + ctrl->iowin[0].size = 0x10000; + + 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); + _bde_add_device(); + } + + 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 const 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, 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, 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, BCM56975_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, BCM56670_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56671_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56672_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56675_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56568_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56670_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56760_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56761_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 }, + { BROADCOM_VENDOR_ID, BCM56070_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56071_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56072_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, BCM88271_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, BCM88274_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88276_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88278_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88279_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, BCM88687_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, 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_DNX_SUPPORT + { BROADCOM_VENDOR_ID, BCM88690_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88690_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88691_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88692_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88693_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88694_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88695_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88696_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88697_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88698_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88699_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8869A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8869B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8869C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8869D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8869E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8869F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88800_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88821_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88826_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88802_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88803_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88804_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88805_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88806_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88820_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88822_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88823_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88824_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88825_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88480_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88481_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88482_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88483_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88484_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88485_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88486_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88487_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88488_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88489_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8848A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8848B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8848C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8848D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8848E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8848F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88280_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88281_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88282_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88283_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88284_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88285_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88286_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88287_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88288_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88289_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8828A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8828B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8828C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8828D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8828E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8828F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88850_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, +#endif /* BCM_DNX_SUPPORT */ +#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 }, + { BROADCOM_VENDOR_ID, BCM88791_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88792_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88793_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88794_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88795_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88796_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88797_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88798_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88799_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8879A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8879B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8879C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8879D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8879F_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, BCM56273_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56274_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56275_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56276_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56277_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56278_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56279_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56575_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56370_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56371_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56372_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56374_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56375_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56376_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56377_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56577_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56578_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56579_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56873_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56770_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56771_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56980_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56981_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56982_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56983_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56984_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53540_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53547_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53548_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM53549_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56470_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56471_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56472_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56475_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { 0, 0, 0, 0 } +};; + +MODULE_DEVICE_TABLE(pci, _id_table); + +#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; + } + pci_disable_msix(dev); + 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), GFP_KERNEL); + + if (!ctrl->entries) { + goto er_intx; + } + /* Only one vector is mapped by default */ + /* May be more in future, can be controlled using module param */ + ctrl->msix_cnt = msixcnt; + 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; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) + ret = pci_enable_msix_range(ctrl->pci_device, + ctrl->entries, ctrl->msix_cnt, ctrl->msix_cnt); +#else + 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; + msixcnt = ret; + ret = pci_enable_msix(ctrl->pci_device, + ctrl->entries, ctrl->msix_cnt); + if (ret != 0) + goto er_intx_free; + } +#endif + if (ret < 0) { + /* Error */ + goto er_intx_free; + } else { + gprintk("Enabled MSI-X interrupts = %d\n", ctrl->msix_cnt); + return 0; + } + } +#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/MSIX 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) { + if (ctrl->msix_cnt) { + pci_disable_msix(ctrl->pci_device); + kfree(ctrl->entries); + ctrl->entries = NULL; + 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(struct pci_dev *dev, bde_ctrl_t *ctrl, int iproc) +{ +#ifdef CONFIG_PCI_MSI + int ret; + shbde_iproc_config_t icfg; + + /* Each device follows global policy by default */ + ctrl->use_msi = use_msi; + + if (unlikely(debug > 1)) + gprintk("%s: msi = %d\n", __func__, ctrl->use_msi); + + /* Check IPROC version for MSIX support */ + if (iproc && ctrl->bde_dev.base_address1 && + (ctrl->use_msi == PCI_USE_INT_MSIX)) { + if (shbde_pci_iproc_version_get(&ctrl->shbde, dev, &icfg.iproc_ver, + &icfg.cmic_ver, &icfg.cmic_rev)) { + if (icfg.iproc_ver < 0xe) { + gprintk("%s: MSI-X not supported, using MSI.\n", __func__); + ctrl->use_msi = PCI_USE_INT_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, using INTx.\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 i, cmic_bar; + int baroff = 0; + int iproc = 0; + int plx_dev = 0; + int eth_dev = 0; + int cpu_dev = 0; + int update_devid = 0; + int paxb_core = 0; + int add_dev = 0, 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; + 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; + ctrl->dev_type |= BDE_ETHER_DEV_TYPE; + ctrl->iLine = dev->irq; + add_dev = 1; + 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; + ctrl->dev_type |= BDE_CPU_DEV_TYPE; + add_dev = 1; + 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; + 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; + add_dev = 1; + } + + /* 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) { + 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 */ + + /* 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); + + /* + * Sample setting of unique ID, used the PCIe address of the device: + * domain, bus, slot, function in hex digits: DDDDBBSS (SS includes the slot/device and function. + * Tested with old kernels from 2.6 . + * Do not use the PCI_DEVID macro which old kernel versions don't have. */ + ctrl->bde_dev.dev_unique_id = dev->bus ? + (((uint32)pci_domain_nr(dev->bus)) << 16) ^ (((uint32)dev->bus->number) << 8) ^ dev->devfn : + dev->devfn; + + /* 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->iowin[0].addr = paddr; + ctrl->iowin[0].size = bar_len; + + 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 */ + for (i = 1; i < BDE_NUM_IOWIN_MAX; i++) { + ctrl->iowin[i].addr = 0; + ctrl->iowin[i].size = 0; + } + ctrl->bde_dev.base_address1 = 0; + + 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->iowin[1].addr = paddr; + ctrl->iowin[1].size = bar_len; + 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); + } + } + + /* configure interrupt type */ + config_pci_intr_type(dev, ctrl, iproc); + + /* 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)); + + + 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) { + ctrl->dev_type |= BDE_256K_REG_SPACE; + if (debug >= 1) gprintk("PCI resource len 256K\n"); + } else if (bar_len == 0x800000) { + ctrl->dev_type |= BDE_256K_REG_SPACE | BDE_8MB_REG_SPACE; + if (debug >= 1) gprintk("PCI resource len 8MB\n"); + } + + +#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); + } + + if (add_dev) { + _bde_add_device(); + } + /* 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); + } + 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; + 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); + } + _bde_add_device(); +} +#endif /* BCM_ICS */ + + + + +#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; + + /* + * 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->iowin[0].addr = addr; + ctrl->iowin[0].size = size; + + _bde_add_device(); + return(ctrl); +} + +#define BME_REVISION_OFFSET (0x0) + +#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; + + /* + * 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->iowin[0].addr = plx_ctrl->iowin[0].addr + (resource_size_t)dev_base; + ctrl->iowin[0].size = size; + +#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); + + + _bde_add_device(); + + switch (ctrl->bde_dev.device) { + default: + 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.iowin[0].addr >> 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.iowin[0].addr)); + + 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 */ + + + + +/* + * 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 +#ifdef CONFIG_OF + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + iproc_platform_driver_register(&iproc_cmicd_driver); + } else +#endif + 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; + + + /* 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_msi = %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_SAND_SUPPORT + sand_device_create(); +#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,","); + } + } + + return 0; +} + +/* + * Function: _cleanup + * + * Purpose: + * Module cleanup function. + * Parameters: + * None + * Returns: + * Always 0 + */ +static int +_cleanup(void) +{ + int i; + + _dma_cleanup(); + +#ifdef IPROC_CMICD +#ifdef CONFIG_OF + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + iproc_platform_driver_unregister(&iproc_cmicd_driver); + } else +#endif + 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 + + 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_SAND_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); + + pprintf("Module parameters:\n"); + pprintf("\tmaxpayload=%d\n", maxpayload); + pprintf("\tusemsi=%d\n", usemsi); + + _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 %02x:%02x.%x 0x%x:0x%x:%d:0x%.8lx:0x%.8lx:%d%s\n", + (unsigned int)ctrl->pci_device->bus->number, + PCI_SLOT(ctrl->pci_device->devfn), + PCI_FUNC(ctrl->pci_device->devfn), + 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->iowin[0].addr, + 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; +} +/* + * Some kernels are configured to prevent mapping of kernel RAM memory + * into user space via the /dev/mem device. + * + * The function below provides a backdoor to map IO and DMA memory to + * user space via the BDE device file. + */ +static int +_bde_mmap(struct file *filp, struct vm_area_struct *vma) +{ + unsigned long paddr = vma->vm_pgoff << PAGE_SHIFT; + unsigned long size = vma->vm_end - vma->vm_start; + int i, j, pio_range_valid = 0; + + for(i = 0; i < _ndevices; i++) { + bde_ctrl_t *ctrl = _devices + i; + if (ctrl->dev_type & BDE_SWITCH_DEV_TYPE) { + for (j = 0; j < BDE_NUM_IOWIN_MAX; j++) { + if (paddr >= (unsigned long)ctrl->iowin[j].addr && + (paddr + size) <= (unsigned long)(ctrl->iowin[j].addr + ctrl->iowin[j].size)) { + pio_range_valid = 1; + break; + } + if ((ctrl->dev_type & BDE_AXI_DEV_TYPE) && (paddr == ctrl->iowin[j].addr)) { + pio_range_valid = 1; + break; + } + } + } + } + + if (pio_range_valid) { + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + 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", + paddr, paddr + size, vma->vm_start,vma->vm_end); + return -EAGAIN; + } + return 0; + } + + return _dma_mmap(filp, vma); +} + +/* 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, + mmap: _bde_mmap, +}; + +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++) { + if (unlikely(debug >= 1)) { + gprintk("%s(%d):device# = %d, irq = %d\n", + __func__, __LINE__, d, ctrl->entries[i].vector); + } + ret = request_irq(ctrl->entries[i].vector, (irq_handler_t)_isr, 0, + LINUX_KERNEL_BDE_NAME, ctrl); + if (ret < 0) + break; + } + if (ret < 0) { + while (i >= 0) + free_irq(ctrl->entries[i--].vector, ctrl); + + goto err_disable_msi; + } + } + else +#endif + { +#if defined(IPROC_CMICD) && defined(CONFIG_OF) + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + int i, j; + for (i = 0; i < IHOST_CMICX_MAX_INTRS; i++) { + if (!iproc_cmicx_irqs[i]) { + continue; + } + if (unlikely(debug >= 1)) + gprintk("%s(%d):device# = %d, request_irq(%d)\n", + __func__, __LINE__, d, iproc_cmicx_irqs[i]); + ret = request_irq(iproc_cmicx_irqs[i], (irq_handler_t)_isr, + irq_flags, LINUX_KERNEL_BDE_NAME, ctrl); + if (ret < 0) { + gprintk("request_irq(%d) failed(%d)\n", iproc_cmicx_irqs[i], ret); + break; + } + } + if (ret < 0) { + for (j = 0; j < i; j++) { + if (!iproc_cmicx_irqs[j]) { + continue; + } + free_irq(iproc_cmicx_irqs[j], ctrl); + } + 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++) { + if (unlikely(debug > 1)) { + gprintk("%s(%d):device# = %d, irq = %d\n", + __func__, __LINE__, d, ctrl->entries[i].vector); + } + free_irq(ctrl->entries[i].vector, ctrl); + } + } + else +#endif +#if defined(IPROC_CMICD) && defined(CONFIG_OF) + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + int i; + for (i = 0; i < IHOST_CMICX_MAX_INTRS; i++) { + if (!iproc_cmicx_irqs[i]) { + continue; + } + if (unlikely(debug > 1)) { + gprintk("%s(%d):device# = %d, free_irq(%d)\n", + __func__, __LINE__, d, iproc_cmicx_irqs[i]); + } + free_irq(iproc_cmicx_irqs[i], ctrl); + } + } 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) { + if (IHOST_GICD_REG_ADDR_VALID(d, addr)) { + return readl(IHOST_GICD_REG_ADDR_REMAP(d, addr)); + } + 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) { + if (IHOST_GICD_REG_ADDR_VALID(d, addr)) { + writel(data, IHOST_GICD_REG_ADDR_REMAP(d, addr)); + return 0; + } + 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_SAND_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 BCM88687_DEVICE_ID: + case BCM88380_DEVICE_ID: + case BCM88381_DEVICE_ID: + case BCM88680_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 BCM88271_DEVICE_ID: + case BCM88272_DEVICE_ID: + case BCM88273_DEVICE_ID: + case BCM88274_DEVICE_ID: + case BCM88276_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; + } + + /* configure iproc >=14 devices by device family */ +#if defined(BCM_DNXF_SUPPORT) || defined(BCM_DNX_SUPPORT) + switch (ctrl->bde_dev.device & DNXC_DEVID_FAMILY_MASK) { +#ifdef BCM_DNX_SUPPORT + case JERICHO2_DEVICE_ID: + case J2C_DEVICE_ID: + case J2C_2ND_DEVICE_ID: + case Q2A_DEVICE_ID: + case Q2U_DEVICE_ID: + case J2P_DEVICE_ID: +#endif +#ifdef BCM_DNXF_SUPPORT + case BCM88790_DEVICE_ID: +#endif + /* + * 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; + } +#endif /* defined(BCM_DNXF_SUPPORT) || defined(BCM_DNX_SUPPORT) */ + + /* 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->iowin[0].addr, 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->iowin[0].addr); + 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 /* BCM_SAND_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, + + NULL, + NULL, + 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].iowin[0].addr; +} + +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].iowin[0].addr >> 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].iowin[0].addr); +#ifdef PHYS_ADDR_IS_64BIT + *phys_hi = (uint32_t)(_devices[d].iowin[0].addr >> 32); +#endif + break; + case 1: + *phys_lo = (uint32_t)(_devices[d].iowin[1].addr); +#ifdef PHYS_ADDR_IS_64BIT + *phys_hi = (uint32_t)(_devices[d].iowin[1].addr >> 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, iproc_reg; + unsigned long flags; + + isr2_dev = d & LKBDE_ISR2_DEV; + iproc_reg = d & LKBDE_IPROC_REG; + d &= ~(LKBDE_ISR2_DEV | LKBDE_IPROC_REG); + + 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; + } + + if (iproc_reg) { + _iproc_write(d, addr, ctrl->imask | ctrl->imask2); + } else { + _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 | LKBDE_IPROC_REG); + + if (!VALID_DEVICE(d)) { + return -1; + } + + if (mask == NULL || fmask == NULL) { + return -1; + } + + ctrl = _devices + d; + + *fmask = ctrl->fmask; + *mask = ctrl->imask | ctrl->imask2; + + return 0; +} + +int +lkbde_get_num_devices(int type) +{ + return _num_devices(type); +} + +/* + * 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); +#ifdef BCM_SAND_SUPPORT +LKM_EXPORT_SYM(lkbde_cpu_write); +LKM_EXPORT_SYM(lkbde_cpu_read); +LKM_EXPORT_SYM(lkbde_cpu_pci_register); +#endif diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux_dma.c b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux_dma.c @@ -0,0 +1,1026 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <gmodule.h> +#include <linux-bde.h> +#include <linux_dma.h> +#include <mpool.h> +#include <sdk_config.h> + +#if defined(IPROC_CMICD) && defined(CONFIG_OF) +#include <linux/of.h> +#endif + +#ifdef BCM_PLX9656_LOCAL_BUS +#include <asm/cacheflush.h> +#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 <linux/dma-mapping.h> +#if 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 +/* Use Linux DMA API to allocate contiguous memory */ +#define ALLOC_METHOD_DEFAULT ALLOC_TYPE_API +#if defined(__arm__) +#define USE_DMA_MMAP_COHERENT +#define _PGPROT_NONCACHED(x) x = pgprot_noncached((x)) +#elif defined(__aarch64__ ) +#define USE_DMA_MMAP_COHERENT +#define _PGPROT_NONCACHED(x) x = pgprot_writecombine((x)) +#endif +#else +#define ALLOC_METHOD_DEFAULT ALLOC_TYPE_CHUNK +#endif + +#ifndef _PGPROT_NONCACHED +#ifdef REMAP_DMA_NONCACHED +#define _PGPROT_NONCACHED(x) x = pgprot_noncached((x)) +#else +#define _PGPROT_NONCACHED(x) +#endif +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) +#include <linux/slab.h> +#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 + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) +#define BDE_DMA_MAPPING_ERROR(d, p) dma_mapping_error((d),(p)) +#else +#define BDE_DMA_MAPPING_ERROR(d, p) dma_mapping_error((p)) +#endif + +#ifndef KMALLOC_MAX_SIZE +#define KMALLOC_MAX_SIZE (1UL << (MAX_ORDER - 1 + PAGE_SHIFT)) +#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)"); + +/* Physical high memory address to use for DMA */ +static char *himemaddr = 0; +LKM_MOD_PARAM(himemaddr, "s", charp, 0); +MODULE_PARM_DESC(himemaddr, +"Physical address to use for high memory DMA"); + +/* DMA memory allocation */ + +#define ONE_KB 1024 +#define ONE_MB (1024*1024) +#define ONE_GB (1024*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 + +/* 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 unsigned long _himemaddr = 0; +static int _use_dma_mapping = 0; +static LIST_HEAD(_dma_seg); + +#define DMA_DEV_INDEX 0 /* Device index to allocate memory pool */ +#define DMA_DEV(n) lkbde_get_dma_dev(n) +#define BDE_NUM_DEVICES(t) lkbde_get_num_devices(t) + +/* + * 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; + for (i = 0; i < blks; 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[start + i] = addr; + ++dseg->blk_cnt; + } else { + gprintk("DMA allocation failed: allocated %d of %d " + "requested blocks\n", i, blks); + 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); + if (blk_ptr_size > KMALLOC_MAX_SIZE) { + blk_ptr_size = KMALLOC_MAX_SIZE; + dseg->blk_cnt_max = KMALLOC_MAX_SIZE / 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 */ + if (_alloc_dma_blocks(dseg, dseg->req_size / dseg->blk_size) != 0) { + gprintk("Failed to allocate minimum number of DMA blocks\n"); + /* + * _alloc_dma_blocks() returns -1 if it fails to allocate the requested + * number of blocks, but it may still have allocated something. Fall + * through and return dseg filled in with as much memory as we could + * allocate. + */ + } + /* 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 */ + gprintk("_pgalloc() failed to get requested size %zu: " + "only got %lu contiguous across %d blocks\n", + size, dseg->seg_size, dseg->blk_cnt); + _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(DMA_DEV_INDEX), _dma_mem_size, _dma_vbase, _dma_pbase); + } + break; +#endif /* _SIMPLE_MEMORY_ALLOCATION_ */ + + case ALLOC_TYPE_CHUNK: { + struct list_head *pos, *tmp; + int i, ndevices; + if (_use_dma_mapping) { + ndevices = BDE_NUM_DEVICES(BDE_SWITCH_DEVICES); + for (i = 0; i < ndevices && DMA_DEV(i); i ++) { + dma_unmap_single(DMA_DEV(i), (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; + struct device *dev = DMA_DEV(DMA_DEV_INDEX); + int dma64_support = 0; + +#if defined(IPROC_CMICD) && defined(CONFIG_OF) + if (of_find_compatible_node(NULL, NULL, "brcm,iproc-cmicx")) { + dma64_support = 1; + } +#endif + +#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 */ + if (_himemaddr) { + pbase = _himemaddr; + } else { + 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 */ + if (dma_debug >= 1) { + gprintk("Allocating DMA memory using method dmaalloc=%d\n", dmaalloc); + } + 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; + _dma_vbase = dma_alloc_coherent(dev, alloc_size, &dma_handle, GFP_KERNEL); + if (!_dma_vbase || !dma_handle) { + gprintk("Failed to allocate coherent memory pool of size 0x%lx\n", (unsigned long)alloc_size); + return; + } + _cpu_pbase = pbase = dma_handle; + } + + if (alloc_size != size) { + gprintk("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_vbase) { + gprintk("Failed to allocate memory pool of size 0x%lx\n", (unsigned long)size); + return; + } + _cpu_pbase = virt_to_bus(_dma_vbase); + /* Use dma_map_single to obtain DMA bus address or IOVA if iommu is present. */ + if (dev) { + pbase = dma_map_single(dev, _dma_vbase, size, DMA_BIDIRECTIONAL); + if (BDE_DMA_MAPPING_ERROR(dev, pbase)) { + gprintk("Failed to map memory at %p\n", _dma_vbase); + _pgcleanup(); + _dma_vbase = NULL; + return; + } + _use_dma_mapping = 1; + } else { + pbase = _cpu_pbase; + } + break; + default: + _dma_vbase = NULL; + gprintk("DMA memory allocation method dmaalloc=%d is not supported\n", dmaalloc); + return; + } + + _dma_pbase = pbase; + + if (!dma64_support && ((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; + } + +#ifdef REMAP_DMA_NONCACHED + _dma_vbase = IOREMAP(_dma_pbase, size); +#endif + if (dma_debug >= 1) { + gprintk("_use_dma_mapping:%d _dma_vbase:%p _dma_pbase:%lx _cpu_pbase:%lx allocated:%lx dmaalloc:%d, dma64_support:%d\n", + _use_dma_mapping, _dma_vbase, (unsigned long)_dma_pbase, + (unsigned long)_cpu_pbase, (unsigned long)size, dmaalloc, dma64_support); + } + } +} + +/* + * 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 dev_index) +{ + unsigned long pbase; + + if (dev_index > DMA_DEV_INDEX) { + if (_use_dma_mapping && DMA_DEV(dev_index) && _dma_vbase) { + pbase = dma_map_single(DMA_DEV(dev_index), _dma_vbase, _dma_mem_size, DMA_BIDIRECTIONAL); + if (BDE_DMA_MAPPING_ERROR(DMA_DEV(dev_index), pbase)) { + gprintk("Failed to map memory for device %d at %p\n", dev_index, _dma_vbase); + return; + } + if (pbase != (unsigned long)_dma_pbase) { + /* Bus address/IOVA must be identical for all devices. */ + gprintk("Device %d has different pbase: %lx (should be %lx)\n", + dev_index, pbase, (unsigned long)_dma_pbase); + } + } + return; + } + + /* 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; + } + } + + 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 (himemaddr && strlen(himemaddr) > 0) { + char suffix = (himemaddr[strlen(himemaddr)-1] & ~0x20); + _himemaddr = simple_strtoul(himemaddr, NULL, 0); + if (suffix == 'M') { + _himemaddr *= ONE_MB; + } else if (suffix == 'G') { + _himemaddr *= ONE_GB; + } else { + gprintk("DMA high memory address must be specified as e.g. himemaddr=8[MG]\n"); + } + } + + 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); + } + } +} + +/* + * Some kernels are configured to prevent mapping of kernel RAM memory + * into user space via the /dev/mem device. + * + * The function below provides a backdoor to mapping the DMA pool to + * user space via the BDE device file. + */ +int _dma_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 (phys_addr < (unsigned long )_cpu_pbase || + (phys_addr + size) > ((unsigned long )_cpu_pbase + _dma_mem_size)) { + gprintk("range 0x%lx-0x%lx outside DMA pool 0x%lx-0x%lx\n", + phys_addr, phys_addr + size, (unsigned long )_cpu_pbase, + (unsigned long )_cpu_pbase + _dma_mem_size); + return -EINVAL; + } + +#ifdef USE_DMA_MMAP_COHERENT + if (dmaalloc == ALLOC_TYPE_API) { + vma->vm_pgoff = 0; + return dma_mmap_coherent(DMA_DEV(DMA_DEV_INDEX), vma, (void *)_dma_vbase, phys_addr, size); + } +#endif + + _PGPROT_NONCACHED(vma->vm_page_prot); + + 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; +} + +/* + * 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("\tdmasize=%s\n", dmasize); + pprintf("\thimem=%s\n", himem); + pprintf("\thimemaddr=%s\n", himemaddr); + 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/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.c b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.c @@ -0,0 +1,120 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#include <gmodule.h> +#include <shbde.h> +#include <shbde_iproc.h> +#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/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.h b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.h @@ -0,0 +1,33 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#ifndef __LINUX_SHBDE_H__ +#define __LINUX_SHBDE_H__ + +#include <shbde.h> +#include <shbde_pci.h> +#include <shbde_iproc.h> + +extern int +linux_shbde_hal_init(shbde_hal_t *shbde, shbde_log_func_t log_func); + +#endif /* __LINUX_SHBDE_H__ */ diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/linux/shared/mpool.c b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/shared/mpool.c @@ -0,0 +1,355 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: mpool.c,v 1.18 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ + +#include <mpool.h> + +#ifdef __KERNEL__ + +/* + * Abstractions used when compiling for Linux kernel mode. + */ + +#include <lkm.h> + +/* + * 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 <stdlib.h> +#include <sal/core/sync.h> + +#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 + +#define MPOOL_BUF_SIZE 1024 +#define MPOOL_BUF_ALLOC_COUNT_MAX 16 + +typedef struct mpool_mem_s { + unsigned char *address; + int size; + struct mpool_mem_s *prev; + struct mpool_mem_s *next; +} mpool_mem_t; + +static int _buf_alloc_count; +static mpool_mem_t *mpool_buf[MPOOL_BUF_ALLOC_COUNT_MAX]; +static mpool_mem_t *free_list; + +#define ALLOC_INIT_MPOOL_BUF(ptr) \ + ptr = MALLOC((sizeof(mpool_mem_t) * MPOOL_BUF_SIZE)); \ + if (ptr) { \ + int i; \ + for (i = 0; i < MPOOL_BUF_SIZE - 1; i++) { \ + ptr[i].next = &ptr[i+1]; \ + } \ + ptr[MPOOL_BUF_SIZE - 1].next = NULL; \ + free_list = &ptr[0]; \ + } + +/* + * 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(); + + if (size < BCM_CACHE_LINE_BYTES) { + size = BCM_CACHE_LINE_BYTES; + } + + 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; + } + + if (!free_list) { + if (_buf_alloc_count == MPOOL_BUF_ALLOC_COUNT_MAX) { + MPOOL_UNLOCK(); + return NULL; + } + + ALLOC_INIT_MPOOL_BUF(mpool_buf[_buf_alloc_count]); + + if (mpool_buf[_buf_alloc_count] == NULL) { + MPOOL_UNLOCK(); + return NULL; + } + + _buf_alloc_count++; + } + + newptr = free_list; + free_list = free_list->next; + + newptr->address = ptr->address + ptr->size; + newptr->size = size; + newptr->next = ptr->next; + newptr->prev = ptr; + ptr->next->prev = newptr; + 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 *head = pool, *ptr = NULL; + + MPOOL_LOCK(); + + if (!(head && head->prev)) { + MPOOL_UNLOCK(); + return; + } + + ptr = head->prev->prev; + + while (ptr && (ptr != head)) { + if (ptr->address == address) { +#ifdef TRACK_DMA_USAGE + _dma_mem_used -= ptr->size; +#endif + ptr->prev->next = ptr->next; + ptr->next->prev = ptr->prev; + ptr->next = free_list; + free_list = ptr; + break; + } + ptr = ptr->prev; + } + + 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)); + int i; + + MPOOL_LOCK(); + + for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) { + mpool_buf[i] = NULL; + } + + _buf_alloc_count = 0; + + ALLOC_INIT_MPOOL_BUF(mpool_buf[_buf_alloc_count]); + + if (mpool_buf[_buf_alloc_count] == NULL) { + MPOOL_UNLOCK(); + return NULL; + } + + _buf_alloc_count++; + + 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 = free_list; + free_list = free_list->next; + tail = free_list; + free_list = free_list->next; + + head->size = tail->size = 0; + head->address = base_ptr; + tail->address = head->address + size; + head->prev = tail; + head->next = tail; + tail->prev = head; + 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) +{ + int i; + + MPOOL_LOCK(); + + if ((mpool_mem_t *)pool != mpool_buf[0]) { + MPOOL_UNLOCK(); + return 0; + } + + for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) { + if (mpool_buf[i]) { + FREE(mpool_buf[i]); + mpool_buf[i] = NULL; + } + } + + 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/sdk-6.5.20/src/gpl-modules/systems/bde/linux/user/kernel/Makefile b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/user/kernel/Makefile @@ -0,0 +1,70 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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/sdk-6.5.20/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.c b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.c @@ -0,0 +1,1661 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* + * Linux User BDE Helper Module + */ +#include <gmodule.h> +#include <mpool.h> +#include <linux-bde.h> + +#include <sal/core/thread.h> +#include <sal/core/sync.h> +#include <soc/devids.h> +#include <linux/jiffies.h> +#include "linux-user-bde.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) +#include <linux/uaccess.h> +#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_MASK5_OFFSET(x) (0x314c0 + (0x1000 * x)) +#define CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(x) (0x314c4 + (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 PAXB_INTRCLR_DELAY_REG_NUM (16) +/* +TODO:HX5 +The INTR base address values are changed for HX5, +hence making new #defines so runtime decisions can +be made. +*/ +#define PAXB_0_PAXB_IC_INTRCLR_0 (0x180123a0) +#define PAXB_0_PAXB_IC_INTRCLR_1 (0x180123a4) +#define PAXB_0_PAXB_IC_INTRCLR_MODE_0 (0x180123a8) +#define PAXB_0_PAXB_IC_INTRCLR_MODE_1 (0x180123ac) +#define PAXB_0_PAXB_INTR_STATUS (0x18012f38) +#define PAXB_0_PAXB_IC_INTR_PACING_CTRL (0x18012398) +#define PAXB_0_PAXB_INTRCLR_DELAY_UNIT (0x1801239c) +#define PAXB_0_PAXB_IC_INTRCLR_DELAY_REG0 (0x180123b0) +#define PAXB_0_PCIE_ERROR_STATUS (0x18012024) + +#define HX5_PAXB_0_PAXB_IC_INTRCLR_0 (0x102303a0) +#define HX5_PAXB_0_PAXB_IC_INTRCLR_1 (0x102303a4) + +#define HX5_PAXB_0_PAXB_IC_INTRCLR_MODE_0 (0x102303a8) +#define HX5_PAXB_0_PAXB_IC_INTRCLR_MODE_1 (0x102303ac) +#define HX5_PAXB_0_PAXB_INTR_STATUS (0x10230f38) +#define HX5_PAXB_0_PAXB_IC_INTR_PACING_CTRL (0x10230398) +#define HX5_PAXB_0_PAXB_INTRCLR_DELAY_UNIT (0x1023039c) +#define HX5_PAXB_0_PAXB_IC_INTRCLR_DELAY_REG0 (0x102303b0) +#define HX5_PAXB_0_PCIE_ERROR_STATUS (0x10230024) + +#define PAXB_0_PAXB_IC_INTRCLR_DELAY_BASE (PAXB_0_PAXB_IC_INTRCLR_DELAY_REG0) +#define HX5_PAXB_0_PAXB_IC_INTRCLR_DELAY_BASE (HX5_PAXB_0_PAXB_IC_INTRCLR_DELAY_REG0) + +#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 HX5_INTC_INTR_ENABLE_REG0 (0x102310f0) +#define HX5_INTC_INTR_STATUS_REG0 (0x10231190) +#define HX5_INTC_INTR_RAW_STATUS_REG0 (0x10231140) + +#define HX5_INTC_INTR_ENABLE_BASE (HX5_INTC_INTR_ENABLE_REG0) +#define HX5_INTC_INTR_STATUS_BASE (HX5_INTC_INTR_STATUS_REG0) +#define HX5_INTC_INTR_RAW_STATUS_BASE (HX5_INTC_INTR_RAW_STATUS_REG0) + +#define IOREMAP(addr, size) ioremap_nocache(addr, size) + +#define HX5_IHOST_GICD_ISENABLERN_0 (0x10781100) +#define HX5_IHOST_GICD_ISENABLERN_1 (0x10781104) +#define HX5_IHOST_GICD_ICENABLERN_1 (0x10781184) +#define HX5_IHOST_GICD_ICENABLERN_8 (0x107811a0) +#define HX5_IHOST_GICD_ISPENDRN_8 (0x10781220) +/* Offset between ISENABLERN_1 and ICENABLERN_1 in 4-bytes */ +#define HX5_IHOST_IRQ_MASK_OFFSET 0x20 +/* Offset between ISENABLERN_1 and ISPENDRN_1 in 4-bytes */ +#define HX5_IHOST_IRQ_PEND_OFFSET 0x40 +#define HX5_IHOST_INTR_MAP_NUM (HX5_IHOST_GICD_ISPENDRN_8 - HX5_IHOST_GICD_ISENABLERN_0) +#define HX5_IHOST_INTR_STATUS_MAP_NUM (INTC_INTR_REG_NUM * (sizeof(uint32))) +#define IRQ_BIT(intr) (intr % (sizeof(uint32)*8)) +#define IRQ_MASK_INDEX(intr) (intr / (sizeof(uint32)*8)) +#define HX5_SW_PROG_INTR_PRIORITY 73 +#define INTR_SW_PROG_INTR_BITPOS (1 << IRQ_BIT(HX5_SW_PROG_INTR_PRIORITY)) +#define INTC_SW_PROG_INTR_REG_IND IRQ_MASK_INDEX(HX5_SW_PROG_INTR_PRIORITY) +#define HX5_CHIP_INTR_LOW_PRIORITY 119 +#define INTR_LOW_PRIORITY_BITPOS (1 << IRQ_BIT(HX5_CHIP_INTR_LOW_PRIORITY)) +#define INTC_LOW_PRIORITY_INTR_REG_IND IRQ_MASK_INDEX(HX5_CHIP_INTR_LOW_PRIORITY) +#define INTC_PDMA_INTR_REG_IND 4 + +#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)) + +#define IHOST_READ_INTR(d, reg, v) \ + (v = readl((reg))) +#define IHOST_WRITE_INTR(d, reg, v) \ + (writel((v), (reg))) + +/* 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 uint32 *ihost_intr_status_base = NULL; +static uint32 *ihost_intr_enable_base = NULL; + +/* Module parameter for Interruptible timeout */ +static int intr_timeout = 0; +LKM_MOD_PARAM(intr_timeout, "i", int, (S_IRUGO | S_IWUSR)); +MODULE_PARM_DESC(intr_timeout, +"Interruptible wait timeout in milliseconds for Interrupt to be triggered."); + +static ulong intr_count = 0; +LKM_MOD_PARAM(intr_count, "intr_count", ulong, (S_IRUGO | S_IWUSR)); +MODULE_PARM_DESC(intr_count, +"Interrupt count provides information about the number of times the ISR is called."); + +/* Debug output */ +static int debug; +LKM_MOD_PARAM(debug, "i", int, (S_IRUGO | S_IWUSR)); +MODULE_PARM_DESC(debug, +"Set debug level (default 0)."); + +static ibde_t *user_bde = NULL; + +typedef void (*isr_f)(void *); + +typedef struct _intr_regs_s { + uint32 intc_intr_status_base; + uint32 intc_intr_enable_base; + uint32 intc_intr_raw_status_base; + uint32 intc_intr_clear_0; + uint32 intc_intr_clear_1; + uint32 intc_intr_clear_mode_0; + uint32 intc_intr_clear_mode_1; + uint32 intc_intr_status; + uint32 intc_intr_pacing_ctrl; + uint32 intc_intr_clear_delay_unit; + uint32 intc_intr_clear_delay_base; + uint32 intc_intr_pcie_err_status; +} _intr_regs_t; + +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[] */ + int timeout_count; + _intr_regs_t intr_regs; +} 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 +} + +void +dump_interrupt_regs(bde_ctrl_t *ctrl , int dev) +{ + int ind; + uint32_t val; + + if (debug >= 2) { + gprintk("Interrupt timeout count = %d\n", ctrl->timeout_count); + gprintk("Interrupt count = %lu\n", intr_count); + for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) { + READ_INTC_INTR(dev, ctrl->intr_regs.intc_intr_status_base + 4 * ind, val); + gprintk("INTC_INTR_STATUS_REG_%d = 0x%x\n", ind, val); + READ_INTC_INTR(dev, ctrl->intr_regs.intc_intr_raw_status_base + 4 * ind, val); + gprintk("INTC_INTR_RAW_STATUS_REG_%d = 0x%x\n", ind, val); + READ_INTC_INTR(dev, ctrl->intr_regs.intc_intr_enable_base + 4 * ind, val); + gprintk("INTC_INTR_ENABLE_REG_%d = 0x%x\n", ind, val); + } + /* Dump PAXB Register */ + READ_INTC_INTR(dev, ctrl->intr_regs.intc_intr_status, val); + gprintk("PAXB_0_PAXB_INTR_STATUS = 0x%x\n", val); + READ_INTC_INTR(dev, ctrl->intr_regs.intc_intr_pacing_ctrl, val); + gprintk("PAXB_0_PAXB_IC_INTR_PACING_CTRL = 0x%x\n", val); + READ_INTC_INTR(dev, ctrl->intr_regs.intc_intr_clear_delay_unit, val); + gprintk("PAXB_0_PAXB_INTRCLR_DELAY_UNIT = 0x%x\n", val); + READ_INTC_INTR(dev, ctrl->intr_regs.intc_intr_pcie_err_status, val); + gprintk("PAXB_0_PCIE_ERROR_STATUS = 0x%x\n", val); + + for (ind = 0; ind < PAXB_INTRCLR_DELAY_REG_NUM; ind++) { + READ_INTC_INTR(dev, ctrl->intr_regs.intc_intr_clear_delay_base + 4 * ind, val); + gprintk("PAXB_0_PAXB_IC_INTRCLR_DELAY_REG_%d = 0x%x\n", ind, val); + } + } + /* Clear interrupt enable registers */ + for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) { + WRITE_INTC_INTR(dev, ctrl->intr_regs.intc_intr_enable_base + 4 * ind, 0); + } +} + +static int +_cmicx_interrupt_prepare(bde_ctrl_t *ctrl) +{ + int d, ind; + uint32 stat, iena, mask, fmask; + + d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t)); + + if (ctrl->dev_type & BDE_PCI_DEV_TYPE) { + READ_INTC_INTR(d, ctrl->intr_regs.intc_intr_clear_mode_0, stat); + /* Clear MSI interrupts immediately to prevent spurious interrupts */ + if (stat == 0) { + WRITE_INTC_INTR(d, ctrl->intr_regs.intc_intr_clear_0, 0xFFFFFFFF); + WRITE_INTC_INTR(d, ctrl->intr_regs.intc_intr_clear_1, 0xFFFFFFFF); + } + } + + lkbde_irq_mask_get(d, &mask, &fmask); + + if (fmask) { + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + IHOST_READ_INTR(d, ihost_intr_status_base + INTC_PDMA_INTR_REG_IND, stat); + IHOST_READ_INTR(d, ihost_intr_enable_base + INTC_PDMA_INTR_REG_IND, iena); + } else { + READ_INTC_INTR(d, ctrl->intr_regs.intc_intr_status_base + 4 * INTC_PDMA_INTR_REG_IND, stat); + READ_INTC_INTR(d, ctrl->intr_regs.intc_intr_enable_base + 4 * INTC_PDMA_INTR_REG_IND, iena); + } + if (stat & iena) { + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + IHOST_WRITE_INTR(d, ihost_intr_enable_base + INTC_PDMA_INTR_REG_IND + + HX5_IHOST_IRQ_MASK_OFFSET, ~0); + } else { + WRITE_INTC_INTR(d, ctrl->intr_regs.intc_intr_enable_base + 4 * INTC_PDMA_INTR_REG_IND, 0); + } + + for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) { + if (ind == INTC_PDMA_INTR_REG_IND) { + continue; + } + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + if (ind < INTC_SW_PROG_INTR_REG_IND) { + continue; + } + if (ind == INTC_SW_PROG_INTR_REG_IND) { + IHOST_READ_INTR(d, ihost_intr_enable_base + ind + HX5_IHOST_IRQ_PEND_OFFSET, stat); + stat &= INTR_SW_PROG_INTR_BITPOS; + } else { + IHOST_READ_INTR(d, ihost_intr_status_base + ind, stat); + if (ind == INTC_LOW_PRIORITY_INTR_REG_IND) { + stat &= INTR_LOW_PRIORITY_BITPOS; + } + } + } else { + READ_INTC_INTR(d, ctrl->intr_regs.intc_intr_status_base + 4 * ind, stat); + READ_INTC_INTR(d, ctrl->intr_regs.intc_intr_enable_base + 4 * ind, iena); + } + if (stat & iena) { + break; + } + } + /* No pending interrupts */ + if (ind >= INTC_INTR_REG_NUM) { + return -1; + } + } + } + + /* 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 (ind = 0; ind < INTC_INTR_REG_NUM; ind++) { + if (fmask && ind == INTC_PDMA_INTR_REG_IND) { + continue; + } + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + if (ind < INTC_SW_PROG_INTR_REG_IND) { + continue; + } + if (ind == INTC_SW_PROG_INTR_REG_IND) { + IHOST_WRITE_INTR(d, ihost_intr_enable_base + INTC_SW_PROG_INTR_REG_IND + + HX5_IHOST_IRQ_MASK_OFFSET, INTR_SW_PROG_INTR_BITPOS); + } else if (ind == INTC_LOW_PRIORITY_INTR_REG_IND) { + IHOST_WRITE_INTR(d, ihost_intr_enable_base + INTC_LOW_PRIORITY_INTR_REG_IND + + HX5_IHOST_IRQ_MASK_OFFSET, INTR_LOW_PRIORITY_BITPOS); + } else { + IHOST_WRITE_INTR(d, ihost_intr_enable_base + ind + + HX5_IHOST_IRQ_MASK_OFFSET, ~0); + } + } else { + WRITE_INTC_INTR(d, ctrl->intr_regs.intc_intr_enable_base + 4*ind, 0); + } + } + return 0; +} + +static void +_cmicx_interrupt(bde_ctrl_t *ctrl) +{ + bde_inst_resource_t *res; + + intr_count++; + + res = &_bde_inst_resource[ctrl->inst]; + if (_cmicx_interrupt_prepare(ctrl) < 0) { + return; + } + + /* 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 +} + +/* some device has cmc0 only */ +static void +_cmicd_cmc0_interrupt(bde_ctrl_t *ctrl) +{ + int d; + int cmc = 0; + 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; + } + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT5_OFFSET(cmc)); + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(cmc)); + } else { + 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)); + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc)); + } else { + mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK6_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_MASK5_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc), 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_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 +_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; + } + /** Check if there are interrupts other than PacketIO interrupts on CMC1 */ + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT0_OFFSET(1)); + imask = mask & ~fmask; + if (stat & imask) { + break; + } + /** Check if there are interrupts other than PacketIO interrupts on CMC2 */ + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT0_OFFSET(2)); + 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; + } + stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT5_OFFSET(cmc)); + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(cmc)); + } else { + 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)); + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc)); + } else { + mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK6_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_MASK5_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK6_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_MASK5_OFFSET(cmc), 0); + user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK6_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 +_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 +} + +/* The actual interrupt handler of ethernet devices */ +static void +_ether_interrupt(bde_ctrl_t *ctrl) +{ + 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)_cmicd_cmc0_interrupt, "CMICd CMC0" }, + { (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 +_intr_regs_init(bde_ctrl_t *ctrl, int hx5_intr) +{ + if (hx5_intr) { + ctrl->intr_regs.intc_intr_status_base = HX5_INTC_INTR_STATUS_BASE; + ctrl->intr_regs.intc_intr_enable_base = HX5_INTC_INTR_ENABLE_BASE; + ctrl->intr_regs.intc_intr_raw_status_base = HX5_INTC_INTR_RAW_STATUS_BASE; + ctrl->intr_regs.intc_intr_clear_0 = HX5_PAXB_0_PAXB_IC_INTRCLR_0; + ctrl->intr_regs.intc_intr_clear_1 = HX5_PAXB_0_PAXB_IC_INTRCLR_1; + ctrl->intr_regs.intc_intr_clear_mode_0 = HX5_PAXB_0_PAXB_IC_INTRCLR_MODE_0; + ctrl->intr_regs.intc_intr_clear_mode_1 = HX5_PAXB_0_PAXB_IC_INTRCLR_MODE_1; + ctrl->intr_regs.intc_intr_status = HX5_PAXB_0_PAXB_INTR_STATUS; + ctrl->intr_regs.intc_intr_pacing_ctrl = HX5_PAXB_0_PAXB_IC_INTR_PACING_CTRL; + ctrl->intr_regs.intc_intr_clear_delay_unit = HX5_PAXB_0_PAXB_INTRCLR_DELAY_UNIT; + ctrl->intr_regs.intc_intr_clear_delay_base = HX5_PAXB_0_PAXB_IC_INTRCLR_DELAY_BASE; + ctrl->intr_regs.intc_intr_pcie_err_status = HX5_PAXB_0_PCIE_ERROR_STATUS; + + } else { + ctrl->intr_regs.intc_intr_status_base = INTC_INTR_STATUS_BASE; + ctrl->intr_regs.intc_intr_raw_status_base = INTC_INTR_RAW_STATUS_BASE; + ctrl->intr_regs.intc_intr_enable_base = INTC_INTR_ENABLE_BASE; + ctrl->intr_regs.intc_intr_clear_0 = PAXB_0_PAXB_IC_INTRCLR_0; + ctrl->intr_regs.intc_intr_clear_1 = PAXB_0_PAXB_IC_INTRCLR_1; + ctrl->intr_regs.intc_intr_clear_mode_0 = PAXB_0_PAXB_IC_INTRCLR_MODE_0; + ctrl->intr_regs.intc_intr_clear_mode_1 = PAXB_0_PAXB_IC_INTRCLR_MODE_1; + ctrl->intr_regs.intc_intr_status = PAXB_0_PAXB_INTR_STATUS; + ctrl->intr_regs.intc_intr_pacing_ctrl = PAXB_0_PAXB_IC_INTR_PACING_CTRL; + ctrl->intr_regs.intc_intr_clear_delay_unit = PAXB_0_PAXB_INTRCLR_DELAY_UNIT; + ctrl->intr_regs.intc_intr_clear_delay_base = PAXB_0_PAXB_IC_INTRCLR_DELAY_BASE; + ctrl->intr_regs.intc_intr_pcie_err_status = PAXB_0_PCIE_ERROR_STATUS; + + } +} + +static void +_devices_init(int d) +{ + bde_ctrl_t *ctrl; + uint32 ver; + uint16 device_id_mask = 0xFFF0; + uint16 device_id; + uint32 state = 0; + + (void)lkbde_dev_state_get(d, &state); + if (state == BDE_DEV_STATE_REMOVED) { + return; + } + + 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 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; + case BCM53540_DEVICE_ID: + case BCM53547_DEVICE_ID: + case BCM53548_DEVICE_ID: + case BCM53549_DEVICE_ID: + ctrl->isr = (isr_f)_cmicd_cmc0_interrupt; + break; + 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 BCM88687_DEVICE_ID: + case BCM88380_DEVICE_ID: + case BCM88381_DEVICE_ID: + case BCM88680_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 BCM88274_DEVICE_ID: + case BCM88278_DEVICE_ID: + case BCM88279_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 BCM88772_DEVICE_ID: + case BCM88952_DEVICE_ID: + ctrl->isr = (isr_f)_cmicd_interrupt; + break; + case BCM56370_DEVICE_ID: + case BCM56371_DEVICE_ID: + case BCM56372_DEVICE_ID: + case BCM56374_DEVICE_ID: + case BCM56375_DEVICE_ID: + case BCM56376_DEVICE_ID: + case BCM56377_DEVICE_ID: + case BCM56577_DEVICE_ID: + case BCM56578_DEVICE_ID: + case BCM56579_DEVICE_ID: + case BCM56273_DEVICE_ID: + case BCM56274_DEVICE_ID: + case BCM56275_DEVICE_ID: + case BCM56276_DEVICE_ID: + case BCM56277_DEVICE_ID: + case BCM56278_DEVICE_ID: + case BCM56279_DEVICE_ID: + case BCM56575_DEVICE_ID: + ctrl->isr = (isr_f)_cmicx_interrupt; + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + if (!ihost_intr_enable_base) { + ihost_intr_enable_base = (uint32_t *)IOREMAP(HX5_IHOST_GICD_ISENABLERN_1, + HX5_IHOST_INTR_MAP_NUM); + } + if (!ihost_intr_status_base) { + ihost_intr_status_base = (uint32_t *)IOREMAP(HX5_INTC_INTR_RAW_STATUS_REG0, + HX5_IHOST_INTR_STATUS_MAP_NUM); + } + } + _intr_regs_init(ctrl, 1); + break; + default: + /* Get CMIC version */ + if (user_bde->get_cmic_ver(d, &ver) != 0) { + ver = -1; + } + device_id = ctrl->devid & device_id_mask; + /* TH/TH+/TH2 should use cmicd interrupt handler */ + if (BCM56960_DEVICE_ID == device_id || + BCM56930_DEVICE_ID == device_id || + BCM56970_DEVICE_ID == device_id) { + ctrl->isr = (isr_f)_cmicd_interrupt; + } + /* check if version is CMICX */ + else if (ver == 0x04) { + ctrl->isr = (isr_f)_cmicx_interrupt; + _intr_regs_init(ctrl, 0); + } 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; + } + + /* configure interrupts for DNX devices using iproc >=14 */ +#if defined(BCM_DNXF_SUPPORT) || defined(BCM_DNX_SUPPORT) + switch (user_bde->get_dev(d)->device & DNXC_DEVID_FAMILY_MASK) { +#ifdef BCM_DNX_SUPPORT + case JERICHO2_DEVICE_ID: + case J2C_DEVICE_ID: + case J2C_2ND_DEVICE_ID: + case Q2A_DEVICE_ID: + case Q2U_DEVICE_ID: + case J2P_DEVICE_ID: +#endif +#ifdef BCM_DNXF_SUPPORT + case BCM88790_DEVICE_ID: +#endif + ctrl->isr = (isr_f)_cmicx_interrupt; + _intr_regs_init(ctrl, 0); + break; + } +#endif /* defined(BCM_DNXF_SUPPORT) || defined(BCM_DNX_SUPPORT) */ + + 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); + + ihost_intr_enable_base = NULL; + ihost_intr_status_base = NULL; + + for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) { + res->inst_id |= (1 << i); + _devices_init(i); + } + + if (intr_timeout > 0) { + gprintk("Interruptible wait timeout = %d msecs\n", intr_timeout); + } + + 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; + } + + if (ihost_intr_enable_base) { + iounmap(ihost_intr_enable_base); + ihost_intr_enable_base = NULL; + } + if (ihost_intr_status_base) { + iounmap(ihost_intr_status_base); + ihost_intr_status_base = 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; + uint32_t *mapaddr; + + 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; + io.dx.dw[0] = bde_dev->dev_unique_id; + 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; + io.d3 = dma_pbase >> 32; +#else + io.dx.dw[1] = 0; + io.d3 = 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 + /* CMICX Devices */ + if ((_devices[io.dev].dev_type & BDE_PCI_DEV_TYPE) && + (_devices[io.dev].isr == (isr_f)_cmicx_interrupt) && + (intr_timeout > 0)) { + unsigned long t_jiffies; + int err=0; + t_jiffies = msecs_to_jiffies(intr_timeout); + err = wait_event_interruptible_timeout(res->intr_wq, + atomic_read(&res->intr) != 0, + t_jiffies); + /* Timeout happend and condition not set */ + if (err == 0) { + bde_ctrl_t *ctrl; + ctrl = &_devices[io.dev]; + ctrl->timeout_count++; + if (debug >= 1) { + gprintk("Timeout happend and condition not set\n"); + } + dump_interrupt_regs(ctrl, io.dev); + } else if (err == -ERESTARTSYS) { + if (debug >= 1) { + gprintk("Interrupted by Signal\n"); + } + } + } 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: + case LUBDE_UDELAY: + case LUBDE_SEM_OP: + return -EINVAL; + 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; +#ifdef BCM_SAND_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: + if (!VALID_DEVICE(io.dev)) { + return -EINVAL; + } + if (_devices[io.dev].dev_type & BDE_AXI_DEV_TYPE) { + mapaddr = IOREMAP(io.d0, sizeof(uint32_t)); + if (mapaddr == NULL) { + io.rc = LUBDE_FAIL; + return -1; + } + io.d1 = readl(mapaddr); + iounmap(mapaddr); + } else { + 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; + case LUBDE_REPROBE: + io.rc = _device_reprobe(); + 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/sdk-6.5.20/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.h b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.h @@ -0,0 +1,114 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <linux/types.h> +#include <linux/ioctl.h> +#include <linux-bde.h> +#ifndef __KERNEL__ +#include <stdint.h> +#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_REPROBE _IO(LUBDE_MAGIC, 31) + +#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 + * 2: add LUBDE_REPROBE to support reprobe available devices + */ +#define KBDE_VERSION 2 + + +/* This is the signal that will be used + * when an interrupt occurs + */ + +#ifndef __KERNEL__ +#include <signal.h> +#endif + +#define LUBDE_INTERRUPT_SIGNAL SIGUSR1 +#define LUBDE_ETHER_INTERRUPT_SIGNAL SIGUSR2 + +#endif /* __LUBDE_H__ */ diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde.h b/sdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde.h @@ -0,0 +1,76 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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/sdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde_iproc.h b/sdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde_iproc.h @@ -0,0 +1,48 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#ifndef __SHBDE_IPROC_H__ +#define __SHBDE_IPROC_H__ + +#include <shbde.h> + +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/sdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde_mdio.h b/sdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde_mdio.h @@ -0,0 +1,59 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2015 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#ifndef __SHBDE_MDIO_H__ +#define __SHBDE_MDIO_H__ + +#include <shbde.h> + +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/sdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde_pci.h b/sdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde_pci.h @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#ifndef __SHBDE_PCI_H__ +#define __SHBDE_PCI_H__ + +#include <shbde.h> + +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/sdk-6.5.20/src/gpl-modules/systems/bde/shared/shbde_iproc.c b/sdk-6.5.20/src/gpl-modules/systems/bde/shared/shbde_iproc.c @@ -0,0 +1,503 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#include <shbde_iproc.h> +#include <shbde_mdio.h> +#include <shbde_pci.h> + +/* 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 PAXB_0_CMICD_TO_PCIE_INTR_EN 0x2380 + +#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 + +#define PAXB_0_FUNC0_IMAP1_3 0x2d88 + +/* 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 +#define PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT 20 + +/* 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 0xb670: /* MO */ + case 0xb760: /* Maverick */ + icfg->iproc_ver = 0xB; + break; + case 0xb160: /* Hurricane3 */ + case 0x8440: /* Buckhound2 */ + case 0x8430: /* Foxhound2 */ + case 0x8540: /* Wolfhound2 */ + 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); + } + } + + /* Configure MSIX interrupt page, need for iproc ver 0x10 and 0x12 */ + if ((icfg->use_msi == 2) && + ((icfg->iproc_ver == 0x10) || (icfg->iproc_ver == 0x12))){ + unsigned int mask = (0x1 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT) - 1; + reg = ROFFS(iproc_regs, PAXB_0_FUNC0_IMAP1_3); + data = iproc32_read(shbde, reg); + data &= mask; + data |= 0x410 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT; + iproc32_write(shbde, reg, data); + } + + /* Disable INTx interrupt if MSI/MSIX is selected */ + reg = ROFFS(iproc_regs, PAXB_0_CMICD_TO_PCIE_INTR_EN); + data = iproc32_read(shbde, reg); + if (icfg->use_msi) { + data &= ~0x1; + } else { + data |= 0x1; + } + iproc32_write(shbde, reg, data); + + 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 == 0x10230000) || (subwin_base == 0x18012000))) { + /* Route the PAXB register through IMAP0_2 */ + reg = ROFFS(iproc_regs, 0x2000 + (addr & 0xfff)); + } else if((icfg->cmic_ver >= 4) && + ((subwin_base == 0x10231000) || (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 == 0x10230000) || (subwin_base == 0x18012000))) { + /* Route the PAXB register through IMAP0_2 */ + reg = ROFFS(iproc_regs, 0x2000 + (addr & 0xfff)); + } else if((icfg->cmic_ver >= 4) && + ((subwin_base == 0x10231000) || (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/sdk-6.5.20/src/gpl-modules/systems/bde/shared/shbde_mdio.c b/sdk-6.5.20/src/gpl-modules/systems/bde/shared/shbde_mdio.c @@ -0,0 +1,186 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2015 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#include <shbde_mdio.h> + +/* 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/sdk-6.5.20/src/gpl-modules/systems/bde/shared/shbde_pci.c b/sdk-6.5.20/src/gpl-modules/systems/bde/shared/shbde_pci.c @@ -0,0 +1,392 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: $ + * $Copyright: (c) 2014 Broadcom Corp. + * All Rights Reserved.$ + * + */ + +#include <shbde_pci.h> + +/* 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/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/Makefile @@ -0,0 +1,31 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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= + +include ${SDK}/make/Make.subdirs + +include ${SDK}/make/Make.depend diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/Makefile @@ -0,0 +1,64 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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 + +# 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/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c @@ -0,0 +1,9034 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* + * 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 before removing the + * device. + * + * For a list of supported module parameters, please see below. + */ + +#include <gmodule.h> /* Must be included first */ +#include <linux-bde.h> +#include <kcom.h> +#include <bcm-knet.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/random.h> +#include <linux/seq_file.h> +#include <linux/if_vlan.h> +#include <linux/nsproxy.h> + + +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[8] = { 100000, 100000, 100000, 100000, 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[8] = { 0, 0, 0, 0, 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)"); + +/* + * Force to add one layer of VLAN tag to untagged packets on Dune devices + */ +static int force_tagged = 1; +LKM_MOD_PARAM(force_tagged, "i", int, 0); +MODULE_PARM_DESC(force_tagged, +"Always tagged with VLAN tag with spceified VID or VSI(default 1)"); + +static int ft_tpid=0x8100; +LKM_MOD_PARAM(ft_tpid, "i", int, 0); +MODULE_PARM_DESC(ft_tpid, +"Tag Protocol Identifier (TPID) indicates the frame type (default 0x8100)"); + +static int ft_pri=0; +LKM_MOD_PARAM(ft_pri, "i", int, 0); +MODULE_PARM_DESC(ft_cfi, +"Priority (PRI) indicates the frame priority (default 0)"); + +static int ft_cfi=0; +LKM_MOD_PARAM(ft_cfi, "i", int, 0); +MODULE_PARM_DESC(ft_cfi, +"Canonical Format Indicator (CFI) indicates whether a MAC address is encapsulated in canonical format over different transmission media (default 0)"); + +static int ft_vid=0; +LKM_MOD_PARAM(ft_vid, "i", int, 0); +MODULE_PARM_DESC(ft_vid, +"VLAN ID (VID) indicates the VLAN to which a frame belongs (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 + +/* Compatibility */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)) +#define NETDEV_UPDATE_TRANS_START_TIME(dev) dev->trans_start = jiffies +#else +#define NETDEV_UPDATE_TRANS_START_TIME(dev) netif_trans_update(dev) +#endif + +#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) */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) +#define bkn_vlan_hwaccel_put_tag(_skb, _proto, _tci) \ + __vlan_hwaccel_put_tag(_skb, _tci) +#else +#define bkn_vlan_hwaccel_put_tag(_skb, _proto, _tci) \ + __vlan_hwaccel_put_tag(_skb, htons(_proto), _tci) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0) +#define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */ +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) +#define bkn_dma_mapping_error(d, a) \ + dma_mapping_error(a) +#define bkn_pci_dma_mapping_error(d, a) \ + pci_dma_mapping_error(a) +#else +#define bkn_dma_mapping_error(d, a) \ + dma_mapping_error(d, a) +#define bkn_pci_dma_mapping_error(d, a) \ + pci_dma_mapping_error(d, a) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) +enum hwtstamp_tx_types { + HWTSTAMP_TX_OFF, + HWTSTAMP_TX_ON, + HWTSTAMP_TX_ONESTEP_SYNC +}; +enum { + SKBTX_HW_TSTAMP = 1 << 0, + SKBTX_SW_TSTAMP = 1 << 1, + SKBTX_IN_PROGRESS = 1 << 2, +}; +struct skb_shared_hwtstamps { + ktime_t hwtstamp; + ktime_t syststamp; +}; +struct bkn_skb_shared_info { + uint8_t tx_flags; + struct skb_shared_hwtstamps hwtstamps; +}; +#define bkn_skb_shinfo(_skb) ((struct bkn_skb_shared_info *)(unsigned char *)_skb->end) +#define bkn_skb_tx_flags(_skb) bkn_skb_shinfo(_skb)->tx_flags +static inline struct skb_shared_hwtstamps *skb_hwtstamps(struct sk_buff *skb) +{ + return &bkn_skb_shinfo(skb)->hwtstamps; +} +void skb_tstamp_tx(struct sk_buff *orig_skb, struct skb_shared_hwtstamps *hwtstamps) +{ +} +static inline void bkn_skb_tx_timestamp(struct sk_buff *skb) +{ +} +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) +static inline ktime_t ns_to_ktime(u64 ns) +{ + static const ktime_t ktime; + return ktime; +} +#endif +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +#include <linux/net_tstamp.h> +#define HWTSTAMP_TX_ONESTEP_SYNC 2 +enum { + SKBTX_HW_TSTAMP = 1 << 0, + SKBTX_SW_TSTAMP = 1 << 1, + SKBTX_IN_PROGRESS = 1 << 2, +}; +#define bkn_skb_tx_flags(_skb) skb_shinfo(_skb)->tx_flags.flags +static inline void bkn_skb_tx_timestamp(struct sk_buff *skb) +{ +} +#else +#include <linux/net_tstamp.h> + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) +#define HWTSTAMP_TX_ONESTEP_SYNC 2 +#endif + +#define bkn_skb_tx_flags(_skb) skb_shinfo(_skb)->tx_flags +static inline void bkn_skb_tx_timestamp(struct sk_buff *skb) +{ + return skb_tx_timestamp(skb); +} +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) +#define bkn_dev_net_set(dev, net) +#else +#define bkn_dev_net_set(dev, net) dev_net_set(dev, net) +#endif + +#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT +#define BKN_DMA_DEV device +#define BKN_DMA_FROMDEV DMA_FROM_DEVICE +#define BKN_DMA_TODEV DMA_TO_DEVICE +#define BKN_DMA_MAP_SINGLE(d,p,s,r) dma_map_single(d,p,s,r) +#define BKN_DMA_UNMAP_SINGLE(d,a,s,r) dma_unmap_single(d,a,s,r) +#define BKN_DMA_ALLOC_COHERENT(d,s,h) dma_alloc_coherent(d,s,h,GFP_ATOMIC|GFP_DMA32) +#define BKN_DMA_FREE_COHERENT(d,s,a,h) dma_free_coherent(d,s,a,h) +#define BKN_DMA_MAPPING_ERROR(d,a) bkn_dma_mapping_error(d,a) +#else +#define BKN_DMA_DEV pci_dev +#define BKN_DMA_FROMDEV PCI_DMA_FROMDEVICE +#define BKN_DMA_TODEV PCI_DMA_TODEVICE +#define BKN_DMA_MAP_SINGLE(d,p,s,r) pci_map_single(d,p,s,r) +#define BKN_DMA_UNMAP_SINGLE(d,a,s,r) pci_unmap_single(d,a,s,r) +#define BKN_DMA_ALLOC_COHERENT(d,s,h) pci_alloc_consistent(d,s,h) +#define BKN_DMA_FREE_COHERENT(d,s,a,h) pci_free_consistent(d,s,a,h) +#define BKN_DMA_MAPPING_ERROR(d,a) bkn_pci_dma_mapping_error(d,a) +#endif + +/* + * Get a 16-bit value from packet offset + * _data Pointer to packet + * _offset Offset + */ +#define PKT_U16_GET(_data, _offset) \ + (uint16_t)(_data[_offset] << 8 | _data[_offset + 1]) + + +/* 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) + +#define PKT_TX_HDR_SIZE 16 + +static volatile int module_initialized; + +static ibde_t *kernel_bde = NULL; + +/* Descriptor info */ +typedef struct bkn_desc_info_s { + uint32_t *dcb_mem; + uint64_t dcb_dma; + struct sk_buff *skb; + uint64_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; + uint64_t dcb_dma; +} bkn_dcb_chain_t; + +#define MAX_TX_DCBS 64 +#define MAX_RX_DCBS 64 + +#define NUM_DMA_CHAN 8 +#define NUM_RX_CHAN 7 +#define NUM_CMICX_RX_CHAN 7 +#define NUM_CMICM_RX_CHAN 3 + +#define FCS_SZ 4 +#define TAG_SZ 4 + +/* 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 BKN_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) */ + int pkt_hdr_size; /* Packet header size */ + uint32_t ftmh_lb_key_ext_size; /* FTMH LB-Key Extension existence/size */ + uint32_t ftmh_stacking_ext_size; /* FTMH Stacking extension existence/size */ + uint32_t pph_base_size; /* Size of PPH base */ + uint32_t pph_lif_ext_size[8]; /* Size of PPH Lif extension header */ + uint32_t udh_length_type[4]; /* Size of UDH header per type */ + uint32_t udh_size; /* Size of UDH header on legacy devices */ + uint32_t oamp_punt; /* OAMP port if nonzero */ + uint8_t no_skip_udh_check; /* Indicates UDH won't be skipped */ + uint8_t system_headers_mode; /* Indicates system header mode */ + uint8_t udh_enable; /* Indicates UDH existence */ + int rx_chans; /* Number of Rx channels */ + uint32_t dma_hi; /* DMA higher address */ + 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 */ + uint64_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 */ + uint64_t halt_addr[NUM_DMA_CHAN]; /* DMA halt address */ + uint32_t cdma_channels; /* Active channels for Continuous DMA mode */ + uint32_t poll_channels; /* Channels for polling */ + 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 sk_buff_head tx_ptp_queue; /* Tx PTP skb queue */ + struct work_struct tx_ptp_work; /* Tx PTP work */ + 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; + +/* 0x1 - Jericho 2 mode */ +#define BKN_DNX_JR2_MODE 1 +/* PTCH_2 */ +#define BKN_DNX_PTCH_2_SIZE 2 +/* ITMH */ +#define BKN_DNX_ITMH_SIZE 5 +/* Modlue Header */ +#define BKN_DNX_MODULE_HEADER_SIZE 20 +/* FTMH */ +#define BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_MSB 17 +#define BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_NOF_BITS 16 +#define BKN_DNX_FTMH_PP_DSP_MSB 33 +#define BKN_DNX_FTMH_PP_DSP_NOF_BITS 8 +#define BKN_DNX_FTMH_ACTION_TYPE_MSB 43 +#define BKN_DNX_FTMH_ACTION_TYPE_NOF_BITS 2 +#define BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_MSB 73 +#define BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_NOF_BITS 1 +#define BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_MSB 74 +#define BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_NOF_BITS 1 +#define BKN_DNX_FTMH_TM_DST_EXT_PRESENT_MSB 75 +#define BKN_DNX_FTMH_TM_DST_EXT_PRESENT_NOF_BITS 1 +#define BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_MSB 76 +#define BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_NOF_BITS 1 +#define BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_MSB 77 +#define BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_NOF_BITS 1 +#define BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_MSB 78 +#define BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_NOF_BITS 1 +/* Fix Length for FTMH and Extension headers */ +#define BKN_DNX_FTMH_BASE_SIZE 10 +#define BKN_DNX_FTMH_BIER_BFR_EXT_SIZE 2 +#define BKN_DNX_FTMH_TM_DST_EXT_SIZE 3 +#define BKN_DNX_FTMH_FLOW_ID_EXT_SIZE 3 +#define BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE 6 +/* TSH */ +#define BKN_DNX_TSH_SIZE 4 +/* PPH */ +#define BKN_DNX_INTERNAL_BASE_TYPE_9 9 +#define BKN_DNX_INTERNAL_BASE_TYPE_10 10 +#define BKN_DNX_INTERNAL_BASE_TYPE_12 12 +#define BKN_DNX_INTERNAL_9_FORWARD_DOMAIN_MSB 5 +#define BKN_DNX_INTERNAL_9_FORWARD_DOMAIN_NOF_BITS 16 +#define BKN_DNX_INTERNAL_9_LEARN_EXT_PRESENT_MSB 53 +#define BKN_DNX_INTERNAL_9_LEARN_EXT_PRESENT_NOF_BITS 1 +#define BKN_DNX_INTERNAL_9_FHEI_SIZE_MSB 54 +#define BKN_DNX_INTERNAL_9_FHEI_SIZE_NOF_BITS 2 +#define BKN_DNX_INTERNAL_9_LIF_EXT_TYPE_MSB 56 +#define BKN_DNX_INTERNAL_9_LIF_EXT_TYPE_NOF_BITS 3 +#define BKN_DNX_INTERNAL_10_FORWARD_DOMAIN_MSB 9 +#define BKN_DNX_INTERNAL_10_FORWARD_DOMAIN_NOF_BITS 16 +#define BKN_DNX_INTERNAL_10_LEARN_EXT_PRESENT_MSB 61 +#define BKN_DNX_INTERNAL_10_LEARN_EXT_PRESENT_NOF_BITS 1 +#define BKN_DNX_INTERNAL_10_FHEI_SIZE_MSB 62 +#define BKN_DNX_INTERNAL_10_FHEI_SIZE_NOF_BITS 2 +#define BKN_DNX_INTERNAL_10_LIF_EXT_TYPE_MSB 64 +#define BKN_DNX_INTERNAL_10_LIF_EXT_TYPE_NOF_BITS 3 +#define BKN_DNX_INTERNAL_12_FORWARD_DOMAIN_MSB 21 +#define BKN_DNX_INTERNAL_12_FORWARD_DOMAIN_NOF_BITS 18 +#define BKN_DNX_INTERNAL_12_LEARN_EXT_PRESENT_MSB 77 +#define BKN_DNX_INTERNAL_12_LEARN_EXT_PRESENT_NOF_BITS 1 +#define BKN_DNX_INTERNAL_12_FHEI_SIZE_MSB 78 +#define BKN_DNX_INTERNAL_12_FHEI_SIZE_NOF_BITS 2 +#define BKN_DNX_INTERNAL_12_LIF_EXT_TYPE_MSB 80 +#define BKN_DNX_INTERNAL_12_LIF_EXT_TYPE_NOF_BITS 3 +/* PPH.FHEI_TYPE */ +#define BKN_DNX_INTERNAL_FHEI_TYPE_SZ0 1 +#define BKN_DNX_INTERNAL_FHEI_TYPE_SZ1 2 +#define BKN_DNX_INTERNAL_FHEI_TYPE_SZ2 3 +/* FHEI */ +#define BKN_DNX_INTERNAL_FHEI_SZ0_SIZE 3 +#define BKN_DNX_INTERNAL_FHEI_SZ1_SIZE 5 +#define BKN_DNX_INTERNAL_FHEI_SZ2_SIZE 8 +#define BKN_DNX_INTERNAL_FHEI_TRAP_5B_QUALIFIER_MSB 0 +#define BKN_DNX_INTERNAL_FHEI_TRAP_5B_QUALIFIER_NOF_BITS 27 +#define BKN_DNX_INTERNAL_FHEI_TRAP_5B_CODE_MSB 27 +#define BKN_DNX_INTERNAL_FHEI_TRAP_5B_CODE_NOF_BITS 9 +#define BKN_DNX_INTERNAL_FHEI_TRAP_5B_TYPE_MSB 36 +#define BKN_DNX_INTERNAL_FHEI_TRAP_5B_TYPE_NOF_BITS 4 +/* PPH Extension */ +#define BKN_DNX_INTERNAL_LEARN_EXT_SIZE 19 +/* UDH */ +#define BKN_DNX_UDH_DATA_TYPE_0_MSB 0 +#define BKN_DNX_UDH_DATA_TYPE_0_NOF_BITS 2 +#define BKN_DNX_UDH_DATA_TYPE_1_MSB 2 +#define BKN_DNX_UDH_DATA_TYPE_1_NOF_BITS 2 +#define BKN_DNX_UDH_DATA_TYPE_2_MSB 4 +#define BKN_DNX_UDH_DATA_TYPE_2_NOF_BITS 2 +#define BKN_DNX_UDH_DATA_TYPE_3_MSB 6 +#define BKN_DNX_UDH_DATA_TYPE_3_NOF_BITS 2 +#define BKN_DNX_UDH_BASE_SIZE 1 + +#define BKN_DPP_HDR_MAX_SIZE 40 +/* PTCH_2 */ +#define BKN_DPP_PTCH_2_SIZE 2 +/* ITMH */ +#define BKN_DPP_ITMH_SIZE 4 +/* FTMH */ +#define BKN_DPP_FTMH_LB_EXT_EN 0x1 +#define BKN_DPP_FTMH_STACKING_EXT_EN 0x2 +#define BKN_DPP_FTMH_SIZE_BYTE 9 +#define BKN_DPP_FTMH_LB_EXT_SIZE_BYTE 1 +#define BKN_DPP_FTMH_STACKING_SIZE_BYTE 2 +#define BKN_DPP_FTMH_DEST_EXT_SIZE_BYTE 2 +#define BKN_DPP_FTMH_LB_EXT_SIZE_BYTE 1 +#define BKN_DPP_FTMH_PKT_SIZE_MSB 0 +#define BKN_DPP_FTMH_PKT_SIZE_NOF_BITS 14 +#define BKN_DPP_FTMH_TC_MSB 14 +#define BKN_DPP_FTMH_TC_NOF_BITS 3 +#define BKN_DPP_FTMH_SRC_SYS_PORT_MSB 17 +#define BKN_DPP_FTMH_SRC_SYS_PORT_NOF_BITS 16 +#define BKN_DPP_FTMH_EXT_DSP_EXIST_MSB 68 +#define BKN_DPP_FTMH_EXT_DSP_EXIST_NOF_BITS 1 +#define BKN_DPP_FTMH_EXT_MSB 45 +#define BKN_DPP_FTMH_EXT_NOF_BITS 2 +#define BKN_DPP_FTMH_FIRST_EXT_MSB 72 +#define BKN_DPP_FTMH_ACTION_TYPE_MSB 43 +#define BKN_DPP_FTMH_ACTION_TYPE_NOF_BITS 2 +#define BKN_DPP_FTMH_PPH_TYPE_MSB 45 +#define BKN_DPP_FTMH_PPH_TYPE_NOF_BITS 2 + +/* OTSH */ +#define BKN_DPP_OTSH_SIZE_BYTE 6 +#define BKN_DPP_OTSH_TYPE_MSB 0 +#define BKN_DPP_OTSH_TYPE_NOF_BITS 2 +#define BKN_DPP_OTSH_OAM_SUB_TYPE_MSB 2 +#define BKN_DPP_OTSH_OAM_SUB_TYPE_NOF_BITS 3 + +#define BKN_DPP_OTSH_TYPE_OAM 0 +#define BKN_DPP_OTSH_OAM_SUB_TYPE_DM_1588 2 +#define BKN_DPP_OTSH_OAM_SUB_TYPE_DM_NTP 3 + +#define BKN_DPP_OAM_DM_TOD_SIZE_BYTE 4 + +/* PPH */ +#define BKN_DPP_INTERNAL_SIZE_BYTE 7 +#define BKN_DPP_INTERNAL_EEI_EXTENSION_PRESENT_MSB 0 +#define BKN_DPP_INTERNAL_EEI_EXTENSION_PRESENT_NOF_BITS 1 +#define BKN_DPP_INTERNAL_LEARN_EXENSION_PRESENT_MSB 1 +#define BKN_DPP_INTERNAL_LEARN_EXENSION_PRESENT_NOF_BITS 1 +#define BKN_DPP_INTERNAL_FHEI_SIZE_MSB 2 +#define BKN_DPP_INTERNAL_FHEI_SIZE_NOF_BITS 2 +#define BKN_DPP_INTERNAL_FORWARD_CODE_MSB 4 +#define BKN_DPP_INTERNAL_FORWARD_CODE_NOF_BITS 4 +#define BKN_DPP_INTERNAL_FORWARD_CODE_CPU_TRAP 7 +#define BKN_DPP_INTERNAL_FORWARDING_HEADER_OFFSET_MSB 8 +#define BKN_DPP_INTERNAL_FORWARDING_HEADER_OFFSET_NOF_BITS 7 +#define BKN_DPP_INTERNAL_VSI_MSB 22 +#define BKN_DPP_INTERNAL_VSI_NOF_BITS 16 + +/* FHEI TRAP/SNOOP 3B */ +#define BKN_DPP_INTERNAL_FHEI_3B_SIZE_BYTE 3 +#define BKN_DPP_INTERNAL_FHEI_5B_SIZE_BYTE 5 +#define BKN_DPP_INTERNAL_FHEI_8B_SIZE_BYTE 8 +#define BKN_DPP_INTERNAL_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_MSB 0 +#define BKN_DPP_INTERNAL_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_NOF_BITS 16 +#define BKN_DPP_INTERNAL_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_MSB 16 +#define BKN_DPP_INTERNAL_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_NOF_BITS 8 +/* PPH extension */ +#define BKN_DPP_INTERNAL_EXPLICIT_EDITING_INFOMATION_EXTENSION_SIZE_BYTE 3 +#define BKN_DPP_INTERNAL_LEARN_EXTENSION_SIZE_BYTE 5 + +#define BKN_SAND_SCRATCH_DATA_SIZE 4 + +/* ftmh action type. */ +typedef enum bkn_dpp_ftmh_action_type_e { + BKN_DPP_FTMH_ACTION_TYPE_FORWARD = 0, /* TM action is forward */ + BKN_DPP_FTMH_ACTION_TYPE_SNOOP = 1, /* TM action is snoop */ + BKN_DPP_FTMH_ACTION_TYPE_INBOUND_MIRROR = 2, /* TM action is inbound mirror. */ + BKN_DPP_FTMH_ACTION_TYPE_OUTBOUND_MIRROR = 3 /* TM action is outbound mirror. */ +}bkn_dpp_ftmh_action_type_t; + +/* ftmh dest extension. */ +typedef struct bkn_dpp_ftmh_dest_extension_s { + uint8_t valid; /* Set if the extension is present */ + uint32_t dst_sys_port; /* Destination System Port */ +} bkn_dpp_ftmh_dest_extension_t; + +/* dnx packet */ +typedef struct bkn_dune_system_header_info_s { + uint32_t system_header_size; + struct { + uint32_t action_type; /* Indicates if the copy is one of the Forward Snoop or Mirror packet copies */ + uint32_t source_sys_port_aggregate; /* Source System port*/ + } ftmh; + struct { + uint32_t forward_domain; + uint32_t trap_qualifier; + uint32_t trap_id; + } internal; +} bkn_dune_system_header_info_t; + +#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 smp_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; + int qnum; + uint32_t vlan; + uint32_t flags; + uint32_t cb_user_data; + uint8_t system_headers[27]; + uint32_t system_headers_size; + int tx_hwts; /* HW timestamp for Tx */ + int rx_hwts; /* HW timestamp for Rx */ + int phys_port; +} 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; +static knet_hw_tstamp_enable_cb_f knet_hw_tstamp_enable_cb = NULL; +static knet_hw_tstamp_enable_cb_f knet_hw_tstamp_disable_cb = NULL; +static knet_hw_tstamp_tx_time_get_cb_f knet_hw_tstamp_tx_time_get_cb = NULL; +static knet_hw_tstamp_tx_meta_get_cb_f knet_hw_tstamp_tx_meta_get_cb = NULL; +static knet_hw_tstamp_ptp_clock_index_cb_f knet_hw_tstamp_ptp_clock_index_cb = NULL; +static knet_hw_tstamp_rx_time_upscale_cb_f knet_hw_tstamp_rx_time_upscale_cb = NULL; +static knet_hw_tstamp_ioctl_cmd_cb_f knet_hw_tstamp_ioctl_cmd_cb = NULL; + +/* + * Thread management + */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)) +static void +bkn_sleep(int clicks) +{ + wait_queue_head_t wq; + + init_waitqueue_head(&wq); + sleep_on_timeout(&wq, clicks); +} +#else +static void +bkn_sleep(int clicks) +{ + wait_queue_head_t wq; + + init_waitqueue_head(&wq); + wait_event_timeout(wq, 0, clicks); +} +#endif + +/* + * 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 + +/* CMICx registers */ +#define CMICX_CMC_BASE 0x00000000 +#define CMICX_DMA_CTRLr (CMICX_CMC_BASE + 0x00002100) +#define CMICX_DMA_STATr (CMICX_CMC_BASE + 0x00002114) +#define CMICX_DMA_DESC_HIr (CMICX_CMC_BASE + 0x00002108) +#define CMICX_DMA_DESC_LOr (CMICX_CMC_BASE + 0x00002104) +#define CMICX_DMA_HALT_HIr (CMICX_CMC_BASE + 0x00002110) +#define CMICX_DMA_HALT_LOr (CMICX_CMC_BASE + 0x0000210c) +#define CMICX_IRQ_STATr (CMICX_CMC_BASE + 0x0000106c) +#define CMICX_IRQ_STAT_CLRr (CMICX_CMC_BASE + 0x00001074) +#define CMICX_IRQ_ENABr 0x18013100 +#define IHOST_GIC_GIC400_GICD_ISENABLERN_5r 0x10781114 +#define IHOST_GIC_GIC400_GICD_ICENABLERN_5r 0x10781194 + +/* CMICx interrupts reserved for kernel handler */ +#define CMICX_TXRX_IRQ_MASK 0xffffffff + +#define DEV_IS_CMICX(_sinfo) ((_sinfo)->cmic_type == 'x') +#define DEV_IS_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)) + +#define CMICX_DS_CMC_DESC_DONE(ch) (0x00000001 << ((ch) * 4)) +#define CMICX_DS_CMC_CHAIN_DONE(ch) (0x00000002 << ((ch) * 4)) +#define CMICX_DS_CMC_CTRLD_INT(ch) (0x00000008 << ((ch) * 4)) +#define CMICX_DS_CMC_DMA_CHAIN_DONE (0x00000001) +#define CMICX_DS_CMC_DMA_ACTIVE (0x00000002) + +#define DMA_TO_BUS_HI(dma) ((dma) | sinfo->dma_hi) +#define BUS_TO_DMA_HI(bus) ((bus) & ~sinfo->dma_hi) + +/* + * 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) + +#define CMICX_DC_CMC_DIRECTION (0x00000001) +#define CMICX_DC_CMC_ENABLE (0x00000002) +#define CMICX_DC_CMC_ABORT (0x00000004) +#define CMICX_DC_CMC_CTRLD_INT (0x00000080) +#define CMICX_DC_CMC_CONTINUOUS (0x00000100) + +/* + * 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, uint64_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, uint64_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 +xgsx_dma_chain_clear(bkn_switch_info_t *sinfo, int chan) +{ + uint32_t ctrl, stat; + + /* Disabing DMA clears chain done */ + DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl); + ctrl &= ~(CMICX_DC_CMC_ENABLE | CMICX_DC_CMC_ABORT); + DEV_WRITE32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, ctrl); + + stat = CMICX_DS_CMC_CHAIN_DONE(chan); + DEV_WRITE32(sinfo, CMICX_IRQ_STAT_CLRr, stat); + + MEMORY_BARRIER; + + /* Flush write buffer */ + DEV_READ32(sinfo, CMICX_IRQ_STAT_CLRr, &stat); + + MEMORY_BARRIER; +} + +static inline void +xgsx_dma_desc_clear(bkn_switch_info_t *sinfo, int chan) +{ + uint32_t stat; + + if (CDMA_CH(sinfo, chan)) { + stat = CMICX_DS_CMC_CTRLD_INT(chan); + } else { + stat = CMICX_DS_CMC_DESC_DONE(chan); + } + DEV_WRITE32(sinfo, CMICX_IRQ_STAT_CLRr, stat); + + MEMORY_BARRIER; + + /* Flush write buffer */ + DEV_READ32(sinfo, CMICX_IRQ_STAT_CLRr, &stat); + + MEMORY_BARRIER; +} + +static int +xgsx_dma_chan_clear(bkn_switch_info_t *sinfo, int chan) +{ + xgsx_dma_chain_clear(sinfo, chan); + xgsx_dma_desc_clear(sinfo, chan); + + return 0; +} + +static inline void +xgsx_cdma_halt_set(bkn_switch_info_t *sinfo, int chan) +{ + DEV_WRITE32(sinfo, CMICX_DMA_HALT_LOr + 0x80 * chan, + sinfo->halt_addr[chan]); + DEV_WRITE32(sinfo, CMICX_DMA_HALT_HIr + 0x80 * chan, + DMA_TO_BUS_HI(sinfo->halt_addr[chan] >> 32)); + + MEMORY_BARRIER; +} + +static int +xgsx_dma_chan_init(bkn_switch_info_t *sinfo, int chan, int dir) +{ + uint32_t ctrl; + + DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl); + ctrl &= ~CMICX_DC_CMC_DIRECTION; + if (dir) { + ctrl |= CMICX_DC_CMC_DIRECTION; + } + if (CDMA_CH(sinfo, chan)) { + ctrl |= CMICX_DC_CMC_CONTINUOUS | CMICX_DC_CMC_CTRLD_INT; + xgsx_cdma_halt_set(sinfo, chan); + } + DEV_WRITE32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, ctrl); + + MEMORY_BARRIER; + + return 0; +} + +static int +xgsx_dma_chan_start(bkn_switch_info_t *sinfo, int chan, uint64_t dcb) +{ + uint32_t ctrl; + + /* Write the DCB address to the DESC address for this channel */ + DEV_WRITE32(sinfo, CMICX_DMA_DESC_LOr + 0x80 * chan, dcb); + DEV_WRITE32(sinfo, CMICX_DMA_DESC_HIr + 0x80 * chan, DMA_TO_BUS_HI(dcb >> 32)); + + MEMORY_BARRIER; + + /* Kick it off */ + DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl); + ctrl |= CMICX_DC_CMC_ENABLE; + DEV_WRITE32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, ctrl); + + MEMORY_BARRIER; + + return 0; +} + +static int +xgsx_dma_chan_abort(bkn_switch_info_t *sinfo, int chan, int polls) +{ + uint32_t ctrl, stat; + int p; + + /* Skip abort sequence if channel is not active */ + DEV_READ32(sinfo, CMICX_DMA_STATr + 0x80 * chan, &stat); + if (!(stat & CMICX_DS_CMC_DMA_ACTIVE)) { + return 0; + } + + /* Abort the channel */ + DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl); + ctrl |= CMICX_DC_CMC_ENABLE | CMICX_DC_CMC_ABORT; + DEV_WRITE32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, ctrl); + + MEMORY_BARRIER; + + /* Poll for abort completion */ + for (p = 0; p < polls; p++) { + DEV_READ32(sinfo, CMICX_DMA_STATr + 0x80 * chan, &stat); + if (!(stat & CMICX_DS_CMC_DMA_ACTIVE)) { + /* Clear up channel */ + xgsx_dma_chan_clear(sinfo, chan); + return polls; + } + } + + DBG_WARN(("DMA channel %d abort failed\n", chan)); + + return -1; +} + +static inline void +xgsx_irq_mask_set(bkn_switch_info_t *sinfo, uint32_t mask) +{ + uint32_t irq_mask_reg = CMICX_IRQ_ENABr; + uint32_t irq_mask, irq_fmask, disable_mask; + + if (sinfo->napi_poll_mode) { + mask = 0; + } + + if (sinfo->cpu_no == 1) { + lkbde_irq_mask_get(sinfo->dev_no, &irq_mask, &irq_fmask); + disable_mask = ~mask & (irq_mask & irq_fmask); + if (disable_mask) { + lkbde_irq_mask_set(sinfo->dev_no | LKBDE_ISR2_DEV | LKBDE_IPROC_REG, + IHOST_GIC_GIC400_GICD_ICENABLERN_5r, disable_mask, CMICX_TXRX_IRQ_MASK); + } + irq_mask_reg = IHOST_GIC_GIC400_GICD_ISENABLERN_5r; + } + + lkbde_irq_mask_set(sinfo->dev_no | LKBDE_ISR2_DEV | LKBDE_IPROC_REG, + irq_mask_reg, mask, CMICX_TXRX_IRQ_MASK); +} + +static inline void +xgsx_irq_mask_enable(bkn_switch_info_t *sinfo, int chan, int update_hw) +{ + uint32_t mask; + + if (CDMA_CH(sinfo, chan)) { + mask = CMICX_DS_CMC_CTRLD_INT(chan); + } else { + if (chan == XGS_DMA_TX_CHAN) { + mask = CMICX_DS_CMC_CHAIN_DONE(chan); + } else { + mask = CMICX_DS_CMC_DESC_DONE(chan) | + CMICX_DS_CMC_CHAIN_DONE(chan); + } + } + + sinfo->irq_mask |= mask; + + if (update_hw) { + xgsx_irq_mask_set(sinfo, sinfo->irq_mask); + } +} + +static inline void +xgsx_irq_mask_disable(bkn_switch_info_t *sinfo, int chan, int update_hw) +{ + uint32_t mask; + + if (CDMA_CH(sinfo, chan)) { + mask = CMICX_DS_CMC_CTRLD_INT(chan); + } else { + if (chan == XGS_DMA_TX_CHAN) { + mask = CMICX_DS_CMC_CHAIN_DONE(chan); + } else { + mask = CMICX_DS_CMC_DESC_DONE(chan) | + CMICX_DS_CMC_CHAIN_DONE(chan); + } + } + + sinfo->irq_mask &= ~mask; + + if (update_hw) { + xgsx_irq_mask_set(sinfo, sinfo->irq_mask); + } +} + +static inline void +dev_dma_chain_clear(bkn_switch_info_t *sinfo, int chan) +{ + if (DEV_IS_CMICX(sinfo)) { + xgsx_dma_chain_clear(sinfo, chan); + } else if (DEV_IS_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_IS_CMICX(sinfo)) { + xgsx_dma_desc_clear(sinfo, chan); + } else if (DEV_IS_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_IS_CMICX(sinfo)) { + return xgsx_dma_chan_clear(sinfo, chan); + } else if (DEV_IS_CMICM(sinfo)) { + return xgsm_dma_chan_clear(sinfo, chan); + } else { + return xgs_dma_chan_clear(sinfo, chan); + } +} + +static void +dev_cdma_halt_set(bkn_switch_info_t *sinfo, int chan) +{ + if (DEV_IS_CMICX(sinfo)) { + xgsx_cdma_halt_set(sinfo, chan); + } else if (DEV_IS_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_IS_CMICX(sinfo)) { + return xgsx_dma_chan_init(sinfo, chan, dir); + } else if (DEV_IS_CMICM(sinfo)) { + return xgsm_dma_chan_init(sinfo, chan, dir); + } else { + return xgs_dma_chan_init(sinfo, chan, dir); + } +} + +static int +dev_dma_chan_start(bkn_switch_info_t *sinfo, int chan, uint64_t dcb) +{ + if (DEV_IS_CMICX(sinfo)) { + return xgsx_dma_chan_start(sinfo, chan, dcb); + } else if (DEV_IS_CMICM(sinfo)) { + return xgsm_dma_chan_start(sinfo, chan, dcb); + } else { + 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_IS_CMICX(sinfo)) { + return xgsx_dma_chan_abort(sinfo, chan, polls); + } else if (DEV_IS_CMICM(sinfo)) { + return xgsm_dma_chan_abort(sinfo, chan, polls); + } else { + 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_IS_CMICX(sinfo)) { + xgsx_irq_mask_set(sinfo, mask); + } else if (DEV_IS_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_IS_CMICX(sinfo)) { + xgsx_irq_mask_enable(sinfo, chan, update_hw); + } else if (DEV_IS_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_IS_CMICX(sinfo)) { + xgsx_irq_mask_disable(sinfo, chan, update_hw); + } else if (DEV_IS_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; + dma_addr_t dcb_dma = 0; + + 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 * sinfo->rx_chans; + + sinfo->dcb_mem = BKN_DMA_ALLOC_COHERENT(sinfo->dma_dev, + sinfo->dcb_mem_size, + &dcb_dma); + if (sinfo->dcb_mem == NULL) { + gprintk("DCB memory allocation (%d bytes) failed.\n", + sinfo->dcb_mem_size); + return -ENOMEM; + } + sinfo->dcb_dma = (uint64_t)dcb_dma; + + return 0; +} + +static void +bkn_free_dcbs(bkn_switch_info_t *sinfo) +{ + if (sinfo->dcb_mem != NULL) { + BKN_DMA_FREE_COHERENT(sinfo->dma_dev, sinfo->dcb_mem_size, + sinfo->dcb_mem, (dma_addr_t)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)); + BKN_DMA_UNMAP_SINGLE(sinfo->dma_dev, + desc->skb_dma, desc->dma_size, + BKN_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)); + BKN_DMA_UNMAP_SINGLE(sinfo->dma_dev, + desc->skb_dma, desc->dma_size, + BKN_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 < sinfo->rx_chans; chan++) { + bkn_clean_rx_dcbs(sinfo, chan); + } +} + +static void +bkn_init_dcbs(bkn_switch_info_t *sinfo) +{ + int dcb_size; + uint32_t *dcb_mem; + uint64_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)) { + if (sinfo->cmic_type == 'x') { + dcb_mem[2] |= 1 << 24 | 1 << 16; + } else { + dcb_mem[1] |= 1 << 24 | 1 << 16; + } + if (idx == MAX_TX_DCBS) { + if (sinfo->cmic_type == 'x') { + dcb_mem[0] = sinfo->tx.desc[0].dcb_dma; + dcb_mem[1] = DMA_TO_BUS_HI(sinfo->tx.desc[0].dcb_dma >> 32); + dcb_mem[2] |= 1 << 18; + } else { + dcb_mem[0] = sinfo->tx.desc[0].dcb_dma; + dcb_mem[1] |= 1 << 18; + } + } + } + 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; + sinfo->tx.cur = 0; + sinfo->tx.dirty = 0; + + DBG_DCB_TX(("Tx DCBs @ 0x%08x.\n", + (uint32_t)sinfo->tx.desc[0].dcb_dma)); + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + for (idx = 0; idx < (MAX_RX_DCBS + 1); idx++) { + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + if (sinfo->cmic_type == 'x') { + dcb_mem[2] |= 1 << 24 | 1 << 16; + } else { + dcb_mem[1] |= 1 << 24 | 1 << 16; + } + if (idx == MAX_RX_DCBS) { + if (sinfo->cmic_type == 'x') { + dcb_mem[0] = sinfo->rx[chan].desc[0].dcb_dma; + dcb_mem[1] = DMA_TO_BUS_HI(sinfo->rx[chan].desc[0].dcb_dma >> 32); + dcb_mem[2] |= 1 << 18; + } else { + dcb_mem[0] = sinfo->rx[chan].desc[0].dcb_dma; + dcb_mem[1] |= 1 << 18; + } + } + } + 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; + sinfo->rx[chan].cur = 0; + sinfo->rx[chan].dirty = 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) { + if (wsize > 4) { + 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_TX(("%s: 0x%08x 0x%08x 0x%08x 0x%08x\n", + prefix, dcb[0], dcb[1], dcb[2], dcb[3])); + } + } else { + if (wsize > 4) { + 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])); + } else { + DBG_DCB_RX(("%s: 0x%08x 0x%08x 0x%08x 0x%08x\n", + prefix, dcb[0], dcb[1], dcb[2], dcb[3])); + } + } +} + +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; + } + + 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_cdma_goto(bkn_switch_info_t *sinfo, int chan, uint64_t dcb) +{ + if (sinfo->basedev_suspended) { + return; + } + + /* Set the new halt location */ + sinfo->halt_addr[chan] = dcb; + dev_cdma_halt_set(sinfo, chan); +} + +static void +bkn_api_rx_restart(bkn_switch_info_t *sinfo, int chan) +{ + bkn_dcb_chain_t *dcb_chain; + 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, chan); +} + +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; + uint64_t pkt_dma; + 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 ((sinfo->cmic_type == 'x' && (dcb[2] & 0xffff) < pktlen) || + (sinfo->cmic_type != 'x' && (dcb[1] & 0xffff) < pktlen)) { + DBG_WARN(("Rx API buffer too small\n")); + return -1; + } + if (sinfo->cmic_type == 'x') { + pkt_dma = BUS_TO_DMA_HI(dcb[1]); + pkt_dma = pkt_dma << 32 | dcb[0]; + } else { + pkt_dma = dcb[0]; + } + pkt = (uint8_t *)kernel_bde->p2l(sinfo->dev_no, (sal_paddr_t)pkt_dma); + 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 */ + if (sinfo->cmic_type != 'x') { + 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; + MEMORY_BARRIER; + + 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 ((sinfo->cmic_type == 'x' && dcb[2] & (1 << 18)) || + (sinfo->cmic_type != 'x' && dcb[1] & (1 << 18))) { + /* Get the next chain if reload done */ + dcb[sinfo->dcb_wsize-1] |= 1 << 31 | SOC_DCB_KNET_DONE; + MEMORY_BARRIER; + 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 ((sinfo->cmic_type == 'x' && (dcb[2] & (1 << 16)) == 0) || + (sinfo->cmic_type != 'x' && (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; + uint32_t resv_size = sinfo->cmic_type == 'x' ? RCPU_HDR_SIZE : RCPU_RX_ENCAP_SIZE; + uint32_t meta_size = sinfo->cmic_type == 'x' ? RCPU_RX_META_SIZE : 0; + 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, resv_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 + meta_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 = BKN_DMA_MAP_SINGLE(sinfo->dma_dev, + skb->data, desc->dma_size, + BKN_DMA_FROMDEV); + if (BKN_DMA_MAPPING_ERROR(sinfo->dma_dev, desc->skb_dma)) { + dev_kfree_skb_any(skb); + desc->skb = NULL; + break; + } + 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; + dcb[0] = desc->skb_dma; + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + if (sinfo->cmic_type == 'x') { + dcb[2] |= 1 << 24 | 1 << 16; + } else { + dcb[1] |= 1 << 24 | 1 << 16; + } + } else { + prev = PREV_IDX(sinfo->rx[chan].cur, MAX_RX_DCBS); + if (prev < (MAX_RX_DCBS - 1)) { + if (sinfo->cmic_type == 'x') { + sinfo->rx[chan].desc[prev].dcb_mem[2] |= 1 << 16; + } else { + sinfo->rx[chan].desc[prev].dcb_mem[1] |= 1 << 16; + } + } + } + if (sinfo->cmic_type == 'x') { + dcb[1] = DMA_TO_BUS_HI(desc->skb_dma >> 32); + dcb[2] |= rx_buffer_size + meta_size; + } else { + dcb[1] |= rx_buffer_size; + } + + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) && + sinfo->rx[chan].tokens > MAX_RX_DCBS) { + /* DMA run to the new halt location */ + bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, desc->dcb_dma); + } + + 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 < sinfo->rx_chans; 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 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 < sinfo->rx_chans; chan++) { + bkn_dma_abort_rx(sinfo, chan); + } + + return 0; +} + +static int +device_is_dpp(bkn_switch_info_t *sinfo) +{ + int is_dpp = 0; + + is_dpp = (sinfo->dcb_type == 28) ? 1 : 0; + return is_dpp; +} + +static int +device_is_dnx(bkn_switch_info_t *sinfo) +{ + int is_dnx = 0; + + is_dnx = (sinfo->dcb_type == 39) ? 1 : 0; + return is_dnx; +} + +/* is DPP or is DNX*/ +static int +device_is_sand(bkn_switch_info_t *sinfo) +{ + int is_sand = 0; + + if (device_is_dpp(sinfo) || device_is_dnx(sinfo)) { + is_sand = 1; + } + return is_sand; +} + +static bkn_filter_t * +bkn_match_rx_pkt(bkn_switch_info_t *sinfo, uint8_t *pkt, int pktlen, + void *meta, int chan, bkn_filter_t *cbf) +{ + struct list_head *list; + bkn_filter_t *filter; + kcom_filter_t scratch, *kf; + uint8_t *oob = (uint8_t *)meta; + 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])); + + if (device_is_sand(sinfo)) { + DBG_DUNE(("Filter: size = %d (wsize %d)\n", size, wsize)); + for (idx = 0; idx < wsize; idx++) + { + DBG_DUNE(("OOB[%d]: 0x%08x [0x%08x]\n", idx, kf->data.w[idx], kf->mask.w[idx])); + } + DBG_DUNE(("Meta Data [+ Selected Raw packet data]\n")); + for (idx = 0; idx < wsize; idx++) + { + DBG_DUNE(("Scratch[%d]: 0x%08x\n", idx, scratch.data.w[idx])); + } + } + + match = 1; + if (match) { + if (device_is_dnx(sinfo)) + { + /* + * Mutliple RX channels are enabled on JR2 and above devices + * Bind between priority 0 and RX channel 0 is not checked, then all enabled RX channels can receive packets. + */ + if (kf->priority && (kf->priority < (num_rx_prio * sinfo->rx_chans))) { + if (kf->priority < (num_rx_prio * chan) || + kf->priority >= (num_rx_prio * (chan + 1))) { + match = 0; + } + } + } + else { + if (kf->priority < (num_rx_prio * sinfo->rx_chans)) { + 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) { + memset(cbf, 0, sizeof(*cbf)); + memcpy(&cbf->kf, kf, sizeof(cbf->kf)); + if (knet_filter_cb(pkt, pktlen, sinfo->dev_no, + meta, 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_hw_tstamp_rx_set(bkn_switch_info_t *sinfo, int phys_port, struct sk_buff *skb, uint32 *meta) +{ + struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); + uint64_t ts = 0; + + + if (knet_hw_tstamp_rx_time_upscale_cb) { + if (knet_hw_tstamp_rx_time_upscale_cb(sinfo->dev_no, phys_port, skb, meta, &ts) < 0) { + return -1; + } + } + + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); + shhwtstamps->hwtstamp = ns_to_ktime(ts); + + return 0; +} + +static int +bkn_add_rcpu_encap(bkn_switch_info_t *sinfo, struct sk_buff *skb, void *meta, int len) +{ + int pktlen = skb->len; + uint32_t *dmeta, *smeta, wsize, psize; + int idx; + + /* Add and clear RCPU encapsulation */ + if (device_is_sand(sinfo)) { + psize = RCPU_RX_ENCAP_SIZE; + skb_push(skb, psize); + memset(skb->data, 0, RCPU_RX_ENCAP_SIZE); + } else if (sinfo->cmic_type == 'x') { + psize = RCPU_HDR_SIZE + sinfo->pkt_hdr_size; + skb_push(skb, psize); + memset(skb->data, 0, RCPU_HDR_SIZE); + } else { + psize = RCPU_RX_ENCAP_SIZE; + skb_push(skb, psize); + memset(skb->data, 0, RCPU_RX_ENCAP_SIZE); + } + + /* RCPU Header */ + memcpy(skb->data, &skb->data[psize], 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 */ + dmeta = (uint32_t *)&skb->data[RCPU_HDR_SIZE]; + + if (device_is_sand(sinfo)) { + /* Copy at most 64 bytes system headers */ + len = len > RCPU_RX_META_SIZE ? RCPU_RX_META_SIZE : len; + memcpy(&skb->data[RCPU_HDR_SIZE], (uint8_t *)meta, len); + } else { + smeta = sinfo->cmic_type == 'x' ? (uint32_t *)meta : (uint32_t *)meta + 2; + wsize = sinfo->cmic_type == 'x' ? sinfo->pkt_hdr_size / 4 : sinfo->dcb_wsize - 3; + for (idx = 0; idx < wsize; idx++) { + dmeta[idx] = htonl(smeta[idx]); + } + } + + + 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 +packet_is_untagged(uint16_t tpid) +{ + int is_untagged = 0; + + /* 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_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_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_dpp_packet_parse_ftmh( + bkn_switch_info_t *sinfo, + uint8_t *buf, + uint32_t buf_len, + bkn_dune_system_header_info_t *packet_info, + uint8_t *is_tsh_en, + uint8_t *is_inter_hdr_en) +{ + uint32_t pkt_offset = packet_info->system_header_size; + uint32_t dsp_ext_exist = 0; + uint32_t fld_val; + + /* FTMH: Source-system-port-aggregate */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DPP_FTMH_SRC_SYS_PORT_MSB, + BKN_DPP_FTMH_SRC_SYS_PORT_NOF_BITS, + &packet_info->ftmh.source_sys_port_aggregate); + /* FTMH: TM-action-type */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DPP_FTMH_ACTION_TYPE_MSB, + BKN_DPP_FTMH_ACTION_TYPE_NOF_BITS, + &packet_info->ftmh.action_type); + /* FTMH: Internal-type */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DPP_FTMH_PPH_TYPE_MSB, + BKN_DPP_FTMH_PPH_TYPE_NOF_BITS, + &fld_val); + + /* FTMH: DSP Extension */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DPP_FTMH_EXT_DSP_EXIST_MSB, + BKN_DPP_FTMH_EXT_DSP_EXIST_NOF_BITS, + &dsp_ext_exist); + + if (fld_val & 0x1) + { + *is_inter_hdr_en = TRUE; + } + if (fld_val & 0x2) + { + *is_tsh_en = TRUE; + } + + pkt_offset += BKN_DPP_FTMH_SIZE_BYTE; + DBG_DUNE(("FTMH(9-%u): Action-type %d Source-system-port 0x%x\n", pkt_offset, + packet_info->ftmh.action_type, + packet_info->ftmh.source_sys_port_aggregate)); + + /* FTMH LB-Key Extension */ + if (sinfo->ftmh_lb_key_ext_size) + { + pkt_offset += sinfo->ftmh_lb_key_ext_size; + DBG_DUNE(("FTMH LB-Key Extension(1-%u) is present\n", pkt_offset)); + } + + if (dsp_ext_exist) + { + pkt_offset += BKN_DPP_FTMH_DEST_EXT_SIZE_BYTE; + DBG_DUNE(("FTMH DSP Extension(2-%u) is present\n", pkt_offset)); + } + + /* FTMH Stacking Extension */ + if (sinfo->ftmh_stacking_ext_size) + { + pkt_offset += sinfo->ftmh_stacking_ext_size; + DBG_DUNE(("FTMH Stacking Extension(2-%u) is present\n", pkt_offset)); + } + + packet_info->system_header_size = pkt_offset; + return; +} + +static void +bkn_dpp_packet_parse_otsh( + bkn_switch_info_t *sinfo, + uint8_t *buf, + uint32_t buf_len, + bkn_dune_system_header_info_t *packet_info, + uint8_t *is_oam_dm_tod_en, + uint8_t *is_skip_udh) +{ + uint32_t pkt_offset = packet_info->system_header_size; + uint32_t type = 0; + uint32_t oam_sub_type = 0; + + /* OTSH: TYPE */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DPP_OTSH_TYPE_MSB, + BKN_DPP_OTSH_TYPE_NOF_BITS, + &type); + if (type == BKN_DPP_OTSH_TYPE_OAM) { + /* OTSH: OAM_SUB_TYPE */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DPP_OTSH_OAM_SUB_TYPE_MSB, + BKN_DPP_OTSH_OAM_SUB_TYPE_NOF_BITS, + &oam_sub_type); + if ((oam_sub_type == BKN_DPP_OTSH_OAM_SUB_TYPE_DM_1588) || (oam_sub_type == BKN_DPP_OTSH_OAM_SUB_TYPE_DM_NTP)) { + *is_oam_dm_tod_en = TRUE; + /* Down MEP DM trapped packets will not have UDH present (even if configured), except for QAX when custom_feature_oam_dm_tod_msb_add_enable=0 */ + if (!sinfo->no_skip_udh_check) { + *is_skip_udh = TRUE; + } + } + } + packet_info->system_header_size += BKN_DPP_OTSH_SIZE_BYTE; + + DBG_DUNE(("OTSH(%d): Type 0x%x OAM-Sub-Type 0x%x\n", BKN_DPP_OTSH_SIZE_BYTE, type, oam_sub_type)); + return; +} + +static void +bkn_dpp_packet_parse_internal( + bkn_switch_info_t *sinfo, + uint8_t *buf, + uint32_t buf_len, + bkn_dune_system_header_info_t *packet_info, + uint8_t is_oamp_punted, + uint8_t *is_trapped) +{ + uint32_t pkt_offset = packet_info->system_header_size; + uint32_t fld_val = 0; + uint32_t eei_extension_present = 0; + uint32_t learn_extension_present = 0; + uint32_t fhei_size = 0; + + /* Internal: EEI EXT */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DPP_INTERNAL_EEI_EXTENSION_PRESENT_MSB, + BKN_DPP_INTERNAL_EEI_EXTENSION_PRESENT_NOF_BITS, + &eei_extension_present); + /* Internal: LERAN EXT */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DPP_INTERNAL_LEARN_EXENSION_PRESENT_MSB, + BKN_DPP_INTERNAL_LEARN_EXENSION_PRESENT_NOF_BITS, + &learn_extension_present); + /* Internal: FHEI EXT */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DPP_INTERNAL_FHEI_SIZE_MSB, + BKN_DPP_INTERNAL_FHEI_SIZE_NOF_BITS, + &fhei_size); + /* Internal: FORWARD_CODE */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DPP_INTERNAL_FORWARD_CODE_MSB, + BKN_DPP_INTERNAL_FORWARD_CODE_NOF_BITS, + &fld_val); + *is_trapped = (uint8_t)(fld_val == BKN_DPP_INTERNAL_FORWARD_CODE_CPU_TRAP); + /* Internal: VSI */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DPP_INTERNAL_VSI_MSB, + BKN_DPP_INTERNAL_VSI_NOF_BITS, + &fld_val); + packet_info->internal.forward_domain = fld_val; + + if (is_oamp_punted && *is_trapped) { + if(fhei_size == 3) { + /* Force to FHEI size 1 when packets are punted by OAMP */ + fhei_size = 1; + } + } + + /* Move forward to end of Internal header */ + pkt_offset += BKN_DPP_INTERNAL_SIZE_BYTE; + + DBG_DUNE(("PPH(7-%u): EEI-Extension %d Learn-Extension %d VSI %d FHEI-size %d\n", + pkt_offset, eei_extension_present,learn_extension_present, packet_info->internal.forward_domain, fhei_size)); + + /* Advance header according to FHEI Trap extension */ + switch(fhei_size) { + case 1: + /* 3B FHEI Extension: do nothing, header poniter is in the right location */ + break; + case 2: + /* 5B FHEI Extension: adavance header pointer in 2B */ + pkt_offset += 2; + break; + case 3: + /* 8B FHEI Extension: adavance header pointer in 5B */ + pkt_offset += 5; + break; + default: + break; + } + + /* Internal extension */ + if (*is_trapped && fhei_size) + { + /* CPU trap code qualifier */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DPP_INTERNAL_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_MSB, + BKN_DPP_INTERNAL_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_NOF_BITS, + &packet_info->internal.trap_qualifier); + /* CPU trap code */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DPP_INTERNAL_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_MSB, + BKN_DPP_INTERNAL_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_NOF_BITS, + &packet_info->internal.trap_id); + + DBG_DUNE(("FHEI: trap_qualifier 0x%x trap_id 0x%x\n", + packet_info->internal.trap_qualifier, + packet_info->internal.trap_id)); + } + + /* Move forward to end of FHEI Trap extension */ + if (fhei_size) { + pkt_offset += 3; + } + + /* EEI extension */ + if (eei_extension_present) { + pkt_offset += BKN_DPP_INTERNAL_EXPLICIT_EDITING_INFOMATION_EXTENSION_SIZE_BYTE; + } + /* Learn extension */ + if (learn_extension_present) { + pkt_offset += BKN_DPP_INTERNAL_LEARN_EXTENSION_SIZE_BYTE; + } + + packet_info->system_header_size = pkt_offset; + return; +} + +static int +bkn_dpp_packet_header_parse( + bkn_switch_info_t *sinfo, + uint8_t *buff, + uint32_t buff_len, + bkn_dune_system_header_info_t *packet_info) +{ + uint8_t is_inter_hdr_en = FALSE; + uint8_t is_tsh_en = FALSE; + uint8_t is_oamp_punted = FALSE; + uint8_t is_trapped = FALSE; + uint8_t is_oam_dm_tod_en = FALSE; + uint8_t is_skip_udh = FALSE; + + if ((sinfo == NULL) || (buff == NULL) || (packet_info == NULL)) { + return -1; + } + + /* FTMH */ + bkn_dpp_packet_parse_ftmh(sinfo, buff, buff_len, packet_info, &is_tsh_en, &is_inter_hdr_en); + /* Check if packet is punted from OAMP */ + if (sinfo->oamp_punt && (packet_info->ftmh.source_sys_port_aggregate == sinfo->oamp_punt)) { + is_oamp_punted = TRUE; + } + /* OTSH */ + if (is_tsh_en == TRUE) + { + bkn_dpp_packet_parse_otsh(sinfo, buff, buff_len, packet_info, &is_oam_dm_tod_en, &is_skip_udh); + } + /* Internal header is forced to be present if packet was punted to CPU by OAMP */ + if (sinfo->oamp_punt && (packet_info->ftmh.source_sys_port_aggregate == sinfo->oamp_punt)) + { + is_inter_hdr_en = TRUE; + } + /* Internal */ + if (is_inter_hdr_en) + { + bkn_dpp_packet_parse_internal(sinfo, buff, buff_len, packet_info, is_oamp_punted, &is_trapped); + } + /* Skip UDH for the outer layer when packet is punted by OAM for JR2 in JR1 mode */ + if (device_is_dnx(sinfo) && is_oamp_punted) { + is_skip_udh = TRUE; + } + /* UDH */ + if (sinfo->udh_size && !is_skip_udh) { + packet_info->system_header_size += sinfo->udh_size; + } + /* OAM DM TOD header */ + if(is_oam_dm_tod_en) { + packet_info->system_header_size += BKN_DPP_OAM_DM_TOD_SIZE_BYTE; + } + + /* Additional layer of system headers */ + if (is_oamp_punted && is_trapped) + { + is_inter_hdr_en = FALSE; + is_tsh_en = FALSE; + is_oamp_punted = FALSE; + is_trapped = FALSE; + is_oam_dm_tod_en = FALSE; + is_skip_udh = FALSE; + + /* FTMH */ + bkn_dpp_packet_parse_ftmh(sinfo, buff, buff_len, packet_info, &is_tsh_en, &is_inter_hdr_en); + /* OTSH */ + if (is_tsh_en == TRUE) + { + bkn_dpp_packet_parse_otsh(sinfo, buff, buff_len, packet_info, &is_oam_dm_tod_en, &is_skip_udh); + } + /* Internal */ + if (is_inter_hdr_en) + { + bkn_dpp_packet_parse_internal(sinfo, buff, buff_len, packet_info, is_oamp_punted, &is_trapped); + } + /* OAMP Punted packets do not have UDH in the inner header for both JR1 and JR2 in JR1 mode */ + /* OAM DM TOD header */ + if(is_oam_dm_tod_en) { + packet_info->system_header_size += BKN_DPP_OAM_DM_TOD_SIZE_BYTE; + } + } + + DBG_DUNE(("Total length of headers is %u\n", packet_info->system_header_size)); + + return 0; +} + + +static int +bkn_dnx_packet_parse_ftmh( + bkn_switch_info_t *sinfo, + uint8_t *buf, + uint32_t buf_len, + bkn_dune_system_header_info_t *packet_info, + uint8_t *is_tsh_en, + uint8_t *is_inter_hdr_en) +{ + uint32_t fld_val; + uint32_t pkt_offset = packet_info->system_header_size; + uint8_t tm_dst_ext_present = 0; + uint8_t app_specific_ext_size = 0; + uint8_t flow_id_ext_size = 0; + uint8_t bier_bfr_ext_size = 0; + + if ((sinfo == NULL) || (buf == NULL) || (packet_info == NULL)) { + return -1; + } + + /* FTMH: Source-System-Port-Aggregate */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_MSB, + BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_NOF_BITS, + &fld_val); + packet_info->ftmh.source_sys_port_aggregate = fld_val; + /* FTMH: Action-Type */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_FTMH_ACTION_TYPE_MSB, + BKN_DNX_FTMH_ACTION_TYPE_NOF_BITS, + &fld_val); + packet_info->ftmh.action_type = fld_val; + /* FTMH: PPH-Type TSH */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_MSB, + BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_NOF_BITS, + &fld_val); + *is_tsh_en = fld_val; + /* FTMH: PPH-Type PPH base */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_MSB, + BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_NOF_BITS, + &fld_val); + *is_inter_hdr_en = fld_val; + /* FTMH: TM-Destination-Extension-Present */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_FTMH_TM_DST_EXT_PRESENT_MSB, + BKN_DNX_FTMH_TM_DST_EXT_PRESENT_NOF_BITS, + &fld_val); + tm_dst_ext_present = fld_val; + /* FTMH: Application-Specific-Extension-Size */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_MSB, + BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_NOF_BITS, + &fld_val); + app_specific_ext_size = fld_val; + /* FTMH: Flow-ID-Extension-Size */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_MSB, + BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_NOF_BITS, + &fld_val); + flow_id_ext_size = fld_val; + /* FTMH: BIER-BFR-Extension-Size */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_MSB, + BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_NOF_BITS, + &fld_val); + bier_bfr_ext_size = fld_val; + + pkt_offset += BKN_DNX_FTMH_BASE_SIZE; + + DBG_DUNE(("FTMH(10-%u): source-system-port 0x%x action_type %u is_tsh_en %u is_inter_hdr_en %u\n", + pkt_offset, packet_info->ftmh.source_sys_port_aggregate, + packet_info->ftmh.action_type, *is_tsh_en, *is_inter_hdr_en)); + + /* FTMH LB-Key Extension */ + if (sinfo->ftmh_lb_key_ext_size > 0) + { + pkt_offset += sinfo->ftmh_lb_key_ext_size; + DBG_DUNE(("FTMH LB-Key Extension(%u-%u) is present\n", sinfo->ftmh_lb_key_ext_size, pkt_offset)); + } + /* FTMH Stacking Extension */ + if (sinfo->ftmh_stacking_ext_size > 0) + { + pkt_offset += sinfo->ftmh_stacking_ext_size; + DBG_DUNE(("FTMH Stacking Extension(%u-%u) is present\n", sinfo->ftmh_stacking_ext_size, pkt_offset)); + } + /* FTMH BIER BFR Extension */ + if (bier_bfr_ext_size > 0) + { + pkt_offset += BKN_DNX_FTMH_BIER_BFR_EXT_SIZE; + DBG_DUNE(("FTMH BIER BFR Extension(2-%u) is present\n", pkt_offset)); + } + /* FTMH TM Destination Extension */ + if (tm_dst_ext_present > 0) + { + pkt_offset += BKN_DNX_FTMH_TM_DST_EXT_SIZE; + DBG_DUNE(("FTMH TM Destination Extension(3-%u) is present\n", pkt_offset)); + } + /* FTMH Application Specific Extension */ + if (app_specific_ext_size > 0) + { + pkt_offset += BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE; + DBG_DUNE(("FTMH Application Specific Extension(6-%u) is present\n", pkt_offset)); + } + /* FTMH Flow-ID Extension */ + if (flow_id_ext_size > 0) + { + pkt_offset += BKN_DNX_FTMH_FLOW_ID_EXT_SIZE; + DBG_DUNE(("FTMH Flow-ID Extension(3-%u) is present\n", pkt_offset)); + } + + packet_info->system_header_size = pkt_offset; + + return 0; +} + + +static int +bkn_dnx_packet_parse_internal( + bkn_switch_info_t *sinfo, + uint8_t *buf, + uint32_t buf_len, + bkn_dune_system_header_info_t *packet_info, + uint8_t is_oamp_punted, + uint8_t *is_trapped) +{ + uint32_t fld_val; + uint32_t pkt_offset = packet_info->system_header_size; + uint8_t learn_ext_present; + uint8_t fhei_size; + uint8_t lif_ext_type; + uint8_t udh_en = sinfo->udh_enable; + + if ((sinfo == NULL) || (buf == NULL) || (packet_info == NULL)) { + return -1; + } + + /* Internal: Forward-Domain */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_INTERNAL_12_FORWARD_DOMAIN_MSB, + BKN_DNX_INTERNAL_12_FORWARD_DOMAIN_NOF_BITS, + &fld_val); + packet_info->internal.forward_domain = fld_val; + /* Internal: Learn-Extension-Present */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_INTERNAL_12_LEARN_EXT_PRESENT_MSB, + BKN_DNX_INTERNAL_12_LEARN_EXT_PRESENT_NOF_BITS, + &fld_val); + learn_ext_present = fld_val; + /* Internal: FHEI-Size */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_INTERNAL_12_FHEI_SIZE_MSB, + BKN_DNX_INTERNAL_12_FHEI_SIZE_NOF_BITS, + &fld_val); + fhei_size = fld_val; + /* Internal: LIF-Extension-Type */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_INTERNAL_12_LIF_EXT_TYPE_MSB, + BKN_DNX_INTERNAL_12_LIF_EXT_TYPE_NOF_BITS, + &fld_val); + lif_ext_type = fld_val; + + pkt_offset += BKN_DNX_INTERNAL_BASE_TYPE_12; + DBG_DUNE(("Internal(12-%u): FWD_DOMAIN %d, LEARN_EXT %d, FHEI_SIZE %d, LIF_EXT %d \n", + pkt_offset, packet_info->internal.forward_domain, + learn_ext_present, fhei_size, lif_ext_type)); + + if (fhei_size) + { + switch (fhei_size) + { + case BKN_DNX_INTERNAL_FHEI_TYPE_SZ0: + pkt_offset += BKN_DNX_INTERNAL_FHEI_SZ0_SIZE; + DBG_DUNE(("FHEI(3-%u) is present\n", pkt_offset)); + break; + case BKN_DNX_INTERNAL_FHEI_TYPE_SZ1: + /* FHEI: Type */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_INTERNAL_FHEI_TRAP_5B_TYPE_MSB, + BKN_DNX_INTERNAL_FHEI_TRAP_5B_TYPE_NOF_BITS, + &fld_val); + /* FHEI-Size == 5B, FHEI-Type == Trap/Sniff */ + if (fld_val == 0x5) + { + *is_trapped = TRUE; + /* FHEI: Qualifier */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_INTERNAL_FHEI_TRAP_5B_QUALIFIER_MSB, + BKN_DNX_INTERNAL_FHEI_TRAP_5B_QUALIFIER_NOF_BITS, + &fld_val); + packet_info->internal.trap_qualifier = fld_val; + /* FHEI: Code */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_INTERNAL_FHEI_TRAP_5B_CODE_MSB, + BKN_DNX_INTERNAL_FHEI_TRAP_5B_CODE_NOF_BITS, + &fld_val); + packet_info->internal.trap_id= fld_val; + } + pkt_offset += BKN_DNX_INTERNAL_FHEI_SZ1_SIZE; + DBG_DUNE(("FHEI(5-%u): code 0x%x qualifier 0x%x\n", pkt_offset, packet_info->internal.trap_id, packet_info->internal.trap_qualifier)); + break; + case BKN_DNX_INTERNAL_FHEI_TYPE_SZ2: + pkt_offset += BKN_DNX_INTERNAL_FHEI_SZ1_SIZE; + DBG_DUNE(("FHEI(8-%u) is present\n", pkt_offset)); + break; + } + } + + /* PPH LIF Extension */ + if (lif_ext_type) + { + pkt_offset += sinfo->pph_lif_ext_size[lif_ext_type]; + DBG_DUNE(("PPH LIF Extension(%d-%u) is present\n", sinfo->pph_lif_ext_size[lif_ext_type], pkt_offset)); + } + + /* PPH Learn Extension */ + if (learn_ext_present) + { + pkt_offset += BKN_DNX_INTERNAL_LEARN_EXT_SIZE; + DBG_DUNE(("PPH Learn Extension(19-%u) is present\n", pkt_offset)); + } + + /** Skip UDH If packet is punted to CPU by OAMP */ + if (is_oamp_punted) { + udh_en = FALSE; + } + + /* UDH Header */ + if (udh_en) + { + uint8_t data_type_0; + uint8_t data_type_1; + uint8_t data_type_2; + uint8_t data_type_3; + + /* UDH: UDH-Data-Type[0] */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_UDH_DATA_TYPE_0_MSB, + BKN_DNX_UDH_DATA_TYPE_0_NOF_BITS, + &fld_val); + data_type_0 = fld_val; + /* UDH: UDH-Data-Type[1] */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_UDH_DATA_TYPE_1_MSB, + BKN_DNX_UDH_DATA_TYPE_1_NOF_BITS, + &fld_val); + data_type_1 = fld_val; + /* UDH: UDH-Data-Type[2] */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_UDH_DATA_TYPE_2_MSB, + BKN_DNX_UDH_DATA_TYPE_2_NOF_BITS, + &fld_val); + data_type_2 = fld_val; + /* UDH: UDH-Data-Type[3] */ + bkn_bitstream_get_field( + &buf[pkt_offset], + BKN_DNX_UDH_DATA_TYPE_3_MSB, + BKN_DNX_UDH_DATA_TYPE_3_NOF_BITS, + &fld_val); + data_type_3 = fld_val; + pkt_offset += BKN_DNX_UDH_BASE_SIZE; + pkt_offset += sinfo->udh_length_type[data_type_0]; + pkt_offset += sinfo->udh_length_type[data_type_1]; + pkt_offset += sinfo->udh_length_type[data_type_2]; + pkt_offset += sinfo->udh_length_type[data_type_3]; + DBG_DUNE(("UDH base(1-%u) is present\n", pkt_offset)); + } + + packet_info->system_header_size = pkt_offset; + + return 0; +} + +static int +bkn_dnx_packet_header_parse( + bkn_switch_info_t *sinfo, + uint8_t *buff, + uint32_t buff_len, + bkn_dune_system_header_info_t *packet_info) +{ + uint8_t is_inter_hdr_en = FALSE; + uint8_t is_tsh_en = FALSE; + uint8_t is_oamp_punted = FALSE; + uint8_t is_trapped = FALSE; + + if ((sinfo == NULL) || (buff == NULL) || (packet_info == NULL)) { + return -1; + } + + /* FTMH */ + bkn_dnx_packet_parse_ftmh(sinfo, buff, buff_len, packet_info, &is_tsh_en, &is_inter_hdr_en); + + /* Time-Stamp */ + if (is_tsh_en == TRUE) + { + packet_info->system_header_size += BKN_DNX_TSH_SIZE; + DBG_DUNE(("Time-Stamp Header(4-%u) is present\n", packet_info->system_header_size)); + } + + /* Check if packet was punted to CPU by OAMP */ + if ((packet_info->ftmh.source_sys_port_aggregate == 232) + || (packet_info->ftmh.source_sys_port_aggregate == 233)) + { + is_oamp_punted = TRUE; + } + + /* Internal */ + if (is_inter_hdr_en) + { + bkn_dnx_packet_parse_internal(sinfo, buff, buff_len, packet_info, is_oamp_punted, &is_trapped); + } + + if (is_oamp_punted) + { + is_inter_hdr_en = FALSE; + is_tsh_en = FALSE; + is_oamp_punted = FALSE; + is_trapped = FALSE; + + /* FTMH */ + bkn_dnx_packet_parse_ftmh(sinfo, buff, buff_len, packet_info, &is_tsh_en, &is_inter_hdr_en); + /* Time-Stamp */ + if (is_tsh_en == TRUE) + { + packet_info->system_header_size += BKN_DNX_TSH_SIZE; + DBG_DUNE(("Time-Stamp Header(4-%u) is present\n", packet_info->system_header_size)); + } + /* Internal */ + if (is_inter_hdr_en) + { + bkn_dnx_packet_parse_internal(sinfo, buff, buff_len, packet_info, is_oamp_punted, &is_trapped); + } + } + + DBG_DUNE(("Total length of headers is %u\n", packet_info->system_header_size)); + + return 0; +} + +static int +bkn_packet_header_parse(bkn_switch_info_t *sinfo, uint8_t *buf, uint32_t buf_len, bkn_dune_system_header_info_t *packet_info) +{ + if (device_is_dpp(sinfo)) + { + bkn_dpp_packet_header_parse(sinfo, buf, buf_len, packet_info); + } + else if (device_is_dnx(sinfo)) + { + if (sinfo->system_headers_mode == BKN_DNX_JR2_MODE) + { + /* Jericho 2 mode */ + bkn_dnx_packet_header_parse(sinfo, buf, buf_len, packet_info); + } + else + { + /* Jericho/QMX/QAX mode */ + bkn_dpp_packet_header_parse(sinfo, buf, buf_len, packet_info); + } + } + 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 err_woff; + uint32_t *dcb, *meta; + uint8_t *pkt; + uint64_t pkt_dma; + int drop_api; + int ethertype; + int pktlen; + int idx; + int dcbs_done = 0; + bkn_dune_system_header_info_t packet_info; + uint32_t sand_scratch_data[BKN_SAND_SCRATCH_DATA_SIZE] = {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 ((sinfo->cmic_type == 'x' && dcb[2] & (1 << 18)) || + (sinfo->cmic_type != 'x' && 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 ((sinfo->cmic_type == 'x' && (dcb[2] & (1 << 16)) == 0) || + (sinfo->cmic_type != 'x' && (dcb[1] & (1 << 16)) == 0)) { + sinfo->rx[chan].chain_complete = 1; + } + sinfo->rx[chan].pkts++; + if (sinfo->cmic_type == 'x') { + pkt_dma = BUS_TO_DMA_HI(dcb[1]); + pkt_dma = pkt_dma << 32 | dcb[0]; + } else { + pkt_dma = dcb[0]; + } + pkt = (uint8_t *)kernel_bde->p2l(sinfo->dev_no, (sal_paddr_t)pkt_dma); + + if (device_is_sand(sinfo)) { + err_woff = BKN_SAND_SCRATCH_DATA_SIZE - 1; + sand_scratch_data[err_woff] = dcb[sinfo->dcb_wsize-1]; + meta = (uint32_t *)pkt; + } else { + if (sinfo->cmic_type == 'x') { + meta = (uint32_t *)pkt; + err_woff = sinfo->pkt_hdr_size / sizeof(uint32_t) - 1; + meta[err_woff] = dcb[sinfo->dcb_wsize-1]; + } else { + meta = dcb; + err_woff = sinfo->dcb_wsize - 1; + } + } + + pktlen = dcb[sinfo->dcb_wsize-1] & SOC_DCB_KNET_COUNT_MASK; + bkn_dump_pkt(pkt, pktlen, XGS_DMA_RX_CHAN); + + if (device_is_sand(sinfo)) { + memset(&packet_info, 0, sizeof(bkn_dune_system_header_info_t)); + /* decode system headers and fill sratch data */ + bkn_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info); + bkn_bitstream_set_field(sand_scratch_data, 0, 16, packet_info.internal.trap_id); + bkn_bitstream_set_field(sand_scratch_data, 16, 16, packet_info.internal.trap_qualifier); + bkn_bitstream_set_field(sand_scratch_data, 32, 16, packet_info.ftmh.source_sys_port_aggregate); + bkn_bitstream_set_field(sand_scratch_data, 48, 16, packet_info.internal.forward_domain); + bkn_bitstream_set_field(sand_scratch_data, 64, 2, packet_info.ftmh.action_type); + + if (force_tagged) { + uint8_t *eth_hdr = pkt + packet_info.system_header_size; + uint16_t tpid = 0; + + tpid = PKT_U16_GET(eth_hdr, 12); + if (packet_is_untagged(tpid)) { + int raw_packet_len = pktlen - packet_info.system_header_size; + uint32_t vid = 0; + + if ((pktlen + 4) < rx_buffer_size) { + for (idx = (raw_packet_len - 1); idx >= 12; idx--) { + eth_hdr[idx+4] = eth_hdr[idx]; + } + if (ft_vid) { + vid = ft_vid; + } + else if (packet_info.internal.forward_domain) { + vid = packet_info.internal.forward_domain & 0xfff; + } + else { + vid = 1; + } + DBG_DUNE(("add vlan tag (%d) to untagged packets\n", vid)); + + eth_hdr[12] = (ft_tpid >> 8) & 0xff; + eth_hdr[13] = ft_tpid & 0xff; + eth_hdr[14] = (((ft_pri & 0x7) << 5) | ((ft_cfi & 0x1) << 4) | ((vid >> 8) & 0xf)) & 0xff; + eth_hdr[15] = vid & 0xff; + /* reset packet length in DCB */ + pktlen += 4; + bkn_dump_pkt(pkt, pktlen, XGS_DMA_RX_CHAN); + dcb[sinfo->dcb_wsize-1] &= ~SOC_DCB_KNET_COUNT_MASK; + dcb[sinfo->dcb_wsize-1] |= pktlen & SOC_DCB_KNET_COUNT_MASK; + } + } + } + } + + if (device_is_sand(sinfo)) { + filter = bkn_match_rx_pkt(sinfo, pkt + packet_info.system_header_size, + pktlen - packet_info.system_header_size, sand_scratch_data, chan, &cbf); + } else { + filter = bkn_match_rx_pkt(sinfo, pkt + sinfo->pkt_hdr_size, + pktlen - sinfo->pkt_hdr_size, meta, chan, &cbf); + } + if ((dcb[sinfo->dcb_wsize-1] & 0xf0000) != 0x30000) { + /* Fragment or error */ + if (filter && filter->kf.mask.w[err_woff] == 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; + } + + if (device_is_sand(sinfo)) { + pkt += packet_info.system_header_size; + pktlen -= packet_info.system_header_size; + } else if (sinfo->cmic_type == 'x') { + pkt += sinfo->pkt_hdr_size; + pktlen -= sinfo->pkt_hdr_size; + } + + /* 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_U16_GET(pkt, 16); + if ((priv->flags & KCOM_NETIF_F_KEEP_RX_TAG) == 0) { + uint16_t vlan_proto = PKT_U16_GET(pkt, 12); + + if (filter->kf.flags & KCOM_FILTER_F_STRIP_TAG) { + /* Strip the VLAN tag */ + if (vlan_proto == ETH_P_8021Q || + vlan_proto == ETH_P_8021AD) { + DBG_FLTR(("Strip VLAN tag\n")); + for (idx = 11; idx >= 0; idx--) { + pkt[idx+4] = pkt[idx]; + } + pktlen -= 4; + pkt += 4; + } + } else { + /* + * Mark packet as VLAN-tagged, otherwise newer + * kernels will strip the tag. + */ + uint16_t tci = PKT_U16_GET(pkt, 14); + + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { + bkn_vlan_hwaccel_put_tag(skb, ETH_P_8021Q, tci); + } else { + if (vlan_proto == ETH_P_8021AD) { + bkn_vlan_hwaccel_put_tag + (skb, ETH_P_8021AD, tci); + } else { + bkn_vlan_hwaccel_put_tag + (skb, ETH_P_8021Q, tci); + } + } + } + } + + skb_copy_to_linear_data(skb, pkt, pktlen); + if (device_is_sand(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 += skb->len; + + /* Optional SKB updates */ + KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF; + 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; + if (device_is_sand(sinfo)) { + skb = knet_rx_cb(skb, sinfo->dev_no, sand_scratch_data); + } + else { + skb = knet_rx_cb(skb, sinfo->dev_no, meta); + } + if (skb == NULL) { + /* Consumed by call-back */ + sinfo->rx[chan].pkts_d_callback++; + break; + } + } + + /* Do Rx timestamping */ + if (priv->rx_hwts) { + bkn_hw_tstamp_rx_set(sinfo, priv->phys_port, skb, meta); + } + + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { + bkn_add_rcpu_encap(sinfo, skb, meta, packet_info.system_header_size); + DBG_PDMP(("After add RCPU ENCAP\n")); + bkn_dump_pkt(skb->data, pktlen + RCPU_RX_ENCAP_SIZE, XGS_DMA_RX_CHAN); + } + 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; + } + } else { + DBG_PKT(("Rx packet dropped.\n")); + sinfo->rx[chan].pkts_d_no_match++; + } + 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 err_woff; + uint32_t *dcb, *meta; + int ethertype; + int pktlen; + int idx; + int dcbs_done = 0; + bkn_dune_system_header_info_t packet_info = {0}; + uint32_t sand_scratch_data[BKN_SAND_SCRATCH_DATA_SIZE] = {0}; + uint8_t sand_system_headers[RCPU_RX_META_SIZE] = {0}; + uint8_t *pkt = NULL; + + 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 ((sinfo->cmic_type == 'x' && (dcb[2] & (1 << 16)) == 0) || + (sinfo->cmic_type != 'x' && (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++; + skb = desc->skb; + + if (device_is_sand(sinfo)) { + err_woff = BKN_SAND_SCRATCH_DATA_SIZE - 1; + sand_scratch_data[err_woff] = dcb[sinfo->dcb_wsize-1]; + meta = (uint32_t *)skb->data; + pkt = skb->data; + } else { + if (sinfo->cmic_type == 'x') { + meta = (uint32_t *)skb->data; + err_woff = sinfo->pkt_hdr_size / sizeof(uint32_t) - 1; + meta[err_woff] = dcb[sinfo->dcb_wsize-1]; + } else { + meta = dcb; + err_woff = sinfo->dcb_wsize - 1; + } + } + + pktlen = dcb[sinfo->dcb_wsize-1] & 0xffff; + priv = netdev_priv(sinfo->dev); + DBG_DCB_RX(("Rx%d SKB DMA done (%d).\n", chan, sinfo->rx[chan].dirty)); + BKN_DMA_UNMAP_SINGLE(sinfo->dma_dev, + desc->skb_dma, desc->dma_size, + BKN_DMA_FROMDEV); + desc->skb_dma = 0; + bkn_dump_pkt(skb->data, pktlen, XGS_DMA_RX_CHAN); + + if (device_is_sand(sinfo)) { + memset(&packet_info, 0, sizeof(bkn_dune_system_header_info_t)); + /* decode system headers and fill sratch data */ + bkn_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info); + bkn_bitstream_set_field(sand_scratch_data, 0, 16, packet_info.internal.trap_id); + bkn_bitstream_set_field(sand_scratch_data, 16, 16, packet_info.internal.trap_qualifier); + bkn_bitstream_set_field(sand_scratch_data, 32, 16, packet_info.ftmh.source_sys_port_aggregate); + bkn_bitstream_set_field(sand_scratch_data, 48, 16, packet_info.internal.forward_domain); + bkn_bitstream_set_field(sand_scratch_data, 64, 2, packet_info.ftmh.action_type); + memcpy(sand_system_headers, pkt, + ((packet_info.system_header_size > RCPU_RX_META_SIZE) ? RCPU_RX_META_SIZE : packet_info.system_header_size)); + meta = (uint32_t *)sand_system_headers; + if (force_tagged) { + uint8_t *eth_hdr = pkt + packet_info.system_header_size; + uint16_t tpid = 0; + + tpid = PKT_U16_GET(eth_hdr, 12); + if (packet_is_untagged(tpid)) { + int raw_packet_len = pktlen - packet_info.system_header_size; + uint32_t vid = 0; + + if ((pktlen + 4) < rx_buffer_size) { + for (idx = (raw_packet_len - 1); idx >= 12; idx--) { + eth_hdr[idx+4] = eth_hdr[idx]; + } + if (ft_vid) { + vid = ft_vid; + } + else if (packet_info.internal.forward_domain) { + vid = packet_info.internal.forward_domain & 0xfff; + } + else { + vid = 1; + } + DBG_DUNE(("add vlan tag (%d) to untagged packets\n", vid)); + eth_hdr[12] = (ft_tpid >> 8) & 0xff; + eth_hdr[13] = ft_tpid & 0xff; + eth_hdr[14] = (((ft_pri & 0x7) << 5) | ((ft_cfi & 0x1) << 4) | ((vid >> 8) & 0xf)) & 0xff; + eth_hdr[15] = vid & 0xff; + /* reset packet length in DCB */ + pktlen += 4; + bkn_dump_pkt(pkt, pktlen, XGS_DMA_RX_CHAN); + dcb[sinfo->dcb_wsize-1] &= ~SOC_DCB_KNET_COUNT_MASK; + dcb[sinfo->dcb_wsize-1] |= pktlen & SOC_DCB_KNET_COUNT_MASK; + } + } + } + } + if (device_is_sand(sinfo)) { + filter = bkn_match_rx_pkt(sinfo, skb->data + packet_info.system_header_size, + pktlen - packet_info.system_header_size, sand_scratch_data, chan, &cbf); + } else { + filter = bkn_match_rx_pkt(sinfo, skb->data + sinfo->pkt_hdr_size, + pktlen - sinfo->pkt_hdr_size, meta, chan, &cbf); + } + if ((dcb[sinfo->dcb_wsize-1] & 0xf0000) != 0x30000) { + /* Fragment or error */ + priv->stats.rx_errors++; + if (filter && filter->kf.mask.w[err_woff] == 0) { + /* Drop unless DCB status is part of filter */ + filter = NULL; + } + } + DBG_PKT(("Rx packet (%d bytes).\n", pktlen)); + 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 ((filter->kf.mirror_type == KCOM_DEST_T_API) || dbg_pkt_enable) { + sinfo->rx[chan].pkts_m_api++; + bkn_api_rx_copy_from_skb(sinfo, chan, desc); + } + + if (device_is_sand(sinfo)) { + /* CRC has been stripped on Dune*/ + skb_put(skb, pktlen); + } else { + skb_put(skb, pktlen - 4); /* Strip CRC */ + } + + if (device_is_sand(sinfo)) { + skb_pull(skb, packet_info.system_header_size); + } else if (sinfo->cmic_type == 'x') { + skb_pull(skb, sinfo->pkt_hdr_size); + } + + /* Optional SKB updates */ + KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF; + /* Do Rx timestamping */ + if (priv->rx_hwts) { + bkn_hw_tstamp_rx_set(sinfo, priv->phys_port, skb, meta); + } + + /* Save for RCPU before stripping tag */ + ethertype = PKT_U16_GET(skb->data, 16); + if ((priv->flags & KCOM_NETIF_F_KEEP_RX_TAG) == 0) { + uint16_t vlan_proto; + + vlan_proto = PKT_U16_GET(skb->data, 12); + if (filter->kf.flags & KCOM_FILTER_F_STRIP_TAG) { + /* Strip VLAN tag */ + if (vlan_proto == ETH_P_8021Q || + vlan_proto == ETH_P_8021AD) { + 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); + if (device_is_sand(sinfo)) { + for (idx = packet_info.system_header_size; idx >= 4; idx--) { + pkt[idx] = pkt[idx - 4]; + } + } else if (sinfo->cmic_type == 'x') { + for (idx = sinfo->pkt_hdr_size / sizeof(uint32_t); idx; idx--) { + meta[idx] = meta[idx - 1]; + } + meta++; + } + } + } else { + /* + * Mark packet as VLAN-tagged, otherwise newer + * kernels will strip the tag. + */ + uint16_t tci = PKT_U16_GET(skb->data, 14); + + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { + bkn_vlan_hwaccel_put_tag(skb, ETH_P_8021Q, tci); + } else { + if (vlan_proto == ETH_P_8021AD) { + bkn_vlan_hwaccel_put_tag + (skb, ETH_P_8021AD, tci); + } else { + bkn_vlan_hwaccel_put_tag + (skb, ETH_P_8021Q, tci); + } + } + } + } + + priv->stats.rx_packets++; + priv->stats.rx_bytes += skb->len; + skb->dev = priv->dev; + + 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; + if (device_is_sand(sinfo)) { + skb = knet_rx_cb(skb, sinfo->dev_no, sand_scratch_data); + } + else { + skb = knet_rx_cb(skb, sinfo->dev_no, meta); + } + if (skb == NULL) { + /* Consumed by call-back */ + sinfo->rx[chan].pkts_d_callback++; + priv->stats.rx_dropped++; + desc->skb = NULL; + break; + } + } + + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { + bkn_add_rcpu_encap(sinfo, skb, meta, packet_info.system_header_size); + DBG_PDMP(("After add RCPU ENCAP\n")); + bkn_dump_pkt(skb->data, pktlen + RCPU_RX_ENCAP_SIZE, XGS_DMA_RX_CHAN); + } + 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 += mskb->len; + 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; + } 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; + } + } else { + DBG_PKT(("Rx packet dropped.\n")); + sinfo->rx[chan].pkts_d_no_match++; + priv->stats.rx_dropped++; + } + dcb[sinfo->dcb_wsize-1] &= ~(1 << 31); + 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); + } + } + + 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 void +bkn_skb_tstamp_copy(struct sk_buff *new_skb, struct sk_buff *skb) +{ + bkn_skb_tx_flags(new_skb) = bkn_skb_tx_flags(skb); + new_skb->sk = skb->sk; + + return; +} + +static int +bkn_hw_tstamp_tx_set(bkn_switch_info_t *sinfo, struct sk_buff *skb) +{ + int hwts; + int port; + uint64_t ts = 0; + uint32_t hdrlen = sinfo->cmic_type == 'x' ? PKT_TX_HDR_SIZE : 0; + struct skb_shared_hwtstamps shhwtstamps; + + if (!knet_hw_tstamp_tx_time_get_cb) { + return -1; + } + + port = KNET_SKB_CB(skb)->port; + hwts = KNET_SKB_CB(skb)->hwts; + ts = KNET_SKB_CB(skb)->ts; + + + if (hwts == HWTSTAMP_TX_ONESTEP_SYNC) { + if (ts == 0) { + return 1; + } + } else if (hwts == HWTSTAMP_TX_ON) { + if (knet_hw_tstamp_tx_time_get_cb(sinfo->dev_no, port, skb->data + hdrlen, &ts) < 0) { + return -1; + } + } + + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); + shhwtstamps.hwtstamp = ns_to_ktime(ts); + skb_tstamp_tx(skb, &shhwtstamps); + + return 0; +} + +static void +bkn_hw_tstamp_tx_work(struct work_struct *work) +{ + bkn_switch_info_t *sinfo = container_of(work, bkn_switch_info_t, tx_ptp_work); + struct sk_buff *skb; + + while (skb_queue_len(&sinfo->tx_ptp_queue)) { + skb = skb_dequeue(&sinfo->tx_ptp_queue); + if (bkn_hw_tstamp_tx_set(sinfo, skb) < 0) { + gprintk("Timestamp has not been taken for the current skb.\n"); + } + dev_kfree_skb_any(skb); + } +} + +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)); + BKN_DMA_UNMAP_SINGLE(sinfo->dma_dev, + desc->skb_dma, desc->dma_size, + BKN_DMA_TODEV); + + if ((KNET_SKB_CB(desc->skb)->hwts == HWTSTAMP_TX_ONESTEP_SYNC) && + (bkn_skb_tx_flags(desc->skb) & SKBTX_IN_PROGRESS)) { + + if (bkn_hw_tstamp_tx_set(sinfo, desc->skb) < 0) { + gprintk("Timestamp has not been taken for the current skb.\n"); + } + bkn_skb_tx_flags(desc->skb) &= ~SKBTX_IN_PROGRESS; + } + + if (bkn_skb_tx_flags(desc->skb) & SKBTX_IN_PROGRESS) { + skb_queue_tail(&sinfo->tx_ptp_queue, desc->skb); + schedule_work(&sinfo->tx_ptp_work); + } else { + dev_kfree_skb_any(desc->skb); + } + desc->skb = NULL; + desc->skb_dma = 0; + } + desc->dcb_mem[sinfo->dcb_wsize-1] &= ~(1 << 31); + 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; + uint64_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; + if (sinfo->cmic_type == 'x') { + dcb_mem[1] = DMA_TO_BUS_HI(dcb_chain->dcb_dma >> 32); + dcb_mem[2] |= 1 << 24 | 1 << 18 | 1 << 16; + } else { + 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; + if (sinfo->cmic_type == 'x') { + dcb_mem[1] = DMA_TO_BUS_HI(sinfo->tx.desc[sinfo->tx.dirty].dcb_dma >> 32); + } + 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; + uint64_t pkt_dma; + unsigned char *pktdata; + int pktlen; + int i; + + /* 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)); + for (i = 0; i < dcb_chain->dcb_cnt && debug & DBG_LVL_PDMP; i++) { + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN) && i == dcb_chain->dcb_cnt - 1) { + break; + } + if (sinfo->cmic_type == 'x') { + pkt_dma = BUS_TO_DMA_HI(dcb_chain->dcb_mem[sinfo->dcb_wsize * i + 1]); + pkt_dma = pkt_dma << 32 | dcb_chain->dcb_mem[sinfo->dcb_wsize * i]; + } else { + pkt_dma = dcb_chain->dcb_mem[sinfo->dcb_wsize * i]; + } + pktdata = kernel_bde->p2l(sinfo->dev_no, pkt_dma); + if (sinfo->cmic_type == 'x') { + pktlen = dcb_chain->dcb_mem[sinfo->dcb_wsize * i + 2] & 0xffff; + } else { + pktlen = dcb_chain->dcb_mem[sinfo->dcb_wsize * i + 1] & 0xffff; + } + bkn_dump_pkt(pktdata, pktlen, XGS_DMA_TX_CHAN); + } + + 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; + + DBG_IRQ(("Tx CDMA chain done \n")); + + evt = &_bkn_evt[sinfo->evt_idx]; + + if (sinfo->tx.api_active) { + /* 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; + } + sinfo->tx.api_dcb_chain->dcb_mem[woffset - sinfo->dcb_wsize] |= SOC_DCB_KNET_DONE; + sinfo->dma_events |= KCOM_DMA_INFO_F_TX_DONE; + evt->evt_wq_put++; + wake_up_interruptible(&evt->evt_wq); + kfree(sinfo->tx.api_dcb_chain); + sinfo->tx.api_dcb_chain = NULL; + 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; + } + sinfo->tx.api_dcb_chain->dcb_mem[woffset] |= SOC_DCB_KNET_DONE; + /* Try and park at SKB Tx if API Tx done */ + bkn_skb_tx(sinfo); + sinfo->dma_events |= KCOM_DMA_INFO_F_TX_DONE; + evt->evt_wq_put++; + wake_up_interruptible(&evt->evt_wq); + 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; + + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) { + return bkn_tx_cdma_chain_done(sinfo, done); + } + + DBG_IRQ(("Tx chain done (%d/%d)\n", sinfo->tx.cur, sinfo->tx.dirty)); + + dev_irq_mask_disable(sinfo, XGS_DMA_TX_CHAN, 0); + + 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); + /* 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)) { + if (sinfo->cmic_type == 'x') { + sinfo->tx.desc[idx++].dcb_mem[2] |= 1 << 16; + } else { + 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; + int chan_done, budget_chans = 0; + uint32_t dma_stat; + int chan; + + DEV_READ32(sinfo, CMIC_DMA_STATr, &dma_stat); + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (dma_stat & DS_DESC_DONE_TST(XGS_DMA_RX_CHAN + chan)) { + xgs_dma_desc_clear(sinfo, XGS_DMA_RX_CHAN + chan); + sinfo->poll_channels |= 1 << chan; + } + } + if (!sinfo->poll_channels) { + sinfo->poll_channels = (uint32_t)(1 << sinfo->rx_chans) - 1; + budget_chans = budget / sinfo->rx_chans; + } else { + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + budget_chans++; + } + } + budget_chans = budget / budget_chans; + } + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + chan_done = bkn_do_rx(sinfo, chan, budget_chans); + rx_dcbs_done += chan_done; + if (chan_done < budget_chans) { + sinfo->poll_channels &= ~(1 << chan); + } + 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 sinfo->poll_channels ? budget : rx_dcbs_done; +} + +static int +xgsm_do_dma(bkn_switch_info_t *sinfo, int budget) +{ + int rx_dcbs_done = 0, tx_dcbs_done = 0; + int chan_done, budget_chans = 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 < sinfo->rx_chans; 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); + sinfo->poll_channels |= 1 << chan; + } + } + if (!sinfo->poll_channels) { + sinfo->poll_channels = (uint32_t)(1 << sinfo->rx_chans) - 1; + budget_chans = budget / sinfo->rx_chans; + } else { + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + budget_chans++; + } + } + budget_chans = budget / budget_chans; + } + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + chan_done = bkn_do_rx(sinfo, chan, budget_chans); + rx_dcbs_done += chan_done; + if (chan_done < budget_chans) { + sinfo->poll_channels &= ~(1 << chan); + } + 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 sinfo->poll_channels ? budget : rx_dcbs_done; +} + +static int +xgsx_do_dma(bkn_switch_info_t *sinfo, int budget) +{ + int rx_dcbs_done = 0, tx_dcbs_done = 0; + int chan_done, budget_chans = 0; + uint32_t irq_stat, tx_dma_stat, rx_dma_stat[NUM_CMICX_RX_CHAN]; + int chan; + + DEV_READ32(sinfo, CMICX_IRQ_STATr, &irq_stat); + DEV_READ32(sinfo, CMICX_DMA_STATr + 0x80 * XGS_DMA_TX_CHAN, &tx_dma_stat); + for (chan = 0; chan < sinfo->rx_chans; chan++) { + DEV_READ32(sinfo, + CMICX_DMA_STATr + 0x80 * (XGS_DMA_RX_CHAN + chan), + &rx_dma_stat[chan]); + } + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if ((irq_stat & CMICX_DS_CMC_CTRLD_INT(XGS_DMA_RX_CHAN + chan)) || + (irq_stat & CMICX_DS_CMC_DESC_DONE(XGS_DMA_RX_CHAN + chan))) { + xgsx_dma_desc_clear(sinfo, XGS_DMA_RX_CHAN + chan); + sinfo->poll_channels |= 1 << chan; + } + } + if (!sinfo->poll_channels) { + sinfo->poll_channels = (uint32_t)(1 << sinfo->rx_chans) - 1; + budget_chans = budget / sinfo->rx_chans; + } else { + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + budget_chans++; + } + } + budget_chans = budget / budget_chans; + } + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + chan_done = bkn_do_rx(sinfo, chan, budget_chans); + rx_dcbs_done += chan_done; + if (chan_done < budget_chans) { + sinfo->poll_channels &= ~(1 << chan); + } + bkn_rx_desc_done(sinfo, chan); + } + + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + continue; + } + + if (rx_dma_stat[chan] & CMICX_DS_CMC_DMA_CHAIN_DONE) { + xgsx_dma_chain_clear(sinfo, XGS_DMA_RX_CHAN + chan); + bkn_rx_chain_done(sinfo, chan); + } + } + + if ((irq_stat & CMICX_DS_CMC_CTRLD_INT(XGS_DMA_TX_CHAN)) || + (tx_dma_stat & CMICX_DS_CMC_DMA_CHAIN_DONE)) { + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) { + xgsx_dma_desc_clear(sinfo, XGS_DMA_TX_CHAN); + } else { + xgsx_dma_chain_clear(sinfo, XGS_DMA_TX_CHAN); + } + tx_dcbs_done = bkn_do_tx(sinfo); + bkn_tx_chain_done(sinfo, tx_dcbs_done); + } + + return sinfo->poll_channels ? budget : rx_dcbs_done; +} + +static int +dev_do_dma(bkn_switch_info_t *sinfo, int budget) +{ + if (DEV_IS_CMICX(sinfo)) { + return xgsx_do_dma(sinfo, budget); + } else if (DEV_IS_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 +xgsx_isr(bkn_switch_info_t *sinfo) +{ + uint32_t irq_stat; + int rx_dcbs_done; + + DEV_READ32(sinfo, CMICX_IRQ_STATr, &irq_stat); + if ((irq_stat & sinfo->irq_mask) == 0) { + /* Not ours */ + return; + } + + /* Bypass chain_done from Abort */ + if (device_is_dnx(sinfo)) { + uint32_t ctrl = 0; + int chan = 0; + for (chan = 0; chan < NUM_DMA_CHAN; chan++) { + if (irq_stat & CMICX_DS_CMC_CHAIN_DONE(chan)) { + DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl); + if (ctrl & CMICX_DC_CMC_ABORT) { + DBG_IRQ(("chain %d: chain done for Abort\n", chan)); + 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 { + xgsx_irq_mask_set(sinfo, 0); + do { + rx_dcbs_done = xgsx_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); + } + + xgsx_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_IS_CMICX(sinfo)) { + xgsx_isr(sinfo); + } else if (DEV_IS_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; + uint64_t cur_halt, last_dcb, dcb_dma; + int woffset, chan, cdma_running; + + /* Resume Rx DMA on all channels */ + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (sinfo->rx[chan].use_rx_skb) { + cdma_running = 0; + bkn_api_rx_restart(sinfo, chan); + 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, chan); + } + } + } +} + +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 (LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,12)) + if (!is_valid_ether_addr((const u8*)(((struct sockaddr *)addr)->sa_data))) { +#else + if (!is_valid_ether_addr(((struct sockaddr *)addr)->sa_data)) { +#endif + return -EINVAL; + } + memcpy(dev->dev_addr, ((struct sockaddr *)addr)->sa_data, dev->addr_len); + return 0; +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) +static int +bkn_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + bkn_priv_t *priv = netdev_priv(dev); + bkn_switch_info_t *sinfo = priv->sinfo; + struct hwtstamp_config config; + + if (cmd == SIOCSHWTSTAMP) { + if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) { + return -EFAULT; + } + + if (!knet_hw_tstamp_enable_cb || !knet_hw_tstamp_disable_cb || + priv->type != KCOM_NETIF_T_PORT) { + return -ENOSYS; + } + + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + knet_hw_tstamp_disable_cb(sinfo->dev_no, priv->phys_port, config.tx_type); + priv->tx_hwts = (config.tx_type); + break; + case HWTSTAMP_TX_ON: + knet_hw_tstamp_enable_cb(sinfo->dev_no, priv->phys_port, config.tx_type); + priv->tx_hwts = (config.tx_type); + break; + case HWTSTAMP_TX_ONESTEP_SYNC: + knet_hw_tstamp_enable_cb(sinfo->dev_no, priv->phys_port, config.tx_type); + priv->tx_hwts = (config.tx_type); + break; + default: + return -ERANGE; + } + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + if (priv->rx_hwts) { + knet_hw_tstamp_disable_cb(sinfo->dev_no, priv->phys_port, config.tx_type); + priv->rx_hwts = 0; + } + break; + default: + if (!priv->rx_hwts) { + knet_hw_tstamp_enable_cb(sinfo->dev_no, priv->phys_port, config.tx_type); + priv->rx_hwts = 1; + } + config.rx_filter = HWTSTAMP_FILTER_ALL; + break; + } + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) + if (cmd == SIOCGHWTSTAMP) { + config.flags = 0; + config.tx_type = priv->tx_hwts; + config.rx_filter = priv->rx_hwts ? HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE; + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; + } +#endif + + return -EINVAL; +} +#endif + +static int +bkn_change_mtu(struct net_device *dev, int new_mtu) +{ + int max_size = new_mtu + ETH_HLEN + VLAN_HLEN + 4; + + if (new_mtu < 68 || max_size > 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_hw_tstamp_tx_config(bkn_switch_info_t *sinfo, + int hwts, int hdrlen, + struct sk_buff *skb, u32 *meta) +{ + uint32_t *md = NULL; + + if (!knet_hw_tstamp_tx_meta_get_cb) { + return -1; + } + + KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF; + knet_hw_tstamp_tx_meta_get_cb(sinfo->dev_no, hwts, hdrlen, skb, + &(KNET_SKB_CB(skb)->ts), (meta ? &md : NULL)); + + if (!meta) { + return 0; + } + + if (!md) { + return -1; + } + + switch (sinfo->dcb_type) { + case 26: + case 32: + case 33: + meta[2] |= md[0]; + meta[3] |= md[1]; + meta[4] |= md[2]; + meta[5] |= md[3]; + break; + case 36: + case 38: + meta[0] |= htonl(md[0]); + meta[1] |= htonl(md[1]); + meta[2] |= htonl(md[2]); + meta[3] |= htonl(md[3]); + break; + default: + return -1; + } + + return 0; +} + +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 = NULL; + unsigned char *pktdata; + int pktlen, hdrlen, taglen, rcpulen, metalen; + int sop, idx; + uint16_t tpid; + uint32_t *metadata; + unsigned long flags; + uint32_t cpu_channel = 0; + int headroom, tailroom; + + DBG_VERB(("Netif Tx: Len=%d priv->id=%d\n", skb->len, priv->id)); + + if (priv->id <= 0) { + /* Do not transmit on base device */ + priv->stats.tx_dropped++; + dev_kfree_skb_any(skb); + return 0; + } + + if (device_is_dnx(sinfo) && (skb->len == 0)) { + priv->stats.tx_dropped++; + dev_kfree_skb_any(skb); + return 0; + } + + if (!netif_carrier_ok(dev)) { + DBG_WARN(("Tx drop: Netif link is down.\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, *meta; + + pktdata = skb->data; + pktlen = skb->len; + + if (device_is_sand(sinfo)) { + hdrlen = priv->system_headers_size; + } + else { + hdrlen = (sinfo->cmic_type == 'x' ) ? PKT_TX_HDR_SIZE : 0; + } + 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 && + PKT_U16_GET(skb->data, 18) != 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 (device_is_sand(sinfo)) { + /* Dune devices don't use meta data */ + sop = 0; + /* Get CPU channel from rcpu_hdr_t.reserved */ + cpu_channel = (skb->data[28] << 24) | (skb->data[29] << 16) | (skb->data[30] << 8) | (skb->data[31]); + /* System headers are supposed to be set by users in RCPU mode. */ + hdrlen = 0; + } else if (skb->data[21] & RCPU_F_MODHDR) { + 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; + } + if (sinfo->cmic_type != 'x') { + rcpulen += RCPU_TX_META_SIZE; + } + } + /* Skip over RCPU encapsulation */ + pktdata = &skb->data[rcpulen]; + pktlen -= rcpulen; + + /* CPU packets require tag */ + if (sop == 0) { + if (device_is_sand(sinfo)) { + /* + * There should be Module Header + PTCH_2 + [ITMH] on JR2, + * PTCH_2 +[ITMH] on JR1 + */ + } else { + hdrlen = 0; + tpid = PKT_U16_GET(pktdata, 12); + if (tpid != 0x8100) { + if (skb_header_cloned(skb)) { + /* Current SKB cannot be modified */ + DBG_SKB(("Realloc Tx SKB\n")); + /* + * New SKB needs extra TAG_SZ for VLAN tag + * and extra FCS_SZ for Ethernet FCS. + */ + headroom = TAG_SZ; + tailroom = FCS_SZ; + new_skb = skb_copy_expand(skb, + headroom + skb_headroom(skb), + tailroom + skb_tailroom(skb), + GFP_ATOMIC); + 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; + } + /* Remove rcpulen from buffer. */ + skb_pull(new_skb, rcpulen); + /* Extended by TAG_SZ at the start of buffer. */ + skb_push(new_skb, TAG_SZ); + /* Restore the data before the tag. */ + memcpy(new_skb->data, pktdata, 12); + bkn_skb_tstamp_copy(new_skb, skb); + dev_kfree_skb_any(skb); + skb = new_skb; + pktdata = skb->data; + rcpulen = 0; + } else { + /* Add tag to RCPU header space */ + DBG_SKB(("Expand into unused RCPU header\n")); + rcpulen -= TAG_SZ; + pktdata = &skb->data[rcpulen]; + for (idx = 0; idx < 12; idx++) { + pktdata[idx] = pktdata[idx + TAG_SZ]; + } + } + pktdata[12] = 0x81; + pktdata[13] = 0x00; + pktdata[14] = (priv->vlan >> 8) & 0xf; + pktdata[15] = priv->vlan & 0xff; + pktlen += TAG_SZ; + } + } + } + } else { + if (((sinfo->cmic_type == 'x') && (priv->port >= 0)) + || device_is_sand(sinfo)) { + if (skb_header_cloned(skb) || skb_headroom(skb) < hdrlen + 4) { + /* Current SKB cannot be modified */ + DBG_SKB(("Realloc Tx SKB\n")); + if (device_is_sand(sinfo)) { + headroom = hdrlen; + } else { + headroom = hdrlen + 4; + } + tailroom = FCS_SZ; + new_skb = skb_copy_expand(skb, + headroom + skb_headroom(skb), + tailroom + skb_tailroom(skb), + GFP_ATOMIC); + 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; + } + skb_push(new_skb, hdrlen); + bkn_skb_tstamp_copy(new_skb, skb); + dev_kfree_skb_any(skb); + skb = new_skb; + } else { + DBG_SKB(("Expand Tx SKB\n")); + skb_push(skb, hdrlen); + } + memset(skb->data, 0, hdrlen); + pktdata = skb->data; + pktlen += hdrlen; + } else { + hdrlen = 0; + } + + if (priv->port < 0 || (priv->flags & KCOM_NETIF_F_ADD_TAG)) { + DBG_DUNE(("ADD VLAN TAG\n")); + /* Need to add VLAN tag if packet is untagged */ + tpid = PKT_U16_GET(skb->data, hdrlen + 12); + if (tpid != 0x8100) { + if (skb_header_cloned(skb) || skb_headroom(skb) < 4) { + /* Current SKB cannot be modified */ + DBG_SKB(("Realloc Tx SKB\n")); + headroom = TAG_SZ; + tailroom = FCS_SZ; + new_skb = skb_copy_expand(skb, + headroom + skb_headroom(skb), + tailroom + skb_tailroom(skb), + GFP_ATOMIC); + 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; + } + skb_push(new_skb, TAG_SZ); + memcpy(new_skb->data, pktdata, hdrlen + 12); + bkn_skb_tstamp_copy(new_skb, skb); + dev_kfree_skb_any(skb); + skb = new_skb; + } else { + /* Add tag to existing buffer */ + DBG_SKB(("Expand Tx SKB\n")); + skb_push(skb, TAG_SZ); + for (idx = 0; idx < hdrlen + 12; idx++) { + skb->data[idx] = skb->data[idx + TAG_SZ]; + } + } + pktdata = skb->data; + pktdata[hdrlen + 12] = 0x81; + pktdata[hdrlen + 13] = 0x00; + pktdata[hdrlen + 14] = (priv->vlan >> 8) & 0xf; + pktdata[hdrlen + 15] = priv->vlan & 0xff; + pktlen += TAG_SZ; + } + } + } + + /* Pad packet if needed */ + taglen = 0; + tpid = PKT_U16_GET(pktdata, hdrlen + 12); + if (tpid == 0x8100) { + taglen = 4; + } + if (pktlen < (60 + taglen + hdrlen)) { + pktlen = (60 + taglen + hdrlen); + 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; + } + /* skb_padto may update the skb->data pointer */ + pktdata = &skb->data[rcpulen]; + } + + if ((pktlen + FCS_SZ) > SOC_DCB_KNET_COUNT_MASK) { + DBG_WARN(("Tx drop: size of pkt (%d) is out of range(%d)\n", + (pktlen + FCS_SZ), 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; + meta = (sinfo->cmic_type == 'x') ? (uint32_t *)pktdata : dcb; + memset(dcb, 0, sinfo->dcb_wsize * sizeof(uint32_t)); + if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) { + if (device_is_sand(sinfo)) { + if (sinfo->cmic_type == 'x') { + dcb[2] |= 1 << 19; + /* Given Module Header exists and set first byte to be CPU channel */ + pktdata[0] = cpu_channel; + } else { + dcb[1] |= 1 << 19; + /* Set CPU channel */ + dcb[2] = (cpu_channel & 0xff) << 24; + } + + } else if (sop != 0) { + /* If module header SOP is non-zero, use RCPU meta data */ + if (sinfo->cmic_type == 'x') { + dcb[2] |= 1 << 19; + } else { + 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; + } + } + } else if (priv->port >= 0) { + /* Send to physical port */ + if (sinfo->cmic_type == 'x') { + dcb[2] |= 1 << 19; + } else { + 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 24: + dcb[2] = 0xff000000; + dcb[3] = 0x00000100; + dcb[4] = priv->port; + dcb[4] |= (priv->qnum & 0xfff) << 14; + break; + case 28: + /* + * If KCOM_NETIF_T_PORT, add PTCH+ITMH header + * If KCOM_NETIF_T_VLAN, add PTCH+header + */ + pktdata = skb->data; + memcpy(&pktdata[0], priv->system_headers, priv->system_headers_size); + /* Set CPU channel */ + dcb[2] = ((priv->qnum & 0xff) << 24); + break; + case 29: + dcb[2] = 0x81000000; + dcb[3] = priv->port; + dcb[4] = 0x00100000; + dcb[4] |= (priv->qnum & 0xfff) << 8; + break; + case 32: + dcb[2] = 0x81000000; + dcb[3] = priv->port; + dcb[4] = 0x00004000; + 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 36: + if (sinfo->cmic_type == 'x') { + meta[0] = htonl(0x81000000); + meta[1] = htonl(priv->port); + meta[2] = htonl(0x00008000 | (priv->qnum & 0x3f) << 9); + } else { + dcb[2] = 0x81000000; + dcb[3] = priv->port; + dcb[4] = 0x00008000; + dcb[4] |= (priv->qnum & 0x3f) << 9; + } + break; + case 38: + if (sinfo->cmic_type == 'x') { + meta[0] = htonl(0x81000000); + meta[1] = htonl(priv->port); + meta[2] = htonl(0x00004000 | (priv->qnum & 0x3f) << 8); + } else { + dcb[2] = 0x81000000; + dcb[3] = priv->port; + dcb[4] = 0x00004000; + dcb[4] |= (priv->qnum & 0x3f) << 8; + } + break; + case 39: + if (device_is_dnx(sinfo)) { + /* + * if KCOM_NETIF_T_PORT, add MH+PTCH+ITMH header + * if KCOM_NETIF_T_VLAN, add MH+PTCH+header + */ + pktdata = skb->data; + memcpy(&pktdata[0], priv->system_headers, priv->system_headers_size); + } + break; + case 40: + if (sinfo->cmic_type == 'x') { + meta[0] = htonl(0x81000000); + meta[1] = htonl(priv->port | (priv->qnum & 0xc00) << 20); + meta[2] = htonl(0x00040000 | (priv->qnum & 0x3ff) << 8); + } else { + dcb[2] = 0x81000000; + dcb[3] = priv->port; + dcb[3] |= (priv->qnum & 0xc00) << 20; + dcb[4] = 0x00040000; + dcb[4] |= (priv->qnum & 0x3ff) << 8; + } + break; + default: + dcb[2] = 0xff000000; + dcb[3] = 0x00000100; + dcb[4] = priv->port; + break; + } + } + + /* Optional SKB updates */ + if (knet_tx_cb != NULL) { + KNET_SKB_CB(skb)->netif_user_data = priv->cb_user_data; + KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF; + skb = knet_tx_cb(skb, sinfo->dev_no, meta); + 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 + FCS_SZ) <= SOC_DCB_KNET_COUNT_MASK) { + pktlen = skb->len; + if (pktlen < (60 + taglen + hdrlen)) { + pktlen = (60 + taglen + hdrlen); + 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)); + } + pktdata = skb->data; + if (sinfo->cmic_type == 'x') { + meta = (uint32_t *)pktdata; + } + } else { + DBG_WARN(("Tx drop: size of pkt (%d) is out of range(%d)\n", + (pktlen + FCS_SZ), 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; + } + } + + /* Do Tx timestamping */ + if (bkn_skb_tx_flags(skb) & SKBTX_HW_TSTAMP) { + KNET_SKB_CB(skb)->hwts = priv->tx_hwts; + if ((priv->port >= 0) && (priv->tx_hwts & HWTSTAMP_TX_ON)) { + /* TwoStep Processing of ptp-packets */ + KNET_SKB_CB(skb)->port = priv->phys_port; + bkn_hw_tstamp_tx_config(sinfo, priv->tx_hwts, PKT_TX_HDR_SIZE, skb, meta); + + bkn_skb_tx_flags(skb) |= SKBTX_IN_PROGRESS; + bkn_skb_tx_timestamp(skb); + + } else if (priv->tx_hwts & HWTSTAMP_TX_ONESTEP_SYNC) { + + /* OneStep Processing of ptp-packets */ + KNET_SKB_CB(skb)->port = priv->phys_port; + KNET_SKB_CB(skb)->ts = 0; + bkn_hw_tstamp_tx_config(sinfo, priv->tx_hwts, PKT_TX_HDR_SIZE, skb, + ((priv->port >= 0) ? meta : NULL)); + + if (KNET_SKB_CB(skb)->ts != 0) { + bkn_skb_tx_flags(skb) |= SKBTX_IN_PROGRESS; + bkn_skb_tx_timestamp(skb); + } + + } + } + + /* Prepare for DMA */ + desc->skb = skb; + /* + * Add FCS bytes + * FCS bytes are always appended to packet by MAC on Dune devices + */ + if (!device_is_sand(sinfo)) { + pktlen = pktlen + FCS_SZ; + } + desc->dma_size = pktlen; + desc->skb_dma = BKN_DMA_MAP_SINGLE(sinfo->dma_dev, + pktdata, desc->dma_size, + BKN_DMA_TODEV); + if (BKN_DMA_MAPPING_ERROR(sinfo->dma_dev, desc->skb_dma)) { + priv->stats.tx_dropped++; + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&sinfo->lock, flags); + return 0; + } + dcb[0] = desc->skb_dma; + if (sinfo->cmic_type == 'x') { + dcb[1] = DMA_TO_BUS_HI(desc->skb_dma >> 32); + dcb[2] &= ~SOC_DCB_KNET_COUNT_MASK; + dcb[2] |= pktlen; + } else { + dcb[1] &= ~SOC_DCB_KNET_COUNT_MASK; + dcb[1] |= pktlen; + } + + bkn_dump_dcb("Tx RCPU", dcb, sinfo->dcb_wsize, XGS_DMA_TX_CHAN); + 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, pktlen, XGS_DMA_TX_CHAN); + + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) { + if (sinfo->cmic_type == 'x') { + dcb[2] |= 1 << 24 | 1 << 16; + } else { + 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); + } + + NETDEV_UPDATE_TRANS_START_TIME(dev); + + spin_unlock_irqrestore(&sinfo->lock, flags); + + return 0; +} + +static void +bkn_timer_func(bkn_switch_info_t *sinfo) +{ + unsigned long flags; + int chan; + int restart_timer; + + spin_lock_irqsave(&sinfo->lock, flags); + + sinfo->timer_runs++; + + restart_timer = 0; + for (chan = 0; chan < sinfo->rx_chans; 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); +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)) +static void +bkn_timer(unsigned long context) +{ + bkn_switch_info_t *sinfo = (bkn_switch_info_t *)context; + return bkn_timer_func(sinfo); +} +#else +static void +bkn_timer(struct timer_list *t) +{ + bkn_switch_info_t *sinfo = from_timer(sinfo, t, timer); + return bkn_timer_func(sinfo); +} +#endif + +static void +bkn_rx_add_tokens(bkn_switch_info_t *sinfo, int chan) +{ + unsigned long cur_jif, ticks; + uint32_t tokens_per_tick; + bkn_desc_info_t *desc; + + 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 Rx is suppressed */ + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { + bkn_rx_refill(sinfo, chan); + desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty]; + if (desc->dcb_dma == sinfo->halt_addr[XGS_DMA_RX_CHAN + chan]) { + desc = &sinfo->rx[chan].desc[MAX_RX_DCBS]; + bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, desc->dcb_dma); + } + } else { + if (sinfo->rx[chan].running == 0) { + bkn_rx_refill(sinfo, chan); + bkn_rx_restart(sinfo, chan); + } + } +} + +static void +bkn_rxtick_func(bkn_switch_info_t *sinfo) +{ + 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 < sinfo->rx_chans; 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 < sinfo->rx_chans; 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); +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)) +static void +bkn_rxtick(unsigned long context) +{ + bkn_switch_info_t *sinfo = (bkn_switch_info_t *)context; + return bkn_rxtick_func(sinfo); +} +#else +static void +bkn_rxtick(struct timer_list *t) +{ + bkn_switch_info_t *sinfo = from_timer(sinfo, t, rxtick); + return bkn_rxtick_func(sinfo); +} +#endif + +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; + 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); + skb_queue_head_init(&sinfo->tx_ptp_queue); + INIT_WORK(&sinfo->tx_ptp_work, bkn_hw_tstamp_tx_work); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)) + init_timer(&sinfo->timer); + sinfo->timer.data = (unsigned long)sinfo; + sinfo->timer.function = bkn_timer; +#else + timer_setup(&sinfo->timer, bkn_timer, 0); +#endif + sinfo->timer.expires = jiffies + 1; + + 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; + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)) + init_timer(&sinfo->rxtick); + sinfo->rxtick.data = (unsigned long)sinfo; + sinfo->rxtick.function = bkn_rxtick; +#else + timer_setup(&sinfo->rxtick, bkn_rxtick, 0); +#endif + sinfo->rxtick.expires = jiffies + 1; + + 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); + + 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 = bkn_ioctl, + .ndo_tx_timeout = NULL, + .ndo_change_mtu = bkn_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = bkn_poll_controller, +#endif +}; +#endif + +static void +bkn_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) +{ + strlcpy(drvinfo->driver, "bcm-knet", sizeof(drvinfo->driver)); + snprintf(drvinfo->version, sizeof(drvinfo->version), "%d", KCOM_VERSION); + strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); + strlcpy(drvinfo->bus_info, "N/A", sizeof(drvinfo->bus_info)); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)) +static int +bkn_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) +{ + bkn_priv_t *priv = netdev_priv(dev); + bkn_switch_info_t *sinfo = priv->sinfo; + + switch (sinfo->dcb_type) { + case 26: + case 32: + case 33: + case 36: + case 38: + case 40: + info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + info->tx_types = 1 << HWTSTAMP_TX_OFF | 1 << HWTSTAMP_TX_ON; + info->rx_filters = 1 << HWTSTAMP_FILTER_NONE | 1 << HWTSTAMP_FILTER_ALL; + if (knet_hw_tstamp_ptp_clock_index_cb) { + info->phc_index = knet_hw_tstamp_ptp_clock_index_cb(sinfo->dev_no); + } else { + info->phc_index = -1; + } + break; + default: + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE; + info->phc_index = -1; + break; + } + + return 0; +} +#endif + +static const struct ethtool_ops bkn_ethtool_ops = { + .get_drvinfo = bkn_get_drvinfo, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)) + .get_ts_info = bkn_get_ts_info, +#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 + dev->ethtool_ops = &bkn_ethtool_ops; + if (name && *name) { + strncpy(dev->name, name, IFNAMSIZ-1); + } + + bkn_dev_net_set(dev, current->nsproxy->net_ns); + + /* 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: + * <netif>=up|down + * + * Where <netif> 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; + link_str[count] = '\0'; + } + 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 < sinfo->rx_chans; 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: + * [<unit>:]rx_rate=<rate0>[,<rate1>[,<rate2]] + * + * Where <rate0> is packets/sec for the first Rx DMA channel, + * <rate1> 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[80]; + char *ptr; + int unit, chan; + + if (count > sizeof(rate_str)) { + count = sizeof(rate_str) - 1; + rate_str[count] = '\0'; + } + 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: %d\n", unit); + 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 < sinfo->rx_chans); + 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 < sinfo->rx_chans); + 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) +{ + bkn_switch_info_t *sinfo; + + sinfo = bkn_sinfo_from_unit(iter->dev_no); + while (pos) { + if (iter->rx_dma) { + if (++iter->idx >= MAX_RX_DCBS + 1) { + iter->idx = -1; + if (++iter->ch_no >= sinfo->rx_chans) { + iter->rx_dma = 0; + iter->ch_no = 0; + iter->dev_no++; + if ((sinfo = bkn_sinfo_from_unit(iter->dev_no)) == NULL) { + return -1; + } + } + } + } else { + if (++iter->idx >= MAX_TX_DCBS + 1) { + 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; + bkn_dcb_chain_t *dcb_chain = NULL; + struct list_head *curr, *next; + unsigned long flags; + int chan, cnt; + + 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) { + spin_lock_irqsave(&sinfo->lock, flags); + curr = &sinfo->tx.api_dcb_list; + dcb_chain = sinfo->tx.api_dcb_chain; + while (dcb_chain) { + seq_printf(s, " [0x%08lx]--->\n", (unsigned long)dcb_chain->dcb_dma); + for (cnt = 0; cnt < dcb_chain->dcb_cnt; cnt++) { + dcb = &dcb_chain->dcb_mem[sinfo->dcb_wsize * cnt]; + if (sinfo->cmic_type == 'x') { + seq_printf(s, " DCB %2d: 0x%08x 0x%08x 0x%08x 0x%08x\n", cnt, + dcb[0], dcb[1], dcb[2], dcb[sinfo->dcb_wsize-1]); + } else { + seq_printf(s, " DCB %2d: 0x%08x 0x%08x ... 0x%08x\n", cnt, + dcb[0], dcb[1], dcb[sinfo->dcb_wsize-1]); + } + } + next = curr->next; + if (next != &sinfo->tx.api_dcb_list) { + dcb_chain = list_entry(next, bkn_dcb_chain_t, list); + curr = next; + } else { + dcb_chain = NULL; + } + } + dcb = NULL; + spin_unlock_irqrestore(&sinfo->lock, flags); + 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"); + if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) { + bkn_desc_info_t *desc = &sinfo->tx.desc[0]; + uint64_t halt = sinfo->halt_addr[XGS_DMA_TX_CHAN]; + seq_printf(s, + " halt: %d\n", + (int)((uint32_t)(halt - desc->dcb_dma) / (sinfo->dcb_wsize * sizeof(uint32_t)))); + } + } else { + dcb = sinfo->tx.desc[iter->idx].dcb_mem; + if (iter->idx == 0) { + seq_printf(s, " [0x%08lx]--->\n", (unsigned long)sinfo->tx.desc[0].dcb_dma); + } + } + } 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); + if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) && sinfo->rx[chan].use_rx_skb) { + bkn_desc_info_t *desc = &sinfo->rx[chan].desc[0]; + uint64_t halt = sinfo->halt_addr[XGS_DMA_RX_CHAN + chan]; + seq_printf(s, + " halt: %d\n", + (int)((uint32_t)(halt - desc->dcb_dma) / (sinfo->dcb_wsize * sizeof(uint32_t)))); + } + } else if (sinfo->rx[iter->ch_no].use_rx_skb) { + dcb = sinfo->rx[iter->ch_no].desc[iter->idx].dcb_mem; + if (iter->idx == 0) { + seq_printf(s, " [0x%08lx]--->\n", (unsigned long)sinfo->rx[iter->ch_no].desc[0].dcb_dma); + } + } else if (!sinfo->rx[iter->ch_no].use_rx_skb && iter->idx == 0) { + spin_lock_irqsave(&sinfo->lock, flags); + curr = &sinfo->rx[iter->ch_no].api_dcb_list; + dcb_chain = sinfo->rx[iter->ch_no].api_dcb_chain; + while (dcb_chain) { + seq_printf(s, " [0x%08lx]--->\n", (unsigned long)dcb_chain->dcb_dma); + for (cnt = 0; cnt < dcb_chain->dcb_cnt; cnt++) { + dcb = &dcb_chain->dcb_mem[sinfo->dcb_wsize * cnt]; + if (sinfo->cmic_type == 'x') { + seq_printf(s, " DCB %2d: 0x%08x 0x%08x 0x%08x 0x%08x\n", cnt, + dcb[0], dcb[1], dcb[2], dcb[sinfo->dcb_wsize-1]); + } else { + seq_printf(s, " DCB %2d: 0x%08x 0x%08x ... 0x%08x\n", cnt, + dcb[0], dcb[1], dcb[sinfo->dcb_wsize-1]); + } + } + next = curr->next; + if (next != &sinfo->rx[iter->ch_no].api_dcb_list) { + dcb_chain = list_entry(next, bkn_dcb_chain_t, list); + curr = next; + } else { + dcb_chain = NULL; + } + } + dcb = NULL; + spin_unlock_irqrestore(&sinfo->lock, flags); + } + } + if (dcb) { + if (sinfo->cmic_type == 'x') { + seq_printf(s, " DCB %2d: 0x%08x 0x%08x 0x%08x 0x%08x\n", iter->idx, + dcb[0], dcb[1], dcb[2], dcb[sinfo->dcb_wsize-1]); + } else { + 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: + * [<unit>:]debug=<mask> + * + * Where <mask> 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; + debug_str[count] = '\0'; + } + 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: %d\n", unit); + 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, " force_tagged: %d\n", force_tagged); + seq_printf(m, " ft_tpid: %d\n", ft_tpid); + seq_printf(m, " ft_pri: %d\n", ft_pri); + seq_printf(m, " ft_pri: %d\n", ft_cfi); + seq_printf(m, " ft_tpid: %d\n", ft_vid); + 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, " cmic_type: %c\n", sinfo->cmic_type); + seq_printf(m, " dcb_type: %d\n", sinfo->dcb_type); + seq_printf(m, " dcb_wsize: %d\n", sinfo->dcb_wsize); + seq_printf(m, " pkt_hdr_size: %d\n", sinfo->pkt_hdr_size); + seq_printf(m, " rx_chans: %d\n", sinfo->rx_chans); + seq_printf(m, " cdma_chans: 0x%x\n", sinfo->cdma_channels); + 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 *)(sal_paddr_t)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 < sinfo->rx_chans; chan++) { + seq_printf(m, " Rx%d packets %10u\n", chan, sinfo->rx[chan].pkts); + } + for (chan = 0; chan < sinfo->rx_chans; 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: + * [<unit>:]clear[=all] + * + * Where <mask> 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; + debug_str[count] = '\0'; + } + 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: %d\n", unit); + 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 < sinfo->rx_chans; 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 < sinfo->rx_chans; 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: + * [<unit>:]clear[=all|tx|rx[<chan>]] + * + * Where <mask> 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; + debug_str[count] = '\0'; + } + 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: %d\n", unit); + 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 < sinfo->rx_chans; 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; + uint64_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, + (sal_paddr_t)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 (sinfo->cmic_type == 'x') { + woffset += 1; + } + if ((dcb_chain->dcb_mem[woffset] & ((1 << 18) | (1 << 16))) != 0x50000) { + gprintk("Not suitable API DCB chain for Continuous DMA mode\n"); + list_del(&dcb_chain->list); + 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; + if (sinfo->cmic_type == 'x') { + dcb_chain_end->dcb_mem[woffset + 1] = DMA_TO_BUS_HI(dcb_chain->dcb_dma >> 32); + } + MEMORY_BARRIER; + } + 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); + + chan = kmsg->dma_info.chan - 1; + if ((chan < 0) || (chan > sinfo->rx_chans)) { + gprintk("Invalid RX DMA channel specified: %d\n", + kmsg->dma_info.chan); + kmsg->hdr.status = KCOM_E_PARAM; + spin_unlock_irqrestore(&sinfo->lock, flags); + return sizeof(kcom_msg_hdr_t); + } + + 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 (sinfo->cmic_type == 'x') { + woffset += 1; + } + if ((dcb_chain->dcb_mem[woffset] & ((1 << 18) | (1 << 16))) != 0x50000) { + gprintk("Not suitable API DCB chain for Continuous DMA mode\n"); + list_del(&dcb_chain->list); + 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; + if (sinfo->cmic_type == 'x') { + dcb_chain_end->dcb_mem[woffset + 1] = DMA_TO_BUS_HI(dcb_chain->dcb_dma >> 32); + } + MEMORY_BARRIER; + } + 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, chan); + } + + 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_reprobe_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) +{ + 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); + skb_queue_purge(&sinfo->tx_ptp_queue); + } else { + if (kmsg->channels & (1 << XGS_DMA_TX_CHAN)) { + bkn_dma_abort_tx(sinfo); + bkn_clean_tx_dcbs(sinfo); + skb_queue_purge(&sinfo->tx_ptp_queue); + } + for (chan = 0; chan < sinfo->rx_chans; 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; + uint32_t dev_type; + 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); + + sinfo->cmic_type = kmsg->cmic_type; + sinfo->dcb_type = kmsg->dcb_type; + sinfo->dcb_wsize = BYTES2WORDS(kmsg->dcb_size); + sinfo->pkt_hdr_size = kmsg->pkt_hdr_size; + sinfo->dma_hi = kmsg->dma_hi; + sinfo->rx_chans = sinfo->cmic_type == 'x' ? NUM_CMICX_RX_CHAN : NUM_CMICM_RX_CHAN; + if (sinfo->rx_chans > NUM_RX_CHAN) { + sinfo->rx_chans = NUM_RX_CHAN; + } + + DBG_DUNE(("CMIC:%c DCB:%d WSIZE:%d DMA HI: 0x%08x HDR size: %d\n", + sinfo->cmic_type, sinfo->dcb_type, sinfo->dcb_wsize, + sinfo->dma_hi, sinfo->pkt_hdr_size)); + + /* Config Continuous DMA mode */ + sinfo->cdma_channels = kmsg->cdma_channels & ~(~0 << (sinfo->rx_chans + 1)); + + /* Ensure 32-bit PCI DMA is mapped properly on 64-bit platforms */ + dev_type = kernel_bde->get_dev_type(sinfo->dev_no); + if (dev_type & BDE_PCI_DEV_TYPE && sinfo->cmic_type != 'x') { + if (pci_set_dma_mask(sinfo->pdev, 0xffffffff)) { + spin_unlock_irqrestore(&sinfo->lock, flags); + gprintk("No suitable DMA available for SKBs\n"); + kmsg->hdr.status = KCOM_E_RESOURCE; + return sizeof(kcom_msg_hdr_t); + } + } + + /* First time called we need to allocate DCBs */ + if (sinfo->dcb_mem == NULL) { + if (bkn_alloc_dcbs(sinfo) < 0) { + spin_unlock_irqrestore(&sinfo->lock, flags); + kmsg->hdr.status = KCOM_E_RESOURCE; + return sizeof(kcom_msg_hdr_t); + } + } + + if (device_is_sand(sinfo)) { + int idx = 0; + /* Information to parser Dune system headers */ + sinfo->ftmh_lb_key_ext_size = kmsg->ftmh_lb_key_ext_size; + sinfo->ftmh_stacking_ext_size = kmsg->ftmh_stacking_ext_size; + sinfo->pph_base_size = kmsg->pph_base_size; + for (idx = 0; idx < 8; idx++) + { + sinfo->pph_lif_ext_size[idx] = kmsg->pph_lif_ext_size[idx]; + } + for (idx = 0; idx < 4; idx++) + { + sinfo->udh_length_type[idx] = kmsg->udh_length_type[idx]; + } + sinfo->udh_size = kmsg->udh_size; + sinfo->oamp_punt = kmsg->oamp_punted; + sinfo->no_skip_udh_check = kmsg->no_skip_udh_check; + sinfo->system_headers_mode = kmsg->system_headers_mode; + sinfo->udh_enable = kmsg->udh_enable; + } + + /* 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; + } + } + + /* 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); + + /* Init DCBs */ + bkn_init_dcbs(sinfo); + + 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); + if (sinfo->evt_idx != -1) { + /* 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_reprobe(kcom_msg_reprobe_t *kmsg, int len) +{ + kmsg->hdr.type = KCOM_MSG_TYPE_RSP; + + /* 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_reprobe_t); + } + + return sizeof(kcom_msg_reprobe_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_t *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; + /* System headers are prepared at BCM API for Dune headers */ + if (device_is_sand(sinfo)) { + int idx = 0; + for (idx = 0; idx < KCOM_NETIF_SYSTEM_HEADERS_SIZE_MAX; idx++) + { + priv->system_headers[idx] = kmsg->netif.system_headers[idx]; + } + priv->system_headers_size = kmsg->netif.system_headers_size; + } + if (priv->type == KCOM_NETIF_T_PORT) { + priv->port = kmsg->netif.port; + priv->phys_port = kmsg->netif.phys_port; + priv->qnum = kmsg->netif.qnum; + } else { + if (device_is_sand(sinfo) && (priv->type == KCOM_NETIF_T_VLAN)) { + /* PTCH.SSPA */ + 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); + + if (device_is_sand(sinfo)) { + int idx = 0; + for (idx = 0; idx < priv->system_headers_size; idx++) { + DBG_DUNE(("System Header[%d]: 0x%02x\n", idx, priv->system_headers[idx])); + } + } + + 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; + kmsg->netif.cb_user_data = priv->cb_user_data; + + 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)); + if (device_is_sand(sinfo)) { + int idx, wsize; + wsize = BYTES2WORDS(filter->kf.oob_data_size + filter->kf.pkt_data_size); + DBG_DUNE(("Filter: oob_data_size = %d pkt_data_size=%d wsize %d\n", filter->kf.oob_data_size, filter->kf.pkt_data_size, wsize)); + for (idx = 0; idx < wsize; idx++) + { + DBG_DUNE(("OOB[%d]: 0x%08x [0x%08x]\n", idx, filter->kf.data.w[idx], filter->kf.mask.w[idx])); + } + DBG_DUNE(("DNX system headers parameters:LB_KEY_EXT %d, STK_EXT %d, PPH_BASE %d, LIF_EXT %d %d %d, UDH_ENA %d, %d %d %d %d\n", + sinfo->ftmh_lb_key_ext_size, sinfo->ftmh_stacking_ext_size, sinfo->pph_base_size, + sinfo->pph_lif_ext_size[1],sinfo->pph_lif_ext_size[2], sinfo->pph_lif_ext_size[3], + sinfo->udh_enable, sinfo->udh_length_type[0], sinfo->udh_length_type[1], sinfo->udh_length_type[2], sinfo->udh_length_type[3])); + } + 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_knet_wb_cleanup(kcom_msg_wb_cleanup_t *kmsg, int len) +{ + bkn_switch_info_t *sinfo; + bkn_dcb_chain_t *dcb_chain; + 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); + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + 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; + sinfo->rx[chan].api_active = 0; + } + + spin_unlock_irqrestore(&sinfo->lock, flags); + + return sizeof(kcom_msg_hdr_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_REPROBE: + DBG_CMD(("KCOM_M_REPROBE\n")); + /* Reprobe device */ + len = bkn_knet_reprobe(&kmsg->reprobe, 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; + case KCOM_M_WB_CLEANUP: + DBG_CMD(("KCOM_M_WB_CLEANUP\n")); + /* Clean up for warmbooting */ + len = bkn_knet_wb_cleanup(&kmsg->wb_cleanup, len); + break; + case KCOM_M_CLOCK_CMD: + /* PHC clock control*/ + if (knet_hw_tstamp_ioctl_cmd_cb) { + bkn_switch_info_t *sinfo; + sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit); + if (sinfo == NULL) { + /* The device is not probed or initialized yet.*/ + return 0; + } + DBG_CMD(("KCOM_M_CLOCK_CMD\n")); + len = knet_hw_tstamp_ioctl_cmd_cb(&kmsg->clock_cmd, len, sinfo->dcb_type); + } else { + 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; + 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_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)); + dev_no = last_dev_no; + 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_no)); + continue; + } + + if (sinfo->evt_idx == -1) { + /* Event queue is not ready yet */ + 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) || + (_bkn_multi_inst && (dev_no == dev_evt))) { + evt = &_bkn_evt[sinfo->evt_idx]; + DBG_INST(("dev_no %d dev_evt %d wait queue index %d\n", + dev_no, dev_evt, 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 +_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; + + 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); + skb_queue_purge(&sinfo->tx_ptp_queue); + 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; + 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); + spin_unlock_irqrestore(&sinfo->lock, flags); + + 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; + } + + /* 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; + } + + /* 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; + 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); + + 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_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. + * + * The HW timestamp callbacks invoke an external module to enable, disable + * HW timestamp on a specific port which is indicated while the netif is + * created through KNET API. KNET can also get device-specific SOBMH and + * timestamp for a Tx PTP packet through these callbacks. + */ + +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; +} + +int +bkn_hw_tstamp_enable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb) +{ + if (knet_hw_tstamp_enable_cb != NULL) { + return -1; + } + knet_hw_tstamp_enable_cb = hw_tstamp_enable_cb; + return 0; +} + +int +bkn_hw_tstamp_enable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb) +{ + if (hw_tstamp_enable_cb == NULL || + knet_hw_tstamp_enable_cb != hw_tstamp_enable_cb) { + return -1; + } + knet_hw_tstamp_enable_cb = NULL; + return 0; +} + +int +bkn_hw_tstamp_disable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb) +{ + if (knet_hw_tstamp_disable_cb != NULL) { + return -1; + } + knet_hw_tstamp_disable_cb = hw_tstamp_disable_cb; + return 0; +} + +int +bkn_hw_tstamp_disable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb) +{ + if (hw_tstamp_disable_cb == NULL || + knet_hw_tstamp_disable_cb != hw_tstamp_disable_cb) { + return -1; + } + knet_hw_tstamp_disable_cb = NULL; + return 0; +} + +int +bkn_hw_tstamp_tx_time_get_cb_register(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb) +{ + if (knet_hw_tstamp_tx_time_get_cb != NULL) { + return -1; + } + knet_hw_tstamp_tx_time_get_cb = hw_tstamp_tx_time_get_cb; + return 0; +} + +int +bkn_hw_tstamp_tx_time_get_cb_unregister(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb) +{ + if (hw_tstamp_tx_time_get_cb == NULL || + knet_hw_tstamp_tx_time_get_cb != hw_tstamp_tx_time_get_cb) { + return -1; + } + knet_hw_tstamp_tx_time_get_cb = NULL; + return 0; +} + +int +bkn_hw_tstamp_tx_meta_get_cb_register(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb) +{ + if (knet_hw_tstamp_tx_meta_get_cb != NULL) { + return -1; + } + knet_hw_tstamp_tx_meta_get_cb = hw_tstamp_tx_meta_get_cb; + return 0; +} + +int +bkn_hw_tstamp_tx_meta_get_cb_unregister(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb) +{ + if (hw_tstamp_tx_meta_get_cb == NULL || + knet_hw_tstamp_tx_meta_get_cb != hw_tstamp_tx_meta_get_cb) { + return -1; + } + knet_hw_tstamp_tx_meta_get_cb = NULL; + return 0; +} + +int +bkn_hw_tstamp_ptp_clock_index_cb_register(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb) +{ + if (knet_hw_tstamp_ptp_clock_index_cb != NULL) { + return -1; + } + knet_hw_tstamp_ptp_clock_index_cb = hw_tstamp_ptp_clock_index_cb; + return 0; +} + +int +bkn_hw_tstamp_ptp_clock_index_cb_unregister(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb) +{ + if (hw_tstamp_ptp_clock_index_cb == NULL || + knet_hw_tstamp_ptp_clock_index_cb != hw_tstamp_ptp_clock_index_cb) { + return -1; + } + knet_hw_tstamp_ptp_clock_index_cb = NULL; + return 0; +} + +int +bkn_hw_tstamp_rx_time_upscale_cb_register(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb) +{ + if (knet_hw_tstamp_rx_time_upscale_cb != NULL) { + return -1; + } + knet_hw_tstamp_rx_time_upscale_cb = hw_tstamp_rx_time_upscale_cb; + return 0; +} + +int +bkn_hw_tstamp_rx_time_upscale_cb_unregister(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb) +{ + if (hw_tstamp_rx_time_upscale_cb == NULL || + knet_hw_tstamp_rx_time_upscale_cb != hw_tstamp_rx_time_upscale_cb) { + return -1; + } + knet_hw_tstamp_rx_time_upscale_cb = NULL; + return 0; +} + +int +bkn_hw_tstamp_ioctl_cmd_cb_register(knet_hw_tstamp_ioctl_cmd_cb_f hw_tstamp_ioctl_cmd_cb) +{ + if (knet_hw_tstamp_ioctl_cmd_cb != NULL) { + return -1; + } + knet_hw_tstamp_ioctl_cmd_cb = hw_tstamp_ioctl_cmd_cb; + return 0; +} + +int +bkn_hw_tstamp_ioctl_cmd_cb_unregister(knet_hw_tstamp_ioctl_cmd_cb_f hw_tstamp_ioctl_cmd_cb) +{ + if (knet_hw_tstamp_ioctl_cmd_cb == NULL || + knet_hw_tstamp_ioctl_cmd_cb != hw_tstamp_ioctl_cmd_cb) { + return -1; + } + knet_hw_tstamp_ioctl_cmd_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); +LKM_EXPORT_SYM(bkn_hw_tstamp_enable_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_enable_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_disable_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_disable_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_tx_time_get_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_tx_time_get_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_tx_meta_get_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_tx_meta_get_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_ptp_clock_index_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_ptp_clock_index_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_rx_time_upscale_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_rx_time_upscale_cb_unregister); +LKM_EXPORT_SYM(bkn_hw_tstamp_ioctl_cmd_cb_register); +LKM_EXPORT_SYM(bkn_hw_tstamp_ioctl_cmd_cb_unregister); diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/include/bcm-knet.h b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/include/bcm-knet.h @@ -0,0 +1,141 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <stdint.h> +#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 <linux/skbuff.h> + +typedef struct { + uint32 netif_user_data; + uint32 filter_user_data; + uint16 dcb_type; + int port; + uint64_t ts; + uint32 hwts; +} knet_skb_cb_t; + +#define KNET_SKB_CB(_skb) ((knet_skb_cb_t *)_skb->cb) + +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); + +typedef int +(*knet_hw_tstamp_enable_cb_f)(int dev_no, int phys_port, int tx_type); + +typedef int +(*knet_hw_tstamp_tx_time_get_cb_f)(int dev_no, int phys_port, uint8_t *pkt, uint64_t *ts); + +typedef int +(*knet_hw_tstamp_tx_meta_get_cb_f)(int dev_no, int hwts, int hdrlen, struct sk_buff *skb, uint64_t *ts, uint32_t **md); + +typedef int +(*knet_hw_tstamp_ptp_clock_index_cb_f)(int dev_no); + +typedef int +(*knet_hw_tstamp_rx_time_upscale_cb_f)(int dev_no, int phys_port, struct sk_buff *skb, uint32_t *meta, uint64_t *ts); + +typedef int +(*knet_hw_tstamp_ioctl_cmd_cb_f)(kcom_msg_clock_cmd_t *kmsg, int len, int dcb_type); + +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); + +extern int +bkn_hw_tstamp_enable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb); + +extern int +bkn_hw_tstamp_enable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb); + +extern int +bkn_hw_tstamp_disable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb); + +extern int +bkn_hw_tstamp_disable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb); + +extern int +bkn_hw_tstamp_tx_time_get_cb_register(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb); + +extern int +bkn_hw_tstamp_tx_time_get_cb_unregister(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb); + +extern int +bkn_hw_tstamp_tx_meta_get_cb_register(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb); + +extern int +bkn_hw_tstamp_tx_meta_get_cb_unregister(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb); + +extern int +bkn_hw_tstamp_ptp_clock_index_cb_register(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb); + +extern int +bkn_hw_tstamp_ptp_clock_index_cb_unregister(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb); + +extern int +bkn_hw_tstamp_rx_time_upscale_cb_register(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb); + +extern int +bkn_hw_tstamp_rx_time_upscale_cb_unregister(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb); + +extern int +bkn_hw_tstamp_ioctl_cmd_cb_register(knet_hw_tstamp_ioctl_cmd_cb_f hw_tstamp_ioctl_cmd_cb); + +extern int +bkn_hw_tstamp_ioctl_cmd_cb_unregister(knet_hw_tstamp_ioctl_cmd_cb_f hw_tstamp_ioctl_cmd_cb); + +#endif + +#endif /* __LINUX_BCM_KNET_H__ */ diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/include/gmodule.h b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/include/gmodule.h @@ -0,0 +1,65 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <lkm.h> + +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/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/include/lkm.h b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/include/lkm.h @@ -0,0 +1,188 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <linux/init.h> +#include <linux/version.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#include <linux/config.h> +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) +/* The version kconfig.h became available in. */ +#include <linux/kconfig.h> +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) +#if defined(INCLUDE_KNET) && LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0) +#ifdef CONFIG_NF_CONNTRACK_MODULE +#include <linux/netfilter.h> +#endif +#endif +#include <linux/slab.h> +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) +#include <linux/smp_lock.h> +#endif +#include <linux/module.h> + +/* 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 <linux/kernel.h> /* printk() */ +#include <linux/fs.h> /* everything... */ +#include <linux/errno.h> /* error codes */ +#include <linux/types.h> /* size_t */ +#include <linux/proc_fs.h> +#include <linux/fcntl.h> /* O_ACCMODE */ +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/stat.h> +#include <linux/sched.h> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0) +#include <linux/sched/signal.h> +#endif +#include <linux/delay.h> + +#include <asm/io.h> +#include <asm/hardirq.h> +#include <asm/uaccess.h> + +#ifdef CONFIG_DEVFS_FS +#include <linux/devfs_fs_kernel.h> +#endif + +#define PROC_INTERFACE_KERN_VER_3_10 (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) + +/* Compatibility Macros */ + +#ifdef LKM_2_4 + +#include <linux/compatmac.h> +#include <linux/wrapper.h> +#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/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/knet-cb/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/knet-cb/Makefile @@ -0,0 +1,64 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- Makefile -*- +# $Id: Makefile,v 1.3 Broadcom SDK $ +# $Copyright: (c) 2005 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/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c @@ -0,0 +1,134 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* + * Test driver for call-back functions in Linux KNET driver. + * + * 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/gto-2_6 + * BUILD_KNET_CB=1 make -s mod + * + */ + +#include <gmodule.h> /* Must be included first */ +#include <kcom.h> +#include <bcm-knet.h> + +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" + +static void +show_mac(struct sk_buff *skb) +{ + printk("DMAC=%02X:%02X:%02X:%02X:%02X:%02X\n", + skb->data[0], skb->data[1], skb->data[2], + skb->data[3], skb->data[4], skb->data[5]); +} + +static struct sk_buff * +test_rx_cb(struct sk_buff *skb, int dev_no, void *meta) +{ + printk("rx_cb for dev %d\n", dev_no); + printk("netif user data 0x%x\n", KNET_SKB_CB(skb)->netif_user_data); + printk("filter user data 0x%x\n", KNET_SKB_CB(skb)->filter_user_data); + printk("dcb type 0x%x\n", KNET_SKB_CB(skb)->dcb_type); + if (skb->data[5] == 0x03) { + dev_kfree_skb(skb); + return NULL; + } + show_mac(skb); + return skb; +} + +static struct sk_buff * +test_tx_cb(struct sk_buff *skb, int dev_no, void *meta) +{ + printk("tx_cb for dev %d\n", dev_no); + show_mac(skb); + skb->data[5] += 1; + return skb; +} + +static int +test_filter_cb(uint8_t *pkt, int size, int dev_no, void *meta, + int chan, kcom_filter_t *kf) +{ + printk("filter_cb (%d) for dev %d\n", kf->dest_id, dev_no); + if (pkt[12] == 0x81 && pkt[13] == 0x00) { + printk(" VTAG %d\n", pkt[15]); + kf->dest_type = KCOM_DEST_T_NETIF; + kf->dest_id = pkt[15]; + return 1; + } + return 0; +} + +/* + * Generic module functions + */ + +static int +_pprint(void) +{ + pprintf("Broadcom Linux KNET Call-Back Driver\n"); + + return 0; +} + +static int +_cleanup(void) +{ + bkn_rx_skb_cb_unregister(test_rx_cb); + bkn_tx_skb_cb_unregister(test_tx_cb); + bkn_filter_cb_unregister(test_filter_cb); + + return 0; +} + +static int +_init(void) +{ + bkn_rx_skb_cb_register(test_rx_cb); + bkn_tx_skb_cb_register(test_tx_cb); + bkn_filter_cb_register(test_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/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/shared/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/shared/Makefile @@ -0,0 +1,29 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/shared/gmodule.c b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/shared/gmodule.c @@ -0,0 +1,427 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $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 <lkm.h> +#include <gmodule.h> +#include <linux/init.h> +#include <linux/seq_file.h> + +/* 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/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/shared/ksal.c b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/shared/ksal.c @@ -0,0 +1,249 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: ksal.c,v 1.1 Broadcom SDK $ + * $Copyright: (c) 2005 Broadcom Corp. + * All Rights Reserved.$ + */ + +#include <sal/core/sync.h> +#include <sal/core/thread.h> + +#include "lkm.h" +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +#include <linux/semaphore.h> +#else +#include <asm/semaphore.h> +#endif +#include <linux/interrupt.h> +#include <linux/sched.h> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) +#include <linux/sched/rt.h> +#endif +#include <linux/time.h> + +#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(&ltv); + 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/sdk-6.5.20/src/gpl-modules/systems/linux/user/common/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/common/Makefile @@ -0,0 +1,229 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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 + +ifneq ($(kernel_version),2_4) +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) + +KNET_CB_LOCAL := linux-knet-cb.$(KOBJ) +KNET_CB := $(DEST_DIR)/$(KNET_CB_LOCAL) + +BCM_KNET_LOCAL :=linux-bcm-knet.$(KOBJ) +BCM_KNET=$(DEST_DIR)/$(BCM_KNET_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 + +ifdef BUILD_KNET_CB +all_targets += $(KNET_CB) + +ifeq ($(NO_LOCAL_TARGETS),) +LOCAL_TARGETS +=$(patsubst %,../$(platform)/%,$(KNET_CB_LOCAL)) +all_targets +=$(LOCAL_TARGETS) +endif +endif + +ADD_TO_CFLAGS += -I$(SDK)/systems/linux/kernel/modules/include +COND_KNET_LIBS = libuser.$(libext) +endif + +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_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) -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \ + subdirs="shared bcm-knet" override-target=linux-$(platform) CFLAGS="$(CFLAGS)" +ifdef BUILD_KNET_CB + $(MAKE) -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \ + subdirs="knet-cb" override-target=linux-$(platform) CFLAGS="$(CFLAGS)" +endif +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="shared bcm-knet knet-cb" \ + override-target=linux-$(platform) $@ + $(RM) $(KERNEL_BDE) $(USER_BDE) + $(RM) $(BCM_KNET) $(KNET_CB) + $(RM) $(KERN_BLDROOT)/linux-kernel-bde.$(KOBJ) + $(RM) $(KERN_BLDROOT)/linux-user-bde.$(KOBJ) + $(RM) $(KERN_BLDROOT)/linux-bcm-knet.$(KOBJ) + $(RM) $(KERN_BLDROOT)/linux-knet-cb.$(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/sdk-6.5.20/src/gpl-modules/systems/linux/user/gts/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/gts/Makefile @@ -0,0 +1,63 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- Makefile -*- +# $Id: Makefile,v 0.1 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: +# +# TOOLS_DIR - path to build tools (if not in PATH already) +# 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_19 +platform=gts +LINUX_MAKE_USER=1 +export LINKER_RELAX = 1 +export ADD_TO_CFLAGS +export BR_NO_CCACHE + + +include ${SDK}/make/Make.linux + diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/user/iproc-3_14/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/iproc-3_14/Makefile @@ -0,0 +1,65 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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/sdk-6.5.20/src/gpl-modules/systems/linux/user/iproc-4_4/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/iproc-4_4/Makefile @@ -0,0 +1,59 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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-$(kernel_version) + +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/sdk-6.5.20/src/gpl-modules/systems/linux/user/iproc/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/iproc/Makefile @@ -0,0 +1,59 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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_14 +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/sdk-6.5.20/src/gpl-modules/systems/linux/user/iproc_64/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/iproc_64/Makefile @@ -0,0 +1,59 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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_14 +platform=iproc_64 + +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/sdk-6.5.20/src/gpl-modules/systems/linux/user/slk/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/slk/Makefile @@ -0,0 +1,60 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- Makefile -*- +# $Id: Makefile,v 0.1 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: +# +# TOOLS_DIR - path to build tools (if not in PATH already) +# 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=slk +LINUX_MAKE_USER=1 +export LINKER_RELAX = 1 + +include ${SDK}/make/Make.linux + diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile @@ -0,0 +1,45 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- 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/sdk-6.5.20/src/gpl-modules/systems/linux/user/xlr/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/xlr/Makefile @@ -0,0 +1,63 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# -*- Makefile -*- +# $Id: Makefile,v 0.1 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: +# +# TOOLS_DIR - path to build tools (if not in PATH already) +# 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_19 +platform=xlr +LINUX_MAKE_USER=1 +export LINKER_RELAX = 1 +export ADD_TO_CFLAGS +export BR_NO_CCACHE + + +include ${SDK}/make/Make.linux + diff --git a/sdk-6.5.20/src/gpl-modules/tools/mktool.pl b/sdk-6.5.20/src/gpl-modules/tools/mktool.pl @@ -0,0 +1,292 @@ +# +# Copyright 2017 Broadcom +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation (the "GPL"). +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License version 2 (GPLv2) for more details. +# +# You should have received a copy of the GNU General Public License +# version 2 (GPLv2) along with this source code. +# +# +# 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 <<MKTOOL; + +mktool.pl:: +curdir $curdir + +MKTOOL + + # derive the path to the target + $curdir = "$sdk/$curdir"; + + # save the basename + $dirName = substr($target,0,rindex($target,"\/")); + + # prepare the top line of the %.d file + $resultant="$source \\\n\${BLDDIR}/"; + if(!$?) + { + foreach $line (@result) + { + $line =~ s/^#.*\n//g; # some makedeps produce comments + $line =~ s/\n+$//; # toss trailing newlines + $line =~ s/(\s+)(\.\/)/ /g; # remove leading ./ + + # insert SDK path before ../ + $line =~ s/(\s+)(\.\.\/)/${1}$curdir\/${2}/g; + + # insert SDK path + $line =~ s/(\s+)(\w+)/${1}$curdir\/${2}/g; + + $count=0; + $tmp=$line; + while( (index($line,"..")>-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"; +}