[BCMSAI] Update BCMSAI debian to 4.3.0.10 with 6.5.21 SDK, and opennsl module to 6.5.21 (#6526)

BCMSAI 4.3.0.10, 6.5.21 SDK release with enhancements and fixes for vxlan, TD3 MMU, TD4-X9 EA support, etc.
This commit is contained in:
Mahesh Maddikayala 2021-01-28 08:38:47 -08:00 committed by Danny Allen
parent c7d8faee18
commit bc2a13136a
152 changed files with 27192 additions and 855 deletions

View File

@ -1,6 +1,6 @@
# Broadcom SAI modules
BRCM_OPENNSL_KERNEL_VERSION = 4.2.1.3-1
BRCM_OPENNSL_KERNEL_VERSION = 4.3.0.10-2
BRCM_OPENNSL_KERNEL = opennsl-modules_$(BRCM_OPENNSL_KERNEL_VERSION)_amd64.deb
$(BRCM_OPENNSL_KERNEL)_SRC_PATH = $(PLATFORM_PATH)/saibcm-modules

View File

@ -1,8 +1,8 @@
BRCM_SAI = libsaibcm_4.2.1.5-10_amd64.deb
$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/4.2/master/buster/libsaibcm_4.2.1.5-10_amd64.deb?sv=2019-12-12&st=2021-01-12T07%3A30%3A31Z&se=2035-01-13T07%3A30%3A00Z&sr=b&sp=r&sig=yCGwk%2FW%2Fg%2FaFxhr0oNSTZ%2BVy5B6kX1WDEsbbyz9J088%3D"
BRCM_SAI_DEV = libsaibcm-dev_4.2.1.5-10_amd64.deb
BRCM_SAI = libsaibcm_4.3.0.10-2_amd64.deb
$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/4.3/master/libsaibcm_4.3.0.10-2_amd64.deb?sv=2015-04-05&sr=b&sig=1L2kJwYBuXDc9ObuVBBUS%2F%2FBVIfAA651ig5k6O1ZztE%3D&se=2022-06-10T21%3A25%3A43Z&sp=r"
BRCM_SAI_DEV = libsaibcm-dev_4.3.0.10-2_amd64.deb
$(eval $(call add_derived_package,$(BRCM_SAI),$(BRCM_SAI_DEV)))
$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/4.2/master/buster/libsaibcm-dev_4.2.1.5-10_amd64.deb?sv=2019-12-12&st=2021-01-12T07%3A32%3A43Z&se=2035-01-13T07%3A32%3A00Z&sr=b&sp=r&sig=wuCNc6pa12JQCBi%2BM9rLWvVI92ldan9hKNF%2BfVfUWN8%3D"
$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/4.3/master/libsaibcm-dev_4.3.0.10-2_amd64.deb?sv=2015-04-05&sr=b&sig=2Vm6o8HtbjI%2BfVoHJUiO5b75USqGra9CLSFXViQm8yM%3D&se=2022-06-10T21%3A26%3A35Z&sp=r"
SONIC_ONLINE_DEBS += $(BRCM_SAI)
$(BRCM_SAI_DEV)_DEPENDS += $(BRCM_SAI)

View File

@ -1,3 +1,10 @@
opennsl (4.3.0.10-2) unstable; urgency=medium
* Update to Broadcom SAI 4.3.0.10
* Added SDKLT modules 4.3.0.10-2
-- Mahesh Maddikayala <samaddik@microsoft.com> Thu, 21 Jan 2021 18:36:38 +0000
opennsl (4.2.1.3-1) unstable; urgency=medium
* Update to Broadcom SAI 4.2.1.3

View File

@ -18,7 +18,9 @@ function create_devices()
rm -f /dev/linux-bcm-knet
rm -f /dev/linux-bcm-bde
rm -f /dev/linux-kernel-bde
rm -f /dev/linux_ngbde
mknod /dev/linux_ngbde c 120 0
mknod /dev/linux-knet-cb c 121 0
mknod /dev/linux-bcm-knet c 122 0
mknod /dev/linux-bcm-bde c 126 0
@ -57,8 +59,9 @@ function load_kernel_modules()
# There is a different psample.ko module getting created at net/psample/psample.ko
insmod /lib/modules/$(uname -r)/extra/psample.ko
modprobe linux-bcm-knet use_rx_skb=1 rx_buffer_size=9238 debug=0x5020
modprobe linux-bcm-knet use_rx_skb=1 rx_buffer_size=9238 debug=0x5020 default_mtu=9100
modprobe linux-knet-cb
modprobe linux_ngbde
}
function remove_kernel_modules()
@ -68,6 +71,7 @@ function remove_kernel_modules()
rmmod linux-bcm-knet
rmmod linux-user-bde
rmmod linux-kernel-bde
rmmod linux_ngbde
}
case "$1" in

View File

@ -5,3 +5,4 @@ systems/linux/user/x86-smp_generic_64-2_6/linux-knet-cb.ko lib/modules/4.19.0-9-
systems/linux/user/x86-smp_generic_64-2_6/psample.ko lib/modules/4.19.0-9-2-amd64/extra
systems/linux/user/x86-smp_generic_64-2_6/linux-bcm-ptp-clock.ko lib/modules/4.19.0-9-2-amd64/extra
systemd/opennsl-modules.service lib/systemd/system
sdklt/linux/bde/linux_ngbde.ko lib/modules/4.19.0-9-2-amd64/extra

View File

@ -67,6 +67,9 @@ kdist_clean: clean
KERNDIR=/usr/src/linux-headers-$(KERNVERSION)-common \
KERNEL_SRC=/usr/src/linux-headers-$(KERNVERSION)-amd64 \
$(MAKE) -C systems/linux/user/x86-smp_generic_64-2_6 clean
SDK=$(realpath .) BUILD_KNET_CB=1 BUILD_PSAMPLE=1 \
KDIR=/usr/src/linux-headers-$(KERNVERSION)-common \
$(MAKE) -C sdklt/ clean
# rm -f driver/*.o driver/*.ko
#
### end KERNEL SETUP
@ -100,6 +103,10 @@ build-arch-stamp:
KERNEL_SRC=/usr/src/linux-headers-$(KERNVERSION)-amd64 \
$(MAKE) -C systems/linux/user/x86-smp_generic_64-2_6
SDK=$(realpath .) BUILD_KNET_CB=1 BUILD_PSAMPLE=1 \
KDIR=/usr/src/linux-headers-$(KERNVERSION)-common \
$(MAKE) -C sdklt/ kmod
touch $@
#k = $(shell echo $(KVERS) | grep -q ^2.6 && echo k)
@ -128,6 +135,10 @@ clean:
KERNEL_SRC=/usr/src/linux-headers-$(KERNVERSION)-amd64 \
$(MAKE) -C systems/linux/user/x86-smp_generic_64-2_6 clean
SDK=$(realpath .) BUILD_KNET_CB=1 BUILD_PSAMPLE=1 \
KDIR=/usr/src/linux-headers-$(KERNVERSION)-common \
$(MAKE) -C sdklt/ clean
dh_clean
install: DH_OPTIONS=

View File

@ -1,5 +1,10 @@
/*
* Copyright 2017 Broadcom
* Copyright 2007-2020 Broadcom Inc. All rights reserved.
*
* Permission is granted to use, copy, modify and/or distribute this
* software under either one of the licenses below.
*
* License Option 1: GPL
*
* 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
@ -12,6 +17,12 @@
*
* You should have received a copy of the GNU General Public License
* version 2 (GPLv2) along with this source code.
*
*
* License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
*
* This software is governed by the Broadcom Open Network Switch APIs license:
* https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
*/
/*
* $Id: ibde.h,v 1.27 Broadcom SDK $

View File

@ -1,5 +1,10 @@
/*
* Copyright 2017 Broadcom
* Copyright 2007-2020 Broadcom Inc. All rights reserved.
*
* Permission is granted to use, copy, modify and/or distribute this
* software under either one of the licenses below.
*
* License Option 1: GPL
*
* 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
@ -12,6 +17,12 @@
*
* You should have received a copy of the GNU General Public License
* version 2 (GPLv2) along with this source code.
*
*
* License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
*
* This software is governed by the Broadcom Open Network Switch APIs license:
* https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
*/
/*
* $Id: kcom.h,v 1.9 Broadcom SDK $
@ -341,6 +352,8 @@ typedef struct kcom_msg_version_s {
#define KSYNC_M_HW_DEINIT 1
#define KSYNC_M_VERSION 2
#define KSYNC_M_HW_TS_DISABLE 3
#define KSYNC_M_MTP_TS_UPDATE_ENABLE 4
#define KSYNC_M_MTP_TS_UPDATE_DISABLE 5
typedef struct kcom_clock_info_s {
uint8 cmd;

View File

@ -1,5 +1,10 @@
/*
* Copyright 2017 Broadcom
* Copyright 2007-2020 Broadcom Inc. All rights reserved.
*
* Permission is granted to use, copy, modify and/or distribute this
* software under either one of the licenses below.
*
* License Option 1: GPL
*
* 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
@ -12,6 +17,12 @@
*
* You should have received a copy of the GNU General Public License
* version 2 (GPLv2) along with this source code.
*
*
* License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
*
* This software is governed by the Broadcom Open Network Switch APIs license:
* https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
*/
/*
* $Id: sync.h,v 1.1 Broadcom SDK $

View File

@ -1,5 +1,10 @@
/*
* Copyright 2017 Broadcom
* Copyright 2007-2020 Broadcom Inc. All rights reserved.
*
* Permission is granted to use, copy, modify and/or distribute this
* software under either one of the licenses below.
*
* License Option 1: GPL
*
* 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
@ -12,6 +17,12 @@
*
* You should have received a copy of the GNU General Public License
* version 2 (GPLv2) along with this source code.
*
*
* License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
*
* This software is governed by the Broadcom Open Network Switch APIs license:
* https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
*/
/*
* $Id: thread.h,v 1.1 Broadcom SDK $

View File

@ -1,5 +1,10 @@
/*
* Copyright 2017 Broadcom
* Copyright 2007-2020 Broadcom Inc. All rights reserved.
*
* Permission is granted to use, copy, modify and/or distribute this
* software under either one of the licenses below.
*
* License Option 1: GPL
*
* 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
@ -12,6 +17,12 @@
*
* You should have received a copy of the GNU General Public License
* version 2 (GPLv2) along with this source code.
*
*
* License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
*
* This software is governed by the Broadcom Open Network Switch APIs license:
* https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
*/
/*
* $Id: types.h,v 1.3 Broadcom SDK $

View File

@ -1,5 +1,10 @@
/*
* Copyright 2017 Broadcom
* Copyright 2007-2020 Broadcom Inc. All rights reserved.
*
* Permission is granted to use, copy, modify and/or distribute this
* software under either one of the licenses below.
*
* License Option 1: GPL
*
* 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
@ -12,6 +17,12 @@
*
* You should have received a copy of the GNU General Public License
* version 2 (GPLv2) along with this source code.
*
*
* License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
*
* This software is governed by the Broadcom Open Network Switch APIs license:
* https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
*/
/*
* $Id: sdk_config.h,v 1.5 Broadcom SDK $

View File

@ -1,5 +1,10 @@
/*
* Copyright 2017 Broadcom
* Copyright 2007-2020 Broadcom Inc. All rights reserved.
*
* Permission is granted to use, copy, modify and/or distribute this
* software under either one of the licenses below.
*
* License Option 1: GPL
*
* 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
@ -12,6 +17,12 @@
*
* You should have received a copy of the GNU General Public License
* version 2 (GPLv2) along with this source code.
*
*
* License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
*
* This software is governed by the Broadcom Open Network Switch APIs license:
* https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
*/
/*
* Copyright: (c) 2020 Broadcom.
@ -1274,6 +1285,18 @@
#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 BCM56175_DEVICE_ID 0xb175
#define BCM56175_A1_REV_ID 2
#define BCM56176_DEVICE_ID 0xb176
#define BCM56176_A1_REV_ID 2
#define BCM53440_DEVICE_ID 0x8440
#define BCM53440_A0_REV_ID 1
#define BCM53440_B0_REV_ID 0x11
@ -1404,6 +1427,8 @@
#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
@ -1499,6 +1524,8 @@
#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
@ -1537,19 +1564,6 @@
#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
@ -1767,22 +1781,57 @@
#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 BCM88801_DEVICE_ID 0x8801
#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 BCM88807_DEVICE_ID 0x8807
#define BCM88808_DEVICE_ID 0x8808
#define BCM88809_DEVICE_ID 0x8809
#define BCM8880A_DEVICE_ID 0x880A
#define BCM8880B_DEVICE_ID 0x880B
#define BCM8880C_DEVICE_ID 0x880C
#define BCM8880D_DEVICE_ID 0x880D
#define BCM8880E_DEVICE_ID 0x880E
#define BCM8880F_DEVICE_ID 0x880F
#define BCM88821_DEVICE_ID 0x8821
#define BCM88822_DEVICE_ID 0x8822
#define BCM88823_DEVICE_ID 0x8823
#define BCM88824_DEVICE_ID 0x8824
#define BCM88825_DEVICE_ID 0x8825
#define BCM88826_DEVICE_ID 0x8826
#define BCM88827_DEVICE_ID 0x8827
#define BCM88828_DEVICE_ID 0x8828
#define BCM88829_DEVICE_ID 0x8829
#define BCM8882A_DEVICE_ID 0x882A
#define BCM8882B_DEVICE_ID 0x882B
#define BCM8882C_DEVICE_ID 0x882C
#define BCM8882D_DEVICE_ID 0x882D
#define BCM8882E_DEVICE_ID 0x882E
#define BCM8882F_DEVICE_ID 0x882F
#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 BCM88851_DEVICE_ID 0x8851
#define BCM88852_DEVICE_ID 0x8852
#define BCM88853_DEVICE_ID 0x8853
#define BCM88854_DEVICE_ID 0x8854
#define BCM88855_DEVICE_ID 0x8855
#define BCM88856_DEVICE_ID 0x8856
#define BCM88857_DEVICE_ID 0x8857
#define BCM88858_DEVICE_ID 0x8858
#define BCM88859_DEVICE_ID 0x8859
#define BCM8885A_DEVICE_ID 0x885A
#define BCM8885B_DEVICE_ID 0x885B
#define BCM8885C_DEVICE_ID 0x885C
#define BCM8885D_DEVICE_ID 0x885D
#define BCM8885E_DEVICE_ID 0x885E
#define BCM8885F_DEVICE_ID 0x885F
#define Q2A_DEVICE_ID 0x8480
#define Q2A_A0_REV_ID DNXC_A0_REV_ID
@ -1808,6 +1857,24 @@
#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
@ -1833,9 +1900,11 @@
#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
@ -1844,16 +1913,6 @@
#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
@ -1901,16 +1960,6 @@
#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
@ -1930,7 +1979,33 @@
#define BCM56883_DEVICE_ID 0xb883
#define BCM56883_A0_REV_ID 0x0001
#define BCM56883_B0_REV_ID 0x0011
#define BCM56889_DEVICE_ID 0xb889
#define BCM56889_A0_REV_ID 0x0001
#define BCM56889_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 BCM56789_DEVICE_ID 0xb789
#define BCM56789_A0_REV_ID 0x0001
#define BCM56990_DEVICE_ID 0xb990
#define BCM56990_A0_REV_ID 0x0001
#define BCM56990_B0_REV_ID 0x0011
#define BCM56992_DEVICE_ID 0xb992
#define BCM56992_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

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Make.config,v 1.3 Broadcom SDK $
# $Copyright: (c) 2005 Broadcom Corp.

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Make.depend,v 1.14 Broadcom SDK $
# $Copyright: (c) 2005 Broadcom Corp.

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Make.kernlib,v 1.7 Broadcom SDK $
# $Copyright: (c) 2005 Broadcom Corp.

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Make.lib,v 1.14 Broadcom SDK $
# $Copyright: (c) 2005 Broadcom Corp.
@ -62,7 +73,7 @@ endif
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}))
$(AR) ${ARFLAGS} $@ $(sort ${BOBJS})
endif
endif # !Borland

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
#
# $Id: Make.linux,v 1.18 Broadcom SDK $
@ -85,7 +96,7 @@ endif
build:
$(MAKE) $(CMD)
DELIVER clean C_COMPILER CXX_COMPILER variable mod bcm user issu:
DELIVER clean C_COMPILER CXX_COMPILER variable mod bcm user issu libopennsa:
$(MAKE) $(CMD) $@
clean_d: clean

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Make.subdirs,v 1.8 Broadcom SDK $
# $Copyright: (c) 2005 Broadcom Corp.

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Make.tools,v 1.2 Broadcom SDK $
# $Copyright: (c) 2005 Broadcom Corp.

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Makefile.linux-xlr-4_19,v 0.1 Broadcom SDK $
# $Copyright: (c) 2015 Broadcom Corp.
@ -37,6 +48,8 @@
# 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
# Target machine for EDK-Host defconfig
TARGET_MACHINE ?= x86_64
KERNDIR = $(XLR_TOOLS_BASE)/kernel/linux
# set up cross compile prefix, tools dir variables. #
@ -125,12 +138,21 @@ OPENSRC_BUILD ?= fed21-x86_64
# Hardware interface (see $SDKLT/bcma/sys/probe directory)
SYSTEM_INTERFACE ?= ngbde
# Support BCMSIM in the same build
ifeq (1,$(BCM_SIM_PATH_SUPPORT))
EXTRA_SYSTEM_INTERFACES = plisim
endif
# Turn on direct register access if running on real hardware.
ifeq (ngbde,$(SYSTEM_INTERFACE))
# Except if using multiple probe interfaces
ifeq (,$(EXTRA_SYSTEM_INTERFACES))
LTSW_ADD_CPPFLAGS += -DBCMDRD_CONFIG_MEMMAP_DIRECT=1
endif
endif
export SYSTEM_INTERFACE
export EXTRA_SYSTEM_INTERFACES
endif
ifneq ($(targetplat),user)

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Makefile.linux-iproc Exp $
# $Copyright: (c) 2007 Broadcom Corp.

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Makefile.linux-iproc-3_6,v 1.1 Broadcom SDK $
# $Copyright: (c) 2007 Broadcom Corp.

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Makefile.linux-iproc Exp $
# $Copyright: (c) 2007 Broadcom Corp.

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Makefile.linux-iproc Exp $
# $Copyright: (c) 2007 Broadcom Corp.

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Makefile.linux-kernel,v 1.27 Broadcom SDK $
# $Copyright: (c) 2005 Broadcom Corp.

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Makefile.linux-kernel-2_6,v 1.40 Broadcom SDK $
# $Copyright: (c) 2005 Broadcom Corp.

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Makefile.linux-kernel-3_6,v 1.2 Broadcom SDK $
# $Copyright: (c) 2005 Broadcom Corp.

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Makefile.linux-kernel-2_6,v 1.40 Broadcom SDK $
# $Copyright: (c) 2005 Broadcom Corp.

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Makefile.linux-kmodule-3_6,v 1.2 Broadcom SDK $
# $Copyright: (c) 2006 Broadcom Corp.
@ -61,6 +72,13 @@ KERNBLDDIR ?= $(KERNDIR)
# kernel symbols.
override EXTRA_CFLAGS = -I${SDK}/include -I${SDK}/systems/linux/kernel/modules/include -I${SDK}/systems/bde/linux/include
#
# If, for any reason, the definition of LD was erased, then
# set it, again.
#
ifeq ($(LD),)
LD = $(CROSS_COMPILE)ld
endif
# The precopiled object needs a dummy command file to avoid warnings
# from the Kbuild scripts (modpost stage).

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Makefile.linux-slk-3_14,v 1.2 Broadcom SDK $
# $Copyright: (c) 2013 Broadcom Corp.
@ -27,11 +38,15 @@ endif
ifeq (BE,$(ENDIAN_MODE))
TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/toolchains/slk/linaro-be
TARGET_ARCHITECTURE:=aarch64_be-linux-gnu
# Target machine for EDK-Host defconfig
TARGET_MACHINE ?= slk_be
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
# Target machine for EDK-Host defconfig
TARGET_MACHINE ?= slk_le
# Kernel directory
KERNDIR ?= /projects/ntsw-tools/linux/iproc_ldks/slk/poky/brcm-released-source/git
endif

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Makefile.linux-x86-common-2_6,v 1.13 Broadcom SDK $
# $Copyright: (c) 2005 Broadcom Corp.

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Makefile.linux-x86-generic-common-2_6,v 1.2 Broadcom SDK $
# $Copyright: (c) 2008 Broadcom Corp.
@ -48,5 +59,4 @@ AUTOCONF = $(KERNDIR)/include/linux/autoconf.h
endif
# gcc system include path
# SAI_FIXUP /* SDK-218654 */
SYSINC = $(shell $(CC) -print-search-dirs | grep install | cut -c 10-)include

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Makefile.linux-x86-smp_generic_64-2_6,v 1.5 Broadcom SDK $
# $Copyright: (c) 2008 Broadcom Corp.
@ -25,7 +36,7 @@ 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
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
ifeq ($(LINUX_MAKE_SHARED_LIB), 1)

View File

@ -1,5 +1,10 @@
#
# Copyright 2017 Broadcom
# Copyright 2007-2020 Broadcom Inc. All rights reserved.
#
# Permission is granted to use, copy, modify and/or distribute this
# software under either one of the licenses below.
#
# License Option 1: GPL
#
# 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
@ -12,6 +17,12 @@
#
# You should have received a copy of the GNU General Public License
# version 2 (GPLv2) along with this source code.
#
#
# License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
#
# This software is governed by the Broadcom Open Network Switch APIs license:
# https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
#
# $Id: Makefile.linux-xlr-4_19,v 0.1 Broadcom SDK $
# $Copyright: (c) 2015 Broadcom Corp.
@ -37,6 +48,8 @@
# 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
# Target machine for EDK-Host defconfig
TARGET_MACHINE ?= x86_64
KERNDIR = $(XLR_TOOLS_BASE)/kernel/linux
# set up cross compile prefix, tools dir variables. #
@ -125,12 +138,21 @@ OPENSRC_BUILD ?= fed21-x86_64
# Hardware interface (see $SDKLT/bcma/sys/probe directory)
SYSTEM_INTERFACE ?= ngbde
# Support BCMSIM in the same build
ifeq (1,$(BCM_SIM_PATH_SUPPORT))
EXTRA_SYSTEM_INTERFACES = plisim
endif
# Turn on direct register access if running on real hardware.
ifeq (ngbde,$(SYSTEM_INTERFACE))
# Except if using multiple probe interfaces
ifeq (,$(EXTRA_SYSTEM_INTERFACES))
LTSW_ADD_CPPFLAGS += -DBCMDRD_CONFIG_MEMMAP_DIRECT=1
endif
endif
export SYSTEM_INTERFACE
export EXTRA_SYSTEM_INTERFACES
endif
ifneq ($(targetplat),user)

View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@ -0,0 +1,83 @@
#
# $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
# The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# A copy of the GNU General Public License version 2 (GPLv2) can
# be found in the LICENSES folder.$
#
help:
@echo ''
@echo 'Build Linux GPL kernel modules for SDKLT.'
@echo ''
@echo 'Available make targets:'
@echo 'kmod - Build kernel modules'
@echo 'clean - Remove object files'
@echo ''
@echo 'Supported make variables:'
@echo 'KDIR - Linux kernel source directory (mandatory)'
@echo 'CROSS_COPILE - Cross-compiler prefix (optional)'
@echo ''
@echo 'Examples:'
@echo 'make -s KDIR=$$KERNEL/linux kmod'
@echo 'make -s clean'
@echo ''
ifndef KDIR
nokdir:
@echo 'Error: The $$KDIR environment variable is not set.'
@echo '$$KDIR must point to a configured Linux kernel source tree.'
exit 1
endif
export KDIR
export CROSS_COMPILE
override SDK := $(CURDIR)
ifeq ($(BUILD_PSAMPLE),1)
PSAMPLE=psample
PSAMPLE_SYMVERS=$(SDK)/linux/psample/Module.symvers
endif
kmod: bde knet knetcb $(PSAMPLE)
bde:
$(MAKE) -C $(SDK)/linux/bde SDK=$(SDK) \
$(TARGET)
ln -sf $(SDK)/linux/bde/*.ko
knet: bde
$(MAKE) -C $(SDK)/linux/knet SDK=$(SDK) \
KBUILD_EXTRA_SYMBOLS=$(SDK)/linux/bde/Module.symvers \
$(TARGET)
ln -sf $(SDK)/linux/knet/*.ko
knetcb: knet $(PSAMPLE)
$(MAKE) -C $(SDK)/linux/knetcb SDK=$(SDK) \
KBUILD_EXTRA_SYMBOLS=$(SDK)/linux/knet/Module.symvers \
KBUILD_EXTRA_SYMBOLS+=$(PSAMPLE_SYMVERS) \
$(TARGET)
ln -sf $(SDK)/linux/knetcb/*.ko
ifeq ($(BUILD_PSAMPLE),1)
$(PSAMPLE):
$(MAKE) -C $(SDK)/linux/psample SDK=$(SDK) \
$(TARGET)
ln -sf $(SDK)/linux/psample/*.ko
endif
clean:
$(MAKE) kmod TARGET=clean
rm -f *.ko
.PHONY: help kmod bde knet knetcb $(PSAMPLE) clean

View File

@ -0,0 +1,38 @@
/*! \file bcm56780_a0_pdma_attach.c
*
* Initialize PDMA driver resources.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <bcmcnet/bcmcnet_core.h>
#include <bcmcnet/bcmcnet_dev.h>
#include <bcmcnet/bcmcnet_cmicx.h>
int
bcm56780_a0_cnet_pdma_attach(struct pdma_dev *dev)
{
return bcmcnet_cmicx_pdma_driver_attach(dev);
}
int
bcm56780_a0_cnet_pdma_detach(struct pdma_dev *dev)
{
return bcmcnet_cmicx_pdma_driver_detach(dev);
}

View File

@ -0,0 +1,38 @@
/*! \file bcm56880_a0_pdma_attach.c
*
* Initialize PDMA driver resources.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <bcmcnet/bcmcnet_core.h>
#include <bcmcnet/bcmcnet_dev.h>
#include <bcmcnet/bcmcnet_cmicx.h>
int
bcm56880_a0_cnet_pdma_attach(struct pdma_dev *dev)
{
return bcmcnet_cmicx_pdma_driver_attach(dev);
}
int
bcm56880_a0_cnet_pdma_detach(struct pdma_dev *dev)
{
return bcmcnet_cmicx_pdma_driver_detach(dev);
}

View File

@ -0,0 +1,38 @@
/*! \file bcm56990_a0_pdma_attach.c
*
* Initialize PDMA driver resources.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <bcmcnet/bcmcnet_core.h>
#include <bcmcnet/bcmcnet_dev.h>
#include <bcmcnet/bcmcnet_cmicx.h>
int
bcm56990_a0_cnet_pdma_attach(struct pdma_dev *dev)
{
return bcmcnet_cmicx_pdma_driver_attach(dev);
}
int
bcm56990_a0_cnet_pdma_detach(struct pdma_dev *dev)
{
return bcmcnet_cmicx_pdma_driver_detach(dev);
}

View File

@ -0,0 +1,38 @@
/*! \file bcm56990_b0_pdma_attach.c
*
* Initialize PDMA driver resources.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <bcmcnet/bcmcnet_core.h>
#include <bcmcnet/bcmcnet_dev.h>
#include <bcmcnet/bcmcnet_cmicx.h>
int
bcm56990_b0_cnet_pdma_attach(struct pdma_dev *dev)
{
return bcmcnet_cmicx_pdma_driver_attach(dev);
}
int
bcm56990_b0_cnet_pdma_detach(struct pdma_dev *dev)
{
return bcmcnet_cmicx_pdma_driver_detach(dev);
}

View File

@ -0,0 +1,38 @@
/*! \file bcm56996_a0_pdma_attach.c
*
* Initialize PDMA driver resources.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <bcmcnet/bcmcnet_core.h>
#include <bcmcnet/bcmcnet_dev.h>
#include <bcmcnet/bcmcnet_cmicx.h>
int
bcm56996_a0_cnet_pdma_attach(struct pdma_dev *dev)
{
return bcmcnet_cmicx_pdma_driver_attach(dev);
}
int
bcm56996_a0_cnet_pdma_detach(struct pdma_dev *dev)
{
return bcmcnet_cmicx_pdma_driver_detach(dev);
}

View File

@ -0,0 +1,530 @@
/*! \file bcmcnet_cmicd_pdma_hw.c
*
* Utility routines for handling BCMCNET hardware (CMICd).
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <bcmcnet/bcmcnet_core.h>
#include <bcmcnet/bcmcnet_dev.h>
#include <bcmcnet/bcmcnet_rxtx.h>
#include <bcmcnet/bcmcnet_cmicd.h>
/*!
* Read 32-bit register
*/
static inline void
cmicd_pdma_reg_read32(struct pdma_hw *hw, uint32_t addr, uint32_t *data)
{
if (hw->dev->dev_read32) {
hw->dev->dev_read32(hw->dev, addr, data);
} else {
DEV_READ32(&hw->dev->ctrl, addr, data);
}
}
/*!
* Write 32-bit register
*/
static inline void
cmicd_pdma_reg_write32(struct pdma_hw *hw, uint32_t addr, uint32_t data)
{
if (hw->dev->dev_write32) {
hw->dev->dev_write32(hw->dev, addr, data);
} else {
DEV_WRITE32(&hw->dev->ctrl, addr, data);
}
}
/*!
* Enable interrupt for a channel
*/
static inline void
cmicd_pdma_intr_enable(struct pdma_hw *hw, int cmc, int chan, uint32_t mask)
{
uint32_t reg = CMICD_IRQ_STAT(cmc);
hw->dev->intr_unmask(hw->dev, cmc, chan, reg, mask);
}
/*!
* Disable interrupt for a channel
*/
static inline void
cmicd_pdma_intr_disable(struct pdma_hw *hw, int cmc, int chan, uint32_t mask)
{
uint32_t reg = CMICD_IRQ_STAT(cmc);
hw->dev->intr_mask(hw->dev, cmc, chan, reg, mask);
}
/*!
* Initialize HW
*/
static int
cmicd_pdma_hw_init(struct pdma_hw *hw)
{
dev_mode_t mode = DEV_MODE_MAX;
uint32_t val;
/* Temporarily upgrade work mode to get HW information in VNET mode. */
if (hw->dev->mode == DEV_MODE_VNET) {
mode = DEV_MODE_VNET;
hw->dev->mode = DEV_MODE_UNET;
}
/* Release credits to EP. Only do this once when HW is initialized. */
hw->hdls.reg_rd32(hw, CMICD_EPINTF_RELEASE_CREDITS, &val);
if (!val) {
hw->hdls.reg_wr32(hw, CMICD_EPINTF_RELEASE_CREDITS, 1);
}
hw->info.name = CMICD_DEV_NAME;
hw->hdls.reg_rd32(hw, CMICD_CMICM_REV_ID, &val);
hw->info.ver_no = val;
hw->hdls.reg_rd32(hw, CMICD_DEV_REV_ID, &val);
hw->info.dev_id = val & 0xffff;
hw->info.rev_id = val >> 16;
hw->info.num_cmcs = CMICD_PDMA_CMC_MAX;
hw->info.cmc_chans = CMICD_PDMA_CMC_CHAN;
hw->info.num_chans = CMICD_PDMA_CMC_MAX * CMICD_PDMA_CMC_CHAN;
hw->info.rx_dcb_size = CMICD_PDMA_DCB_SIZE;
hw->info.tx_dcb_size = CMICD_PDMA_DCB_SIZE;
hw->info.rx_ph_size = 0;
hw->info.tx_ph_size = 0;
/* Restore work mode to VNET. */
if (mode == DEV_MODE_VNET) {
hw->dev->mode = DEV_MODE_VNET;
}
return SHR_E_NONE;
}
/*!
* Configure HW
*/
static int
cmicd_pdma_hw_config(struct pdma_hw *hw)
{
struct dev_ctrl *ctrl = &hw->dev->ctrl;
struct pdma_rx_queue *rxq = NULL;
struct pdma_tx_queue *txq = NULL;
uint32_t val, que_ctrl;
int grp, que;
uint32_t qi;
for (qi = 0; qi < ctrl->nb_rxq; qi++) {
rxq = (struct pdma_rx_queue *)ctrl->rx_queue[qi];
grp = rxq->group_id;
que = rxq->chan_id % CMICD_PDMA_CMC_CHAN;
que_ctrl = ctrl->grp[grp].que_ctrl[que];
hw->hdls.reg_wr32(hw, CMICD_PDMA_STAT_CLR(grp), CMICD_PDMA_DESC_CMPLT(que));
hw->hdls.reg_wr32(hw, CMICD_PDMA_STAT_CLR(grp), CMICD_PDMA_DESC_CNTLD(que));
val = 0;
if (que_ctrl & PDMA_PKT_BYTE_SWAP) {
val |= CMICD_PDMA_PKT_BIG_ENDIAN;
}
if (que_ctrl & PDMA_OTH_BYTE_SWAP) {
val |= CMICD_PDMA_DESC_BIG_ENDIAN;
}
if (!(hw->dev->flags & PDMA_CHAIN_MODE)) {
val |= CMICD_PDMA_CONTINUOUS;
}
val |= CMICD_PDMA_CNTLD_INTR;
val &= ~CMICD_PDMA_DIR;
hw->hdls.reg_wr32(hw, CMICD_PDMA_CTRL(grp, que), val);
}
for (qi = 0; qi < ctrl->nb_txq; qi++) {
txq = (struct pdma_tx_queue *)ctrl->tx_queue[qi];
grp = txq->group_id;
que = txq->chan_id % CMICD_PDMA_CMC_CHAN;
que_ctrl = ctrl->grp[grp].que_ctrl[que];
hw->hdls.reg_wr32(hw, CMICD_PDMA_STAT_CLR(grp), CMICD_PDMA_DESC_CMPLT(que));
hw->hdls.reg_wr32(hw, CMICD_PDMA_STAT_CLR(grp), CMICD_PDMA_DESC_CNTLD(que));
val = 0;
if (que_ctrl & PDMA_PKT_BYTE_SWAP) {
val |= CMICD_PDMA_PKT_BIG_ENDIAN;
}
if (que_ctrl & PDMA_OTH_BYTE_SWAP) {
val |= CMICD_PDMA_DESC_BIG_ENDIAN;
}
if (!(hw->dev->flags & PDMA_CHAIN_MODE)) {
val |= CMICD_PDMA_CONTINUOUS;
}
val |= CMICD_PDMA_CNTLD_INTR | CMICD_PDMA_DIR;
hw->hdls.reg_wr32(hw, CMICD_PDMA_CTRL(grp, que), val);
}
return SHR_E_NONE;
}
/*!
* Reset HW
*/
static int
cmicd_pdma_hw_reset(struct pdma_hw *hw)
{
int gi, qi;
for (gi = 0; gi < hw->dev->num_groups; gi++) {
if (!hw->dev->ctrl.grp[gi].attached) {
continue;
}
for (qi = 0; qi < CMICD_PDMA_CMC_CHAN; qi++) {
if (1 << qi & hw->dev->ctrl.grp[gi].bm_rxq ||
1 << qi & hw->dev->ctrl.grp[gi].bm_txq) {
hw->hdls.reg_wr32(hw, CMICD_PDMA_CTRL(gi, qi), 0);
}
}
}
return SHR_E_NONE;
}
/*!
* Start a channel
*/
static int
cmicd_pdma_chan_start(struct pdma_hw *hw, int chan)
{
uint32_t val;
int grp, que;
grp = chan / CMICD_PDMA_CMC_CHAN;
que = chan % CMICD_PDMA_CMC_CHAN;
hw->hdls.reg_rd32(hw, CMICD_PDMA_CTRL(grp, que), &val);
val |= CMICD_PDMA_ENABLE;
hw->hdls.reg_wr32(hw, CMICD_PDMA_CTRL(grp, que), val);
MEMORY_BARRIER;
return SHR_E_NONE;
}
/*!
* Stop a channel
*/
static int
cmicd_pdma_chan_stop(struct pdma_hw *hw, int chan)
{
uint32_t val;
int grp, que;
int retry = CMICD_HW_RETRY_TIMES;
grp = chan / CMICD_PDMA_CMC_CHAN;
que = chan % CMICD_PDMA_CMC_CHAN;
hw->hdls.reg_rd32(hw, CMICD_PDMA_CTRL(grp, que), &val);
val |= CMICD_PDMA_ENABLE | CMICD_PDMA_ABORT;
hw->hdls.reg_wr32(hw, CMICD_PDMA_CTRL(grp, que), val);
MEMORY_BARRIER;
do {
val = ~CMICD_PDMA_ACTIVE(que);
hw->hdls.reg_rd32(hw, CMICD_PDMA_STAT(grp), &val);
} while ((val & CMICD_PDMA_ACTIVE(que)) && (--retry > 0));
hw->hdls.reg_rd32(hw, CMICD_PDMA_CTRL(grp, que), &val);
val &= ~(CMICD_PDMA_ENABLE | CMICD_PDMA_ABORT);
hw->hdls.reg_wr32(hw, CMICD_PDMA_CTRL(grp, que), val);
hw->hdls.reg_wr32(hw, CMICD_PDMA_STAT_CLR(grp), CMICD_PDMA_DESC_CNTLD(que));
MEMORY_BARRIER;
return SHR_E_NONE;
}
/*!
* Setup a channel
*/
static int
cmicd_pdma_chan_setup(struct pdma_hw *hw, int chan, uint64_t addr)
{
int grp, que;
grp = chan / CMICD_PDMA_CMC_CHAN;
que = chan % CMICD_PDMA_CMC_CHAN;
hw->hdls.reg_wr32(hw, CMICD_PDMA_DESC(grp, que), addr);
MEMORY_BARRIER;
return SHR_E_NONE;
}
/*!
* Set halt point for a channel
*/
static int
cmicd_pdma_chan_goto(struct pdma_hw *hw, int chan, uint64_t addr)
{
int grp, que;
grp = chan / CMICD_PDMA_CMC_CHAN;
que = chan % CMICD_PDMA_CMC_CHAN;
hw->hdls.reg_wr32(hw, CMICD_PDMA_DESC_HALT(grp, que), addr);
MEMORY_BARRIER;
return SHR_E_NONE;
}
/*!
* Clear a channel
*/
static int
cmicd_pdma_chan_clear(struct pdma_hw *hw, int chan)
{
int grp, que;
grp = chan / CMICD_PDMA_CMC_CHAN;
que = chan % CMICD_PDMA_CMC_CHAN;
hw->hdls.reg_wr32(hw, CMICD_PDMA_STAT_CLR(grp), CMICD_PDMA_DESC_CNTLD(que));
MEMORY_BARRIER;
return SHR_E_NONE;
}
/*!
* Get interrupt number for a channel
*/
static int
cmicd_pdma_chan_intr_num_get(struct pdma_hw *hw, int chan)
{
int grp, que, start_num, mask_shift;
grp = chan / CMICD_PDMA_CMC_CHAN;
que = chan % CMICD_PDMA_CMC_CHAN;
mask_shift = 0;
if (grp > 0) {
mask_shift = CMICD_IRQ_MASK_SHIFT + grp * 32;
}
start_num = CMICD_IRQ_START_NUM + mask_shift;
return start_num + (que * CMICD_IRQ_NUM_OFFSET);
}
/*!
* Enable interrupt for a channel
*/
static int
cmicd_pdma_chan_intr_enable(struct pdma_hw *hw, int chan)
{
int grp, que;
grp = chan / CMICD_PDMA_CMC_CHAN;
que = chan % CMICD_PDMA_CMC_CHAN;
cmicd_pdma_intr_enable(hw, grp, que, CMICD_IRQ_DESC_CNTLD(que));
return SHR_E_NONE;
}
/*!
* Disable interrupt for a channel
*/
static int
cmicd_pdma_chan_intr_disable(struct pdma_hw *hw, int chan)
{
int grp, que;
grp = chan / CMICD_PDMA_CMC_CHAN;
que = chan % CMICD_PDMA_CMC_CHAN;
cmicd_pdma_intr_disable(hw, grp, que, CMICD_IRQ_DESC_CNTLD(que));
return SHR_E_NONE;
}
/*!
* Query interrupt status for a channel
*
* In group mode (interrupt processing per CMC), need to query each channel's
* interrupt status.
*
*/
static int
cmicd_pdma_chan_intr_query(struct pdma_hw *hw, int chan)
{
uint32_t val;
int grp, que;
grp = chan / CMICD_PDMA_CMC_CHAN;
que = chan % CMICD_PDMA_CMC_CHAN;
hw->hdls.reg_rd32(hw, CMICD_IRQ_STAT(grp), &val);
return val & CMICD_IRQ_DESC_CNTLD(que);
}
/*!
* Check interrupt validity for a channel
*
* In group mode (interrupt processing per CMC), need to check each channel's
* interrupt validity based on its interrupt mask.
*
*/
static int
cmicd_pdma_chan_intr_check(struct pdma_hw *hw, int chan)
{
int grp, que;
grp = chan / CMICD_PDMA_CMC_CHAN;
que = chan % CMICD_PDMA_CMC_CHAN;
if (!(hw->dev->ctrl.grp[grp].irq_mask & CMICD_IRQ_DESC_CNTLD(que))) {
return 0;
}
return cmicd_pdma_chan_intr_query(hw, chan);
}
/*!
* Coalesce interrupt for a channel
*/
static int
cmicd_pdma_chan_intr_coalesce(struct pdma_hw *hw, int chan, int count, int timer)
{
uint32_t val;
int grp, que;
grp = chan / CMICD_PDMA_CMC_CHAN;
que = chan % CMICD_PDMA_CMC_CHAN;
val = CMICD_PDMA_INTR_COAL_ENA |
CMICD_PDMA_INTR_THRESH(count) |
CMICD_PDMA_INTR_TIMER(timer);
hw->hdls.reg_wr32(hw, CMICD_PDMA_INTR_COAL(grp, que), val);
return SHR_E_NONE;
}
/*!
* Dump registers for a channel
*/
static int
cmicd_pdma_chan_reg_dump(struct pdma_hw *hw, int chan)
{
uint32_t val;
int grp, que;
grp = chan / CMICD_PDMA_CMC_CHAN;
que = chan % CMICD_PDMA_CMC_CHAN;
hw->hdls.reg_rd32(hw, CMICD_PDMA_CTRL(grp, que), &val);
CNET_PR("CMIC_CMC%d_CH%d_DMA_CTRL: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICD_PDMA_DESC(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_DESC%d: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICD_PDMA_CURR_DESC(grp, que), &val);
CNET_PR("CMIC_CMC%d_CH%d_DMA_CURR_DESC: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICD_PDMA_DESC_HALT(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_DESC_HALT_ADDR: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICD_PDMA_COS_RX0(grp, que), &val);
CNET_PR("CMIC_CMC%d_CH%d_COS_CTRL_RX_0: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICD_PDMA_COS_RX1(grp, que), &val);
CNET_PR("CMIC_CMC%d_CH%d_COS_CTRL_RX_1: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICD_PDMA_COS_MASK0(grp), &val);
CNET_PR("CMIC_CMC%d_PROGRAMMABLE_COS_MASK0: 0x%08x\n", grp, val);
hw->hdls.reg_rd32(hw, CMICD_PDMA_COS_MASK1(grp), &val);
CNET_PR("CMIC_CMC%d_PROGRAMMABLE_COS_MASK1: 0x%08x\n", grp, val);
hw->hdls.reg_rd32(hw, CMICD_PDMA_INTR_COAL(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_INTR_COAL: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICD_PDMA_RBUF_THRE(grp, que), &val);
CNET_PR("CMIC_CMC%d_CH%d_RXBUF_THRESHOLD_CONFIG: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICD_PDMA_STAT(grp), &val);
CNET_PR("CMIC_CMC%d_DMA_STAT: 0x%08x\n", grp, val);
hw->hdls.reg_rd32(hw, CMICD_PDMA_STAT_HI(grp), &val);
CNET_PR("CMIC_CMC%d_DMA_STAT_HI: 0x%08x\n", grp, val);
hw->hdls.reg_rd32(hw, CMICD_PDMA_STAT_CLR(grp), &val);
CNET_PR("CMIC_CMC%d_DMA_STAT_CLR: 0x%08x\n", grp, val);
hw->hdls.reg_rd32(hw, CMICD_PDMA_COUNT_RX(grp, que), &val);
CNET_PR("CMIC_CMC%d_PKT_COUNT_CH%d_RXPKT: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICD_PDMA_COUNT_TX(grp, que), &val);
CNET_PR("CMIC_CMC%d_PKT_COUNT_CH%d_TXPKT: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICD_IRQ_STAT(grp), &val);
CNET_PR("CMIC_CMC%d_IRQ_STAT0: 0x%08x\n", grp, val);
hw->hdls.reg_rd32(hw, CMICD_IRQ_PCI_MASK(grp), &val);
CNET_PR("CMIC_CMC%d_PCIE_IRQ_MASK0: 0x%08x\n", grp, val);
hw->hdls.reg_rd32(hw, CMICD_DEV_REV_ID, &val);
CNET_PR("CMIC_DEV_REV_ID: 0x%08x\n", val);
hw->hdls.reg_rd32(hw, CMICD_CMICM_REV_ID, &val);
CNET_PR("CMIC_CMICM_REV_ID: 0x%08x\n", val);
return SHR_E_NONE;
}
/*!
* Initialize function pointers
*/
int
bcmcnet_cmicd_pdma_hw_hdls_init(struct pdma_hw *hw)
{
if (!hw) {
return SHR_E_PARAM;
}
hw->hdls.reg_rd32 = cmicd_pdma_reg_read32;
hw->hdls.reg_wr32 = cmicd_pdma_reg_write32;
hw->hdls.hw_init = cmicd_pdma_hw_init;
hw->hdls.hw_config = cmicd_pdma_hw_config;
hw->hdls.hw_reset = cmicd_pdma_hw_reset;
hw->hdls.chan_start = cmicd_pdma_chan_start;
hw->hdls.chan_stop = cmicd_pdma_chan_stop;
hw->hdls.chan_setup = cmicd_pdma_chan_setup;
hw->hdls.chan_goto = cmicd_pdma_chan_goto;
hw->hdls.chan_clear = cmicd_pdma_chan_clear;
hw->hdls.chan_intr_num_get = cmicd_pdma_chan_intr_num_get;
hw->hdls.chan_intr_enable = cmicd_pdma_chan_intr_enable;
hw->hdls.chan_intr_disable = cmicd_pdma_chan_intr_disable;
hw->hdls.chan_intr_query = cmicd_pdma_chan_intr_query;
hw->hdls.chan_intr_check = cmicd_pdma_chan_intr_check;
hw->hdls.chan_intr_coalesce = cmicd_pdma_chan_intr_coalesce;
hw->hdls.chan_reg_dump = cmicd_pdma_chan_reg_dump;
return SHR_E_NONE;
}

View File

@ -0,0 +1,604 @@
/*! \file bcmcnet_cmicx_pdma_hw.c
*
* Utility routines for handling BCMCNET hardware (CMICx).
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <bcmcnet/bcmcnet_core.h>
#include <bcmcnet/bcmcnet_dev.h>
#include <bcmcnet/bcmcnet_rxtx.h>
#include <bcmcnet/bcmcnet_cmicx.h>
/*!
* Read 32-bit register
*/
static inline void
cmicx_pdma_reg_read32(struct pdma_hw *hw, uint32_t addr, uint32_t *data)
{
if (hw->dev->dev_read32) {
hw->dev->dev_read32(hw->dev, addr, data);
} else {
DEV_READ32(&hw->dev->ctrl, addr, data);
}
}
/*!
* Write 32-bit register
*/
static inline void
cmicx_pdma_reg_write32(struct pdma_hw *hw, uint32_t addr, uint32_t data)
{
if (hw->dev->dev_write32) {
hw->dev->dev_write32(hw->dev, addr, data);
} else {
DEV_WRITE32(&hw->dev->ctrl, addr, data);
}
}
/*!
* Enable interrupt for a channel
*/
static inline void
cmicx_pdma_intr_enable(struct pdma_hw *hw, int cmc, int chan, uint32_t mask)
{
uint32_t reg, irq_mask;
hw->dev->ctrl.grp[cmc].irq_mask |= mask;
irq_mask = hw->dev->ctrl.grp[cmc].irq_mask;
if (cmc == 0) {
reg = CMICX_PDMA_IRQ_RAW_STAT0;
} else {
if (chan < 4) {
reg = CMICX_PDMA_IRQ_RAW_STAT1;
hw->dev->ctrl.grp[cmc].irq_mask <<= CMICX_IRQ_MASK_SHIFT;
} else {
reg = CMICX_PDMA_IRQ_RAW_STAT2;
hw->dev->ctrl.grp[cmc].irq_mask >>= 32 - CMICX_IRQ_MASK_SHIFT;
}
}
hw->dev->intr_unmask(hw->dev, cmc, chan, reg & 0xfff, 0);
hw->dev->ctrl.grp[cmc].irq_mask = irq_mask;
}
/*!
* Disable interrupt for a channel
*/
static inline void
cmicx_pdma_intr_disable(struct pdma_hw *hw, int cmc, int chan, uint32_t mask)
{
uint32_t reg, irq_mask;
hw->dev->ctrl.grp[cmc].irq_mask &= ~mask;
irq_mask = hw->dev->ctrl.grp[cmc].irq_mask;
if (cmc == 0) {
reg = CMICX_PDMA_IRQ_RAW_STAT0;
} else {
if (chan < 4) {
reg = CMICX_PDMA_IRQ_RAW_STAT1;
hw->dev->ctrl.grp[cmc].irq_mask <<= CMICX_IRQ_MASK_SHIFT;
} else {
reg = CMICX_PDMA_IRQ_RAW_STAT2;
hw->dev->ctrl.grp[cmc].irq_mask >>= 32 - CMICX_IRQ_MASK_SHIFT;
}
}
hw->dev->intr_mask(hw->dev, cmc, chan, reg & 0xfff, 0);
hw->dev->ctrl.grp[cmc].irq_mask = irq_mask;
}
/*!
* Release Packet DMA credits to EP.
*/
static int
cmicx_pdma_credits_release(struct pdma_hw *hw)
{
int credits;
uint32_t val;
/*
* Since only 6 bits of iproc_cmic_to_ep_credits[5:0] are being used,
* so we have to set the max credits value twice in order to release
* 64 credits to EP.
* Only do this once when HW is initialized.
*/
hw->hdls.reg_rd32(hw, CMICX_EPINTF_RELEASE_CREDITS, &val);
if (!val) {
credits = 63;
hw->hdls.reg_wr32(hw, CMICX_EPINTF_MAX_CREDITS, (0x1 << 8) | credits);
hw->hdls.reg_wr32(hw, CMICX_EPINTF_RELEASE_CREDITS, 1);
hw->hdls.reg_wr32(hw, CMICX_EPINTF_RELEASE_CREDITS, 0);
credits = 1;
hw->hdls.reg_wr32(hw, CMICX_EPINTF_MAX_CREDITS, (0x1 << 8) | credits);
hw->hdls.reg_wr32(hw, CMICX_EPINTF_RELEASE_CREDITS, 1);
}
return SHR_E_NONE;
}
/*!
* Initialize HW
*/
static int
cmicx_pdma_hw_init(struct pdma_hw *hw)
{
dev_mode_t mode = DEV_MODE_MAX;
uint32_t val;
/* Temporarily upgrade work mode to get HW information in VNET mode. */
if (hw->dev->mode == DEV_MODE_VNET) {
mode = DEV_MODE_VNET;
hw->dev->mode = DEV_MODE_UNET;
}
/* Release Packet DMA credits to EP. */
cmicx_pdma_credits_release(hw);
hw->info.name = CMICX_DEV_NAME;
hw->info.dev_id = hw->dev->dev_id;
hw->info.num_cmcs = CMICX_PDMA_CMC_MAX;
hw->info.cmc_chans = CMICX_PDMA_CMC_CHAN;
hw->info.num_chans = CMICX_PDMA_CMC_MAX * CMICX_PDMA_CMC_CHAN;
hw->info.rx_dcb_size = CMICX_PDMA_DCB_SIZE;
hw->info.tx_dcb_size = CMICX_PDMA_DCB_SIZE;
hw->hdls.reg_rd32(hw, CMICX_EP_TO_CPU_HEADER_SIZE, &val);
hw->info.rx_ph_size = (val & 0xf) * 8;
hw->info.tx_ph_size = CMICX_TX_PKT_HDR_SIZE;
/* Restore work mode to VNET. */
if (mode == DEV_MODE_VNET) {
hw->dev->mode = DEV_MODE_VNET;
}
return SHR_E_NONE;
}
/*!
* Configure HW
*/
static int
cmicx_pdma_hw_config(struct pdma_hw *hw)
{
struct dev_ctrl *ctrl = &hw->dev->ctrl;
struct pdma_rx_queue *rxq = NULL;
struct pdma_tx_queue *txq = NULL;
uint32_t val, que_ctrl;
int grp, que;
uint32_t qi;
int ip_if_hdr_endian = 0;
for (qi = 0; qi < ctrl->nb_rxq; qi++) {
rxq = (struct pdma_rx_queue *)ctrl->rx_queue[qi];
grp = rxq->group_id;
que = rxq->chan_id % CMICX_PDMA_CMC_CHAN;
que_ctrl = ctrl->grp[grp].que_ctrl[que];
hw->hdls.reg_wr32(hw, CMICX_PDMA_IRQ_STAT_CLR(grp), CMICX_PDMA_IRQ_MASK(que));
val = 0;
if (que_ctrl & PDMA_PKT_BYTE_SWAP) {
val |= CMICX_PDMA_PKT_BIG_ENDIAN;
}
if (que_ctrl & PDMA_OTH_BYTE_SWAP) {
val |= CMICX_PDMA_DESC_BIG_ENDIAN;
}
if (que_ctrl & PDMA_HDR_BYTE_SWAP) {
val |= CMICX_PDMA_HDR_BIG_ENDIAN;
}
if (!(hw->dev->flags & PDMA_CHAIN_MODE)) {
val |= CMICX_PDMA_CONTINUOUS;
}
if (hw->dev->flags & PDMA_DESC_PREFETCH) {
val |= CMICX_PDMA_CONTINUOUS_DESC;
}
val |= CMICX_PDMA_INTR_ON_DESC;
hw->hdls.reg_wr32(hw, CMICX_PDMA_CTRL(grp, que), val);
}
for (qi = 0; qi < ctrl->nb_txq; qi++) {
txq = (struct pdma_tx_queue *)ctrl->tx_queue[qi];
grp = txq->group_id;
que = txq->chan_id % CMICX_PDMA_CMC_CHAN;
que_ctrl = ctrl->grp[grp].que_ctrl[que];
hw->hdls.reg_wr32(hw, CMICX_PDMA_IRQ_STAT_CLR(grp), CMICX_PDMA_IRQ_MASK(que));
val = 0;
if (que_ctrl & PDMA_PKT_BYTE_SWAP) {
val |= CMICX_PDMA_PKT_BIG_ENDIAN;
val |= CMICX_PDMA_HDR_BIG_ENDIAN;
ip_if_hdr_endian = 1;
}
if (que_ctrl & PDMA_OTH_BYTE_SWAP) {
val |= CMICX_PDMA_DESC_BIG_ENDIAN;
}
if (que_ctrl & PDMA_HDR_BYTE_SWAP) {
ip_if_hdr_endian = 1;
}
if (!(hw->dev->flags & PDMA_CHAIN_MODE)) {
val |= CMICX_PDMA_CONTINUOUS;
}
if (hw->dev->flags & PDMA_DESC_PREFETCH) {
val |= CMICX_PDMA_CONTINUOUS_DESC;
}
val |= CMICX_PDMA_INTR_ON_DESC | CMICX_PDMA_DIR;
hw->hdls.reg_wr32(hw, CMICX_PDMA_CTRL(grp, que), val);
}
if (ip_if_hdr_endian == 1) {
hw->hdls.reg_rd32(hw, CMICX_TOP_CONFIG, &val);
val |= 0x80;
hw->hdls.reg_wr32(hw, CMICX_TOP_CONFIG, val);
}
return SHR_E_NONE;
}
/*!
* Reset HW
*/
static int
cmicx_pdma_hw_reset(struct pdma_hw *hw)
{
int gi, qi;
for (gi = 0; gi < hw->dev->num_groups; gi++) {
if (!hw->dev->ctrl.grp[gi].attached) {
continue;
}
for (qi = 0; qi < CMICX_PDMA_CMC_CHAN; qi++) {
if (1 << qi & hw->dev->ctrl.grp[gi].bm_rxq ||
1 << qi & hw->dev->ctrl.grp[gi].bm_txq) {
hw->hdls.reg_wr32(hw, CMICX_PDMA_CTRL(gi, qi), 0);
}
}
}
return SHR_E_NONE;
}
/*!
* Start a channel
*/
static int
cmicx_pdma_chan_start(struct pdma_hw *hw, int chan)
{
uint32_t val;
int grp, que;
grp = chan / CMICX_PDMA_CMC_CHAN;
que = chan % CMICX_PDMA_CMC_CHAN;
hw->hdls.reg_rd32(hw, CMICX_PDMA_CTRL(grp, que), &val);
val |= CMICX_PDMA_ENABLE;
hw->hdls.reg_wr32(hw, CMICX_PDMA_CTRL(grp, que), val);
MEMORY_BARRIER;
return SHR_E_NONE;
}
/*!
* Stop a channel
*/
static int
cmicx_pdma_chan_stop(struct pdma_hw *hw, int chan)
{
uint32_t val;
int grp, que;
int retry = CMICX_HW_RETRY_TIMES;
grp = chan / CMICX_PDMA_CMC_CHAN;
que = chan % CMICX_PDMA_CMC_CHAN;
hw->hdls.reg_rd32(hw, CMICX_PDMA_CTRL(grp, que), &val);
val |= CMICX_PDMA_ENABLE | CMICX_PDMA_ABORT;
hw->hdls.reg_wr32(hw, CMICX_PDMA_CTRL(grp, que), val);
MEMORY_BARRIER;
do {
val = ~CMICX_PDMA_IS_ACTIVE;
hw->hdls.reg_rd32(hw, CMICX_PDMA_STAT(grp, que), &val);
} while ((val & CMICX_PDMA_IS_ACTIVE) && (--retry > 0));
hw->hdls.reg_rd32(hw, CMICX_PDMA_CTRL(grp, que), &val);
val &= ~(CMICX_PDMA_ENABLE | CMICX_PDMA_ABORT);
hw->hdls.reg_wr32(hw, CMICX_PDMA_CTRL(grp, que), val);
hw->hdls.reg_wr32(hw, CMICX_PDMA_IRQ_STAT_CLR(grp), CMICX_PDMA_IRQ_MASK(que));
MEMORY_BARRIER;
return SHR_E_NONE;
}
/*!
* Setup a channel
*/
static int
cmicx_pdma_chan_setup(struct pdma_hw *hw, int chan, uint64_t addr)
{
int grp, que;
grp = chan / CMICX_PDMA_CMC_CHAN;
que = chan % CMICX_PDMA_CMC_CHAN;
hw->hdls.reg_wr32(hw, CMICX_PDMA_DESC_LO(grp, que), addr);
hw->hdls.reg_wr32(hw, CMICX_PDMA_DESC_HI(grp, que), DMA_TO_BUS_HI(addr >> 32));
MEMORY_BARRIER;
return SHR_E_NONE;
}
/*!
* Set halt point for a channel
*/
static int
cmicx_pdma_chan_goto(struct pdma_hw *hw, int chan, uint64_t addr)
{
int grp, que;
grp = chan / CMICX_PDMA_CMC_CHAN;
que = chan % CMICX_PDMA_CMC_CHAN;
hw->hdls.reg_wr32(hw, CMICX_PDMA_DESC_HALT_LO(grp, que), addr);
hw->hdls.reg_wr32(hw, CMICX_PDMA_DESC_HALT_HI(grp, que), DMA_TO_BUS_HI(addr >> 32));
MEMORY_BARRIER;
return SHR_E_NONE;
}
/*!
* Clear a channel
*/
static int
cmicx_pdma_chan_clear(struct pdma_hw *hw, int chan)
{
int grp, que;
grp = chan / CMICX_PDMA_CMC_CHAN;
que = chan % CMICX_PDMA_CMC_CHAN;
hw->hdls.reg_wr32(hw, CMICX_PDMA_IRQ_STAT_CLR(grp), CMICX_PDMA_IRQ_CTRLD_INTR(que));
MEMORY_BARRIER;
return SHR_E_NONE;
}
/*!
* Get interrupt number for a channel
*/
static int
cmicx_pdma_chan_intr_num_get(struct pdma_hw *hw, int chan)
{
int grp, que, start_num, mask_shift;
grp = chan / CMICX_PDMA_CMC_CHAN;
que = chan % CMICX_PDMA_CMC_CHAN;
mask_shift = 0;
if (grp > 0) {
mask_shift = CMICX_IRQ_MASK_SHIFT + grp * 32;
}
start_num = CMICX_IRQ_START_NUM + mask_shift;
return start_num + (que * CMICX_IRQ_NUM_OFFSET);
}
/*!
* Enable interrupt for a channel
*/
static int
cmicx_pdma_chan_intr_enable(struct pdma_hw *hw, int chan)
{
int grp, que;
grp = chan / CMICX_PDMA_CMC_CHAN;
que = chan % CMICX_PDMA_CMC_CHAN;
cmicx_pdma_intr_enable(hw, grp, que, CMICX_PDMA_IRQ_CTRLD_INTR(que));
return SHR_E_NONE;
}
/*!
* Disable interrupt for a channel
*/
static int
cmicx_pdma_chan_intr_disable(struct pdma_hw *hw, int chan)
{
int grp, que;
grp = chan / CMICX_PDMA_CMC_CHAN;
que = chan % CMICX_PDMA_CMC_CHAN;
cmicx_pdma_intr_disable(hw, grp, que, CMICX_PDMA_IRQ_CTRLD_INTR(que));
return SHR_E_NONE;
}
/*!
* Query interrupt status for a channel
*
* In group mode (interrupt processing per CMC), need to query each channel's
* interrupt status.
*
*/
static int
cmicx_pdma_chan_intr_query(struct pdma_hw *hw, int chan)
{
uint32_t val;
int grp, que;
grp = chan / CMICX_PDMA_CMC_CHAN;
que = chan % CMICX_PDMA_CMC_CHAN;
hw->hdls.reg_rd32(hw, CMICX_PDMA_IRQ_STAT(grp), &val);
return val & CMICX_PDMA_IRQ_CTRLD_INTR(que);
}
/*!
* Check interrupt validity for a channel
*
* In group mode (interrupt processing per CMC), need to check each channel's
* interrupt validity based on its interrupt mask.
*
*/
static int
cmicx_pdma_chan_intr_check(struct pdma_hw *hw, int chan)
{
int grp, que;
grp = chan / CMICX_PDMA_CMC_CHAN;
que = chan % CMICX_PDMA_CMC_CHAN;
if (!(hw->dev->ctrl.grp[grp].irq_mask & CMICX_PDMA_IRQ_CTRLD_INTR(que))) {
return 0;
}
return cmicx_pdma_chan_intr_query(hw, chan);
}
/*!
* Coalesce interrupt for a channel
*/
static int
cmicx_pdma_chan_intr_coalesce(struct pdma_hw *hw, int chan, int count, int timer)
{
uint32_t val;
int grp, que;
grp = chan / CMICX_PDMA_CMC_CHAN;
que = chan % CMICX_PDMA_CMC_CHAN;
val = CMICX_PDMA_INTR_COAL_ENA |
CMICX_PDMA_INTR_THRESH(count) |
CMICX_PDMA_INTR_TIMER(timer);
hw->hdls.reg_wr32(hw, CMICX_PDMA_INTR_COAL(grp, que), val);
return SHR_E_NONE;
}
/*!
* Dump registers for a channel
*/
static int
cmicx_pdma_chan_reg_dump(struct pdma_hw *hw, int chan)
{
uint32_t val;
int grp, que;
grp = chan / CMICX_PDMA_CMC_CHAN;
que = chan % CMICX_PDMA_CMC_CHAN;
hw->hdls.reg_rd32(hw, CMICX_PDMA_CTRL(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_CTRL: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICX_PDMA_DESC_LO(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_DESC_LO: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICX_PDMA_DESC_HI(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_DESC_HI: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICX_PDMA_CURR_DESC_LO(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_CURR_DESC_LO: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICX_PDMA_CURR_DESC_HI(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_CURR_DESC_HI: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICX_PDMA_DESC_HALT_LO(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_DESC_HALT_ADDR_LO: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICX_PDMA_DESC_HALT_HI(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_DESC_HALT_ADDR_HI: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICX_PDMA_COS_CTRL_RX0(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_COS_CTRL_RX_0: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICX_PDMA_COS_CTRL_RX1(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_COS_CTRL_RX_1: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICX_PDMA_INTR_COAL(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_INTR_COAL: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICX_PDMA_RBUF_THRE(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_RXBUF_THRESHOLD_CONFIG: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICX_PDMA_STAT(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_STAT: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICX_PDMA_COUNT_RX(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_PKT_COUNT_RXPKT: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICX_PDMA_COUNT_TX(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_PKT_COUNT_TXPKT: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICX_PDMA_COUNT_RX_DROP(grp, que), &val);
CNET_PR("CMIC_CMC%d_DMA_CH%d_PKT_COUNT_RXPKT_DROP: 0x%08x\n", grp, que, val);
hw->hdls.reg_rd32(hw, CMICX_PDMA_IRQ_STAT(grp), &val);
CNET_PR("CMIC_CMC%d_IRQ_STAT: 0x%08x\n", grp, val);
hw->hdls.reg_rd32(hw, CMICX_PDMA_IRQ_STAT_CLR(grp), &val);
CNET_PR("CMIC_CMC%d_IRQ_STAT_CLR: 0x%08x\n", grp, val);
val = hw->dev->ctrl.grp[grp].irq_mask;
CNET_PR("CMIC_CMC%d_IRQ_ENAB: 0x%08x\n", grp, val);
hw->hdls.reg_rd32(hw, CMICX_EP_TO_CPU_HEADER_SIZE, &val);
CNET_PR("CMIC_EP_TO_CPU_HEADER_SIZE: 0x%08x\n", val);
return SHR_E_NONE;
}
/*!
* Initialize function pointers
*/
int
bcmcnet_cmicx_pdma_hw_hdls_init(struct pdma_hw *hw)
{
if (!hw) {
return SHR_E_PARAM;
}
hw->hdls.reg_rd32 = cmicx_pdma_reg_read32;
hw->hdls.reg_wr32 = cmicx_pdma_reg_write32;
hw->hdls.hw_init = cmicx_pdma_hw_init;
hw->hdls.hw_config = cmicx_pdma_hw_config;
hw->hdls.hw_reset = cmicx_pdma_hw_reset;
hw->hdls.chan_start = cmicx_pdma_chan_start;
hw->hdls.chan_stop = cmicx_pdma_chan_stop;
hw->hdls.chan_setup = cmicx_pdma_chan_setup;
hw->hdls.chan_goto = cmicx_pdma_chan_goto;
hw->hdls.chan_clear = cmicx_pdma_chan_clear;
hw->hdls.chan_intr_num_get = cmicx_pdma_chan_intr_num_get;
hw->hdls.chan_intr_enable = cmicx_pdma_chan_intr_enable;
hw->hdls.chan_intr_disable = cmicx_pdma_chan_intr_disable;
hw->hdls.chan_intr_query = cmicx_pdma_chan_intr_query;
hw->hdls.chan_intr_check = cmicx_pdma_chan_intr_check;
hw->hdls.chan_intr_coalesce = cmicx_pdma_chan_intr_coalesce;
hw->hdls.chan_reg_dump = cmicx_pdma_chan_reg_dump;
return SHR_E_NONE;
}

View File

@ -0,0 +1,369 @@
/*! \file bcmcnet_cmicd.h
*
* CMICd registers and descriptors definitions.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef BCMCNET_CMICD_H
#define BCMCNET_CMICD_H
/*!
* \name CMICD PDMA HW definitions
*/
/*! \{ */
/*! CMICD CMC number */
#define CMICD_PDMA_CMC_MAX 3
/*! CMICD CMC PDMA channels */
#define CMICD_PDMA_CMC_CHAN 4
/*! CMICD PDMA DCB size */
#define CMICD_PDMA_DCB_SIZE 64
/*! \} */
/*!
* \name CMICD PDMA register definitions
*/
/*! \{ */
#define CMICD_PDMA_CTRLr 0x0140
#define CMICD_PDMA_STATr 0x0150
#define CMICD_PDMA_STAT_HIr 0x0130
#define CMICD_PDMA_STAT_CLRr 0x01a4
#define CMICD_PDMA_DESCr 0x0158
#define CMICD_PDMA_CURR_DESCr 0x01a8
#define CMICD_PDMA_DESC_HALTr 0x0120
#define CMICD_PDMA_COS_RX0r 0x0168
#define CMICD_PDMA_COS_RX1r 0x016c
#define CMICD_PDMA_COS_MASK0r 0x019c
#define CMICD_PDMA_COS_MASK1r 0x01a0
#define CMICD_PDMA_INTR_COALr 0x0188
#define CMICD_PDMA_RBUF_THREr 0x0110
#define CMICD_PDMA_COUNT_RXr 0x0480
#define CMICD_PDMA_COUNT_TXr 0x0484
#define CMICD_PDMA_COUNT_ALL_RXr 0x04a0
#define CMICD_PDMA_COUNT_ALL_TXr 0x04a4
#define CMICD_IRQ_STATr 0x0400
#define CMICD_IRQ_PCI_MASKr 0x0414
#define CMICD_IRQ_UC0_MASKr 0x0428
/*! \} */
/*!
* \name CMICD PDMA register address
*/
/*! \{ */
/*! Base address */
#define CMICD_GRP_BASE(g) (0x00031000 + 0x1000 * g)
/*! Control register address */
#define CMICD_PDMA_CTRL(g, q) (CMICD_GRP_BASE(g) + CMICD_PDMA_CTRLr + q * 4)
/*! Status register address */
#define CMICD_PDMA_STAT(g) (CMICD_GRP_BASE(g) + CMICD_PDMA_STATr)
/*! Status higher register address */
#define CMICD_PDMA_STAT_HI(g) (CMICD_GRP_BASE(g) + CMICD_PDMA_STAT_HIr)
/*! Status clear register address */
#define CMICD_PDMA_STAT_CLR(g) (CMICD_GRP_BASE(g) + CMICD_PDMA_STAT_CLRr)
/*! Descriptor register address */
#define CMICD_PDMA_DESC(g, q) (CMICD_GRP_BASE(g) + CMICD_PDMA_DESCr + q * 4)
/*! Current descriptor register address */
#define CMICD_PDMA_CURR_DESC(g, q) (CMICD_GRP_BASE(g) + CMICD_PDMA_CURR_DESCr + q * 4)
/*! Descriptor halt register address */
#define CMICD_PDMA_DESC_HALT(g, q) (CMICD_GRP_BASE(g) + CMICD_PDMA_DESC_HALTr + q * 4)
/*! COS Rx0 register address */
#define CMICD_PDMA_COS_RX0(g, q) (CMICD_GRP_BASE(g) + CMICD_PDMA_COS_RX0r + q * 8)
/*! COS Rx1 register address */
#define CMICD_PDMA_COS_RX1(g, q) (CMICD_GRP_BASE(g) + CMICD_PDMA_COS_RX1r + q * 8)
/*! COS Mask0 register address */
#define CMICD_PDMA_COS_MASK0(g) (CMICD_GRP_BASE(g) + CMICD_PDMA_COS_MASK0r)
/*! COS Mask1 register address */
#define CMICD_PDMA_COS_MASK1(g) (CMICD_GRP_BASE(g) + CMICD_PDMA_COS_MASK1r)
/*! Interrupt coalesce register address */
#define CMICD_PDMA_INTR_COAL(g, q) (CMICD_GRP_BASE(g) + CMICD_PDMA_INTR_COALr + q * 4)
/*! Rx buffer threshhold register address */
#define CMICD_PDMA_RBUF_THRE(g, q) (CMICD_GRP_BASE(g) + CMICD_PDMA_RBUF_THREr + q * 4)
/*! Rx counter register address */
#define CMICD_PDMA_COUNT_RX(g, q) (CMICD_GRP_BASE(g) + CMICD_PDMA_COUNT_RXr + q * 8)
/*! Tx counter register address */
#define CMICD_PDMA_COUNT_TX(g, q) (CMICD_GRP_BASE(g) + CMICD_PDMA_COUNT_TXr + q * 8)
/*! Rx global counter register address */
#define CMICD_PDMA_COUNT_ALL_RX(g) (CMICD_GRP_BASE(g) + CMICD_PDMA_COUNT_ALL_RXr)
/*! Tx gloable counter register address */
#define CMICD_PDMA_COUNT_ALL_TX(g) (CMICD_GRP_BASE(g) + CMICD_PDMA_COUNT_ALL_TXr)
/*! Interrupt status register address */
#define CMICD_IRQ_STAT(g) (CMICD_GRP_BASE(g) + CMICD_IRQ_STATr)
/*! Interrupt PCI mask register address */
#define CMICD_IRQ_PCI_MASK(g) (CMICD_GRP_BASE(g) + CMICD_IRQ_PCI_MASKr)
/*! Interrupt UC0 mask register address */
#define CMICD_IRQ_UC0_MASK(g) (CMICD_GRP_BASE(g) + CMICD_IRQ_UC0_MASKr)
/*! Credits release release register address */
#define CMICD_EPINTF_RELEASE_CREDITS 0x0001a000
/*! Device revision register address */
#define CMICD_DEV_REV_ID 0x00010224
/*! CMIC revison register address */
#define CMICD_CMICM_REV_ID 0x00010228
/*! \} */
/*!
* \name Control register definitions
*/
/*! \{ */
/*! Continuous DMA mode */
#define CMICD_PDMA_CONTINUOUS 0x00000200
/*! Controlled interrupt */
#define CMICD_PDMA_CNTLD_INTR 0x00000100
/*! Update status on reload */
#define CMICD_PDMA_RLD_STAT_DIS 0x00000080
/*! Dropped on chain end */
#define CMICD_PDMA_DROP_ON_END 0x00000040
/*! Descriptor big endianess */
#define CMICD_PDMA_DESC_BIG_ENDIAN 0x00000020
/*! Packet DMA big endianess */
#define CMICD_PDMA_PKT_BIG_ENDIAN 0x00000010
/*! Interrupt after descriptor */
#define CMICD_PDMA_INTR_ON_DESC 0x00000008
/*! Abort DMA */
#define CMICD_PDMA_ABORT 0x00000004
/*! Enable DMA */
#define CMICD_PDMA_ENABLE 0x00000002
/*! DMA direction */
#define CMICD_PDMA_DIR 0x00000001
/*! \} */
/*!
* \name Status register definitions
*/
/*! \{ */
/*! Chain done */
#define CMICD_PDMA_CHAIN_DONE(q) (0x00000001 << (q))
/*! Descriptor done */
#define CMICD_PDMA_DESC_DONE(q) (0x00000010 << (q))
/*! Active */
#define CMICD_PDMA_ACTIVE(q) (0x00000100 << (q))
/*! \} */
/*!
* \name Status clear register definitions
*/
/*! \{ */
/*! Clear completed interrupt */
#define CMICD_PDMA_DESC_CMPLT(q) (0x00000001 << (q))
/*! Clear controlled interrupt */
#define CMICD_PDMA_DESC_CNTLD(q) (0x00000100 << (q))
/*! \} */
/*!
* \name Interrupt_coalesce register definitions
*/
/*! \{ */
/*! Interrupt coalesce enable */
#define CMICD_PDMA_INTR_COAL_ENA (1 << 31)
/*! Interrupt coalesce threshhold */
#define CMICD_PDMA_INTR_THRESH(cnt) (((cnt) & 0x7fff) << 16)
/*! Interrupt coalesce timeout */
#define CMICD_PDMA_INTR_TIMER(tmr) ((tmr) & 0xffff)
/*! \} */
/*!
* \name Interrupt status&mask register definitions
*/
/*! \{ */
/*! Interrupt mask */
#define CMICD_PDMA_IRQ_MASK 0x78000000
/*! Descriptor done */
#define CMICD_IRQ_DESC_DONE(q) (0x00004000 >> (2 * (q)))
/*! Chain done */
#define CMICD_IRQ_CHAIN_DONE(q) (0x00008000 >> (2 * (q)))
/*! Controlled interrupt */
#define CMICD_IRQ_DESC_CNTLD(q) (0x08000000 << (q))
/*! Interrupt start number */
#define CMICD_IRQ_START_NUM 27
/*! Interrupt number offset */
#define CMICD_IRQ_NUM_OFFSET 1
/*! Interrupt mask shift */
#define CMICD_IRQ_MASK_SHIFT 0
/*! Interrupt mask zeroing */
#define CMICD_IRQ_ACT_CHAN(mask) (((mask) & CMICD_PDMA_IRQ_MASK) >> CMICD_IRQ_START_NUM)
/*! \} */
/*! 32-bit register read */
#define DEV_READ32(_c, _a, _p) \
do { \
if ((_c)->dev->mode != DEV_MODE_VNET) { \
*(_p) = ((volatile uint32_t *)(_c)->hw_addr)[(_a) / 4]; \
} \
} while (0)
/*! 32-bit register write */
#define DEV_WRITE32(_c, _a, _v) \
do { \
if ((_c)->dev->mode != DEV_MODE_VNET) { \
((volatile uint32_t *)(_c)->hw_addr)[(_a) / 4] = (_v); \
} \
} while (0)
/*!
* \brief Rx metadata in descriptor.
*/
struct rx_metadata {
/*! Metadata */
volatile uint32_t data[13];
/*! Status */
volatile uint32_t status;
} __attribute__((packed));
/*!
* \brief Rx descriptor.
*/
struct cmicd_rx_desc {
/*! Packet address */
volatile uint32_t addr;
/*! Packet control */
volatile uint32_t ctrl;
/*! Metadata fields */
struct rx_metadata md;
} __attribute__((packed));
/*! Reserve Rx meta data size in packet buffer */
#define CMICD_RX_META_RESV 64
/*!
* \brief Tx metadata in descriptor.
*/
struct tx_metadata {
/*! Metadata */
volatile uint32_t data[4];
/*! Reserved */
volatile uint32_t rsvd[9];
/*! Status */
volatile uint32_t status;
} __attribute__((packed));
/*!
* \brief Tx descriptor.
*/
struct cmicd_tx_desc {
/*! Packet address */
volatile uint32_t addr;
/*! Packet control */
volatile uint32_t ctrl;
/*! Metadata fields */
struct tx_metadata md;
} __attribute__((packed));
/*! Reserve Tx meta data size in packet buffer */
#define CMICD_TX_META_RESV 16
/*!
* Flags related to descriptors.
*/
/*! Controlled interrupt */
#define CMICD_DESC_CTRL_CNTLD_INTR (1 << 24)
/*! Completed interrupt */
#define CMICD_DESC_CTRL_CMPLT_INTR (1 << 23)
/*! Reload DCB */
#define CMICD_DESC_CTRL_RELOAD (1 << 18)
/*! Scatter DCB */
#define CMICD_DESC_CTRL_SCATTER (1 << 17)
/*! Chained DCB */
#define CMICD_DESC_CTRL_CHAIN (1 << 16)
/*! Control flags */
#define CMICD_DESC_CTRL_FLAGS(f) (((f) & 0xffff) << 16)
/*! Purge packet */
#define CMICD_DESC_TX_PURGE_PKT (1 << 6)
/*! Pause packet */
#define CMICD_DESC_TX_PAUSE_PKT (1 << 5)
/*! Higig packet */
#define CMICD_DESC_TX_HIGIG_PKT (1 << 3)
/*! Packet length */
#define CMICD_DESC_CTRL_LEN(len) ((len) & 0xffff)
/*! Done */
#define CMICD_DESC_STAT_RTX_DONE (1 << 31)
/*! Head error */
#define CMICD_DESC_STAT_HEAD_ERR (1 << 20)
/*! Data error */
#define CMICD_DESC_STAT_DATA_ERR (1 << 19)
/*! Cell error */
#define CMICD_DESC_STAT_CELL_ERR (1 << 18)
/*! Error mask */
#define CMICD_DESC_STAT_ERR_MASK (CMICD_DESC_STAT_HEAD_ERR | \
CMICD_DESC_STAT_DATA_ERR | \
CMICD_DESC_STAT_CELL_ERR)
/*! Packet start */
#define CMICD_DESC_STAT_PKT_START (1 << 17)
/*! Packet end */
#define CMICD_DESC_STAT_PKT_END (1 << 16)
/*! Get done state */
#define CMICD_DESC_STAT_DONE(stat) ((stat) & CMICD_DESC_STAT_RTX_DONE)
/*! Get flags */
#define CMICD_DESC_STAT_FLAGS(stat) (((stat) >> 16) & ~0x8003)
/*! Get packet length */
#define CMICD_DESC_STAT_LEN(stat) ((stat) & 0xffff)
/*! HW access retry times */
#define CMICD_HW_RETRY_TIMES 100000
/*!
* \brief Initialize HW handles.
*
* \param [in] hw HW structure point.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_cmicd_pdma_hw_hdls_init(struct pdma_hw *hw);
/*!
* \brief Initialize descriptor operations.
*
* \param [in] hw HW structure point.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_cmicd_pdma_desc_ops_init(struct pdma_hw *hw);
/*!
* \brief Attach device driver.
*
* \param [in] dev Device structure point.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_cmicd_pdma_driver_attach(struct pdma_dev *dev);
/*!
* \brief Detach device driver.
*
* \param [in] dev Device structure point.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_cmicd_pdma_driver_detach(struct pdma_dev *dev);
#endif /* BCMCNET_CMICD_H */

View File

@ -0,0 +1,379 @@
/*! \file bcmcnet_cmicx.h
*
* CMICx registers and descriptors definitions.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef BCMCNET_CMICX_H
#define BCMCNET_CMICX_H
/*!
* \name CMICX PDMA HW definitions
*/
/*! \{ */
/*! CMICX CMC number */
#define CMICX_PDMA_CMC_MAX 2
/*! CMICX CMC PDMA channels */
#define CMICX_PDMA_CMC_CHAN 8
/*! CMICX PDMA DCB size */
#define CMICX_PDMA_DCB_SIZE 16
/*! \} */
/*!
* \name CMICX PCIe device address definitions
*/
/*! \{ */
/*! CMICX PCIE offset */
#define CMICX_PCIE_SO_OFFSET 0x10000000
/*! Higher DMA address to bus address */
#define DMA_TO_BUS_HI(dma) ((dma) | CMICX_PCIE_SO_OFFSET)
/*! Higher bus address to DMA address */
#define BUS_TO_DMA_HI(bus) ((bus) & ~CMICX_PCIE_SO_OFFSET)
/*! \} */
/*!
* \name CMICX PDMA register definitions
*/
/*! \{ */
#define CMICX_PDMA_CTRLr 0x2100
#define CMICX_PDMA_STATr 0x2114
#define CMICX_PDMA_DESC_LOr 0x2104
#define CMICX_PDMA_DESC_HIr 0x2108
#define CMICX_PDMA_CURR_DESC_LOr 0x2124
#define CMICX_PDMA_CURR_DESC_HIr 0x2128
#define CMICX_PDMA_DESC_HALT_LOr 0x210c
#define CMICX_PDMA_DESC_HALT_HIr 0x2110
#define CMICX_PDMA_COS_CTRL_RX0r 0x2118
#define CMICX_PDMA_COS_CTRL_RX1r 0x211c
#define CMICX_PDMA_INTR_COALr 0x2120
#define CMICX_PDMA_RBUF_THREr 0x212c
#define CMICX_PDMA_DEBUG_CTRLr 0x2130
#define CMICX_PDMA_DEBUG_SM_STATr 0x2134
#define CMICX_PDMA_DEBUG_STATr 0x2138
#define CMICX_PDMA_COUNT_RXr 0x213c
#define CMICX_PDMA_COUNT_TXr 0x2140
#define CMICX_PDMA_COUNT_RX_DROPr 0x2144
#define CMICX_PDMA_DESC_CNT_REQr 0x2148
#define CMICX_PDMA_DESC_CNT_RXr 0x214c
#define CMICX_PDMA_DESC_CNT_STATr 0x2150
#define CMICX_PDMA_IRQ_STATr 0x106c
#define CMICX_PDMA_IRQ_STAT_CLRr 0x1074
/*! \} */
/*!
* \name CMICX PDMA register address
*/
/*! \{ */
/*! Base address */
#define CMICX_GRP_BASE(g) (0x00000000 + 0x3000 * g)
/*! Control register address */
#define CMICX_PDMA_CTRL(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_CTRLr + q * 0x80)
/*! Status register address */
#define CMICX_PDMA_STAT(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_STATr + q * 0x80)
/*! Descriptor Address Lower register address */
#define CMICX_PDMA_DESC_LO(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_DESC_LOr + q * 0x80)
/*! Descriptor Address Higher register address */
#define CMICX_PDMA_DESC_HI(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_DESC_HIr + q * 0x80)
/*! Current Descriptor Address Lower register address */
#define CMICX_PDMA_CURR_DESC_LO(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_CURR_DESC_LOr + q * 0x80)
/*! Current Descriptor Address Higher register address */
#define CMICX_PDMA_CURR_DESC_HI(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_CURR_DESC_HIr + q * 0x80)
/*! Descriptor Halt Address Lower register address */
#define CMICX_PDMA_DESC_HALT_LO(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_DESC_HALT_LOr + q * 0x80)
/*! Descriptor Halt Address Higher register address */
#define CMICX_PDMA_DESC_HALT_HI(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_DESC_HALT_HIr + q * 0x80)
/*! COS Control Rx0 register address */
#define CMICX_PDMA_COS_CTRL_RX0(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_COS_CTRL_RX0r + q * 0x80)
/*! COS Control Rx1 register address */
#define CMICX_PDMA_COS_CTRL_RX1(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_COS_CTRL_RX1r + q * 0x80)
/*! Interrupt Coalesce register address */
#define CMICX_PDMA_INTR_COAL(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_INTR_COALr + q * 0x80)
/*! Rx Buffer Threshhold register address */
#define CMICX_PDMA_RBUF_THRE(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_RBUF_THREr + q * 0x80)
/*! Debug Control register address */
#define CMICX_PDMA_DEBUG_CTRL(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_DEBUG_CTRLr + q * 0x80)
/*! Debug Status register address */
#define CMICX_PDMA_DEBUG_STAT(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_DEBUG_STATr + q * 0x80)
/*! Debug State Machine Status register address */
#define CMICX_PDMA_DEBUG_SM_STAT(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_DEBUG_SM_STATr + q * 0x80)
/*! Rx Packet Count register address */
#define CMICX_PDMA_COUNT_RX(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_COUNT_RXr + q * 0x80)
/*! Tx Packet Count register address */
#define CMICX_PDMA_COUNT_TX(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_COUNT_TXr + q * 0x80)
/*! Dropped Rx Packet Count register address */
#define CMICX_PDMA_COUNT_RX_DROP(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_COUNT_RX_DROPr + q * 0x80)
/*! Requested Descriptor Count register address */
#define CMICX_PDMA_DESC_CNT_REQ(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_DESC_CNT_REQr + q * 0x80)
/*! Received Descriptor Count register address */
#define CMICX_PDMA_DESC_CNT_RX(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_DESC_CNT_RXr + q * 0x80)
/*! Updated Descriptor Count register address */
#define CMICX_PDMA_DESC_CNT_STAT(g, q) (CMICX_GRP_BASE(g) + CMICX_PDMA_DESC_CNT_STATr + q * 0x80)
/*! Interrupt Status register address */
#define CMICX_PDMA_IRQ_STAT(g) (CMICX_GRP_BASE(g) + CMICX_PDMA_IRQ_STATr)
/*! Interrupt Status Clear register address */
#define CMICX_PDMA_IRQ_STAT_CLR(g) (CMICX_GRP_BASE(g) + CMICX_PDMA_IRQ_STAT_CLRr)
/*! Interrupt Enable register address0 */
#define CMICX_PDMA_IRQ_ENAB0 0x18013100
/*! Interrupt Enable register address1 */
#define CMICX_PDMA_IRQ_ENAB1 0x18013104
/*! Interrupt Enable register address2 */
#define CMICX_PDMA_IRQ_ENAB2 0x18013108
/*! Interrupt raw status register address0 */
#define CMICX_PDMA_IRQ_RAW_STAT0 0x18013150
/*! Interrupt raw status register address1 */
#define CMICX_PDMA_IRQ_RAW_STAT1 0x18013154
/*! Interrupt raw status register address2 */
#define CMICX_PDMA_IRQ_RAW_STAT2 0x18013158
/*! EP_TO_CPU Header Size register address */
#define CMICX_EP_TO_CPU_HEADER_SIZE 0x00000004
/*! Top config register address */
#define CMICX_TOP_CONFIG 0x00000008
/*! Credits release register address */
#define CMICX_EPINTF_RELEASE_CREDITS 0x0000006c
/*! Max credits register address */
#define CMICX_EPINTF_MAX_CREDITS 0x00000070
/*! \} */
/*!
* \name Control register definitions
*/
/*! \{ */
/*! Disable abort on error */
#define CMICX_PDMA_NO_ABORT_ON_ERR 0x00002000
/*! EP_TO_CPU header big endianess */
#define CMICX_PDMA_HDR_BIG_ENDIAN 0x00001000
/*! Continuous descriptor mode */
#define CMICX_PDMA_CONTINUOUS_DESC 0x00000200
/*! Continuous DMA mode */
#define CMICX_PDMA_CONTINUOUS 0x00000100
/*! Interrupt after descriptor */
#define CMICX_PDMA_INTR_ON_DESC 0x00000080
/*! Update status on reload */
#define CMICX_PDMA_RLD_STAT_DIS 0x00000040
/*! Dropped on chain end */
#define CMICX_PDMA_DROP_ON_END 0x00000020
/*! Descriptor big endianess */
#define CMICX_PDMA_DESC_BIG_ENDIAN 0x00000010
/*! Packet DMA big endianess */
#define CMICX_PDMA_PKT_BIG_ENDIAN 0x00000008
/*! Abort DMA */
#define CMICX_PDMA_ABORT 0x00000004
/*! Enable DMA */
#define CMICX_PDMA_ENABLE 0x00000002
/*! DMA direction */
#define CMICX_PDMA_DIR 0x00000001
/*! EP_TO_CPU header alignment bytes */
#define CMICX_PDMA_HDR_ALMNT(bytes) (((bytes) & 0x3) << 10)
/*! \} */
/*!
* \name Status register definitions
*/
/*! \{ */
/*! Channel in halt */
#define CMICX_PDMA_IN_HALT 0x00000040
/*! Channel active */
#define CMICX_PDMA_IS_ACTIVE 0x00000002
/*! Chain done */
#define CMICX_PDMA_CHAIN_DONE 0x00000001
/*! \} */
/*!
* \name Interrupt_coalesce register definitions
*/
/*! \{ */
/*! Interrupt coalesce enable */
#define CMICX_PDMA_INTR_COAL_ENA (1 << 31)
/*! Interrupt coalesce threshhold */
#define CMICX_PDMA_INTR_THRESH(cnt) (((cnt) & 0x7fff) << 16)
/*! Interrupt coalesce timeout */
#define CMICX_PDMA_INTR_TIMER(tmr) ((tmr) & 0xffff)
/*! \} */
/*!
* \name Interrupt status&clear register definitions
*/
/*! \{ */
/*! Descriptor done */
#define CMICX_PDMA_IRQ_DESC_DONE(q) (0x00000001 << ((q) * 4))
/*! Chain done */
#define CMICX_PDMA_IRQ_CHAIN_DONE(q) (0x00000002 << ((q) * 4))
/*! Coalescing interrupt */
#define CMICX_PDMA_IRQ_COALESCE_INTR(q) (0x00000004 << ((q) * 4))
/*! Controlled interrupt */
#define CMICX_PDMA_IRQ_CTRLD_INTR(q) (0x00000008 << ((q) * 4))
/*! Interrupt mask */
#define CMICX_PDMA_IRQ_MASK(q) (0xf << ((q) * 4))
/*! Interrupt start number */
#define CMICX_IRQ_START_NUM (128 + 3)
/*! Interrupt number offset */
#define CMICX_IRQ_NUM_OFFSET 4
/*! Interrupt mask shift */
#define CMICX_IRQ_MASK_SHIFT 16
/*! \} */
/*! 32-bit register read */
#define DEV_READ32(_c, _a, _p) \
do { \
if ((_c)->dev->mode != DEV_MODE_VNET) { \
*(_p) = ((volatile uint32_t *)(_c)->hw_addr)[(_a) / 4]; \
} \
} while (0)
/*! 32-bit register write */
#define DEV_WRITE32(_c, _a, _v) \
do { \
if ((_c)->dev->mode != DEV_MODE_VNET) { \
((volatile uint32_t *)(_c)->hw_addr)[(_a) / 4] = (_v); \
} \
} while (0)
/*!
* \brief Rx descriptor.
*/
struct cmicx_rx_desc {
/*! Packet address lower */
volatile uint32_t addr_lo;
/*! Packet address higher */
volatile uint32_t addr_hi;
/*! Packet control */
volatile uint32_t ctrl;
/*! Packet status */
volatile uint32_t status;
} __attribute__((packed));
/*!
* \brief Tx descriptor.
*/
struct cmicx_tx_desc {
/*! Packet address lower */
volatile uint32_t addr_lo;
/*! Packet address higher */
volatile uint32_t addr_hi;
/*! Packet control */
volatile uint32_t ctrl;
/*! Packet status */
volatile uint32_t status;
} __attribute__((packed));
/*!
* Flags related to descriptors.
*/
/*! Disable descriptor status write */
#define CMICX_DESC_CTRL_STAT_WR_DIS (1 << 29)
/*! Descriptors remaining */
#define CMICX_DESC_CTRL_REMAIN(cnt) (((cnt) & 0xf) << 25)
/*! Max remaining descriptors */
#define CMICX_DESC_REMAIN_MAX 8
/*! Controlled interrupt */
#define CMICX_DESC_CTRL_CNTLD_INTR (1 << 24)
/*! Completed interrupt */
#define CMICX_DESC_CTRL_CMPLT_INTR (1 << 23)
/*! Reload DCB */
#define CMICX_DESC_CTRL_RELOAD (1 << 18)
/*! Scatter DCB */
#define CMICX_DESC_CTRL_SCATTER (1 << 17)
/*! Chained DCB */
#define CMICX_DESC_CTRL_CHAIN (1 << 16)
/*! Control flags */
#define CMICX_DESC_CTRL_FLAGS(f) (((f) & 0xffff) << 16)
/*! Purge packet */
#define CMICX_DESC_TX_PURGE_PKT (1 << 6)
/*! Higig packet */
#define CMICX_DESC_TX_HIGIG_PKT (1 << 3)
/*! Packet length */
#define CMICX_DESC_CTRL_LEN(len) ((len) & 0xffff)
/*! Done */
#define CMICX_DESC_STAT_RTX_DONE (1 << 31)
/*! Ecc error */
#define CMICX_DESC_STAT_DATA_ERR (1 << 19)
/*! Cell error */
#define CMICX_DESC_STAT_CELL_ERR (1 << 18)
/*! Error mask */
#define CMICX_DESC_STAT_ERR_MASK (CMICX_DESC_STAT_DATA_ERR | \
CMICX_DESC_STAT_CELL_ERR)
/*! Packet start */
#define CMICX_DESC_STAT_PKT_START (1 << 17)
/*! Packet end */
#define CMICX_DESC_STAT_PKT_END (1 << 16)
/*! Get done state */
#define CMICX_DESC_STAT_DONE(stat) ((stat) & CMICX_DESC_STAT_RTX_DONE)
/*! Get flags */
#define CMICX_DESC_STAT_FLAGS(stat) (((stat) >> 16) & ~0x8003)
/*! Get packet length */
#define CMICX_DESC_STAT_LEN(stat) ((stat) & 0xffff)
/*! Tx packet header size */
#define CMICX_TX_PKT_HDR_SIZE 16
/*! HW access retry times */
#define CMICX_HW_RETRY_TIMES 100000
/*!
* \brief Initialize HW handles.
*
* \param [in] hw HW structure point.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_cmicx_pdma_hw_hdls_init(struct pdma_hw *hw);
/*!
* \brief Initialize descriptor operations.
*
* \param [in] hw HW structure point.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_cmicx_pdma_desc_ops_init(struct pdma_hw *hw);
/*!
* \brief Attach device driver.
*
* \param [in] dev Device structure point.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_cmicx_pdma_driver_attach(struct pdma_dev *dev);
/*!
* \brief Detach device driver.
*
* \param [in] dev Device structure point.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_cmicx_pdma_driver_detach(struct pdma_dev *dev);
#endif /* BCMCNET_CMICX_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,544 @@
/*! \file bcmcnet_dev.h
*
* Generic data structure and macro definitions for BCMCNET device.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef BCMCNET_DEV_H
#define BCMCNET_DEV_H
#include <bcmcnet/bcmcnet_rxtx.h>
/*!
* \brief HW information.
*/
struct hw_info {
/*! HW name */
char *name;
/*! HW version */
int ver_no;
/*! Device ID */
uint32_t dev_id;
/*! Revision ID */
uint32_t rev_id;
/*! Number of CMCs */
uint32_t num_cmcs;
/*! Number of CMC channels */
uint32_t cmc_chans;
/*! Number of channels */
uint32_t num_chans;
/*! Rx DCB size */
uint32_t rx_dcb_size;
/*! Tx DCB size */
uint32_t tx_dcb_size;
/*! Rx packet header size */
uint32_t rx_ph_size;
/*! Tx packet header size */
uint32_t tx_ph_size;
/*! HW structure point */
struct pdma_hw *hw;
};
/*!
* \brief Read 32-bit register.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] addr Register address.
* \param [in] data Pointer to read data.
*/
typedef void (*reg_rd32_f)(struct pdma_hw *hw, uint32_t addr, uint32_t *data);
/*!
* \brief Write 32-bit register.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] addr Register address.
* \param [in] data Data to write.
*/
typedef void (*reg_wr32_f)(struct pdma_hw *hw, uint32_t addr, uint32_t data);
/*!
* \brief Pre-initialize hardware.
*
* \param [in] hw Pointer to hardware structure.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*pre_init_f)(struct pdma_hw *hw);
/*!
* \brief Initialize hardware.
*
* \param [in] hw Pointer to hardware structure.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*hw_init_f)(struct pdma_hw *hw);
/*!
* \brief Configure hardware.
*
* \param [in] hw Pointer to hardware structure.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*hw_config_f)(struct pdma_hw *hw);
/*!
* \brief Reset hardware.
*
* \param [in] hw Pointer to hardware structure.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*hw_reset_f)(struct pdma_hw *hw);
/*!
* \brief Start channel.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] chan Channel number.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*chan_start_f)(struct pdma_hw *hw, int chan);
/*!
* \brief Stop channel.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] chan Channel number.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*chan_stop_f)(struct pdma_hw *hw, int chan);
/*!
* \brief Set up channel.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] chan Channel number.
* \param [in] addr Start DMA address of descriptors.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*chan_setup_f)(struct pdma_hw *hw, int chan, uint64_t addr);
/*!
* \brief Go to ohter descriptor.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] chan Channel number.
* \param [in] addr Destination DMA address of descriptors.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*chan_goto_f)(struct pdma_hw *hw, int chan, uint64_t addr);
/*!
* \brief Clear channel.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] chan Channel number.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*chan_clear_f)(struct pdma_hw *hw, int chan);
/*!
* \brief Get interrupt number.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] chan Channel number.
*
* \retval Returned interrupt number, errors if negative value.
*/
typedef int (*chan_intr_num_get_f)(struct pdma_hw *hw, int chan);
/*!
* \brief Enable interrupt.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] chan Channel number.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*chan_intr_enable_f)(struct pdma_hw *hw, int chan);
/*!
* \brief Disable interrupt.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] chan Channel number.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*chan_intr_disable_f)(struct pdma_hw *hw, int chan);
/*!
* \brief Query interrupt.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] chan Channel number.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*chan_intr_query_f)(struct pdma_hw *hw, int chan);
/*!
* \brief Check interrupt.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] chan Channel number.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*chan_intr_check_f)(struct pdma_hw *hw, int chan);
/*!
* \brief Coalesce interrupt.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] chan Channel number.
* \param [in] count Count value to trigger interrupt.
* \param [in] timer Timer value to triggre interrupt.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*chan_intr_coalesce_f)(struct pdma_hw *hw, int chan, int count, int timer);
/*!
* \brief Dump registers.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] chan Channel number.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*chan_reg_dump_f)(struct pdma_hw *hw, int chan);
/*!
* \brief HW handlers.
*/
struct hw_handlers {
/*! 32 bits register read */
reg_rd32_f reg_rd32;
/*! 32 bits register write */
reg_wr32_f reg_wr32;
/*! HW pre-initialize */
pre_init_f pre_init;
/*! HW initialize */
hw_init_f hw_init;
/*! HW configure */
hw_config_f hw_config;
/*! HW reset */
hw_reset_f hw_reset;
/*! Channel start */
chan_start_f chan_start;
/*! Channel stop */
chan_stop_f chan_stop;
/*! Channel setup */
chan_setup_f chan_setup;
/*! Channel goto */
chan_goto_f chan_goto;
/*! Channel clear */
chan_clear_f chan_clear;
/*! Channel interrupt number get */
chan_intr_num_get_f chan_intr_num_get;
/*! Channel interrupt enable */
chan_intr_enable_f chan_intr_enable;
/*! Channel interrupt disable */
chan_intr_disable_f chan_intr_disable;
/*! Channel interrupt query */
chan_intr_query_f chan_intr_query;
/*! Channel interrupt check */
chan_intr_check_f chan_intr_check;
/*! Channel interrupt coalesce */
chan_intr_coalesce_f chan_intr_coalesce;
/*! Channel registers dump */
chan_reg_dump_f chan_reg_dump;
};
/*!
* \brief Initialize Rx descriptor.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] rxq Pointer to Rx queue struture.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_MEMORY Allocation failed.
*/
typedef int (*rx_desc_init_f)(struct pdma_hw *hw, struct pdma_rx_queue *rxq);
/*!
* \brief Clean up Rx descriptor.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] rxq Pointer to Rx queue struture.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*rx_desc_clean_f)(struct pdma_hw *hw, struct pdma_rx_queue *rxq);
/*!
* \brief Clean up Rx ring.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] rxq Pointer to Rx queue struture.
* \param [in] budget Budget for each operation.
*
* \retval Number of descriptors finished.
*/
typedef int (*rx_ring_clean_f)(struct pdma_hw *hw, struct pdma_rx_queue *rxq, int budget);
/*!
* \brief Dump Rx ring.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] rxq Pointer to Rx queue struture.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*rx_ring_dump_f)(struct pdma_hw *hw, struct pdma_rx_queue *rxq);
/*!
* \brief Suspend Rx queue.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] rxq Pointer to Rx queue struture.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*rx_suspend_f)(struct pdma_hw *hw, struct pdma_rx_queue *rxq);
/*!
* \brief Resume Rx queue.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] rxq Pointer to Rx queue struture.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*rx_resume_f)(struct pdma_hw *hw, struct pdma_rx_queue *rxq);
/*!
* \brief Initialize Tx descriptor.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] txq Pointer to Tx queue struture.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_MEMORY Allocation failed.
*/
typedef int (*tx_desc_init_f)(struct pdma_hw *hw, struct pdma_tx_queue *txq);
/*!
* \brief Clean up Tx descriptor.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] txq Pointer to Tx queue struture.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*tx_desc_clean_f)(struct pdma_hw *hw, struct pdma_tx_queue *txq);
/*!
* \brief Clean up Tx ring.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] txq Pointer to Tx queue struture.
* \param [in] budget Budget for each operation.
*
* \retval Number of descriptors finished.
*/
typedef int (*tx_ring_clean_f)(struct pdma_hw *hw, struct pdma_tx_queue *txq, int budget);
/*!
* \brief Dump Tx ring.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] txq Pointer to Tx queue struture.
*
* \retval SHR_E_NONE No errors.
*/
typedef int (*tx_ring_dump_f)(struct pdma_hw *hw, struct pdma_tx_queue *txq);
/*!
* \brief Transmit packet.
*
* \param [in] hw Pointer to hardware structure.
* \param [in] txq Pointer to Tx queue struture.
* \param [in] buf Pointer to packet buffer struture.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
typedef int (*pkt_xmit_f)(struct pdma_hw *hw, struct pdma_tx_queue *txq, void *buf);
/*!
* \brief Descriptor operations.
*/
struct desc_operations {
/*! Rx descriptor initialize */
rx_desc_init_f rx_desc_init;
/*! Rx descriptor cleanup */
rx_desc_clean_f rx_desc_clean;
/*! Rx ring cleanup */
rx_ring_clean_f rx_ring_clean;
/*! Rx ring dump */
rx_ring_dump_f rx_ring_dump;
/*! Rx suspend */
rx_suspend_f rx_suspend;
/*! Rx resume */
rx_resume_f rx_resume;
/*! Tx descriptor initialize */
tx_desc_init_f tx_desc_init;
/*! Tx descriptor cleanup */
tx_desc_clean_f tx_desc_clean;
/*! Tx ring cleanup */
tx_ring_clean_f tx_ring_clean;
/*! Tx ring dump */
tx_ring_dump_f tx_ring_dump;
/*! Tx transmit */
pkt_xmit_f pkt_xmit;
};
/*!
* \brief HW structure.
*/
struct pdma_hw {
/*! Device number */
int unit;
/*! Device structure point */
struct pdma_dev *dev;
/*! HW information */
struct hw_info info;
/*! HW handlers */
struct hw_handlers hdls;
/*! HW operations */
struct desc_operations dops;
};
/*!
* \brief Open device.
*
* \param [in] dev Device structure point.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_open(struct pdma_dev *dev);
/*!
* \brief Coalesce Rx interrupt.
*
* \param [in] dev Device structure point.
* \param [in] queue Rx queue number.
* \param [in] count Interrupt threshhold.
* \param [in] timer Timer value.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_rx_queue_int_coalesce(struct pdma_dev *dev, int queue, int count, int timer);
/*!
* \brief Coalesce Tx interrupt.
*
* \param [in] dev Device structure point.
* \param [in] queue Tx queue number.
* \param [in] count Interrupt threshhold.
* \param [in] timer Timer value.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_tx_queue_int_coalesce(struct pdma_dev *dev, int queue, int count, int timer);
/*!
* \brief Dump Rx queue registers.
*
* \param [in] dev Device structure point.
* \param [in] queue Rx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_rx_queue_reg_dump(struct pdma_dev *dev, int queue);
/*!
* \brief Dump Tx queue registers.
*
* \param [in] dev Device structure point.
* \param [in] queue Tx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_tx_queue_reg_dump(struct pdma_dev *dev, int queue);
#endif /* BCMCNET_DEV_H */

View File

@ -0,0 +1,305 @@
/*! \file bcmcnet_internal.h
*
* BCMCNET internal data structure and macro definitions.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef BCMCNET_INTERNAL_H
#define BCMCNET_INTERNAL_H
#include <bcmcnet/bcmcnet_dev.h>
/*! CMICD name */
#define CMICD_DEV_NAME "cmicd"
/*! CMICX name */
#define CMICX_DEV_NAME "cmicx"
/*!
* \brief Allocate descriptor ring buffer.
*
* \param [in] dev Pointer to Packet DMA device.
* \param [in] dma DMA address of ring buffer.
*
* \retval Pointer to DMA buffer or NULL if an error occurred.
*/
typedef void *(*ring_buf_alloc_f)(struct pdma_dev *dev, uint32_t, dma_addr_t *dma);
/*!
* \brief Free descriptor ring buffer.
*
* \param [in] dev Pointer to Packet DMA device.
* \param [in] size Size of DMA buffer.
* \param [in] mem Pointer to DMA buffer.
* \param [in] dma DMA address of ring buffer.
*/
typedef void (*ring_buf_free_f)(struct pdma_dev *dev, uint32_t size, void *mem,
dma_addr_t dma);
/*!
* \brief Allocate Rx packet buffer.
*
* \param [in] dev Pointer to Packet DMA device.
* \param [in] rxq Pointer to Rx queue struture.
* \param [in] pbuf Pointer to packet buffer structure.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_MEMORY Allocation failed.
*/
typedef int (*rx_buf_alloc_f)(struct pdma_dev *dev, struct pdma_rx_queue *rxq,
struct pdma_rx_buf *pbuf);
/*!
* \brief Get Rx packet buffer DMA address.
*
* \param [in] dev Pointer to Packet DMA device.
* \param [in] rxq Pointer to Rx queue struture.
* \param [in] pbuf Pointer to packet buffer structure.
* \param [in] dma DMA address of packet buffer.
*/
typedef void (*rx_buf_dma_f)(struct pdma_dev *dev, struct pdma_rx_queue *rxq,
struct pdma_rx_buf *pbuf, dma_addr_t *dma);
/*!
* \brief Check Rx packet buffer validity.
*
* \param [in] dev Pointer to Packet DMA device.
* \param [in] rxq Pointer to Rx queue struture.
* \param [in] pbuf Pointer to packet buffer structure.
*
* \retval Ture Buffer is available or FALSE.
*/
typedef int (*rx_buf_avail_f)(struct pdma_dev *dev, struct pdma_rx_queue *rxq,
struct pdma_rx_buf *pbuf);
/*!
* \brief Get Rx packet buffer.
*
* \param [in] dev Pointer to Packet DMA device.
* \param [in] rxq Pointer to Rx queue struture.
* \param [in] pbuf Pointer to packet buffer structure.
* \param [in] len Packet length.
*
* \retval Pointer to packet header structure or NULL if failed.
*/
typedef struct pkt_hdr *(*rx_buf_get_f)(struct pdma_dev *dev, struct pdma_rx_queue *rxq,
struct pdma_rx_buf *pbuf, int len);
/*!
* \brief Put Rx packet buffer.
*
* \param [in] dev Pointer to Packet DMA device.
* \param [in] rxq Pointer to Rx queue struture.
* \param [in] pbuf Pointer to packet buffer structure.
* \param [in] len Packet length.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_MEMORY Allocation failed.
*/
typedef int (*rx_buf_put_f)(struct pdma_dev *dev, struct pdma_rx_queue *rxq,
struct pdma_rx_buf *pbuf, int len);
/*!
* \brief Free Rx packet buffer.
*
* \param [in] dev Pointer to Packet DMA device.
* \param [in] rxq Pointer to Rx queue struture.
* \param [in] pbuf Pointer to packet buffer structure.
*/
typedef void (*rx_buf_free_f)(struct pdma_dev *dev, struct pdma_rx_queue *rxq,
struct pdma_rx_buf *pbuf);
/*!
* \brief Get Rx packet buffer mode.
*
* \param [in] dev Pointer to Packet DMA device.
* \param [in] rxq Pointer to Rx queue struture.
*
* \retval Buffer mode.
*/
typedef enum buf_mode (*rx_buf_mode_f)(struct pdma_dev *dev, struct pdma_rx_queue *rxq);
/*!
* \brief Get Tx packet buffer.
*
* \param [in] dev Pointer to Packet DMA device.
* \param [in] txq Pointer to Rx queue struture.
* \param [in] pbuf Pointer to packet buffer structure.
* \param [in] buf Packet buffer.
*
* \retval Pointer to packet header structure or NULL if failed.
*/
typedef struct pkt_hdr *(*tx_buf_get_f)(struct pdma_dev *dev, struct pdma_tx_queue *txq,
struct pdma_tx_buf *pbuf, void *buf);
/*!
* \brief Get Tx packet buffer DMA address.
*
* \param [in] dev Pointer to Packet DMA device.
* \param [in] txq Pointer to Rx queue struture.
* \param [in] pbuf Pointer to packet buffer structure.
* \param [in] dma DMA address of packet buffer.
*/
typedef void (*tx_buf_dma_f)(struct pdma_dev *dev, struct pdma_tx_queue *txq,
struct pdma_tx_buf *pbuf, dma_addr_t *dma);
/*!
* \brief Free Tx packet buffer.
*
* \param [in] dev Pointer to Packet DMA device.
* \param [in] txq Pointer to Rx queue struture.
* \param [in] pbuf Pointer to packet buffer structure.
*/
typedef void (*tx_buf_free_f)(struct pdma_dev *dev, struct pdma_tx_queue *txq,
struct pdma_tx_buf *pbuf);
/*!
* \brief Buffer manager.
*/
struct pdma_buf_mngr {
/*! Allocate descriptor ring buffer */
ring_buf_alloc_f ring_buf_alloc;
/*! Free descriptor ring buffer */
ring_buf_free_f ring_buf_free;
/*! Allocate Rx packet buffer */
rx_buf_alloc_f rx_buf_alloc;
/*! Get Rx packet buffer DMA address */
rx_buf_dma_f rx_buf_dma;
/*! Check Rx packet buffer validity */
rx_buf_avail_f rx_buf_avail;
/*! Get Rx packet buffer */
rx_buf_get_f rx_buf_get;
/*! Put Rx packet buffer */
rx_buf_put_f rx_buf_put;
/*! Free Rx packet buffer */
rx_buf_free_f rx_buf_free;
/*! Get Rx packet buffer mode */
rx_buf_mode_f rx_buf_mode;
/*! Get Tx packet buffer */
tx_buf_get_f tx_buf_get;
/*! Get Tx packet buffer DMA address */
tx_buf_dma_f tx_buf_dma;
/*! Free Tx packet buffer */
tx_buf_free_f tx_buf_free;
};
/*!
* \brief Wait for the kernel networking subsystem.
*
* \param [in] unit Device number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_FAIL Operation failed.
*/
typedef int (*bcmcnet_vnet_wait_f)(int unit);
/*!
* \brief Wake up the kernel networking subsystem.
*
* \param [in] unit Device number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_FAIL Operation failed.
*/
typedef int (*bcmcnet_hnet_wake_f)(int unit);
/*!
* \brief Dock to the kernel networking subsystem.
*
* \param [in] unit Device number.
* \param [in] vsync Sync data.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_FAIL Operation failed.
*/
typedef int (*bcmcnet_vnet_dock_f)(int unit, vnet_sync_t *vsync);
/*!
* \brief Undock from the kernel networking subsystem.
*
* \param [in] unit Device number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_FAIL Operation failed.
*/
typedef int (*bcmcnet_vnet_undock_f)(int unit);
/*!
* \brief VNET operations.
*/
typedef struct bcmcnet_vnet_ops_s {
/*!
* VNET wait for HNET.
* VNET calls this to wait for any notification from HNET.
*/
bcmcnet_vnet_wait_f vnet_wait;
/*!
* VNET wake up HNET.
* VNET calls this to notify HNET that Tx/Rx is ready.
*/
bcmcnet_hnet_wake_f hnet_wake;
/*!
* VNET dock to HNET.
* This is called to notify HNET that VNET is ready to work and synchronize
* vrings information to HNET.
*/
bcmcnet_vnet_dock_f vnet_dock;
/*!
* VNET undock from HNET.
* This is called to notify HNET that VNET is ready to leave.
*/
bcmcnet_vnet_undock_f vnet_undock;
} bcmcnet_vnet_ops_t;
/*!
* \brief Initialize buffer manager.
*
* \param [in] dev Device structure pointer.
*/
extern void
bcmcnet_buf_mngr_init(struct pdma_dev *dev);
/*!
* \brief Register VNET operations.
*
* \param [in] unit Device number.
* \param [in] vnet_ops VNET operations.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_PARAM Invalid parameters.
*/
extern int
bcmcnet_vnet_ops_register(int unit, bcmcnet_vnet_ops_t *vnet_ops);
#endif /* BCMCNET_INTERNAL_H */

View File

@ -0,0 +1,512 @@
/*! \file bcmcnet_rxtx.h
*
* Generic data structure and macro definitions for BCMCNET Rx/Tx.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef BCMCNET_RXTX_H
#define BCMCNET_RXTX_H
/*! Default descriptor number in each ring */
#define NUM_RING_DESC 64
/*! Maximum number of packets to be handled in one poll call */
#define NUM_RXTX_BUDGET 64
/*!
* \brief Rx buffer mode definitions.
*/
enum buf_mode {
/*! Private DMA buffer in user space */
PDMA_BUF_MODE_PRIV,
/*! SKB in kernel */
PDMA_BUF_MODE_SKB,
/*! Paged buffer in kernel */
PDMA_BUF_MODE_PAGE,
/*! Kernel buffer mapped to user space */
PDMA_BUF_MODE_MAPPED,
/*! MAX mode */
PDMA_BUF_MODE_MAX
};
/*!
* \brief Rx queue statistics.
*/
struct rx_stats {
/*! Number of received packets */
uint64_t packets;
/*! Number of received bytes */
uint64_t bytes;
/*! Number of dropped packets */
uint64_t dropped;
/*! Number of errors */
uint64_t errors;
/*! Number of head errors */
uint64_t head_errors;
/*! Number of data errors */
uint64_t data_errors;
/*! Number of cell errors */
uint64_t cell_errors;
/*! Number of failed allocation */
uint64_t nomems;
};
/*!
* Rx queue structure
*/
struct pdma_rx_queue {
/*! Group index to which this queue belongs */
uint32_t group_id;
/*! Global channel index */
uint32_t chan_id;
/*! Queue index */
uint32_t queue_id;
/*! Pointer to the device control structure */
struct dev_ctrl *ctrl;
/*! Rx packet buffer pointers */
struct pdma_rx_buf *pbuf;
/*! Rx ring address */
void *ring;
/*! Rx ring DMA address */
dma_addr_t ring_addr;
/*! Rx ring DMA halt address */
dma_addr_t halt_addr;
/*! Rx buffer size */
uint32_t buf_size;
/*! Total number of descriptors */
uint32_t nb_desc;
/*! Next free ring entry */
uint32_t curr;
/*! Halt ring entry */
uint32_t halt;
/*! Max free descriptors to hold */
uint32_t free_thresh;
/*! Rx interrupt coalesce value */
uint32_t ic_val;
/*! Rx interrupt coalescing */
int intr_coalescing;
/*! Queue statistics */
struct rx_stats stats;
/*! Rx queue spin lock */
sal_spinlock_t lock;
/*! Queue state */
int state;
/*! Queue is used */
#define PDMA_RX_QUEUE_USED (1 << 0)
/*! Queue is setup */
#define PDMA_RX_QUEUE_SETUP (1 << 1)
/*! Queue is active */
#define PDMA_RX_QUEUE_ACTIVE (1 << 2)
/*! Queue is busy */
#define PDMA_RX_QUEUE_BUSY (1 << 3)
/*! Queue is suspended */
#define PDMA_RX_QUEUE_XOFF (1 << 4)
/*! Queue is batch refilled */
#define PDMA_RX_BATCH_REFILL (1 << 5)
/*! DMA buffer mode */
enum buf_mode mode;
};
/*!
* \brief Tx queue statistics.
*/
struct tx_stats {
/*! Number of sent packets */
uint64_t packets;
/*! Number of sent bytes */
uint64_t bytes;
/*! Number of dropped packets */
uint64_t dropped;
/*! Number of errors */
uint64_t errors;
/*! Number of suspends */
uint64_t xoffs;
};
/*!
* \brief Tx queue structure.
*/
struct pdma_tx_queue {
/*! Group index to which this queue belongs */
uint32_t group_id;
/*! Global channel index */
uint32_t chan_id;
/*! Queue index */
uint32_t queue_id;
/*! pointer to the device control structure */
struct dev_ctrl *ctrl;
/*! Tx packet buffer pointers */
struct pdma_tx_buf *pbuf;
/*! Tx ring address */
void *ring;
/*! Tx ring DMA address */
dma_addr_t ring_addr;
/*! Tx ring DMA halt address */
dma_addr_t halt_addr;
/*! Total number of descriptors */
uint32_t nb_desc;
/*! Next free ring entry */
uint32_t curr;
/*! First entry to be transmitted */
uint32_t dirt;
/*! Halt ring entry */
uint32_t halt;
/*! Max free descriptors to hold in non-intr mode */
uint32_t free_thresh;
/*! Tx interrupt coalesce value */
uint32_t ic_val;
/*! Tx interrupt coalescing */
int intr_coalescing;
/*! Queue statistics */
struct tx_stats stats;
/*! Tx queue spin lock */
sal_spinlock_t lock;
/*! Tx mutex spin lock */
sal_spinlock_t mutex;
/*! Tx mutex and flow control semaphore */
sal_sem_t sem;
/*! Queue state */
int state;
/*! Queue is used */
#define PDMA_TX_QUEUE_USED (1 << 0)
/*! Queue is setup */
#define PDMA_TX_QUEUE_SETUP (1 << 1)
/*! Queue is active */
#define PDMA_TX_QUEUE_ACTIVE (1 << 2)
/*! Queue is setup */
#define PDMA_TX_QUEUE_BUSY (1 << 3)
/*! Queue is suspended */
#define PDMA_TX_QUEUE_XOFF (1 << 4)
/*! Queue is poll mode */
#define PDMA_TX_QUEUE_POLL (1 << 5)
/*! DMA buffer mode */
enum buf_mode mode;
};
/*!
* \brief Setup Rx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Rx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_rx_queue_setup(struct pdma_dev *dev, int queue);
/*!
* \brief Release Rx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Rx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_rx_queue_release(struct pdma_dev *dev, int queue);
/*!
* \brief Restore Rx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Rx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_rx_queue_restore(struct pdma_dev *dev, int queue);
/*!
* \brief Setup virtual Rx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Rx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_rx_vqueue_setup(struct pdma_dev *dev, int queue);
/*!
* \brief Release virtual Rx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Rx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_rx_vqueue_release(struct pdma_dev *dev, int queue);
/*!
* \brief Setup Tx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Tx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_tx_queue_setup(struct pdma_dev *dev, int queue);
/*!
* \brief Release Tx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Tx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_tx_queue_release(struct pdma_dev *dev, int queue);
/*!
* \brief Restore Tx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Tx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_tx_queue_restore(struct pdma_dev *dev, int queue);
/*!
* \brief Setup virtual Tx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Rx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_tx_vqueue_setup(struct pdma_dev *dev, int queue);
/*!
* \brief Release virtual Tx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Rx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_tx_vqueue_release(struct pdma_dev *dev, int queue);
/*!
* \brief Suspend Rx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Rx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_rx_queue_suspend(struct pdma_dev *dev, int queue);
/*!
* \brief Resume Rx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Rx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_rx_queue_resume(struct pdma_dev *dev, int queue);
/*!
* \brief Suspend Tx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Tx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_tx_queue_suspend(struct pdma_dev *dev, int queue);
/*!
* \brief Resume Tx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Tx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_tx_queue_resume(struct pdma_dev *dev, int queue);
/*!
* \brief Wakeup Tx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Tx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_tx_queue_wakeup(struct pdma_dev *dev, int queue);
/*!
* \brief Start Tx queue transmission.
*
* \param [in] dev Device structure point.
* \param [in] queue Tx queue number.
* \param [in] buf Tx packet buffer.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_tx_queue_xmit(struct pdma_dev *dev, int queue, void *buf);
/*!
* \brief Poll Rx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Rx queue number.
* \param [in] budget Poll budget.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_rx_queue_poll(struct pdma_dev *dev, int queue, int budget);
/*!
* \brief Poll Tx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Tx queue number.
* \param [in] budget Poll budget.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_tx_queue_poll(struct pdma_dev *dev, int queue, int budget);
/*!
* \brief Poll queue group.
*
* \param [in] dev Device structure point.
* \param [in] group Group number.
* \param [in] budget Poll budget.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_group_poll(struct pdma_dev *dev, int group, int budget);
/*!
* \brief Dump Rx ring.
*
* \param [in] dev Device structure point.
* \param [in] queue Rx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_rx_ring_dump(struct pdma_dev *dev, int queue);
/*!
* \brief Dump Tx ring.
*
* \param [in] dev Device structure point.
* \param [in] queue Tx queue number.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
bcmcnet_pdma_tx_ring_dump(struct pdma_dev *dev, int queue);
#endif /* BCMCNET_RXTX_H */

View File

@ -0,0 +1,263 @@
/*! \file bcmcnet_types.h
*
* BCMCNET public data structure and macro definitions.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef BCMCNET_TYPES_H
#define BCMCNET_TYPES_H
#include <bcmcnet/bcmcnet_dep.h>
/*! Maximum length of device name */
#define DEV_NAME_LEN_MAX 16
/*! Maximum number of groups supported each device */
#define NUM_GRP_MAX 4
/*! Maximum number of queues supported each group */
#define NUM_Q_PER_GRP 8
/*! Maximum number of queues supported each device */
#define NUM_QUE_MAX (NUM_GRP_MAX * NUM_Q_PER_GRP)
/*! Maximum length of jumbo frame */
#define JUMBO_FRAME_LEN_MAX 0xffff
/*! Maximum Rx buffer size */
#define RX_BUF_SIZE_MAX JUMBO_FRAME_LEN_MAX
/*! Minimum Rx buffer size */
#define RX_BUF_SIZE_MIN 68
/*! Default Rx buffer size */
#define RX_BUF_SIZE_DFLT 9216
/*!
* \brief Transmission direction.
*/
enum pdma_dir {
PDMA_Q_RX = 0,
PDMA_Q_TX
};
/*!
* \brief Device information.
*/
typedef struct bcmcnet_dev_info {
/*! Device name */
char dev_name[DEV_NAME_LEN_MAX];
/*! Device ID */
uint32_t dev_id;
/*! Device type */
uint32_t dev_type;
/*! Maximum number of groups */
uint32_t max_groups;
/*! Maximum number of queues */
uint32_t max_queues;
/*! Bitmap of groups at work */
uint32_t bm_groups;
/*! Bitmap of Rx queues at work */
uint32_t bm_rx_queues;
/*! Bitmap of Tx queues at work */
uint32_t bm_tx_queues;
/*! Number of groups at work */
uint32_t nb_groups;
/*! Number of Rx queues at work */
uint32_t nb_rx_queues;
/*! Number of Tx queues at work */
uint32_t nb_tx_queues;
/*! Rx descriptor size */
uint32_t rx_desc_size;
/*! Tx descriptor size */
uint32_t tx_desc_size;
/*! Rx packet header size */
uint32_t rx_ph_size;
/*! Tx packet header size */
uint32_t tx_ph_size;
/*! Rx buffer size */
uint32_t rx_buf_dflt;
/*! Number of descriptors for a queue */
uint32_t nb_desc_dflt;
/*! Rx buffer size per queue */
uint32_t rx_buf_size[NUM_QUE_MAX];
/*! Number of Rx descriptors per queue */
uint32_t nb_rx_desc[NUM_QUE_MAX];
/*! Number of Tx descriptors per queue */
uint32_t nb_tx_desc[NUM_QUE_MAX];
} bcmcnet_dev_info_t;
/*!
* \brief Device statistics.
*/
typedef struct bcmcnet_dev_stats {
/*! Number of successfully received packets */
uint64_t rx_packets;
/*! Number of successfully received bytes */
uint64_t rx_bytes;
/*! Number of dropped packets */
uint64_t rx_dropped;
/*! Number of erroneous received packets */
uint64_t rx_errors;
/*! Number of error head packets */
uint64_t rx_head_errors;
/*! Number of error data packets */
uint64_t rx_data_errors;
/*! Number of error cell packets */
uint64_t rx_cell_errors;
/*! Number of RX pktbuf allocation failures */
uint64_t rx_nomems;
/*! Number of successfully transmitted packets */
uint64_t tx_packets;
/*! Number of successfully transmitted bytes */
uint64_t tx_bytes;
/*! Number of dropped packets */
uint64_t tx_dropped;
/*! Number of failed transmitted packets */
uint64_t tx_errors;
/*! Number of suspended transmission */
uint64_t tx_xoffs;
/*! Number of interrupts */
uint64_t intrs;
/*! Number of successfully received packets per queue */
uint64_t rxq_packets[NUM_QUE_MAX];
/*! Number of successfully received bytes per queue */
uint64_t rxq_bytes[NUM_QUE_MAX];
/*! Number of dropped packets per queue */
uint64_t rxq_dropped[NUM_QUE_MAX];
/*! Number of erroneous received packets per queue */
uint64_t rxq_errors[NUM_QUE_MAX];
/*! Number of error head packets per queue */
uint64_t rxq_head_errors[NUM_QUE_MAX];
/*! Number of error data packets per queue */
uint64_t rxq_data_errors[NUM_QUE_MAX];
/*! Number of error cell packets per queue */
uint64_t rxq_cell_errors[NUM_QUE_MAX];
/*! Number of RX pktbuf allocation failures per queue */
uint64_t rxq_nomems[NUM_QUE_MAX];
/*! Number of successfully transmitted bytes per queue */
uint64_t txq_packets[NUM_QUE_MAX];
/*! Number of successfully transmitted bytes per queue */
uint64_t txq_bytes[NUM_QUE_MAX];
/*! Number of dropped packets per queue */
uint64_t txq_dropped[NUM_QUE_MAX];
/*! Number of failed transmitted packets per queue */
uint64_t txq_errors[NUM_QUE_MAX];
/*! Number of suspended transmission per queue */
uint64_t txq_xoffs[NUM_QUE_MAX];
} bcmcnet_dev_stats_t;
/*!
* \brief Device modes.
*/
typedef enum dev_mode_e {
/*!
* User network mode.
* The standalone CNET works in user space.
*/
DEV_MODE_UNET = 0,
/*!
* Kernel network mode.
* Combined with KNET module, CNET works in kernel space.
*/
DEV_MODE_KNET,
/*!
* Virtual network mode.
* CNET works in user space as a virtual network.
* The hypervisor must be deployed in KNET module.
*/
DEV_MODE_VNET,
/*!
* Hyper network mode.
* Combined with KNET module, CNET works in kernel space as a hypervisor.
* The virtual network is not neccessary in this mode.
*/
DEV_MODE_HNET,
/*! Maximum number of mode */
DEV_MODE_MAX
} dev_mode_t;
/*!
* \brief VNET sync data.
*/
typedef struct vnet_sync_s {
/*! Rx ring address */
uint64_t rx_ring_addr[NUM_QUE_MAX];
/*! Rx ring size */
uint32_t rx_ring_size[NUM_QUE_MAX];
/*! Tx ring address */
uint64_t tx_ring_addr[NUM_QUE_MAX];
/*! Tx ring size */
uint32_t tx_ring_size[NUM_QUE_MAX];
} vnet_sync_t;
#endif /* BCMCNET_TYPES_H */

View File

@ -0,0 +1,701 @@
/*! \file bcmcnet_core.c
*
* Utility routines for BCMCNET driver.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <bcmcnet/bcmcnet_core.h>
#include <bcmcnet/bcmcnet_dev.h>
/*!
* Initialize a device
*/
int
bcmcnet_pdma_dev_init(struct pdma_dev *dev)
{
int rv;
/* Open the device */
rv = bcmcnet_pdma_open(dev);
if (SHR_FAILURE(rv)) {
return rv;
}
dev->attached = 1;
return SHR_E_NONE;
}
/*!
* Clean up a device
*/
int
bcmcnet_pdma_dev_cleanup(struct pdma_dev *dev)
{
if (!dev->attached) {
return SHR_E_NONE;
}
dev->ops->dev_close(dev);
dev->ops = NULL;
dev->attached = 0;
return SHR_E_NONE;
}
/*!
* Start a device
*/
int
bcmcnet_pdma_dev_start(struct pdma_dev *dev)
{
struct dev_ctrl *ctrl = &dev->ctrl;
uint32_t qi;
int rv;
if (!dev->attached) {
return SHR_E_UNAVAIL;
}
if (dev->started) {
return SHR_E_NONE;
}
rv = dev->ops->dev_config(dev, ctrl->bm_rxq, ctrl->bm_txq);
if (SHR_FAILURE(rv)) {
return rv;
}
/* Start all the Rx queues */
for (qi = 0; qi < ctrl->nb_rxq; qi++) {
rv = dev->ops->rx_queue_setup(dev, qi);
if (SHR_FAILURE(rv)) {
return rv;
}
dev->ops->rx_queue_intr_enable(dev, qi);
dev->ops->rx_queue_start(dev, qi);
}
/* Start all the Tx queues */
for (qi = 0; qi < ctrl->nb_txq; qi++) {
dev->ops->tx_queue_setup(dev, qi);
dev->ops->tx_queue_intr_enable(dev, qi);
dev->ops->tx_queue_start(dev, qi);
dev->ops->tx_queue_wakeup(dev, qi);
}
bcmcnet_pdma_dev_info_get(dev);
dev->started = 1;
return SHR_E_NONE;
}
/*!
* Stop a device
*/
int
bcmcnet_pdma_dev_stop(struct pdma_dev *dev)
{
struct dev_ctrl *ctrl = &dev->ctrl;
uint32_t qi;
if (!dev->attached) {
return SHR_E_UNAVAIL;
}
if (!dev->started) {
return SHR_E_NONE;
}
/* Stop all the Rx queues */
for (qi = 0; qi < ctrl->nb_rxq; qi++) {
dev->ops->rx_queue_intr_disable(dev, qi);
dev->ops->rx_queue_stop(dev, qi);
dev->ops->rx_queue_release(dev, qi);
}
/* Stop all the Tx queues */
for (qi = 0; qi < ctrl->nb_txq; qi++) {
dev->ops->tx_queue_intr_disable(dev, qi);
dev->ops->tx_queue_stop(dev, qi);
dev->ops->tx_queue_wakeup(dev, qi);
dev->ops->tx_queue_release(dev, qi);
}
dev->started = 0;
return SHR_E_NONE;
}
/*!
* Suspend a device
*/
int
bcmcnet_pdma_dev_suspend(struct pdma_dev *dev)
{
if (!dev->attached) {
return SHR_E_UNAVAIL;
}
return dev->ops->dev_suspend(dev);
}
/*!
* Resume a device
*/
int
bcmcnet_pdma_dev_resume(struct pdma_dev *dev)
{
if (!dev->attached) {
return SHR_E_UNAVAIL;
}
return dev->ops->dev_resume(dev);
}
/*!
* Suspend Rx
*/
int
bcmcnet_pdma_dev_rx_suspend(struct pdma_dev *dev)
{
struct dev_ctrl *ctrl = &dev->ctrl;
uint32_t qi;
if (!dev->attached) {
return SHR_E_UNAVAIL;
}
/* Suspend all the Rx queues */
for (qi = 0; qi < ctrl->nb_rxq; qi++) {
dev->ops->rx_queue_suspend(dev, qi);
}
return SHR_E_NONE;
}
/*!
* Resume Rx
*/
int
bcmcnet_pdma_dev_rx_resume(struct pdma_dev *dev)
{
struct dev_ctrl *ctrl = &dev->ctrl;
uint32_t qi;
if (!dev->attached) {
return SHR_E_UNAVAIL;
}
/* Resume all the Rx queues */
for (qi = 0; qi < ctrl->nb_rxq; qi++) {
dev->ops->rx_queue_resume(dev, qi);
}
return SHR_E_NONE;
}
/*!
* Dock to HNET
*/
int
bcmcnet_pdma_dev_dock(struct pdma_dev *dev)
{
struct dev_ctrl *ctrl = &dev->ctrl;
uint32_t qi;
int rv;
if (!dev->attached) {
return SHR_E_UNAVAIL;
}
/* Set up all the virtual Rx queues */
for (qi = 0; qi < ctrl->nb_rxq; qi++) {
rv = dev->ops->rx_vqueue_setup(dev, qi);
if (SHR_FAILURE(rv)) {
return rv;
}
}
/* Set up all the virtual Tx queues */
for (qi = 0; qi < ctrl->nb_txq; qi++) {
rv = dev->ops->tx_vqueue_setup(dev, qi);
if (SHR_FAILURE(rv)) {
return rv;
}
}
return SHR_E_NONE;
}
/*!
* Undock from HNET
*/
int
bcmcnet_pdma_dev_undock(struct pdma_dev *dev)
{
struct dev_ctrl *ctrl = &dev->ctrl;
uint32_t qi;
if (!dev->attached) {
return SHR_E_UNAVAIL;
}
/* Release all the virtual Rx queues */
for (qi = 0; qi < ctrl->nb_rxq; qi++) {
dev->ops->rx_vqueue_release(dev, qi);
}
/* Release all the virtual Tx queues */
for (qi = 0; qi < ctrl->nb_txq; qi++) {
dev->ops->tx_vqueue_release(dev, qi);
}
return SHR_E_NONE;
}
/*!
* Get device information
*/
int
bcmcnet_pdma_dev_info_get(struct pdma_dev *dev)
{
if (!dev->ops || !dev->ops->dev_info_get) {
return SHR_E_INTERNAL;
}
dev->ops->dev_info_get(dev);
return SHR_E_NONE;
}
/*!
* Get device statistics
*/
int
bcmcnet_pdma_dev_stats_get(struct pdma_dev *dev)
{
if (!dev->ops || !dev->ops->dev_stats_get) {
return SHR_E_INTERNAL;
}
dev->ops->dev_stats_get(dev);
return SHR_E_NONE;
}
/*!
* Reset device statistics
*/
int
bcmcnet_pdma_dev_stats_reset(struct pdma_dev *dev)
{
if (!dev->ops || !dev->ops->dev_stats_reset) {
return SHR_E_INTERNAL;
}
dev->ops->dev_stats_reset(dev);
return SHR_E_NONE;
}
/*!
* Convert a queue index to channel index
*/
int
bcmcnet_pdma_dev_queue_to_chan(struct pdma_dev *dev, int queue, int dir, int *chan)
{
struct dev_ctrl *ctrl = &dev->ctrl;
if (dir == PDMA_Q_RX) {
if ((uint32_t)queue >= ctrl->nb_rxq || chan == NULL) {
return SHR_E_PARAM;
}
} else {
if ((uint32_t)queue >= ctrl->nb_txq || chan == NULL) {
return SHR_E_PARAM;
}
}
if (!dev->ops || !dev->ops->dev_lq_to_pq) {
return SHR_E_INTERNAL;
}
return dev->ops->dev_lq_to_pq(dev, queue, dir, chan);
}
/*!
* Convert a channel index to queue index
*/
int
bcmcnet_pdma_dev_chan_to_queue(struct pdma_dev *dev, int chan, int *queue, int *dir)
{
if (chan < 0 || chan >= dev->num_queues || queue == NULL || dir == NULL) {
return SHR_E_PARAM;
}
if (!dev->ops || !dev->ops->dev_pq_to_lq) {
return SHR_E_INTERNAL;
}
return dev->ops->dev_pq_to_lq(dev, chan, queue, dir);
}
/*!
* Enable interrupt for a Rx queue
*/
int
bcmcnet_rx_queue_intr_enable(struct pdma_dev *dev, int queue)
{
if (!dev->ops || !dev->ops->rx_queue_intr_enable) {
return SHR_E_INTERNAL;
}
return dev->ops->rx_queue_intr_enable(dev, queue);
}
/*!
* Disable interrupt for a Rx queue
*/
int
bcmcnet_rx_queue_intr_disable(struct pdma_dev *dev, int queue)
{
if (!dev->ops || !dev->ops->rx_queue_intr_disable) {
return SHR_E_INTERNAL;
}
return dev->ops->rx_queue_intr_disable(dev, queue);
}
/*!
* Acknowledge interrupt for a Rx queue
*/
int
bcmcnet_rx_queue_intr_ack(struct pdma_dev *dev, int queue)
{
if (!dev->ops || !dev->ops->rx_queue_intr_ack) {
return SHR_E_INTERNAL;
}
return dev->ops->rx_queue_intr_ack(dev, queue);
}
/*!
* Check interrupt for a Rx queue
*/
int
bcmcnet_rx_queue_intr_check(struct pdma_dev *dev, int queue)
{
if (!dev->ops || !dev->ops->rx_queue_intr_check) {
return SHR_E_INTERNAL;
}
return dev->ops->rx_queue_intr_check(dev, queue);
}
/*!
* Enable interrupt for a Tx queue
*/
int
bcmcnet_tx_queue_intr_enable(struct pdma_dev *dev, int queue)
{
if (!dev->ops || !dev->ops->tx_queue_intr_enable) {
return SHR_E_INTERNAL;
}
return dev->ops->tx_queue_intr_enable(dev, queue);
}
/*!
* Disable interrupt for a Tx queue
*/
int
bcmcnet_tx_queue_intr_disable(struct pdma_dev *dev, int queue)
{
if (!dev->ops || !dev->ops->tx_queue_intr_disable) {
return SHR_E_INTERNAL;
}
return dev->ops->tx_queue_intr_disable(dev, queue);
}
/*!
* Acknowledge interrupt for a Tx queue
*/
int
bcmcnet_tx_queue_intr_ack(struct pdma_dev *dev, int queue)
{
if (!dev->ops || !dev->ops->tx_queue_intr_ack) {
return SHR_E_INTERNAL;
}
return dev->ops->tx_queue_intr_ack(dev, queue);
}
/*!
* Check interrupt for a Tx queue
*/
int
bcmcnet_tx_queue_intr_check(struct pdma_dev *dev, int queue)
{
if (!dev->ops || !dev->ops->tx_queue_intr_check) {
return SHR_E_INTERNAL;
}
return dev->ops->tx_queue_intr_check(dev, queue);
}
/*!
* Enable interrupt for a queue
*/
int
bcmcnet_queue_intr_enable(struct pdma_dev *dev, struct intr_handle *hdl)
{
if (hdl->dir == PDMA_Q_RX) {
return bcmcnet_rx_queue_intr_enable(dev, hdl->queue);
} else {
return bcmcnet_tx_queue_intr_enable(dev, hdl->queue);
}
}
/*!
* Disable interrupt for a queue
*/
int
bcmcnet_queue_intr_disable(struct pdma_dev *dev, struct intr_handle *hdl)
{
if (hdl->dir == PDMA_Q_RX) {
return bcmcnet_rx_queue_intr_disable(dev, hdl->queue);
} else {
return bcmcnet_tx_queue_intr_disable(dev, hdl->queue);
}
}
/*!
* Acknowledge interrupt for a queue
*/
int
bcmcnet_queue_intr_ack(struct pdma_dev *dev, struct intr_handle *hdl)
{
if (hdl->dir == PDMA_Q_RX) {
return bcmcnet_rx_queue_intr_ack(dev, hdl->queue);
} else {
return bcmcnet_tx_queue_intr_ack(dev, hdl->queue);
}
}
/*!
* Check interrupt for a queue
*/
int
bcmcnet_queue_intr_check(struct pdma_dev *dev, struct intr_handle *hdl)
{
if (hdl->dir == PDMA_Q_RX) {
return bcmcnet_rx_queue_intr_check(dev, hdl->queue);
} else {
return bcmcnet_tx_queue_intr_check(dev, hdl->queue);
}
}
/*!
* Enable interrupt for a queue group
*/
int
bcmcnet_group_intr_enable(struct pdma_dev *dev, int group)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct queue_group *grp = &ctrl->grp[group];
int queue, dir;
int i;
if (!dev->ops) {
return SHR_E_INTERNAL;
}
for (i = 0; i < dev->grp_queues; i++) {
if (1 << i & grp->bm_rxq) {
dev->ops->dev_pq_to_lq(dev, i + group * dev->grp_queues, &queue, &dir);
dev->ops->rx_queue_intr_enable(dev, queue);
}
}
for (i = 0; i < dev->grp_queues; i++) {
if (1 << i & grp->bm_txq) {
dev->ops->dev_pq_to_lq(dev, i + group * dev->grp_queues, &queue, &dir);
dev->ops->tx_queue_intr_enable(dev, queue);
}
}
return SHR_E_NONE;
}
/*!
* Disable interrupt for a queue group
*/
int
bcmcnet_group_intr_disable(struct pdma_dev *dev, int group)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct queue_group *grp = &ctrl->grp[group];
int queue, dir;
int i;
if (!dev->ops) {
return SHR_E_INTERNAL;
}
for (i = 0; i < dev->grp_queues; i++) {
if (1 << i & grp->bm_rxq) {
dev->ops->dev_pq_to_lq(dev, i + group * dev->grp_queues, &queue, &dir);
dev->ops->rx_queue_intr_disable(dev, queue);
}
}
for (i = 0; i < dev->grp_queues; i++) {
if (1 << i & grp->bm_txq) {
dev->ops->dev_pq_to_lq(dev, i + group * dev->grp_queues, &queue, &dir);
dev->ops->tx_queue_intr_disable(dev, queue);
}
}
return SHR_E_NONE;
}
/*!
* Acknowledge interrupt for a queue group
*/
int
bcmcnet_group_intr_ack(struct pdma_dev *dev, int group)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct queue_group *grp = &ctrl->grp[group];
int queue, dir;
int i;
if (!dev->ops) {
return SHR_E_INTERNAL;
}
for (i = 0; i < dev->grp_queues; i++) {
if (1 << i & grp->bm_rxq) {
dev->ops->dev_pq_to_lq(dev, i + group * dev->grp_queues, &queue, &dir);
dev->ops->rx_queue_intr_ack(dev, queue);
}
}
for (i = 0; i < dev->grp_queues; i++) {
if (1 << i & grp->bm_txq) {
dev->ops->dev_pq_to_lq(dev, i + group * dev->grp_queues, &queue, &dir);
dev->ops->tx_queue_intr_ack(dev, queue);
}
}
return SHR_E_NONE;
}
/*!
* Check interrupt for a queue group
*/
int
bcmcnet_group_intr_check(struct pdma_dev *dev, int group)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct queue_group *grp = &ctrl->grp[group];
int queue, dir;
int i;
if (!dev->ops) {
return SHR_E_INTERNAL;
}
for (i = 0; i < dev->grp_queues; i++) {
if (1 << i & grp->bm_rxq) {
dev->ops->dev_pq_to_lq(dev, i + group * dev->grp_queues, &queue, &dir);
if (dev->ops->rx_queue_intr_check(dev, queue)) {
return TRUE;
}
}
}
for (i = 0; i < dev->grp_queues; i++) {
if (1 << i & grp->bm_txq) {
dev->ops->dev_pq_to_lq(dev, i + group * dev->grp_queues, &queue, &dir);
if (dev->ops->tx_queue_intr_check(dev, queue)) {
return TRUE;
}
}
}
return FALSE;
}
/*!
* Poll a Rx queue
*/
int
bcmcnet_rx_queue_poll(struct pdma_dev *dev, int queue, int budget)
{
if (!dev->ops || !dev->ops->rx_queue_poll) {
return SHR_E_INTERNAL;
}
return dev->ops->rx_queue_poll(dev, queue, budget);
}
/*!
* Poll a Tx queue
*/
int
bcmcnet_tx_queue_poll(struct pdma_dev *dev, int queue, int budget)
{
if (!dev->ops || !dev->ops->tx_queue_poll) {
return SHR_E_INTERNAL;
}
return dev->ops->tx_queue_poll(dev, queue, budget);
}
/*!
* Poll a queue
*/
int
bcmcnet_queue_poll(struct pdma_dev *dev, struct intr_handle *hdl, int budget)
{
if (hdl->dir == PDMA_Q_RX) {
return bcmcnet_rx_queue_poll(dev, hdl->queue, budget);
} else {
return bcmcnet_tx_queue_poll(dev, hdl->queue, budget);
}
}
/*!
* Poll a queue group
*/
int
bcmcnet_group_poll(struct pdma_dev *dev, int group, int budget)
{
if (!dev->ops || !dev->ops->group_poll) {
return SHR_E_INTERNAL;
}
return dev->ops->group_poll(dev, group, budget);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,708 @@
/*! \file bcmcnet_rxtx.c
*
* Utility routines for BCMCNET Rx/Tx.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <bcmcnet/bcmcnet_core.h>
#include <bcmcnet/bcmcnet_dev.h>
#include <bcmcnet/bcmcnet_rxtx.h>
#include <bcmcnet/bcmcnet_buff.h>
/*!
* Free a Rx ring
*/
static void
bcn_rx_ring_free(struct pdma_rx_queue *rxq)
{
struct dev_ctrl *ctrl = rxq->ctrl;
struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)ctrl->buf_mngr;
if (rxq->lock) {
sal_spinlock_destroy(rxq->lock);
rxq->lock = NULL;
}
if (rxq->ring) {
bm->ring_buf_free(ctrl->dev, ctrl->rx_desc_size * (rxq->nb_desc + 1),
rxq->ring, rxq->ring_addr);
rxq->ring = NULL;
}
if (rxq->pbuf) {
sal_free(rxq->pbuf);
rxq->pbuf = NULL;
}
}
/*!
* Allocate a Rx ring
*/
static int
bcn_rx_ring_alloc(struct pdma_rx_queue *rxq)
{
struct dev_ctrl *ctrl = rxq->ctrl;
struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)ctrl->buf_mngr;
/* Setup pktbuf ring */
rxq->pbuf = sal_alloc(sizeof(*rxq->pbuf) * rxq->nb_desc, "bcmcnetRxBufRing");
if (!rxq->pbuf) {
goto cleanup;
}
sal_memset(rxq->pbuf, 0, sizeof(*rxq->pbuf) * rxq->nb_desc);
/* Allocate memory for descriptors */
rxq->ring = bm->ring_buf_alloc(ctrl->dev, ctrl->rx_desc_size * (rxq->nb_desc + 1),
&rxq->ring_addr);
if (!rxq->ring) {
goto cleanup;
}
sal_memset(rxq->ring, 0, ctrl->rx_desc_size * (rxq->nb_desc + 1));
rxq->lock = sal_spinlock_create("bcmcnetRxQueueLock");
if (!rxq->lock) {
goto cleanup;
}
return SHR_E_NONE;
cleanup:
bcn_rx_ring_free(rxq);
return SHR_E_MEMORY;
}
/*!
* Free a Tx ring
*/
static void
bcn_tx_ring_free(struct pdma_tx_queue *txq)
{
struct dev_ctrl *ctrl = txq->ctrl;
struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)ctrl->buf_mngr;
if (txq->sem) {
sal_sem_destroy(txq->sem);
txq->sem = NULL;
}
if (txq->mutex) {
sal_spinlock_destroy(txq->mutex);
txq->mutex = NULL;
}
if (txq->lock) {
sal_spinlock_destroy(txq->lock);
txq->lock = NULL;
}
if (txq->ring) {
bm->ring_buf_free(ctrl->dev, ctrl->tx_desc_size * (txq->nb_desc + 1),
txq->ring, txq->ring_addr);
txq->ring = NULL;
}
if (txq->pbuf) {
sal_free(txq->pbuf);
txq->pbuf = NULL;
}
}
/*!
* Allocate a Tx ring
*/
static int
bcn_tx_ring_alloc(struct pdma_tx_queue *txq)
{
struct dev_ctrl *ctrl = txq->ctrl;
struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)ctrl->buf_mngr;
/* Setup pktbuf ring */
txq->pbuf = sal_alloc(sizeof(*txq->pbuf) * txq->nb_desc, "bcmcnetTxBufRing");
if (!txq->pbuf) {
goto cleanup;
}
sal_memset(txq->pbuf, 0, sizeof(*txq->pbuf) * txq->nb_desc);
/* Allocate memory for descriptors */
txq->ring = bm->ring_buf_alloc(ctrl->dev, ctrl->tx_desc_size * (txq->nb_desc + 1),
&txq->ring_addr);
if (!txq->ring) {
goto cleanup;
}
sal_memset(txq->ring, 0, ctrl->tx_desc_size * (txq->nb_desc + 1));
txq->lock = sal_spinlock_create("bcmcnetTxQueueLock");
if (!txq->lock) {
goto cleanup;
}
txq->mutex = sal_spinlock_create("bcmcnetTxMutexLock");
if (!txq->mutex) {
goto cleanup;
}
txq->sem = sal_sem_create("bcmcnetTxMutexSem", SAL_SEM_BINARY, 0);
if (!txq->sem) {
goto cleanup;
}
return SHR_E_NONE;
cleanup:
bcn_tx_ring_free(txq);
return SHR_E_MEMORY;
}
/*!
* Rx polling
*/
static int
bcn_rx_poll(struct pdma_rx_queue *rxq, int budget)
{
struct dev_ctrl *ctrl = rxq->ctrl;
struct pdma_hw *hw = (struct pdma_hw *)ctrl->hw;
return hw->dops.rx_ring_clean(hw, rxq, budget);
}
/*!
* Tx polling
*/
static int
bcn_tx_poll(struct pdma_tx_queue *txq, int budget)
{
struct dev_ctrl *ctrl = txq->ctrl;
struct pdma_hw *hw = (struct pdma_hw *)ctrl->hw;
return hw->dops.tx_ring_clean(hw, txq, budget);
}
/*!
* Setup a Rx queue
*/
int
bcmcnet_pdma_rx_queue_setup(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_hw *hw = (struct pdma_hw *)ctrl->hw;
struct pdma_rx_queue *rxq = NULL;
int rv;
rxq = (struct pdma_rx_queue *)ctrl->rx_queue[queue];
if (rxq->state & PDMA_RX_QUEUE_SETUP) {
return SHR_E_NONE;
}
rv = bcn_rx_ring_alloc(rxq);
if (SHR_FAILURE(rv)) {
return rv;
}
rv = hw->dops.rx_desc_init(hw, rxq);
if (SHR_FAILURE(rv)) {
return rv;
}
if (dev->mode == DEV_MODE_VNET) {
ctrl->vsync.rx_ring_addr[queue] = rxq->ring_addr;
ctrl->vsync.rx_ring_size[queue] = rxq->nb_desc;
}
rxq->state |= PDMA_RX_QUEUE_SETUP;
return SHR_E_NONE;
}
/*!
* Release a Rx queue
*/
int
bcmcnet_pdma_rx_queue_release(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_hw *hw = (struct pdma_hw *)ctrl->hw;
struct pdma_rx_queue *rxq = NULL;
rxq = (struct pdma_rx_queue *)ctrl->rx_queue[queue];
if (rxq->state & PDMA_RX_QUEUE_SETUP) {
hw->dops.rx_desc_clean(hw, rxq);
bcn_rx_ring_free(rxq);
rxq->state &= ~PDMA_RX_QUEUE_SETUP;
}
return SHR_E_NONE;
}
/*!
* Restore a Rx queue
*/
int
bcmcnet_pdma_rx_queue_restore(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_hw *hw = (struct pdma_hw *)ctrl->hw;
struct pdma_rx_queue *rxq = NULL;
rxq = (struct pdma_rx_queue *)ctrl->rx_queue[queue];
if (rxq->state & PDMA_RX_QUEUE_SETUP) {
hw->dops.rx_desc_init(hw, rxq);
}
return SHR_E_NONE;
}
/*!
* Set up a virtual Rx queue
*/
int
bcmcnet_pdma_rx_vqueue_setup(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_rx_queue *vrxq = NULL;
vrxq = (struct pdma_rx_queue *)ctrl->vnet_rxq[queue];
if (vrxq->state & PDMA_RX_QUEUE_SETUP) {
return SHR_E_NONE;
}
if (dev->ctrl.vsync.rx_ring_addr[queue]) {
vrxq->curr = 0;
vrxq->nb_desc = dev->ctrl.vsync.rx_ring_size[queue];
vrxq->ring_addr = dev->ctrl.vsync.rx_ring_addr[queue];
vrxq->ring = dev->sys_p2v(dev, vrxq->ring_addr);
vrxq->state |= PDMA_RX_QUEUE_SETUP;
} else {
return SHR_E_UNAVAIL;
}
return SHR_E_NONE;
}
/*!
* Release a virtual Rx queue
*/
int
bcmcnet_pdma_rx_vqueue_release(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_rx_queue *vrxq = NULL;
vrxq = (struct pdma_rx_queue *)ctrl->vnet_rxq[queue];
if (vrxq->state & PDMA_RX_QUEUE_SETUP) {
vrxq->state &= ~PDMA_RX_QUEUE_SETUP;
vrxq->ring = NULL;
}
return SHR_E_NONE;
}
/*!
* Setup a Tx queue
*/
int
bcmcnet_pdma_tx_queue_setup(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_hw *hw = (struct pdma_hw *)ctrl->hw;
struct pdma_tx_queue *txq = NULL;
int rv;
txq = (struct pdma_tx_queue *)ctrl->tx_queue[queue];
if (txq->state & PDMA_TX_QUEUE_SETUP) {
return SHR_E_NONE;
}
rv = bcn_tx_ring_alloc(txq);
if (SHR_FAILURE(rv)) {
return rv;
}
rv = hw->dops.tx_desc_init(hw, txq);
if (SHR_FAILURE(rv)) {
return rv;
}
if (dev->mode == DEV_MODE_VNET) {
ctrl->vsync.tx_ring_addr[queue] = txq->ring_addr;
ctrl->vsync.tx_ring_size[queue] = txq->nb_desc;
}
txq->state |= PDMA_TX_QUEUE_SETUP;
return SHR_E_NONE;
}
/*!
* Release a Tx queue
*/
int
bcmcnet_pdma_tx_queue_release(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_hw *hw = (struct pdma_hw *)ctrl->hw;
struct pdma_tx_queue *txq = NULL;
txq = (struct pdma_tx_queue *)ctrl->tx_queue[queue];
if (txq->state & PDMA_TX_QUEUE_SETUP) {
hw->dops.tx_desc_clean(hw, txq);
bcn_tx_ring_free(txq);
txq->state &= ~PDMA_TX_QUEUE_SETUP;
}
return SHR_E_NONE;
}
/*!
* Restore a Tx queue
*/
int
bcmcnet_pdma_tx_queue_restore(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_hw *hw = (struct pdma_hw *)ctrl->hw;
struct pdma_tx_queue *txq = NULL;
txq = (struct pdma_tx_queue *)ctrl->tx_queue[queue];
if (txq->state & PDMA_TX_QUEUE_SETUP) {
hw->dops.tx_desc_init(hw, txq);
}
return SHR_E_NONE;
}
/*!
* Set up a virtual Tx queue
*/
int
bcmcnet_pdma_tx_vqueue_setup(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_tx_queue *vtxq = NULL;
vtxq = (struct pdma_tx_queue *)ctrl->vnet_txq[queue];
if (vtxq->state & PDMA_TX_QUEUE_SETUP) {
return SHR_E_NONE;
}
if (dev->ctrl.vsync.tx_ring_addr[queue]) {
vtxq->curr = 0;
vtxq->dirt = 0;
vtxq->nb_desc = dev->ctrl.vsync.tx_ring_size[queue];
vtxq->ring_addr = dev->ctrl.vsync.tx_ring_addr[queue];
vtxq->ring = dev->sys_p2v(dev, vtxq->ring_addr);
vtxq->state |= PDMA_TX_QUEUE_SETUP;
} else {
return SHR_E_UNAVAIL;
}
return SHR_E_NONE;
}
/*!
* Release a virtual Tx queue
*/
int
bcmcnet_pdma_tx_vqueue_release(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_tx_queue *vtxq = NULL;
vtxq = (struct pdma_tx_queue *)ctrl->vnet_txq[queue];
if (vtxq->state & PDMA_TX_QUEUE_SETUP) {
vtxq->state &= ~PDMA_TX_QUEUE_SETUP;
vtxq->ring = NULL;
}
return SHR_E_NONE;
}
/*!
* Suspend a Rx queue
*/
int
bcmcnet_pdma_rx_queue_suspend(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_hw *hw = (struct pdma_hw *)ctrl->hw;
struct pdma_rx_queue *rxq = NULL;
rxq = (struct pdma_rx_queue *)ctrl->rx_queue[queue];
if (!rxq || !(rxq->state & PDMA_RX_QUEUE_ACTIVE)) {
return SHR_E_UNAVAIL;
}
return hw->dops.rx_suspend(hw, rxq);
}
/*!
* Resume a Rx queue
*/
int
bcmcnet_pdma_rx_queue_resume(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_hw *hw = (struct pdma_hw *)ctrl->hw;
struct pdma_rx_queue *rxq = NULL;
rxq = (struct pdma_rx_queue *)ctrl->rx_queue[queue];
if (!rxq || !(rxq->state & PDMA_RX_QUEUE_ACTIVE)) {
return SHR_E_UNAVAIL;
}
return hw->dops.rx_resume(hw, rxq);
}
/*!
* Suspend a Tx queue
*/
int
bcmcnet_pdma_tx_queue_suspend(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_tx_queue *txq = NULL;
txq = (struct pdma_tx_queue *)ctrl->tx_queue[queue];
if (!txq || !(txq->state & PDMA_TX_QUEUE_ACTIVE)) {
return SHR_E_UNAVAIL;
}
if (txq->sem) {
sal_sem_take(txq->sem, SAL_SEM_FOREVER);
}
if (dev->tx_suspend) {
dev->tx_suspend(dev, txq->queue_id);
}
return SHR_E_NONE;
}
/*!
* Resume a Tx queue
*/
int
bcmcnet_pdma_tx_queue_resume(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_tx_queue *txq = NULL;
txq = (struct pdma_tx_queue *)ctrl->tx_queue[queue];
if (!txq || !(txq->state & PDMA_TX_QUEUE_ACTIVE)) {
return SHR_E_UNAVAIL;
}
if (txq->sem) {
sal_sem_give(txq->sem);
}
if (dev->tx_resume) {
dev->tx_resume(dev, txq->queue_id);
}
return SHR_E_NONE;
}
/*!
* Wake up a Tx queue
*/
int
bcmcnet_pdma_tx_queue_wakeup(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_tx_queue *txq = NULL;
txq = (struct pdma_tx_queue *)ctrl->tx_queue[queue];
if (txq->sem) {
sal_sem_give(txq->sem);
}
return SHR_E_NONE;
}
/*!
* Transmit a outputing packet
*/
int
bcmcnet_pdma_tx_queue_xmit(struct pdma_dev *dev, int queue, void *buf)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_hw *hw = (struct pdma_hw *)ctrl->hw;
struct pdma_tx_queue *txq = NULL;
txq = (struct pdma_tx_queue *)ctrl->tx_queue[queue];
if (!txq || !(txq->state & PDMA_TX_QUEUE_ACTIVE)) {
return SHR_E_UNAVAIL;
}
return hw->dops.pkt_xmit(hw, txq, buf);
}
/*!
* Poll a Rx queues
*/
int
bcmcnet_pdma_rx_queue_poll(struct pdma_dev *dev, int queue, int budget)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_rx_queue *rxq = ctrl->rx_queue[queue];
return bcn_rx_poll(rxq, budget);
}
/*!
* Poll a Tx queues
*/
int
bcmcnet_pdma_tx_queue_poll(struct pdma_dev *dev, int queue, int budget)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_tx_queue *txq = ctrl->tx_queue[queue];
return bcn_tx_poll(txq, budget);
}
/*!
* Poll for Rx/Tx queues in a group
*/
int
bcmcnet_pdma_group_poll(struct pdma_dev *dev, int group, int budget)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_hw *hw = (struct pdma_hw *)ctrl->hw;
struct pdma_rx_queue *rxq = NULL;
struct pdma_tx_queue *txq = NULL;
struct queue_group *grp = &ctrl->grp[group];
int done = 0, done_que, budget_que;
int i;
/* Acknowledge the interrupts */
for (i = 0; i < dev->grp_queues; i++) {
rxq = grp->rx_queue[i];
if (rxq->state & PDMA_RX_QUEUE_ACTIVE) {
if (hw->hdls.chan_intr_query(hw, rxq->chan_id)) {
hw->hdls.chan_clear(hw, rxq->chan_id);
grp->poll_queues |= 1 << i;
} else if (rxq->state & PDMA_RX_QUEUE_BUSY) {
rxq->state &= ~PDMA_RX_QUEUE_BUSY;
grp->poll_queues |= 1 << i;
}
continue;
}
txq = grp->tx_queue[i];
if (txq->state & PDMA_TX_QUEUE_ACTIVE) {
if (hw->hdls.chan_intr_query(hw, txq->chan_id)) {
hw->hdls.chan_clear(hw, txq->chan_id);
grp->poll_queues |= 1 << i;
}
}
}
/* Calculate per queue budget */
if (!grp->poll_queues) {
grp->poll_queues = grp->bm_rxq | grp->bm_txq;
budget_que = budget / grp->nb_rxq;
} else {
budget_que = 0;
for (i = 0; i < dev->grp_queues; i++) {
if (1 << i & grp->bm_rxq & grp->poll_queues) {
budget_que++;
}
}
if (budget_que) {
budget_que = budget / budget_que;
}
}
/* Poll Rx queues */
for (i = 0; i < dev->grp_queues; i++) {
if (1 << i & grp->bm_rxq & grp->poll_queues) {
rxq = grp->rx_queue[i];
done_que = bcn_rx_poll(rxq, budget_que);
if (done_que < budget_que) {
grp->poll_queues &= ~(1 << i);
}
done += done_que;
}
}
/* Poll Tx queues */
for (i = 0; i < dev->grp_queues; i++) {
txq = grp->tx_queue[i];
if (1 << i & grp->bm_txq & grp->poll_queues && !txq->free_thresh) {
if (bcn_tx_poll(txq, budget) < budget) {
grp->poll_queues &= ~(1 << i);
}
}
}
return grp->poll_queues ? budget : done;
}
/*!
* Dump a Rx ring
*/
int
bcmcnet_pdma_rx_ring_dump(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_hw *hw = ctrl->hw;
struct pdma_rx_queue *rxq = NULL;
if ((uint32_t)queue >= ctrl->nb_rxq) {
return SHR_E_PARAM;
}
rxq = (struct pdma_rx_queue *)ctrl->rx_queue[queue];
if (rxq->state & PDMA_RX_QUEUE_ACTIVE) {
hw->dops.rx_ring_dump(hw, rxq);
}
if (dev->mode == DEV_MODE_HNET) {
rxq = (struct pdma_rx_queue *)ctrl->vnet_rxq[queue];
hw->dops.rx_ring_dump(hw, rxq);
}
return SHR_E_NONE;
}
/*!
* Dump a Tx ring
*/
int
bcmcnet_pdma_tx_ring_dump(struct pdma_dev *dev, int queue)
{
struct dev_ctrl *ctrl = &dev->ctrl;
struct pdma_hw *hw = ctrl->hw;
struct pdma_tx_queue *txq = NULL;
if ((uint32_t)queue >= ctrl->nb_txq) {
return SHR_E_PARAM;
}
txq = (struct pdma_tx_queue *)ctrl->tx_queue[queue];
if (txq->state & PDMA_TX_QUEUE_ACTIVE) {
hw->dops.tx_ring_dump(hw, txq);
}
if (dev->mode == DEV_MODE_HNET) {
txq = (struct pdma_tx_queue *)ctrl->vnet_txq[queue];
hw->dops.tx_ring_dump(hw, txq);
}
return SHR_E_NONE;
}

View File

@ -0,0 +1,337 @@
/*
* DO NOT EDIT THIS FILE!
* This file is auto-generated.
* Edits to this file will be lost when it is regenerated.
* Tool: INTERNAL/drd/instpkgs.pl
*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
/*
* This file contains the complete list of supported devices.
* No other device lists should be used anywhere in the SDK.
*/
#ifndef BCMDRD_DEVIDS_H
#define BCMDRD_DEVIDS_H
#include <bcmdrd_config.h>
/*
* All Supported Devices and Revisions
*/
#define BROADCOM_VENDOR_ID 0x14e4
#define BROADCOM_PHYID_MSB 0x0143
/* BCM56780 */
#define BCM56780_VENDOR_ID 0x14e4
#define BCM56780_DEVICE_ID 0xb780
#define BCM56780_REV_A0 0x01
/* BCM56782 */
#define BCM56782_VENDOR_ID 0x14e4
#define BCM56782_DEVICE_ID 0xb782
#define BCM56782_REV_A0 0x01
/* BCM56784 */
#define BCM56784_VENDOR_ID 0x14e4
#define BCM56784_DEVICE_ID 0xb784
#define BCM56784_REV_A0 0x01
/* BCM56786 */
#define BCM56786_VENDOR_ID 0x14e4
#define BCM56786_DEVICE_ID 0xb786
#define BCM56786_REV_A0 0x01
/* BCM56788 */
#define BCM56788_VENDOR_ID 0x14e4
#define BCM56788_DEVICE_ID 0xb788
#define BCM56788_REV_A0 0x01
/* BCM56789 */
#define BCM56789_VENDOR_ID 0x14e4
#define BCM56789_DEVICE_ID 0xb789
#define BCM56789_REV_A0 0x01
/* BCM56880 */
#define BCM56880_VENDOR_ID 0x14e4
#define BCM56880_DEVICE_ID 0xb880
#define BCM56880_REV_A0 0x01
#define BCM56880_REV_B0 0x11
/* BCM56881 */
#define BCM56881_VENDOR_ID 0x14e4
#define BCM56881_DEVICE_ID 0xb881
#define BCM56881_REV_A0 0x01
#define BCM56881_REV_B0 0x11
/* BCM56883 */
#define BCM56883_VENDOR_ID 0x14e4
#define BCM56883_DEVICE_ID 0xb883
#define BCM56883_REV_A0 0x01
#define BCM56883_REV_B0 0x11
/* BCM56889 */
#define BCM56889_VENDOR_ID 0x14e4
#define BCM56889_DEVICE_ID 0xb889
#define BCM56889_REV_A0 0x01
#define BCM56889_REV_B0 0x11
/* BCM56990 */
#define BCM56990_VENDOR_ID 0x14e4
#define BCM56990_DEVICE_ID 0xb990
#define BCM56990_REV_A0 0x01
#define BCM56990_REV_B0 0x11
/* BCM56992 */
#define BCM56992_VENDOR_ID 0x14e4
#define BCM56992_DEVICE_ID 0xb992
#define BCM56992_REV_B0 0x11
/* BCM56996 */
#define BCM56996_VENDOR_ID 0x14e4
#define BCM56996_DEVICE_ID 0xb996
#define BCM56996_REV_A0 0x01
/* BCM56997 */
#define BCM56997_VENDOR_ID 0x14e4
#define BCM56997_DEVICE_ID 0xb997
#define BCM56997_REV_A0 0x01
/*
* End of Supported Devices and Revisions
*/
#endif /* BCMDRD_DEVIDS_H */
#ifdef BCMDRD_DEVLIST_ENTRY
/*
* BCMDRD_DEVLIST_ENTRY macros.
*
* Before including this file, define BCMDRD_DEVLIST_ENTRY
* as a macro to operate on the following parameters:
*
* #define BCMDRD_DEVLIST_ENTRY(_nm,_vn,_dv,_rv,_md,_pi,_bd,_bc,_fn,_cn,_pf,_pd,_r0,_r1)
*
* _nm: Chip Name
* _vn: Chip Vendor ID
* _dv: Chip Device ID
* _rv: Chip Revision
* _md: Chip Model
* _pi: Probe Information
* _bd: SW Base Driver
* _bc: SW Base Configuration
* _fn: SW Full Name
* _cn: Code Name
* _pf: Product Family
* _pd: Product Description
* _r0: Reserved
* _r1: Reserved
*
* Note that this macro will be undefined at the end of this file.
*/
#if BCMDRD_CONFIG_INCLUDE_BCM56780_A0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
BCMDRD_DEVLIST_ENTRY(BCM56780, BCM56780_VENDOR_ID, BCM56780_DEVICE_ID, BCM56780_REV_A0, \
0, 0, \
bcm56780_a0, bcm56780_a0, bcm56780_a0, \
"Trident4-X9", "BCM56780", \
"8 Tb/s 160x50G-PAM4 Programmable Switch", 0, 0)
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56782_A0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
#ifdef BCMDRD_DEVLIST_INCLUDE_ALL
BCMDRD_DEVLIST_ENTRY(BCM56782, BCM56782_VENDOR_ID, BCM56782_DEVICE_ID, BCM56782_REV_A0, \
0, 0, \
bcm56780_a0, bcm56782_a0, bcm56782_a0, \
"Trident4-X9", "BCM56780", \
"8 Tb/s 160x50G-PAM4 Programmable Switch w/MACsec", 0, 0)
#endif
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56784_A0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
#ifdef BCMDRD_DEVLIST_INCLUDE_ALL
BCMDRD_DEVLIST_ENTRY(BCM56784, BCM56784_VENDOR_ID, BCM56784_DEVICE_ID, BCM56784_REV_A0, \
0, 0, \
bcm56780_a0, bcm56784_a0, bcm56784_a0, \
"Trident4-X9", "BCM56780", \
"5.6 Tb/s 96x50G-PAM4/32x35G-NRZ Programmable Switch", 0, 0)
#endif
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56786_A0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
#ifdef BCMDRD_DEVLIST_INCLUDE_ALL
BCMDRD_DEVLIST_ENTRY(BCM56786, BCM56786_VENDOR_ID, BCM56786_DEVICE_ID, BCM56786_REV_A0, \
0, 0, \
bcm56780_a0, bcm56786_a0, bcm56786_a0, \
"Trident4-X9", "BCM56780", \
"5.6 Tb/s 96x50G-PAM4/32x35G-NRZ Programmable Switch w/MACsec", 0, 0)
#endif
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56788_A0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
#ifdef BCMDRD_DEVLIST_INCLUDE_ALL
BCMDRD_DEVLIST_ENTRY(BCM56788, BCM56788_VENDOR_ID, BCM56788_DEVICE_ID, BCM56788_REV_A0, \
0, 0, \
bcm56780_a0, bcm56788_a0, bcm56788_a0, \
"Trident4-X9", "BCM56780", \
"8 Tb/s 160x50G-PAM4 Programmable Switch w/MACsec w/MTop", 0, 0)
#endif
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56789_A0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
#ifdef BCMDRD_DEVLIST_INCLUDE_ALL
BCMDRD_DEVLIST_ENTRY(BCM56789, BCM56789_VENDOR_ID, BCM56789_DEVICE_ID, BCM56789_REV_A0, \
0, 0, \
bcm56780_a0, bcm56789_a0, bcm56789_a0, \
"Trident4-X9", "BCM56780", \
"8 Tb/s 160x50G-PAM4 Programmable Switch w/MTop", 0, 0)
#endif
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56880_A0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
BCMDRD_DEVLIST_ENTRY(BCM56880, BCM56880_VENDOR_ID, BCM56880_DEVICE_ID, BCM56880_REV_A0, \
0, 0, \
bcm56880_a0, bcm56880_a0, bcm56880_a0, \
"Trident4", "BCM56880", \
"12.8 Tb/s Switch Fabric 128x100G/64x200G/32x400G Multilayer Switch", 0, 0)
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56880_B0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
#ifdef BCMDRD_DEVLIST_INCLUDE_ALL
BCMDRD_DEVLIST_ENTRY(BCM56880, BCM56880_VENDOR_ID, BCM56880_DEVICE_ID, BCM56880_REV_B0, \
0, 0, \
bcm56880_a0, bcm56880_a0, bcm56880_b0, \
"Trident4", "BCM56880", \
"12.8 Tb/s Switch Fabric 128x100G/64x200G/32x400G Multilayer Switch", 0, 0)
#endif
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56881_A0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
#ifdef BCMDRD_DEVLIST_INCLUDE_ALL
BCMDRD_DEVLIST_ENTRY(BCM56881, BCM56881_VENDOR_ID, BCM56881_DEVICE_ID, BCM56881_REV_A0, \
0, 0, \
bcm56880_a0, bcm56881_a0, bcm56881_a0, \
"Trident4", "BCM56880", \
"12.8 Tb/s Switch Fabric 128x100G/64x200G/32x400G Multilayer Switch", 0, 0)
#endif
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56881_B0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
#ifdef BCMDRD_DEVLIST_INCLUDE_ALL
BCMDRD_DEVLIST_ENTRY(BCM56881, BCM56881_VENDOR_ID, BCM56881_DEVICE_ID, BCM56881_REV_B0, \
0, 0, \
bcm56880_a0, bcm56881_a0, bcm56881_b0, \
"Trident4", "BCM56880", \
"12.8 Tb/s Switch Fabric 128x100G/64x200G/32x400G Multilayer Switch", 0, 0)
#endif
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56883_A0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
#ifdef BCMDRD_DEVLIST_INCLUDE_ALL
BCMDRD_DEVLIST_ENTRY(BCM56883, BCM56883_VENDOR_ID, BCM56883_DEVICE_ID, BCM56883_REV_A0, \
0, 0, \
bcm56880_a0, bcm56883_a0, bcm56883_a0, \
"Trident4", "BCM56880", \
"8.0 Tb/s Switch Fabric 80x100G/40x200G/20x400G Multilayer Switch", 0, 0)
#endif
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56883_B0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
#ifdef BCMDRD_DEVLIST_INCLUDE_ALL
BCMDRD_DEVLIST_ENTRY(BCM56883, BCM56883_VENDOR_ID, BCM56883_DEVICE_ID, BCM56883_REV_B0, \
0, 0, \
bcm56880_a0, bcm56883_a0, bcm56883_b0, \
"Trident4", "BCM56880", \
"8.0 Tb/s Switch Fabric 80x100G/40x200G/20x400G Multilayer Switch", 0, 0)
#endif
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56889_A0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
#ifdef BCMDRD_DEVLIST_INCLUDE_ALL
BCMDRD_DEVLIST_ENTRY(BCM56889, BCM56889_VENDOR_ID, BCM56889_DEVICE_ID, BCM56889_REV_A0, \
0, 0, \
bcm56880_a0, bcm56889_a0, bcm56889_a0, \
"Trident4", "BCM56880", \
"12.8 Tb/s Switch Fabric 128x100G/64x200G/32x400G Multilayer Switch", 0, 0)
#endif
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56889_B0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
#ifdef BCMDRD_DEVLIST_INCLUDE_ALL
BCMDRD_DEVLIST_ENTRY(BCM56889, BCM56889_VENDOR_ID, BCM56889_DEVICE_ID, BCM56889_REV_B0, \
0, 0, \
bcm56880_a0, bcm56889_a0, bcm56889_b0, \
"Trident4", "BCM56880", \
"12.8 Tb/s Switch Fabric 128x100G/64x200G/32x400G Multilayer Switch", 0, 0)
#endif
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56990_A0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
BCMDRD_DEVLIST_ENTRY(BCM56990, BCM56990_VENDOR_ID, BCM56990_DEVICE_ID, BCM56990_REV_A0, \
0, 0, \
bcm56990_a0, bcm56990_a0, bcm56990_a0, \
"Tomahawk4", "BCM56990", \
"25.6 Tbps Multilayer Switch", 0, 0)
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56990_B0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
BCMDRD_DEVLIST_ENTRY(BCM56990, BCM56990_VENDOR_ID, BCM56990_DEVICE_ID, BCM56990_REV_B0, \
0, 0, \
bcm56990_b0, bcm56990_b0, bcm56990_b0, \
"Tomahawk4", "BCM56990", \
"25.6 Tbps Multilayer Switch", 0, 0)
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56992_B0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
#ifdef BCMDRD_DEVLIST_INCLUDE_ALL
BCMDRD_DEVLIST_ENTRY(BCM56992, BCM56992_VENDOR_ID, BCM56992_DEVICE_ID, BCM56992_REV_B0, \
0, 0, \
bcm56990_b0, bcm56992_b0, bcm56992_b0, \
"Tomahawk4", "BCM56990", \
"25.6 Tbps Multilayer Switch", 0, 0)
#endif
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56996_A0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
BCMDRD_DEVLIST_ENTRY(BCM56996, BCM56996_VENDOR_ID, BCM56996_DEVICE_ID, BCM56996_REV_A0, \
0, 0, \
bcm56996_a0, bcm56996_a0, bcm56996_a0, \
"Tomahawk4G", "BCM56996", \
"25.6 Tbps Multilayer Switch", 0, 0)
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56997_A0 == 1 || defined(BCMDRD_DEVLIST_OVERRIDE)
#ifdef BCMDRD_DEVLIST_INCLUDE_ALL
BCMDRD_DEVLIST_ENTRY(BCM56997, BCM56997_VENDOR_ID, BCM56997_DEVICE_ID, BCM56997_REV_A0, \
0, 0, \
bcm56996_a0, bcm56997_a0, bcm56997_a0, \
"Tomahawk4G", "BCM56996", \
"12.8 Tbps Multilayer Switch", 0, 0)
#endif
#endif
/* End BCMDRD_DEVLIST_ENTRY Macros */
#ifdef BCMDRD_DEVLIST_INCLUDE_ALL
#undef BCMDRD_DEVLIST_INCLUDE_ALL
#endif
#ifdef BCMDRD_DEVLIST_OVERRIDE
#undef BCMDRD_DEVLIST_OVERRIDE
#endif
#undef BCMDRD_DEVLIST_ENTRY
#endif /* BCMDRD_DEVLIST_ENTRY */

View File

@ -0,0 +1,166 @@
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*
* DO NOT EDIT THIS FILE!
* This file will be auto-generated in the near future.
*
* This config file defines all compilation-time specifications for
* the BCMDRD.
*
* Reasonable defaults are provided for all configuration options
* where appropriate.
*
* You need not edit this file directly to change your configuration,
* nor is modifying this file advised -- so doing will require
* manually merging whenever the BCMDRD is upgraded.
*
* You should provide your own configuration options or overrides
* through a combination of:
*
* 1. The compiler command line, such as -D{OPTION}={VALUE}
*
* 2. Create your own custom configuration file:
* a) Create a file called 'bcmdrd_custom_config.h'
* b) Define all custom settings, using this file as
* the reference
* c) Add -DBCMDRD_INCLUDE_CUSTOM_CONFIG to your
* compilation
* d) Make sure the compilation include path includes
* 'bcmdrd_custom_config.h'
*
*/
#ifndef BCMDRD_CONFIG_H
#define BCMDRD_CONFIG_H
/*
* Include system config file if specified:
*/
#ifdef BCMDRD_INCLUDE_CUSTOM_CONFIG
#include <bcmdrd_custom_config.h>
#endif
/*
* OPTIONAL configuration and feature values.
* Defaults are provided for all non-specified values.
*/
/* Maximum number of chips supported */
#ifndef BCMDRD_CONFIG_MAX_UNITS
#define BCMDRD_CONFIG_MAX_UNITS 8
#endif
/* Maximum number of ports per chip supported */
#ifndef BCMDRD_CONFIG_MAX_PORTS
#define BCMDRD_CONFIG_MAX_PORTS 576
#endif
/* Maximum number of SCHAN polls */
#ifndef BCMDRD_CONFIG_SCHAN_MAX_POLLS
#define BCMDRD_CONFIG_SCHAN_MAX_POLLS 100000
#endif
/* Maximum number of MIIM polls */
#ifndef BCMDRD_CONFIG_MIIM_MAX_POLLS
#define BCMDRD_CONFIG_MIIM_MAX_POLLS 100000
#endif
/* Direct access to memory-mapped registers */
#ifndef BCMDRD_CONFIG_MEMMAP_DIRECT
#define BCMDRD_CONFIG_MEMMAP_DIRECT 0
#endif
/*
* Include chip symbol tables for the debug shell.
*
* No symbolic debugging (register/memory names) will be available
* without this defined.
*
* You should enable at least these symbols if you can afford the
* space.
*
* This define is required to get any symbols at all.
*
* If you only wish to include symbols for a subset of chips in the
* system (probably for code space reasons), you can define the
* following for each chip whose symbols you wish to EXCLUDE:
*
* BCMDRD_CONFIG_EXCLUDE_CHIP_SYMBOLS_<CHIP>
*
*/
#ifndef BCMDRD_CONFIG_INCLUDE_CHIP_SYMBOLS
#define BCMDRD_CONFIG_INCLUDE_CHIP_SYMBOLS 1
#endif
/*
* Include register and memory field information for the debug shell.
*
* This provides encoding, decoding, and displaying individual field
* values for each register and memory.
*
* Requires more code space than just the chip symbols alone.
*
* The per-chip exclusion define
* (BCMDRD_CONFIG_EXCLUDE_FIELD_INFO_<CHIP>) also applies.
*/
#ifndef BCMDRD_CONFIG_INCLUDE_FIELD_INFO
#define BCMDRD_CONFIG_INCLUDE_FIELD_INFO 1
#endif
/*
* Include alternative symbol names for registers and memories.
*
* Mainly for internal Broadcom use, so you can safely leave this
* option off.
*/
#ifndef BCMDRD_CONFIG_INCLUDE_ALIAS_NAMES
#define BCMDRD_CONFIG_INCLUDE_ALIAS_NAMES 1
#endif
#endif /* BCMDRD_CONFIG_H */
#ifdef CONFIG_OPTION
#ifdef BCMDRD_INCLUDE_CUSTOM_CONFIG
CONFIG_OPTION(BCMDRD_INCLUDE_CUSTOM_CONFIG)
#endif
#ifdef BCMDRD_CONFIG_MAX_UNITS
CONFIG_OPTION(BCMDRD_CONFIG_MAX_UNITS)
#endif
#ifdef BCMDRD_CONFIG_MAX_PORTS
CONFIG_OPTION(BCMDRD_CONFIG_MAX_PORTS)
#endif
#ifdef BCMDRD_CONFIG_SCHAN_MAX_POLLS
CONFIG_OPTION(BCMDRD_CONFIG_SCHAN_MAX_POLLS)
#endif
#ifdef BCMDRD_CONFIG_MIIM_MAX_POLLS
CONFIG_OPTION(BCMDRD_CONFIG_MIIM_MAX_POLLS)
#endif
#ifdef BCMDRD_CONFIG_MEMMAP_DIRECT
CONFIG_OPTION(BCMDRD_CONFIG_MEMMAP_DIRECT)
#endif
#ifdef BCMDRD_CONFIG_INCLUDE_CHIP_SYMBOLS
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_CHIP_SYMBOLS)
#endif
#ifdef BCMDRD_CONFIG_INCLUDE_FIELD_INFO
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_FIELD_INFO)
#endif
#ifdef BCMDRD_CONFIG_INCLUDE_ALIAS_NAMES
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_ALIAS_NAMES)
#endif
#endif /* CONFIG_OPTION */
#include "bcmdrd_config_chips.h"

View File

@ -0,0 +1,545 @@
/*
* DO NOT EDIT THIS FILE!
* This file is auto-generated.
* Edits to this file will be lost when it is regenerated.
* Tool: INTERNAL/drd/instpkgs.pl
*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
/*
* Chip inclusion and exclusion support within the BCMDRD can be
* specified as a combination of the following defines:
*
* (1) #define BCMDRD_CONFIG_INCLUDE_<CHIPNAME> [1|0]
* -- Include or exclude all revisions of the given device
* Example: #define BCMDRD_CONFIG_INCLUDE_BCM56780 1
*
* (2) #define BCMDRD_CONFIG_INCLUDE_<CHIPNAME>_<REV>X [1|0]
* -- Include or exclude all versions of the given revision
* Example: #define BCMDRD_CONFIG_INCLUDE_BCM56780_Ax 0
* #define BCMDRD_CONFIG_INCLUde_BCM56780_Bx 1
*
* (3) #define BCMDRD_CONFIG_INCLUDE_<EXACT_CHIP> [1|0]
* -- Include or exclude an exact device
* Example: #define BCMDRD_CONFIG_INCLUDE_BCM56780_A0 1
* #define BCMDRD_CONFIG_INCLUDE_BCM56780_A1 0
*
*
* The value of BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT is used for any
* chips which are left unspecified. Set this value to 1 or 0 to
* include or exclude all chips by default.
*
*/
#ifndef BCMDRD_CONFIG_CHIPS_H
#define BCMDRD_CONFIG_CHIPS_H
/* This determines whether a chip is included or excluded by default */
#ifndef BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#define BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT 1
#endif
/*
* Default configuration and dependencies for all chips
*/
/*
* BCM56780
*/
/* Sets the default include state if it was not given */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56780
#define BCMDRD_CONFIG_INCLUDE_BCM56780 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
/* Resolve revision dependencies */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56780_Ax
#define BCMDRD_CONFIG_INCLUDE_BCM56780_Ax BCMDRD_CONFIG_INCLUDE_BCM56780
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56780_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56780_A0 BCMDRD_CONFIG_INCLUDE_BCM56780_Ax
#endif
/*
* BCM56782
*/
/* Sets the default include state if it was not given */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56782
#define BCMDRD_CONFIG_INCLUDE_BCM56782 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
/* Resolve revision dependencies */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56782_Ax
#define BCMDRD_CONFIG_INCLUDE_BCM56782_Ax BCMDRD_CONFIG_INCLUDE_BCM56782
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56782_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56782_A0 BCMDRD_CONFIG_INCLUDE_BCM56782_Ax
#endif
/* Resolve all interchip dependencies */
#if BCMDRD_CONFIG_INCLUDE_BCM56782_A0 == 1
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56780_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56780_A0 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56780_A0 != 1
#undef BCMDRD_CONFIG_INCLUDE_BCM56780_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56780_A0 1
#define BCMDRD_CONFIG_INCLUDE_BCM56780_A0_IMPLIED 1
#endif
#endif
/*
* BCM56784
*/
/* Sets the default include state if it was not given */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56784
#define BCMDRD_CONFIG_INCLUDE_BCM56784 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
/* Resolve revision dependencies */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56784_Ax
#define BCMDRD_CONFIG_INCLUDE_BCM56784_Ax BCMDRD_CONFIG_INCLUDE_BCM56784
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56784_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56784_A0 BCMDRD_CONFIG_INCLUDE_BCM56784_Ax
#endif
/* Resolve all interchip dependencies */
#if BCMDRD_CONFIG_INCLUDE_BCM56784_A0 == 1
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56780_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56780_A0 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56780_A0 != 1
#undef BCMDRD_CONFIG_INCLUDE_BCM56780_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56780_A0 1
#define BCMDRD_CONFIG_INCLUDE_BCM56780_A0_IMPLIED 1
#endif
#endif
/*
* BCM56786
*/
/* Sets the default include state if it was not given */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56786
#define BCMDRD_CONFIG_INCLUDE_BCM56786 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
/* Resolve revision dependencies */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56786_Ax
#define BCMDRD_CONFIG_INCLUDE_BCM56786_Ax BCMDRD_CONFIG_INCLUDE_BCM56786
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56786_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56786_A0 BCMDRD_CONFIG_INCLUDE_BCM56786_Ax
#endif
/* Resolve all interchip dependencies */
#if BCMDRD_CONFIG_INCLUDE_BCM56786_A0 == 1
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56780_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56780_A0 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56780_A0 != 1
#undef BCMDRD_CONFIG_INCLUDE_BCM56780_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56780_A0 1
#define BCMDRD_CONFIG_INCLUDE_BCM56780_A0_IMPLIED 1
#endif
#endif
/*
* BCM56788
*/
/* Sets the default include state if it was not given */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56788
#define BCMDRD_CONFIG_INCLUDE_BCM56788 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
/* Resolve revision dependencies */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56788_Ax
#define BCMDRD_CONFIG_INCLUDE_BCM56788_Ax BCMDRD_CONFIG_INCLUDE_BCM56788
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56788_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56788_A0 BCMDRD_CONFIG_INCLUDE_BCM56788_Ax
#endif
/* Resolve all interchip dependencies */
#if BCMDRD_CONFIG_INCLUDE_BCM56788_A0 == 1
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56780_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56780_A0 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56780_A0 != 1
#undef BCMDRD_CONFIG_INCLUDE_BCM56780_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56780_A0 1
#define BCMDRD_CONFIG_INCLUDE_BCM56780_A0_IMPLIED 1
#endif
#endif
/*
* BCM56789
*/
/* Sets the default include state if it was not given */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56789
#define BCMDRD_CONFIG_INCLUDE_BCM56789 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
/* Resolve revision dependencies */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56789_Ax
#define BCMDRD_CONFIG_INCLUDE_BCM56789_Ax BCMDRD_CONFIG_INCLUDE_BCM56789
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56789_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56789_A0 BCMDRD_CONFIG_INCLUDE_BCM56789_Ax
#endif
/* Resolve all interchip dependencies */
#if BCMDRD_CONFIG_INCLUDE_BCM56789_A0 == 1
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56780_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56780_A0 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56780_A0 != 1
#undef BCMDRD_CONFIG_INCLUDE_BCM56780_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56780_A0 1
#define BCMDRD_CONFIG_INCLUDE_BCM56780_A0_IMPLIED 1
#endif
#endif
/*
* BCM56880
*/
/* Sets the default include state if it was not given */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56880
#define BCMDRD_CONFIG_INCLUDE_BCM56880 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
/* Resolve revision dependencies */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56880_Ax
#define BCMDRD_CONFIG_INCLUDE_BCM56880_Ax BCMDRD_CONFIG_INCLUDE_BCM56880
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56880_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0 BCMDRD_CONFIG_INCLUDE_BCM56880_Ax
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56880_Bx
#define BCMDRD_CONFIG_INCLUDE_BCM56880_Bx BCMDRD_CONFIG_INCLUDE_BCM56880
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56880_B0
#define BCMDRD_CONFIG_INCLUDE_BCM56880_B0 BCMDRD_CONFIG_INCLUDE_BCM56880_Bx
#endif
/* Resolve all interchip dependencies */
#if BCMDRD_CONFIG_INCLUDE_BCM56880_B0 == 1
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56880_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56880_A0 != 1
#undef BCMDRD_CONFIG_INCLUDE_BCM56880_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0 1
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0_IMPLIED 1
#endif
#endif
/*
* BCM56881
*/
/* Sets the default include state if it was not given */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56881
#define BCMDRD_CONFIG_INCLUDE_BCM56881 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
/* Resolve revision dependencies */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56881_Ax
#define BCMDRD_CONFIG_INCLUDE_BCM56881_Ax BCMDRD_CONFIG_INCLUDE_BCM56881
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56881_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56881_A0 BCMDRD_CONFIG_INCLUDE_BCM56881_Ax
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56881_Bx
#define BCMDRD_CONFIG_INCLUDE_BCM56881_Bx BCMDRD_CONFIG_INCLUDE_BCM56881
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56881_B0
#define BCMDRD_CONFIG_INCLUDE_BCM56881_B0 BCMDRD_CONFIG_INCLUDE_BCM56881_Bx
#endif
/* Resolve all interchip dependencies */
#if BCMDRD_CONFIG_INCLUDE_BCM56881_A0 == 1
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56880_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56880_A0 != 1
#undef BCMDRD_CONFIG_INCLUDE_BCM56880_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0 1
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0_IMPLIED 1
#endif
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56881_B0 == 1
#if BCMDRD_CONFIG_INCLUDE_BCM56880_A0 != 1
#undef BCMDRD_CONFIG_INCLUDE_BCM56880_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0 1
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0_IMPLIED 1
#endif
#endif
/*
* BCM56883
*/
/* Sets the default include state if it was not given */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56883
#define BCMDRD_CONFIG_INCLUDE_BCM56883 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
/* Resolve revision dependencies */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56883_Ax
#define BCMDRD_CONFIG_INCLUDE_BCM56883_Ax BCMDRD_CONFIG_INCLUDE_BCM56883
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56883_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56883_A0 BCMDRD_CONFIG_INCLUDE_BCM56883_Ax
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56883_Bx
#define BCMDRD_CONFIG_INCLUDE_BCM56883_Bx BCMDRD_CONFIG_INCLUDE_BCM56883
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56883_B0
#define BCMDRD_CONFIG_INCLUDE_BCM56883_B0 BCMDRD_CONFIG_INCLUDE_BCM56883_Bx
#endif
/* Resolve all interchip dependencies */
#if BCMDRD_CONFIG_INCLUDE_BCM56883_A0 == 1
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56880_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56880_A0 != 1
#undef BCMDRD_CONFIG_INCLUDE_BCM56880_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0 1
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0_IMPLIED 1
#endif
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56883_B0 == 1
#if BCMDRD_CONFIG_INCLUDE_BCM56880_A0 != 1
#undef BCMDRD_CONFIG_INCLUDE_BCM56880_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0 1
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0_IMPLIED 1
#endif
#endif
/*
* BCM56889
*/
/* Sets the default include state if it was not given */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56889
#define BCMDRD_CONFIG_INCLUDE_BCM56889 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
/* Resolve revision dependencies */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56889_Ax
#define BCMDRD_CONFIG_INCLUDE_BCM56889_Ax BCMDRD_CONFIG_INCLUDE_BCM56889
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56889_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56889_A0 BCMDRD_CONFIG_INCLUDE_BCM56889_Ax
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56889_Bx
#define BCMDRD_CONFIG_INCLUDE_BCM56889_Bx BCMDRD_CONFIG_INCLUDE_BCM56889
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56889_B0
#define BCMDRD_CONFIG_INCLUDE_BCM56889_B0 BCMDRD_CONFIG_INCLUDE_BCM56889_Bx
#endif
/* Resolve all interchip dependencies */
#if BCMDRD_CONFIG_INCLUDE_BCM56889_A0 == 1
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56880_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56880_A0 != 1
#undef BCMDRD_CONFIG_INCLUDE_BCM56880_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0 1
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0_IMPLIED 1
#endif
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56889_B0 == 1
#if BCMDRD_CONFIG_INCLUDE_BCM56880_A0 != 1
#undef BCMDRD_CONFIG_INCLUDE_BCM56880_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0 1
#define BCMDRD_CONFIG_INCLUDE_BCM56880_A0_IMPLIED 1
#endif
#endif
/*
* BCM56990
*/
/* Sets the default include state if it was not given */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56990
#define BCMDRD_CONFIG_INCLUDE_BCM56990 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
/* Resolve revision dependencies */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56990_Ax
#define BCMDRD_CONFIG_INCLUDE_BCM56990_Ax BCMDRD_CONFIG_INCLUDE_BCM56990
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56990_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56990_A0 BCMDRD_CONFIG_INCLUDE_BCM56990_Ax
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56990_Bx
#define BCMDRD_CONFIG_INCLUDE_BCM56990_Bx BCMDRD_CONFIG_INCLUDE_BCM56990
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56990_B0
#define BCMDRD_CONFIG_INCLUDE_BCM56990_B0 BCMDRD_CONFIG_INCLUDE_BCM56990_Bx
#endif
/*
* BCM56992
*/
/* Sets the default include state if it was not given */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56992
#define BCMDRD_CONFIG_INCLUDE_BCM56992 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
/* Resolve revision dependencies */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56992_Bx
#define BCMDRD_CONFIG_INCLUDE_BCM56992_Bx BCMDRD_CONFIG_INCLUDE_BCM56992
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56992_B0
#define BCMDRD_CONFIG_INCLUDE_BCM56992_B0 BCMDRD_CONFIG_INCLUDE_BCM56992_Bx
#endif
/* Resolve all interchip dependencies */
#if BCMDRD_CONFIG_INCLUDE_BCM56992_B0 == 1
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56990_B0
#define BCMDRD_CONFIG_INCLUDE_BCM56990_B0 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56990_B0 != 1
#undef BCMDRD_CONFIG_INCLUDE_BCM56990_B0
#define BCMDRD_CONFIG_INCLUDE_BCM56990_B0 1
#define BCMDRD_CONFIG_INCLUDE_BCM56990_B0_IMPLIED 1
#endif
#endif
/*
* BCM56996
*/
/* Sets the default include state if it was not given */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56996
#define BCMDRD_CONFIG_INCLUDE_BCM56996 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
/* Resolve revision dependencies */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56996_Ax
#define BCMDRD_CONFIG_INCLUDE_BCM56996_Ax BCMDRD_CONFIG_INCLUDE_BCM56996
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56996_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56996_A0 BCMDRD_CONFIG_INCLUDE_BCM56996_Ax
#endif
/*
* BCM56997
*/
/* Sets the default include state if it was not given */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56997
#define BCMDRD_CONFIG_INCLUDE_BCM56997 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
/* Resolve revision dependencies */
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56997_Ax
#define BCMDRD_CONFIG_INCLUDE_BCM56997_Ax BCMDRD_CONFIG_INCLUDE_BCM56997
#endif
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56997_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56997_A0 BCMDRD_CONFIG_INCLUDE_BCM56997_Ax
#endif
/* Resolve all interchip dependencies */
#if BCMDRD_CONFIG_INCLUDE_BCM56997_A0 == 1
#ifndef BCMDRD_CONFIG_INCLUDE_BCM56996_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56996_A0 BCMDRD_CONFIG_INCLUDE_CHIP_DEFAULT
#endif
#if BCMDRD_CONFIG_INCLUDE_BCM56996_A0 != 1
#undef BCMDRD_CONFIG_INCLUDE_BCM56996_A0
#define BCMDRD_CONFIG_INCLUDE_BCM56996_A0 1
#define BCMDRD_CONFIG_INCLUDE_BCM56996_A0_IMPLIED 1
#endif
#endif
#endif /* BCMDRD_CONFIG_CHIPS_H */
/*
* CONFIG_OPTION Macros. Can be used to determine the build configuration.
*/
#ifdef CONFIG_OPTION
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56780)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56780_Ax)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56780_A0)
#ifdef BCMDRD_CONFIG_INCLUDE_BCM56780_A0_IMPLIED
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56780_A0_IMPLIED)
#endif
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56782)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56782_Ax)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56782_A0)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56784)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56784_Ax)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56784_A0)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56786)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56786_Ax)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56786_A0)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56788)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56788_Ax)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56788_A0)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56789)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56789_Ax)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56789_A0)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56880)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56880_Ax)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56880_A0)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56880_Bx)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56880_B0)
#ifdef BCMDRD_CONFIG_INCLUDE_BCM56880_A0_IMPLIED
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56880_A0_IMPLIED)
#endif
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56881)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56881_Ax)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56881_A0)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56881_Bx)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56881_B0)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56883)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56883_Ax)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56883_A0)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56883_Bx)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56883_B0)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56889)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56889_Ax)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56889_A0)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56889_Bx)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56889_B0)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56990)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56990_Ax)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56990_A0)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56990_Bx)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56990_B0)
#ifdef BCMDRD_CONFIG_INCLUDE_BCM56990_A0_IMPLIED
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56990_A0_IMPLIED)
#endif
#ifdef BCMDRD_CONFIG_INCLUDE_BCM56990_B0_IMPLIED
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56990_B0_IMPLIED)
#endif
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56992)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56992_Bx)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56992_B0)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56996)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56996_Ax)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56996_A0)
#ifdef BCMDRD_CONFIG_INCLUDE_BCM56996_A0_IMPLIED
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56996_A0_IMPLIED)
#endif
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56997)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56997_Ax)
CONFIG_OPTION(BCMDRD_CONFIG_INCLUDE_BCM56997_A0)
#undef CONFIG_OPTION
#endif /* #ifdef CONFIG_OPTION */

View File

@ -0,0 +1,39 @@
# -*- Kbuild -*-
#
# Linux kernel BDE module.
#
# $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
# The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# A copy of the GNU General Public License version 2 (GPLv2) can
# be found in the LICENSES folder.$
#
obj-m := linux_ngbde.o
ccflags-y := $(LKM_CFLAGS) \
-I$(SDK)/linux/include \
-I$(SDK)/linux/bde \
-I$(SDK)/bcmdrd/include
linux_ngbde-y := ngbde_main.o \
ngbde_kapi.o \
ngbde_ioctl.o \
ngbde_procfs.o \
ngbde_pio.o \
ngbde_iio.o \
ngbde_dma.o \
ngbde_intr.o \
ngbde_pgmem.o \
ngbde_pci_probe.o \
ngbde_iproc_probe.o \
ngbde_swdev.o

View File

@ -0,0 +1,33 @@
# -*- Makefile -*-
#
# Linux kernel BDE module.
#
# $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
# The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# A copy of the GNU General Public License version 2 (GPLv2) can
# be found in the LICENSES folder.$
#
include Kbuild
ifeq ($(KERNELRELEASE),)
MOD_NAME = linux_ngbde
include $(SDK)/make/lkm.mk
endif
.PHONY: distclean
distclean:

View File

@ -0,0 +1,836 @@
/*! \file ngbde.h
*
* Shared definitions and APIs for NGBDE kernel module.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef NGBDE_H
#define NGBDE_H
#include <lkm/lkm.h>
#include <lkm/ngbde_kapi.h>
/*! Module name. */
#define MOD_NAME "linux_ngbde"
/*! Major number for associated charcter device file. */
#define MOD_MAJOR 120
/*! Read memory-mapped device register without byte-swap. */
#define NGBDE_IOREAD32(_a) __raw_readl(_a)
/*! Write memory-mapped device register without byte-swap. */
#define NGBDE_IOWRITE32(_v, _a) __raw_writel(_v, _a)
/*! Maximum number of I/O windows supported per device. */
#define NGBDE_NUM_IOWIN_MAX 3
/*! Maximum number of DMA memory pools supported per device. */
#define NGBDE_NUM_DMAPOOL_MAX 2
/*! Maximum number of IRQ status registers per interrupt source. */
#define NGBDE_NUM_IRQ_REGS_MAX 16
/*! Maximum number of IRQ lines (MSI vectors) per device. */
#define NGBDE_NUM_IRQS_MAX 1
/*!
* Maximum number of interrupt controller registers which may be
* written from both a user mode driver and a kernel mode driver.
*
* This feature is used when the kernel mode driver owns a subset of
* bits within a register, which is also used by the user mode driver.
*
* Both drivers must access such registers through a lock-protected
* access function.
*/
#define NGBDE_NUM_INTR_SHR_REGS_MAX 1
/*! I/O memory window definition. */
struct ngbde_memwin_s {
/*! Physical address of I/O window. */
phys_addr_t addr;
/*! Size of I/O window (in bytes). */
phys_addr_t size;
};
/*!
* \brief Shared register value.
*
* This structure contains the current value of a register where user
* mode and kernel mode owns different bits within the same
* register. In this case access must be carefully controlled to avoid
* that one context overwrites the bits owned by the other context.
*
* The structure also contains the offset of the shared register in
* order to identify the register (in case there is more than one
* shared register).
*/
typedef struct ngbde_shr_reg_s {
/*! Offset of the shared register. */
uint32_t reg_offs;
/*! Current value of the shared register. */
uint32_t cur_val;
} ngbde_shr_reg_t;
/*!
* \brief Shared interrupt mask register control.
*
* This defines which bits of an interrupt mask register are owned by
* user mode context, and which are owned by kernel context.
*
* The structure contains the corresponding interrupt status register
* in order to allow identification of the interrupt mask register
* irrespective of the host CPU being used.
*
* For example, if the host CPU is connected via PCI, then we use one
* mask register, but if the host CPU is an embedded ARM CPU, then we
* use a different mask register (for the same interrupt status
* register). By using the status register to identify the shared mask
* register, the kernel mode driver does not need to know which host
* CPU it is running off.
*/
typedef struct ngbde_irq_reg_s {
/*! Interrupt status register corresponding to the mask register. */
uint32_t status_reg;
/*! Shared interrupt mask register. */
uint32_t mask_reg;
/*! Mask identifying the register bits owned by the kernel mode driver. */
uint32_t kmask;
} ngbde_irq_reg_t;
/*!
* \name Interrupt ACK register access flags.
* \anchor NGBDE_INTR_ACK_F_xxx
*/
/*! \{ */
/*! ACK registers resides in PCI bridge I/O window. */
#define NGBDE_INTR_ACK_F_PAXB (1 << 0)
/*! \} */
/*!
* \brief Interrupt ACK register control.
*
* The structure contains the corresponding register offset
* and value in order to acknowledge interrupt in kernel driver.
*
* For example, if the host CPU is connected via PCI, then we use one
* ACK register, but if the host CPU is an embedded ARM CPU, then we
* use a different ACK register.
*/
typedef struct ngbde_intr_ack_reg_s {
/*! Ack register offset. */
uint32_t ack_reg;
/*! Ack value. */
uint32_t ack_val;
/*! Flags to indicate ack_reg resides in PCI bridge window. */
uint32_t flags;
} ngbde_intr_ack_reg_t;
/*!
* \brief BDE interrupt handler.
*
* The BDE will use a function of this type to register an interrupt
* handler with the Linux kernel.
*
* \param [in] data Interrupt handler context.
*
* \retval 0 Interrupt not recognized.
* \retval 1 Interrupt recognized and handled.
*/
typedef int (*ngbde_isr_f)(void *data);
/*!
* \brief Kernel interrupt control.
*
* This structure controls the sharing of interrupt processing between
* a user mode thread and a kernel mode interrupt handler.
*/
typedef struct ngbde_intr_ctrl_s {
/*! Handle for device I/O (for writing interrupt registers). */
uint8_t *iomem;
/*! Kernel device number (similar to user mode unit number). */
int kdev;
/*! Indicates that our interrupt handler is connected to the kernel. */
int irq_active;
/*! Interrupt number (IRQ# or MSI vector). */
int irq_vect;
/*! Number of interrupt status/mask register pairs. */
int num_regs;
/*! Interrupt status/mask register pairs for this device. */
ngbde_irq_reg_t regs[NGBDE_NUM_IRQ_REGS_MAX];
/*! Interrupt ACK register/value for this device. */
ngbde_intr_ack_reg_t intr_ack;
/*! Wait queue for user mode interrupt thread. */
wait_queue_head_t user_thread_wq;
/*! Flag to wake up user mode interrupt thread. */
atomic_t run_user_thread;
/*! Primary interrupt handler. */
ngbde_isr_f isr_func;
/*! Context for primary interrupt handler. */
void *isr_data;
} ngbde_intr_ctrl_t;
/*! Convenience macro for 1 kilobyte. */
#define ONE_KB 1024
/*! Convenience macro for 1 megabyte. */
#define ONE_MB (1024*1024)
/*!
* \name DMA allocation types.
* \anchor NGBDE_DMA_T_xxx
*/
/*! \{ */
/*!
* Do not allocate any DMA memory.
*/
#define NGBDE_DMA_T_NONE 0
/*!
* Try different allocation methods until DMA memory is successfully
* allocated.
*/
#define NGBDE_DMA_T_AUTO 1
/*! Use kernel DMA API (dma_alloc_coherent). */
#define NGBDE_DMA_T_KAPI 2
/*! Use page allocator and map to physical address manually. */
#define NGBDE_DMA_T_PGMEM 3
/*! \} */
/*! DMA memory allocation control structure. */
typedef struct ngbde_dmactrl_s {
/*! Requested size of DMA memory block (in bytes). */
size_t size;
/*! Kernel flags for memory allocation. */
gfp_t flags;
/*! Preferred DMA memory type (NGBDE_DMA_T_xxx). */
int pref_type;
/*! Kernel device for DMA memory management. */
struct device *dev;
} ngbde_dmactrl_t;
/*! DMA memory descriptor. */
typedef struct ngbde_dmamem_s {
/*! Logical address of DMA memory block. */
void *vaddr;
/*! Physical address of DMA memory block. */
dma_addr_t paddr;
/*! Bus address of DMA memory block. */
dma_addr_t baddr;
/*! Actual size of DMA memory block (in bytes). */
size_t size;
/*! Actual DMA memory type (NGBDE_DMA_T_xxx). */
int type;
/*! Kernel device for DMA memory management. */
struct device *dev;
} ngbde_dmamem_t;
/*! DMA memory pool. */
typedef struct ngbde_dmapool_s {
/*! DMA control parameters. */
struct ngbde_dmactrl_s dmactrl;
/*! DMA memory resources. */
struct ngbde_dmamem_s dmamem;
} ngbde_dmapool_t;
/*! Switch device descriptor. */
struct ngbde_dev_s {
/*! Vendor ID (typically PCI vendor ID). */
uint16_t vendor_id;
/*! Device ID (typically PCI device ID). */
uint16_t device_id;
/*! Device revision (typically PCI revision). */
uint16_t revision;
/*! Additional device identification when primary ID is not unique. */
uint16_t model;
/*! Bus number (typically PCI bus number). */
int bus_no;
/*! Slot number (typically PCI slot number). */
int slot_no;
/*! Interrupt line associated with this device. */
int irq_line;
/*! Use MSI interrupts with this device. */
int use_msi;
/*! Non-zero if device was removed. */
int inactive;
/*! Physical I/O window for kernel driver device access. */
struct ngbde_memwin_s pio_win;
/*! Memory mapped I/O window for kernel driver device access. */
uint8_t *pio_mem;
/*! Physical I/O window for interrupt controller access. */
struct ngbde_memwin_s iio_win;
/*! Memory mapped I/O window for interrupt controller access. */
uint8_t *iio_mem;
/*! Physical I/O window for device PCI bridge access. */
struct ngbde_memwin_s paxb_win;
/*! Memory mapped I/O window for device PCI bridge access. */
uint8_t *paxb_mem;
/*! Current value of shared register (typically an IRQ mask register). */
struct ngbde_shr_reg_s intr_shr_reg[NGBDE_NUM_INTR_SHR_REGS_MAX];
/*! Lock for shared register synchronization. */
spinlock_t lock;
/*! Interrupt control information. */
struct ngbde_intr_ctrl_s intr_ctrl[NGBDE_NUM_IRQS_MAX];
/*! Linux PCI handle. */
struct pci_dev *pci_dev;
/*! Kernel device for DMA memory management. */
struct device *dma_dev;
/*! Physical device I/O. */
struct ngbde_memwin_s iowin[NGBDE_NUM_IOWIN_MAX];
/*! DMA memory pools. */
struct ngbde_dmapool_s dmapool[NGBDE_NUM_DMAPOOL_MAX];
};
/*!
* \brief Linux IOCTL handler.
*
* This function handles communication between user mode and kernel
* mode.
*
* \param [in] file Device file handle.
* \param [in] cmd IOCTL command.
* \param [in] arg IOCTL command argument.
*
* \retval 0 No errors
*/
extern long
ngbde_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
/*!
* \brief Initialize procfs for BDE driver.
*
* Create procfs read interface for dumping probe information.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngbde_procfs_init(void);
/*!
* \brief Clean up procfs for BDE driver.
*
* Clean up resources allocated by \ref ngbde_procfs_init.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngbde_procfs_cleanup(void);
/*!
* \brief Allocate DMA memory pools for all probed devices.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngbde_dma_init(void);
/*!
* \brief Free DMA memory pools for all probed devices.
*
* \return Nothing.
*/
extern void
ngbde_dma_cleanup(void);
/*!
* \brief Connect to hardware interrupt handler.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_intr_connect(int kdev, unsigned int irq_num);
/*!
* \brief Disconnect from hardware interrupt handler.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_intr_disconnect(int kdev, unsigned int irq_num);
/*!
* \brief Disconnect from all hardware interrupt handlers.
*/
void
ngbde_intr_cleanup(void);
/*!
* \brief Wait for hardware interrupt.
*
* A user mode thread will call this function and sleep until a
* hardware interrupt occurs.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_intr_wait(int kdev, unsigned int irq_num);
/*!
* \brief Wake up sleeping interrupt thread.
*
* Wake up interrupt thread even if no interrupt has occurred.
*
* Intended for graceful shut-down procedure.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_intr_stop(int kdev, unsigned int irq_num);
/*!
* \brief Clear list of interrupt status/mask registers.
*
* This function is typically called before new interrupt register
* information is added.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_intr_regs_clr(int kdev, unsigned int irq_num);
/*!
* \brief Add interrupt status/mask register to monitor.
*
* This function adds a new interrupt status/mask register set to the
* list of registers monitored by the user-mode interrupt handler.
*
* The register list is used to determine whether a user-mode
* interrupt has occurred.
*
* See also \ref ngbde_intr_regs_clr.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
* \param [in] ireg Interrupt status/mask register information.
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_intr_reg_add(int kdev, unsigned int irq_num,
struct ngbde_irq_reg_s *ireg);
/*!
* \brief Add interrupt ack register to monitor.
*
* This function adds a interrupt register and mask value
* to acknowledge corresponding irq_num.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
* \param [in] ackreg Interrupt ack register information.
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_intr_ack_reg_add(int kdev, unsigned int irq_num,
struct ngbde_intr_ack_reg_s *ackreg);
/*!
* \brief Write shared interrupt mask register.
*
* This function is used by an interrupt handler when a shared
* interrupt mask register needs to be updated.
*
* Since the register is shared between multiple interrupt handlers,
* access must be protected by a lock.
*
* The register information provided via \ref ngbde_intr_reg_add is
* used to detemine which bits of the mask register belong to the user
* mode driver.
*
* Note that the mask register to access is referenced by the
* corresponding status register. This is because the mask register
* may be different depending on the host CPU interface being used
* (e.g. PCI vs. AXI). On the other hand, the status register is the
* same irrespective of the host CPU interface.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
* \param [in] kapi Must be set to 1 if called from kernel API.
* \param [in] status_reg Corresponding interrupt status register offset.
* \param [in] mask_val New value to write to mask register.
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_intr_mask_write(int kdev, unsigned int irq_num, int kapi,
uint32_t status_reg, uint32_t mask_val);
/*!
* \brief Probe for PCI-attached Broadcom switch devices.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngbde_pci_probe(void);
/*!
* \brief Clean up resources for PCI-attached Broadcom switch devices.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngbde_pci_cleanup(void);
/*!
* \brief Add new switch device to BDE database.
*
* Add device information for probed or fixed switch device.
*
* \param [in] nd Switch device information.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngbde_swdev_add(struct ngbde_dev_s *nd);
/*!
* \brief Get device information for a BDE switch device.
*
* \param [in] kdev Switch device number.
*
* \return Pointer to switch device structure or NULL on error.
*/
struct ngbde_dev_s *
ngbde_swdev_get(int kdev);
/*!
* \brief Get list of all probed switch devices.
*
* Return a pointer to the array of registered switch devices.
*
* \param [out] nd Pointer to array of switch devices.
* \param [in] num_nd number of valid entries in switch device array.
*
* \retval 0 No errors
*/
extern int
ngbde_swdev_get_all(struct ngbde_dev_s **nd, unsigned int *num_nd);
/*!
* \brief Allocate memory using page allocator
*
* For any sizes less than MEM_CHUNK_SIZE, we ask the page allocator
* for the entire memory block, otherwise we try to assemble a
* contiguous cmblock ourselves.
*
* Upon successful allocation, the memory block will be added to the
* global list of allocated memory blocks.
*
* \param [in] size Number of bytes to allocate.
* \param [in] flags Kernel flags (GFP_xxx) for memory allocation.
*
* \return Pointer to allocated memory or NULL if failure.
*/
void *
ngbde_pgmem_alloc(size_t size, gfp_t flags);
/*!
* \brief Free memory block allocated by ngbde_pgmem_alloc.
*
* \param [in] ptr Pointer returned by ngbde_pgmem_alloc.
*
* \return 0 if succesfully freed, otherwise -1.
*/
extern int
ngbde_pgmem_free(void *ptr);
/*!
* \brief Free all memory blocks allocated by ngbde_pgmem_alloc.
*
* This function will walk the global list of allocated memory blocks
* and free all associated resources.
*
* Intended for a full clean up before the module is unloaded.
*
* \return Nothing.
*/
extern void
ngbde_pgmem_free_all(void);
/*!
* \brief Map I/O memory in kernel driver.
*
* This function is used to provide device I/O access to a kernel mode
* driver.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
* \param [in] addr Physical address to map.
* \param [in] size Size of I/O window to map.
*
* \return Pointer to mapped I/O memory, or NULL on error.
*/
extern void *
ngbde_pio_map(void *devh, phys_addr_t addr, phys_addr_t size);
/*!
* \brief Unmap I/O memory in kernel driver.
*
* Unmap I/O memory previously mapped via \ref ngbde_pio_map.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
*
* \return Nothing.
*/
extern void
ngbde_pio_unmap(void *devh);
/*!
* \brief Unmap all I/O windows.
*/
extern void
ngbde_pio_cleanup(void);
/*!
* \brief Write a memory-mapped register from kernel driver.
*
* Write a 32-bit register using I/O memory previously mapped via \ref
* ngbde_pio_map.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
* \param [in] offs Register address offset.
* \param [in] val Value to write to register.
*
* \return Nothing.
*/
extern void
ngbde_pio_write32(void *devh, uint32_t offs, uint32_t val);
/*!
* \brief Read a memory-mapped register from kernel driver.
*
* Read a 32-bit register using I/O memory previously mapped via \ref
* ngbde_pio_map.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
* \param [in] offs Register address offset.
*
* \return Value read from register.
*/
extern uint32_t
ngbde_pio_read32(void *devh, uint32_t offs);
/*!
* \brief Map interrupt controller I/O memory.
*
* On some devices the interrupt controller is a device separate from
* the main switch device. This function is used to provide interrupt
* controller I/O access to a kernel mode driver.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
* \param [in] addr Physical address to map.
* \param [in] size Size of I/O window to map.
*
* \return Pointer to mapped I/O memory, or NULL on error.
*/
extern void *
ngbde_iio_map(void *devh, phys_addr_t addr, phys_addr_t size);
/*!
* \brief Unmap interrupt controller I/O memory.
*
* Unmap I/O memory previously mapped via \ref ngbde_iio_map.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
*
* \return Nothing.
*/
extern void
ngbde_iio_unmap(void *devh);
/*!
* \brief Unmap all interrupt controller I/O windows.
*/
extern void
ngbde_iio_cleanup(void);
/*!
* \brief Write a memory-mapped interrupt controller register.
*
* Write a 32-bit register using I/O memory previously mapped via \ref
* ngbde_iio_map.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
* \param [in] offs Register address offset.
* \param [in] val Value to write to register.
*
* \return Nothing.
*/
extern void
ngbde_iio_write32(void *devh, uint32_t offs, uint32_t val);
/*!
* \brief Read a memory-mapped interrupt controller register.
*
* Read a 32-bit register using I/O memory previously mapped via \ref
* ngbde_iio_map.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
* \param [in] offs Register address offset.
*
* \return Value read from register.
*/
extern uint32_t
ngbde_iio_read32(void *devh, uint32_t offs);
/*!
* \brief Map PCI bridge I/O memory.
*
* On some devices the interrupt controller is a device separate from
* the main switch device. This function is used to provide interrupt
* controller I/O access to a kernel mode driver.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
* \param [in] addr Physical address to map.
* \param [in] size Size of I/O window to map.
*
* \return Pointer to mapped I/O memory, or NULL on error.
*/
extern void *
ngbde_paxb_map(void *devh, phys_addr_t addr, phys_addr_t size);
/*!
* \brief Unmap PCI bridge I/O memory.
*
* Unmap I/O memory previously mapped via \ref ngbde_paxb_map.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
*
* \return Nothing.
*/
extern void
ngbde_paxb_unmap(void *devh);
/*!
* \brief Unmap all PCI bridge I/O windows.
*/
extern void
ngbde_paxb_cleanup(void);
/*!
* \brief Probe for Broadcom switch devices on IPROC internal bus.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngbde_iproc_probe(void);
/*!
* \brief Clean up resources for Broadcom switch devices on IPROC internal bus.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngbde_iproc_cleanup(void);
#endif /* NGBDE_H */

View File

@ -0,0 +1,340 @@
/*! \file ngbde_dma.c
*
* This module handles allocation of DMA memory pools.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <ngbde.h>
/*! \cond */
static int dma_debug = 0;
module_param(dma_debug, int, 0);
MODULE_PARM_DESC(dma_debug,
"DMA debug output enable (default 0).");
/*! \endcond */
/*! Default size of of DMA memory pools (in MB). */
#define DMAPOOL_SIZE_DEFAULT 16
/*! Default number of DMA memory pools per device. */
#define NUM_DMAPOOL_DEFAULT 1
/*! \cond */
static int dma_size = DMAPOOL_SIZE_DEFAULT;
module_param(dma_size, int, 0);
MODULE_PARM_DESC(dma_size,
"Size of of DMA memory pools in MB (default 16 MB).");
/*! \endcond */
/*! \cond */
static char *dma_alloc;
module_param(dma_alloc, charp, 0);
MODULE_PARM_DESC(dma_alloc,
"DMA allocation method auto|kapi|pgmem (default auto)");
/*! \endcond */
/*! \cond */
static int dma_pools = NUM_DMAPOOL_DEFAULT;
module_param(dma_pools, int, 0);
MODULE_PARM_DESC(dma_pools,
"Number of DMA memory pools to pre-allocate per device (default 1).");
/*! \endcond */
/*!
* \brief Allocate DMA memory via kernel API.
*
* \param [in] dmactrl DMA allocation control.
* \param [out] dmamem DMA allocation result.
*
* \return Nothing.
*/
static void
ngbde_dmamem_kapi_alloc(ngbde_dmactrl_t *dmactrl, ngbde_dmamem_t *dmamem)
{
void *vaddr;
dma_addr_t baddr;
vaddr = dma_alloc_coherent(dmactrl->dev, dmactrl->size, &baddr,
dmactrl->flags);
if (vaddr) {
/* Store allocation information in dmamem structure */
dmamem->vaddr = vaddr;
dmamem->paddr = virt_to_phys(vaddr);
dmamem->dev = dmactrl->dev;
dmamem->size = dmactrl->size;
dmamem->type = NGBDE_DMA_T_KAPI;
dmamem->baddr = baddr;
/* Write small signature for debug purposes */
strcpy((char *)vaddr, "DMA_KAPI");
if (dma_debug) {
printk("DMA: Allocated %d KB of KAPI memory at 0x%08lx\n",
(int)(dmamem->size / ONE_KB),
(unsigned long)dmamem->paddr);
}
} else {
if (dma_debug) {
printk("DMA: Failed to allocate KAPI memory\n");
}
}
}
/*!
* \brief Allocate DMA memory via page allocator.
*
* \param [in] dmactrl DMA allocation control.
* \param [out] dmamem DMA allocation result.
*
* \return Nothing.
*/
static void
ngbde_dmamem_pgmem_alloc(ngbde_dmactrl_t *dmactrl, ngbde_dmamem_t *dmamem)
{
void *vaddr;
vaddr = ngbde_pgmem_alloc(dmactrl->size, dmactrl->flags);
if (vaddr) {
/* Store allocation information in dmamem structure */
dmamem->vaddr = vaddr;
dmamem->paddr = virt_to_phys(vaddr);
dmamem->dev = dmactrl->dev;
dmamem->size = dmactrl->size;
dmamem->type = NGBDE_DMA_T_PGMEM;
dmamem->baddr = dma_map_single(dmamem->dev, dmamem->vaddr,
dmamem->size, DMA_BIDIRECTIONAL);
if (dma_mapping_error(dmactrl->dev, dmamem->baddr)) {
dmamem->baddr = 0;
if (dma_debug) {
printk("DMA: Failed to map PGMEM memory\n");
}
}
/* Write small signature for debug purposes */
strcpy((char *)vaddr, "DMA_PGMEM");
if (dma_debug) {
printk("DMA: Allocated %d KB of PGMEM memory at 0x%08lx\n",
(int)(dmamem->size / ONE_KB),
(unsigned long)dmamem->paddr);
}
} else {
if (dma_debug) {
printk("DMA: Failed to allocate PGMEM memory\n");
}
}
}
/*!
* \brief Allocate DMA memory.
*
* Depending on the DMA allocation control parameters, we select one
* of several DMA memory allocation methods.
*
* \param [in] dmactrl DMA allocation control.
* \param [out] dmamem DMA allocation result.
*
* \return Nothing.
*/
static int
ngbde_dmamem_alloc(ngbde_dmactrl_t *dmactrl, ngbde_dmamem_t *dmamem)
{
int kapi = 0;
if (dmamem->vaddr) {
/* Already allocated */
return 0;
}
#ifdef CONFIG_CMA
/* Always allow KAPI when CMA is available */
kapi = 1;
#else
if (dmactrl->size <= (1 << (MAX_ORDER - 1 + PAGE_SHIFT))) {
kapi = 1;
}
#endif
/* Allocation via kernel DMA API (if allowed) */
if (kapi) {
switch (dmactrl->pref_type) {
case NGBDE_DMA_T_AUTO:
case NGBDE_DMA_T_KAPI:
ngbde_dmamem_kapi_alloc(dmactrl, dmamem);
break;
default:
break;
}
}
/* Allocation via private page allocator */
if (dmamem->vaddr == NULL) {
switch (dmactrl->pref_type) {
case NGBDE_DMA_T_AUTO:
case NGBDE_DMA_T_PGMEM:
ngbde_dmamem_pgmem_alloc(dmactrl, dmamem);
break;
default:
break;
}
}
if (dmamem->vaddr == NULL) {
printk(KERN_WARNING "%s: Failed to allocate DMA memory\n",
MOD_NAME);
return -1;
}
return 0;
}
/*!
* \brief Free DMA memory.
*
* Free DMA memory allocated via \ref ngbde_dmamem_alloc.
*
* \param [in] dmamem DMA allocation result from \ref ngbde_dmamem_alloc.
*
* \return Nothing.
*/
static int
ngbde_dmamem_free(ngbde_dmamem_t *dmamem)
{
switch (dmamem->type) {
case NGBDE_DMA_T_KAPI:
if (dma_debug) {
printk("DMA: Freeing %d KB of KAPI memory\n",
(int)(dmamem->size / ONE_KB));
}
dma_free_coherent(dmamem->dev, dmamem->size,
dmamem->vaddr, dmamem->paddr);
memset(dmamem, 0, sizeof(*dmamem));
break;
case NGBDE_DMA_T_PGMEM:
if (dma_debug) {
printk("DMA: Freeing %d KB of PGMEM memory\n",
(int)(dmamem->size / ONE_KB));
}
if (dmamem->baddr) {
if (dma_debug) {
printk("DMA: Unmapping PGMEM memory at 0x%08lx\n",
(unsigned long)dmamem->baddr);
}
dma_unmap_single(dmamem->dev, dmamem->baddr,
dmamem->size, DMA_BIDIRECTIONAL);
}
ngbde_pgmem_free(dmamem->vaddr);
memset(dmamem, 0, sizeof(*dmamem));
break;
case NGBDE_DMA_T_NONE:
/* Nothing to free */
break;
default:
printk(KERN_WARNING "%s: Unable to free unknown DMA memory type\n",
MOD_NAME);
break;
}
return 0;
}
/*!
* \brief Free all DMA memory pools for all devices.
*
* \return Nothing.
*/
void
ngbde_dma_cleanup(void)
{
struct ngbde_dev_s *swdev;
unsigned int num_swdev, idx;
unsigned int pool;
ngbde_swdev_get_all(&swdev, &num_swdev);
for (idx = 0; idx < num_swdev; idx++) {
for (pool = 0; pool < NGBDE_NUM_DMAPOOL_MAX; pool++) {
if (swdev[idx].inactive) {
ngbde_dmamem_free(&swdev[idx].dmapool[pool].dmamem);
}
}
}
}
/*!
* \brief Allocate DMA memory pools for all devices.
*
* \return Nothing.
*/
int
ngbde_dma_init(void)
{
int rv;
struct ngbde_dev_s *swdev;
unsigned int num_swdev, idx;
int dma_type = NGBDE_DMA_T_AUTO;
struct ngbde_dmapool_s *dmapool;
unsigned int pool;
/* Default DMA memory size per device */
if (dma_size < 0) {
dma_size = DMAPOOL_SIZE_DEFAULT;
}
/* Check for forced DMA allocation method */
if (dma_alloc) {
if (strcmp(dma_alloc, "kapi") == 0) {
dma_type = NGBDE_DMA_T_KAPI;
} else if (strcmp(dma_alloc, "pgmem") == 0) {
dma_type = NGBDE_DMA_T_PGMEM;
} else {
printk(KERN_WARNING "%s: Unknown DMA type: %s\n",
MOD_NAME, dma_alloc);
}
}
/* Number of DMA memory pools per device */
if ((unsigned int)dma_pools >= NGBDE_NUM_DMAPOOL_MAX) {
dma_pools = NUM_DMAPOOL_DEFAULT;
}
ngbde_swdev_get_all(&swdev, &num_swdev);
for (idx = 0; idx < num_swdev; idx++) {
/* Set DMA allocation parameters */
for (pool = 0; pool < NGBDE_NUM_DMAPOOL_MAX; pool++) {
dmapool = &swdev[idx].dmapool[pool];
dmapool->dmactrl.dev = swdev[idx].dma_dev;
dmapool->dmactrl.size = dma_size * ONE_MB;
dmapool->dmactrl.pref_type = dma_type;
dmapool->dmactrl.flags = GFP_KERNEL | GFP_DMA32;
}
/* Allocate DMA pools */
for (pool = 0; pool < dma_pools; pool++) {
dmapool = &swdev[idx].dmapool[pool];
rv = ngbde_dmamem_alloc(&dmapool->dmactrl, &dmapool->dmamem);
if (rv < 0) {
printk(KERN_WARNING "%s: Unable to allocate DMA pool %d %d\n",
MOD_NAME, idx, pool);
}
}
}
return 0;
}

View File

@ -0,0 +1,143 @@
/*! \file ngbde_iio.c
*
* API for managing and accessing memory-mapped I/O for interrupt
* controller registers.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <ngbde.h>
void *
ngbde_iio_map(void *devh, phys_addr_t addr, phys_addr_t size)
{
struct ngbde_dev_s *sd = (struct ngbde_dev_s *)devh;
if (sd->iio_mem) {
if (addr == sd->iio_win.addr && size == sd->iio_win.size) {
/* Already mapped */
return sd->iio_mem;
}
ngbde_iio_unmap(devh);
}
sd->iio_mem = ioremap_nocache(addr, size);
if (sd->iio_mem) {
/* Save mapped resources */
sd->iio_win.addr = addr;
sd->iio_win.size = size;
}
return sd->iio_mem;
}
void
ngbde_iio_unmap(void *devh)
{
struct ngbde_dev_s *sd = (struct ngbde_dev_s *)devh;
if (sd->iio_mem) {
iounmap(sd->iio_mem);
sd->iio_mem = NULL;
}
}
void
ngbde_iio_cleanup(void)
{
struct ngbde_dev_s *swdev, *sd;
unsigned int num_swdev, idx;
ngbde_swdev_get_all(&swdev, &num_swdev);
for (idx = 0; idx < num_swdev; idx++) {
sd = ngbde_swdev_get(idx);
ngbde_iio_unmap(sd);
}
}
void
ngbde_iio_write32(void *devh, uint32_t offs, uint32_t val)
{
struct ngbde_dev_s *sd = (struct ngbde_dev_s *)devh;
if (sd->iio_mem) {
NGBDE_IOWRITE32(val, sd->iio_mem + offs);
}
}
uint32_t
ngbde_iio_read32(void *devh, uint32_t offs)
{
struct ngbde_dev_s *sd = (struct ngbde_dev_s *)devh;
if (sd->iio_mem) {
return NGBDE_IOREAD32(sd->iio_mem + offs);
}
return 0;
}
void *
ngbde_paxb_map(void *devh, phys_addr_t addr, phys_addr_t size)
{
struct ngbde_dev_s *sd = (struct ngbde_dev_s *)devh;
if (sd->paxb_mem) {
if (addr == sd->paxb_win.addr && size == sd->paxb_win.size) {
/* Already mapped */
return sd->paxb_mem;
}
iounmap(sd->paxb_mem);
}
sd->paxb_mem = ioremap_nocache(addr, size);
if (sd->paxb_mem) {
/* Save mapped resources */
sd->paxb_win.addr = addr;
sd->paxb_win.size = size;
}
return sd->paxb_mem;
}
void
ngbde_paxb_unmap(void *devh)
{
struct ngbde_dev_s *sd = (struct ngbde_dev_s *)devh;
if (sd->paxb_mem) {
iounmap(sd->paxb_mem);
sd->paxb_mem = NULL;
}
}
void
ngbde_paxb_cleanup(void)
{
struct ngbde_dev_s *swdev, *sd;
unsigned int num_swdev, idx;
ngbde_swdev_get_all(&swdev, &num_swdev);
for (idx = 0; idx < num_swdev; idx++) {
sd = ngbde_swdev_get(idx);
ngbde_paxb_unmap(sd);
}
}

View File

@ -0,0 +1,550 @@
/*! \file ngbde_intr.c
*
* API for controlling a thread-based user-mode interrupt handler.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <ngbde.h>
/*! \cond */
static int intr_debug = 0;
module_param(intr_debug, int, 0);
MODULE_PARM_DESC(intr_debug,
"Interrupt debug output enable (default 0).");
/*! \endcond */
static int
ngbde_intr_shared_write32(struct ngbde_dev_s *sd, struct ngbde_intr_ctrl_s *ic,
uint32_t reg_offs, uint32_t reg_val, uint32_t shr_mask)
{
unsigned long flags;
struct ngbde_shr_reg_s *sr;
int idx;
sr = NULL;
for (idx = 0; idx < NGBDE_NUM_INTR_SHR_REGS_MAX; idx++) {
if (sd->intr_shr_reg[idx].reg_offs == 0) {
/* If not found, then we add a new entry */
sd->intr_shr_reg[idx].reg_offs = reg_offs;
}
if (sd->intr_shr_reg[idx].reg_offs == reg_offs) {
sr = &sd->intr_shr_reg[idx];
break;
}
}
if (sr == NULL) {
return -1;
}
spin_lock_irqsave(&sd->lock, flags);
sr->cur_val &= ~shr_mask;
sr->cur_val |= (reg_val & shr_mask);
NGBDE_IOWRITE32(sr->cur_val, ic->iomem + reg_offs);
spin_unlock_irqrestore(&sd->lock, flags);
return 0;
}
/*!
* \brief Interrupt handler for user mode thread.
*
* This function will determine whether a user-mode interrupt has
* occurred by reading the configured interrupt status and mask
* registers.
*
* If an interrupt has occurred, any waiting user-mode thread is woken
* up.
*
* \param [in] ic Interrupt control information.
*
* \retval 1 One or more user mode interrupts occurred.
* \retval 0 No user mode interrupts occurred.
*/
static int
ngbde_user_isr(ngbde_intr_ctrl_t *ic)
{
int idx;
int active_interrupts = 0;
uint32_t stat = 0, mask = 0;
uint32_t kmask;
/* Check if any enabled interrupts are active */
for (idx = 0; idx < ic->num_regs; idx++) {
ngbde_irq_reg_t *ir = &ic->regs[idx];
/* Get mask of all kernel interrupt sources for this register address */
kmask = ir->kmask;
stat = NGBDE_IOREAD32(&ic->iomem[ir->status_reg]);
mask = NGBDE_IOREAD32(&ic->iomem[ir->mask_reg]);
if (stat & mask & ~kmask) {
active_interrupts = 1;
break;
}
}
/* No active interrupts to service */
if (!active_interrupts) {
return 0;
}
/* Disable (mask off) all interrupts */
for (idx = 0; idx < ic->num_regs; idx++) {
ngbde_irq_reg_t *ir = &ic->regs[idx];
/* Get mask of all kernel interrupt sources for this register address */
kmask = ir->kmask;
if (kmask == 0xffffffff) {
/* Kernel driver owns all interrupts in this register */
continue;
} else if (kmask) {
/* Synchronized write */
struct ngbde_dev_s *sd = ngbde_swdev_get(ic->kdev);
if (ngbde_intr_shared_write32(sd, ic, ir->mask_reg, 0, ~kmask) < 0) {
printk(KERN_WARNING
"%s: Failed to write shared register for device %d\n",
MOD_NAME, ic->kdev);
/* Fall back to normal write to ensure interrupts are masked */
NGBDE_IOWRITE32(0, &ic->iomem[ir->mask_reg]);
}
} else {
NGBDE_IOWRITE32(0, &ic->iomem[ir->mask_reg]);
}
}
atomic_set(&ic->run_user_thread, 1);
wake_up_interruptible(&ic->user_thread_wq);
return 1;
}
/*!
* \brief Interrupt handler for kernel driver.
*
* Typically used by the KNET driver.
*
* \param [in] ic Interrupt control information.
*
* \retval 1 One or more kernel mode interrupts occurred.
* \retval 0 No kernel mode interrupts occurred.
*/
static int
ngbde_kernel_isr(ngbde_intr_ctrl_t *ic)
{
if (ic->isr_func) {
return ic->isr_func(ic->isr_data);
}
return 0;
}
/*!
* \brief Acknowledge interrupt
*
* \param [in] data Interrupt control information
*
* \retval 0
*/
static int
ngbde_intr_ack(ngbde_intr_ctrl_t *ic)
{
struct ngbde_dev_s *sd = ngbde_swdev_get(ic->kdev);
struct ngbde_intr_ack_reg_s *ar = &ic->intr_ack;
if (sd->use_msi) {
if (ar->flags & NGBDE_INTR_ACK_F_PAXB) {
NGBDE_IOWRITE32(ar->ack_val, &sd->paxb_mem[ar->ack_reg]);
} else {
NGBDE_IOWRITE32(ar->ack_val, &sd->pio_mem[ar->ack_reg]);
}
}
return 0;
}
/*!
* \brief Linux ISR
*
* Will call the user-mode interrupts handler and optionally also a
* kernel mode interrupt handler (typically KNET).
*
* \param [in] irq_num Interrupt vector from kernel.
* \param [in] data Interrupt control information
*
* \retval IRQ_NONE Interrupt not recognized.
* \retval IRQ_HANDLED Interrupt recognized and handled (masked off).
*/
static irqreturn_t
ngbde_isr(int irq_num, void *data)
{
struct ngbde_intr_ctrl_s *ic = (struct ngbde_intr_ctrl_s *)data;
irqreturn_t rv = IRQ_NONE;
ngbde_intr_ack(ic);
if (ngbde_user_isr(ic)) {
rv = IRQ_HANDLED;
}
if (ngbde_kernel_isr(ic)) {
rv = IRQ_HANDLED;
}
return rv;
}
int
ngbde_intr_connect(int kdev, unsigned int irq_num)
{
struct ngbde_dev_s *sd;
struct ngbde_intr_ctrl_s *ic;
unsigned long irq_flags;
sd = ngbde_swdev_get(kdev);
if (!sd) {
return -1;
}
if (irq_num >= NGBDE_NUM_IRQS_MAX) {
return -1;
}
ic = &sd->intr_ctrl[irq_num];
if (ic->irq_active) {
return 0;
}
if (sd->irq_line >= 0) {
if (sd->pio_mem == NULL) {
printk(KERN_WARNING "%s: No memory-mapped I/O for device %d\n",
MOD_NAME, kdev);
return -1;
}
ic->kdev = kdev;
ic->iomem = sd->pio_mem;
if (sd->iio_mem) {
if (intr_debug) {
printk("INTR: Using dedicated interrupt controller\n");
}
ic->iomem = sd->iio_mem;
}
init_waitqueue_head(&ic->user_thread_wq);
atomic_set(&ic->run_user_thread, 0);
irq_flags = IRQF_SHARED;
ic->irq_vect = sd->irq_line;
/*
* The pci_enable_msi function must be called after enabling
* BAR0_PAXB_OARR_FUNC0_MSI_PAGE, otherwise, MSI interrupts
* cannot be triggered!
*/
if (sd->use_msi) {
if (pci_enable_msi(sd->pci_dev) == 0) {
irq_flags = 0;
ic->irq_vect = sd->pci_dev->irq;
if (intr_debug) {
printk("INTR: Enabled MSI interrupts\n");
}
} else {
printk(KERN_WARNING "%s: Failed to enable MSI for device %d\n",
MOD_NAME, kdev);
sd->use_msi = 0;
}
}
if (intr_debug) {
printk("INTR: Request IRQ %d\n", ic->irq_vect);
}
if (request_irq(ic->irq_vect, ngbde_isr, irq_flags, MOD_NAME, ic) < 0) {
printk(KERN_WARNING "%s: Could not get IRQ %d for device %d\n",
MOD_NAME, ic->irq_vect, kdev);
return -1;
}
ic->irq_active = 1;
}
return 0;
}
int
ngbde_intr_disconnect(int kdev, unsigned int irq_num)
{
struct ngbde_dev_s *sd;
struct ngbde_intr_ctrl_s *ic;
sd = ngbde_swdev_get(kdev);
if (!sd) {
return -1;
}
if (irq_num >= NGBDE_NUM_IRQS_MAX) {
return -1;
}
ic = &sd->intr_ctrl[irq_num];
if (!ic->irq_active) {
return 0;
}
if (ic->isr_func) {
printk(KERN_WARNING "%s: Disconnecting IRQ %d blocked by kernel ISR\n",
MOD_NAME, irq_num);
return 0;
}
if (ic->irq_vect >= 0) {
free_irq(ic->irq_vect, ic);
if (sd->use_msi) {
pci_disable_msi(sd->pci_dev);
}
ic->irq_active = 0;
}
return 0;
}
void
ngbde_intr_cleanup(void)
{
struct ngbde_dev_s *swdev;
unsigned int num_swdev, idx, irq_num;
ngbde_swdev_get_all(&swdev, &num_swdev);
for (idx = 0; idx < num_swdev; idx++) {
for (irq_num = 0; irq_num < NGBDE_NUM_IRQS_MAX; irq_num++) {
ngbde_intr_disconnect(idx, irq_num);
}
}
}
int
ngbde_intr_wait(int kdev, unsigned int irq_num)
{
struct ngbde_dev_s *sd;
struct ngbde_intr_ctrl_s *ic;
sd = ngbde_swdev_get(kdev);
if (!sd) {
return -1;
}
if (irq_num >= NGBDE_NUM_IRQS_MAX) {
return -1;
}
ic = &sd->intr_ctrl[irq_num];
if (!ic->irq_active) {
return 0;
}
wait_event_interruptible(ic->user_thread_wq,
atomic_read(&ic->run_user_thread) != 0);
atomic_set(&ic->run_user_thread, 0);
return 0;
}
int
ngbde_intr_stop(int kdev, unsigned int irq_num)
{
struct ngbde_dev_s *sd;
struct ngbde_intr_ctrl_s *ic;
sd = ngbde_swdev_get(kdev);
if (!sd) {
return -1;
}
if (irq_num >= NGBDE_NUM_IRQS_MAX) {
return -1;
}
ic = &sd->intr_ctrl[irq_num];
if (!ic->irq_active) {
return 0;
}
/* Wake up user thread */
atomic_set(&ic->run_user_thread, 1);
wake_up_interruptible(&ic->user_thread_wq);
return 0;
}
int
ngbde_intr_regs_clr(int kdev, unsigned int irq_num)
{
struct ngbde_dev_s *sd;
struct ngbde_intr_ctrl_s *ic;
sd = ngbde_swdev_get(kdev);
if (!sd) {
return -1;
}
if (irq_num >= NGBDE_NUM_IRQS_MAX) {
return -1;
}
ic = &sd->intr_ctrl[irq_num];
if (ic->irq_active) {
/* Do not clear configuration with interrupt connected */
return 0;
}
ic->num_regs = 0;
memset(ic->regs, 0, sizeof(ic->regs));
return 0;
}
int
ngbde_intr_reg_add(int kdev, unsigned int irq_num,
struct ngbde_irq_reg_s *ireg)
{
struct ngbde_dev_s *sd;
struct ngbde_intr_ctrl_s *ic;
struct ngbde_irq_reg_s *ir;
unsigned int idx;
sd = ngbde_swdev_get(kdev);
if (!sd) {
return -1;
}
if (irq_num >= NGBDE_NUM_IRQS_MAX) {
return -1;
}
ic = &sd->intr_ctrl[irq_num];
if (ic->irq_active) {
/*
* If the interrupt is connected, then we only update the
* kernel mask for existing entries.
*/
for (idx = 0; idx < ic->num_regs; idx++) {
ir = &ic->regs[idx];
if (ir->status_reg == ireg->status_reg &&
ir->mask_reg == ireg->mask_reg) {
ir->kmask = ireg->kmask;
if (intr_debug) {
printk("INTR: Updating interrupt register "
"0x%08x/0x%08x (0x%08x)\n",
ir->status_reg, ir->mask_reg, ir->kmask);
}
return 0;
}
}
return -1;
}
if (ic->num_regs >= NGBDE_NUM_IRQ_REGS_MAX) {
return -1;
}
ir = &ic->regs[ic->num_regs++];
memcpy(ir, ireg, sizeof (*ir));
if (intr_debug) {
printk("INTR: Adding interrupt register 0x%08x/0x%08x (0x%08x)\n",
ir->status_reg, ir->mask_reg, ir->kmask);
}
return ic->num_regs;
}
int
ngbde_intr_ack_reg_add(int kdev, unsigned int irq_num,
struct ngbde_intr_ack_reg_s *ackreg)
{
struct ngbde_dev_s *sd;
struct ngbde_intr_ctrl_s *ic;
struct ngbde_intr_ack_reg_s *ar;
sd = ngbde_swdev_get(kdev);
if (!sd) {
return -1;
}
if (irq_num >= NGBDE_NUM_IRQS_MAX) {
return -1;
}
ic = &sd->intr_ctrl[irq_num];
if (ic->irq_active) {
/* Ignore request if interrupt is connected */
return 0;
}
ar = &ic->intr_ack;
memcpy(ar, ackreg, sizeof (*ar));
if (intr_debug) {
printk("INTR: Adding interrupt ACK register 0x%08x/0x%08x (0x%08x)\n",
ar->ack_reg, ar->ack_val, ar->flags);
}
return 0;
}
int
ngbde_intr_mask_write(int kdev, unsigned int irq_num, int kapi,
uint32_t status_reg, uint32_t mask_val)
{
struct ngbde_dev_s *sd;
struct ngbde_intr_ctrl_s *ic;
struct ngbde_irq_reg_s *ir;
unsigned int idx;
uint32_t bmask;
sd = ngbde_swdev_get(kdev);
if (!sd) {
return -1;
}
if (irq_num >= NGBDE_NUM_IRQS_MAX) {
return -1;
}
ic = &sd->intr_ctrl[irq_num];
ir = ic->regs;
for (idx = 0; idx < ic->num_regs; idx++) {
if (ir->status_reg == status_reg) {
bmask = kapi ? ir->kmask : ~ir->kmask;
ngbde_intr_shared_write32(sd, ic, ir->mask_reg, mask_val, bmask);
return 0;
}
ir++;
}
return -1;
}

View File

@ -0,0 +1,237 @@
/*! \file ngbde_ioctl.c
*
* NGBDE IOCTL interface.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <lkm/ngbde_ioctl.h>
#include <ngbde.h>
long
ngbde_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct ngbde_ioc_cmd_s ioc;
struct ngbde_dev_s *swdev;
struct ngbde_irq_reg_s ireg;
struct ngbde_intr_ack_reg_s ackreg;
phys_addr_t addr, size;
unsigned int num_swdev;
unsigned int rsrc_type, rsrc_idx;
unsigned int irq_num, intr_cmd;
uint32_t mreg, mval;
if (copy_from_user(&ioc, (void *)arg, sizeof(ioc))) {
return -EFAULT;
}
ioc.rc = NGBDE_IOC_SUCCESS;
switch (cmd) {
case NGBDE_IOC_MOD_INFO:
ioc.op.mod_info.version = NGBDE_IOC_VERSION;
break;
case NGBDE_IOC_PROBE_INFO:
ngbde_swdev_get_all(NULL, &num_swdev);
ioc.op.probe_info.num_swdev = num_swdev;
break;
case NGBDE_IOC_DEV_INFO:
swdev = ngbde_swdev_get(ioc.devid);
if (!swdev) {
ioc.rc = NGBDE_IOC_FAIL;
break;
}
ioc.op.dev_info.vendor_id = swdev->vendor_id;
ioc.op.dev_info.device_id = swdev->device_id;
ioc.op.dev_info.revision = swdev->revision;
ioc.op.dev_info.model = swdev->model;
if (swdev->use_msi) {
ioc.op.dev_info.flags |= NGBDE_DEV_F_MSI;
}
break;
case NGBDE_IOC_PHYS_ADDR:
swdev = ngbde_swdev_get(ioc.devid);
if (!swdev) {
ioc.rc = NGBDE_IOC_FAIL;
break;
}
rsrc_type = ioc.op.rsrc_id.type;
rsrc_idx = ioc.op.rsrc_id.inst;
switch (rsrc_type) {
case NGBDE_IO_RSRC_DEV_IO:
if (rsrc_idx >= NGBDE_NUM_IOWIN_MAX) {
printk(KERN_WARNING
"ngbde: invalid resource index (%d)\n",
rsrc_idx);
ioc.rc = NGBDE_IOC_FAIL;
break;
}
ioc.op.phys_addr.addr = swdev->iowin[rsrc_idx].addr;
ioc.op.phys_addr.size = swdev->iowin[rsrc_idx].size;
break;
case NGBDE_IO_RSRC_DMA_MEM:
if (rsrc_idx >= NGBDE_NUM_DMAPOOL_MAX) {
printk(KERN_WARNING
"ngbde: invalid resource index (%d)\n",
rsrc_idx);
ioc.rc = NGBDE_IOC_FAIL;
break;
}
ioc.op.phys_addr.addr = swdev->dmapool[rsrc_idx].dmamem.paddr;
ioc.op.phys_addr.size = swdev->dmapool[rsrc_idx].dmactrl.size;
break;
case NGBDE_IO_RSRC_DMA_BUS:
if (rsrc_idx >= NGBDE_NUM_DMAPOOL_MAX) {
printk(KERN_WARNING
"ngbde: invalid resource index (%d)\n",
rsrc_idx);
ioc.rc = NGBDE_IOC_FAIL;
break;
}
ioc.op.phys_addr.addr = swdev->dmapool[rsrc_idx].dmamem.baddr;
ioc.op.phys_addr.size = swdev->dmapool[rsrc_idx].dmactrl.size;
break;
default:
printk(KERN_WARNING
"ngbde: unknown resource type (%d)\n",
rsrc_type);
ioc.rc = NGBDE_IOC_FAIL;
break;
}
break;
case NGBDE_IOC_INTR_CTRL:
irq_num = ioc.op.intr_ctrl.irq_num;
intr_cmd = ioc.op.intr_ctrl.cmd;
switch (intr_cmd) {
case NGBDE_ICTL_INTR_CONN:
if (ngbde_intr_connect(ioc.devid, irq_num) < 0) {
ioc.rc = NGBDE_IOC_FAIL;
}
break;
case NGBDE_ICTL_INTR_DISC:
if (ngbde_intr_disconnect(ioc.devid, irq_num) < 0) {
ioc.rc = NGBDE_IOC_FAIL;
}
break;
case NGBDE_ICTL_INTR_WAIT:
if (ngbde_intr_wait(ioc.devid, irq_num) < 0) {
ioc.rc = NGBDE_IOC_FAIL;
}
break;
case NGBDE_ICTL_INTR_STOP:
if (ngbde_intr_stop(ioc.devid, irq_num) < 0) {
ioc.rc = NGBDE_IOC_FAIL;
}
break;
case NGBDE_ICTL_REGS_CLR:
if (ngbde_intr_regs_clr(ioc.devid, irq_num) < 0) {
ioc.rc = NGBDE_IOC_FAIL;
}
break;
default:
printk(KERN_WARNING
"%s: unknown interrupt control command (%d)\n",
MOD_NAME, intr_cmd);
ioc.rc = NGBDE_IOC_FAIL;
break;
}
break;
case NGBDE_IOC_IRQ_REG_ADD:
irq_num = ioc.op.irq_reg_add.irq_num;
ireg.status_reg = ioc.op.irq_reg_add.status_reg;
ireg.mask_reg = ioc.op.irq_reg_add.mask_reg;
ireg.kmask = ioc.op.irq_reg_add.kmask;
if (ngbde_intr_reg_add(ioc.devid, irq_num, &ireg) < 0) {
printk(KERN_WARNING
"%s: Unable to add interrupt register\n",
MOD_NAME);
ioc.rc = NGBDE_IOC_FAIL;
}
break;
case NGBDE_IOC_INTR_ACK_REG_ADD:
irq_num = ioc.op.intr_ack_reg_add.irq_num;
ackreg.ack_reg = ioc.op.intr_ack_reg_add.ack_reg;
ackreg.ack_val = ioc.op.intr_ack_reg_add.ack_val;
ackreg.flags = ioc.op.intr_ack_reg_add.flags;
if (ngbde_intr_ack_reg_add(ioc.devid, irq_num, &ackreg) < 0) {
printk(KERN_WARNING
"%s: Unable to add interrupt ack register\n",
MOD_NAME);
ioc.rc = NGBDE_IOC_FAIL;
}
break;
case NGBDE_IOC_IRQ_MASK_WR:
irq_num = ioc.op.irq_mask_wr.irq_num;
mreg = ioc.op.irq_mask_wr.offs;
mval = ioc.op.irq_mask_wr.val;
if (ngbde_intr_mask_write(ioc.devid, irq_num, 0, mreg, mval) < 0) {
printk(KERN_WARNING
"%s: Unable to write shared register\n",
MOD_NAME);
ioc.rc = NGBDE_IOC_FAIL;
}
break;
case NGBDE_IOC_PIO_WIN_MAP:
swdev = ngbde_swdev_get(ioc.devid);
if (!swdev) {
ioc.rc = NGBDE_IOC_FAIL;
break;
}
addr = ioc.op.pio_win.addr;
size = ioc.op.pio_win.size;
if (ngbde_pio_map(swdev, addr, size) == NULL) {
ioc.rc = NGBDE_IOC_FAIL;
}
break;
case NGBDE_IOC_IIO_WIN_MAP:
swdev = ngbde_swdev_get(ioc.devid);
if (!swdev) {
ioc.rc = NGBDE_IOC_FAIL;
break;
}
addr = ioc.op.pio_win.addr;
size = ioc.op.pio_win.size;
if (ngbde_iio_map(swdev, addr, size) == NULL) {
ioc.rc = NGBDE_IOC_FAIL;
}
break;
case NGBDE_IOC_PAXB_WIN_MAP:
swdev = ngbde_swdev_get(ioc.devid);
if (!swdev) {
ioc.rc = NGBDE_IOC_FAIL;
break;
}
addr = ioc.op.pio_win.addr;
size = ioc.op.pio_win.size;
if (ngbde_paxb_map(swdev, addr, size) == NULL) {
ioc.rc = NGBDE_IOC_FAIL;
}
break;
default:
printk(KERN_ERR "ngbde: invalid ioctl (%08x)\n", cmd);
ioc.rc = NGBDE_IOC_FAIL;
break;
}
if (copy_to_user((void *)arg, &ioc, sizeof(ioc))) {
return -EFAULT;
}
return 0;
}

View File

@ -0,0 +1,164 @@
/*! \file ngbde_iproc_probe.c
*
* BDE probe for IPROC internal bus devices.
*
* Validate CMICD existence on the platform. If Linux device tree matched,
* probe function of platform driver is called and the switch device read from
* CMICD register is added to the device list.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <ngbde.h>
#include <linux/platform_device.h>
#include <linux/of.h>
/*! \cond */
static int iproc_debug = 0;
module_param(iproc_debug, int, 0);
MODULE_PARM_DESC(iproc_debug,
"IPROC debug output enable (default 0).");
/*! \endcond */
/*!
* \brief Probe devices on the IPROC internal bus.
*
* \param [in] pldev Platform device.
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
static int
iproc_cmicd_probe(struct platform_device *pldev)
{
int rv;
uint32_t size;
void *base_address;
uint32_t dev_rev_id;
struct ngbde_dev_s ngbde_dev, *nd = &ngbde_dev;
struct resource *memres, *irqres;
memres = platform_get_resource(pldev, IORESOURCE_MEM, 0);
if (memres == NULL) {
printk("Unable to retrieve iProc CMIC memory resource.");
return -1;
}
size = memres->end - memres->start + 1;
if (iproc_debug) {
printk("CMIC info : Memory start=%p, end=%p\n",
(void *)memres->start, (void *)memres->end);
}
base_address = ioremap_nocache(memres->start, size);
if (!base_address) {
printk(KERN_WARNING "Error mapping iProc CMIC registers");
return -1;
}
memset(nd, 0, sizeof(*nd));
nd->pci_dev = NULL; /* No PCI bus */
nd->dma_dev = &pldev->dev;
/* Read switch device ID from CMIC */
dev_rev_id = *((uint32_t*)(base_address + 0x10224));
nd->vendor_id = 0x14e4;
nd->device_id = dev_rev_id & 0xffff;
nd->revision = (dev_rev_id >> 16) & 0xff;
irqres = platform_get_resource(pldev, IORESOURCE_IRQ, 0);
if (irqres == NULL) {
printk(KERN_WARNING "Unable to retrieve iProc CMIC IRQ resource.");
return -1;
}
nd->irq_line = irqres->start;
if (iproc_debug) {
printk("CMIC info : IRQ line=%p\n", (void *)irqres->start);
}
nd->iowin[0].addr = memres->start;
nd->iowin[0].size = size;
if (base_address) {
iounmap(base_address);
}
rv = ngbde_swdev_add(nd);
return rv;
}
/*!
* \brief Remove the platform device.
*
* \param [in] pldev Platform device.
*
* \retval 0 No errors
*/
static int
iproc_cmicd_remove(struct platform_device *pldev)
{
return 0;
}
/*! Matching compatible property with device tree. */
static const struct of_device_id iproc_cmicd_of_match[] = {
{ .compatible = "brcm,iproc-cmicd" },
{},
};
MODULE_DEVICE_TABLE(of, iproc_cmicd_of_match);
static char iproc_cmicd_string[] = "bcmiproc-cmicd";
/*! Platform driver definition. */
static struct platform_driver iproc_cmicd_driver =
{
.probe = iproc_cmicd_probe,
.remove = iproc_cmicd_remove,
.driver =
{
.name = iproc_cmicd_string,
.owner = THIS_MODULE,
.of_match_table = iproc_cmicd_of_match,
},
};
/*!
* \brief Probe for Broadcom switch devices on IPROC internal bus.
*
* \return 0 if no errors, otherwise -1.
*/
int
ngbde_iproc_probe(void)
{
platform_driver_register(&iproc_cmicd_driver);
return 0;
}
/*!
* \brief Clean up resources for Broadcom switch devices on IPROC internal bus.
*
* \return 0 if no errors, otherwise -1.
*/
int
ngbde_iproc_cleanup(void)
{
platform_driver_unregister(&iproc_cmicd_driver);
return 0;
}

View File

@ -0,0 +1,216 @@
/*! \file ngbde_kapi.c
*
* Public BDE kernel API for use with other kernel modules.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <ngbde.h>
#include <lkm/ngbde_kapi.h>
struct pci_dev *
ngbde_kapi_pci_dev_get(int kdev)
{
struct ngbde_dev_s *sd;
sd = ngbde_swdev_get(kdev);
if (!sd) {
return NULL;
}
return sd->pci_dev;
}
/*! \cond */
EXPORT_SYMBOL(ngbde_kapi_pci_dev_get);
/*! \endcond */
struct device *
ngbde_kapi_dma_dev_get(int kdev)
{
struct ngbde_dev_s *sd;
sd = ngbde_swdev_get(kdev);
if (!sd) {
return NULL;
}
return sd->dma_dev;
}
/*! \cond */
EXPORT_SYMBOL(ngbde_kapi_dma_dev_get);
/*! \endcond */
void *
ngbde_kapi_dma_bus_to_virt(int kdev, dma_addr_t baddr)
{
struct ngbde_dev_s *sd;
struct ngbde_dmamem_s *dmamem;
size_t dma_offset;
int idx;
sd = ngbde_swdev_get(kdev);
if (!sd) {
return NULL;
}
for (idx = 0; idx < NGBDE_NUM_DMAPOOL_MAX; idx++) {
dmamem = &sd->dmapool[idx].dmamem;
dma_offset = baddr - dmamem->baddr;
if (dma_offset < dmamem->size) {
return (uint8_t *)dmamem->vaddr + dma_offset;
}
}
return NULL;
}
/*! \cond */
EXPORT_SYMBOL(ngbde_kapi_dma_bus_to_virt);
/*! \endcond */
dma_addr_t
ngbde_kapi_dma_virt_to_bus(int kdev, void *vaddr)
{
struct ngbde_dev_s *sd;
struct ngbde_dmamem_s *dmamem;
size_t dma_offset;
int idx;
sd = ngbde_swdev_get(kdev);
if (!sd) {
return 0UL;
}
for (idx = 0; idx < NGBDE_NUM_DMAPOOL_MAX; idx++) {
dmamem = &sd->dmapool[idx].dmamem;
dma_offset = (uintptr_t)vaddr - (uintptr_t)dmamem->vaddr;
if (dma_offset < dmamem->size) {
return dmamem->baddr + dma_offset;
}
}
return 0UL;
}
/*! \cond */
EXPORT_SYMBOL(ngbde_kapi_dma_virt_to_bus);
/*! \endcond */
void
ngbde_kapi_pio_write32(int kdev, uint32_t offs, uint32_t val)
{
struct ngbde_dev_s *sd;
sd = ngbde_swdev_get(kdev);
if (sd) {
return ngbde_pio_write32(sd, offs, val);
}
}
/*! \cond */
EXPORT_SYMBOL(ngbde_kapi_pio_write32);
/*! \endcond */
uint32_t
ngbde_kapi_pio_read32(int kdev, uint32_t offs)
{
struct ngbde_dev_s *sd;
sd = ngbde_swdev_get(kdev);
if (sd) {
return ngbde_pio_read32(sd, offs);
}
return (uint32_t)-1;
}
/*! \cond */
EXPORT_SYMBOL(ngbde_kapi_pio_read32);
/*! \endcond */
void *
ngbde_kapi_pio_membase(int kdev)
{
struct ngbde_dev_s *sd;
sd = ngbde_swdev_get(kdev);
if (!sd) {
return NULL;
}
return sd->pio_mem;
}
/*! \cond */
EXPORT_SYMBOL(ngbde_kapi_pio_membase);
/*! \endcond */
int
ngbde_kapi_intr_connect(int kdev, unsigned int irq_num,
int (*isr_func)(void *), void *isr_data)
{
struct ngbde_dev_s *sd;
struct ngbde_intr_ctrl_s *ic;
sd = ngbde_swdev_get(kdev);
if (!sd) {
return -1;
}
if (irq_num >= NGBDE_NUM_IRQS_MAX) {
return -1;
}
ic = &sd->intr_ctrl[irq_num];
ic->isr_func = isr_func;
ic->isr_data = isr_data;
return 0;
}
/*! \cond */
EXPORT_SYMBOL(ngbde_kapi_intr_connect);
/*! \endcond */
int
ngbde_kapi_intr_disconnect(int kdev, unsigned int irq_num)
{
struct ngbde_dev_s *sd;
struct ngbde_intr_ctrl_s *ic;
sd = ngbde_swdev_get(kdev);
if (!sd) {
return -1;
}
if (irq_num >= NGBDE_NUM_IRQS_MAX) {
return -1;
}
ic = &sd->intr_ctrl[irq_num];
ic->isr_func = NULL;
ic->isr_data = NULL;
return 0;
}
/*! \cond */
EXPORT_SYMBOL(ngbde_kapi_intr_disconnect);
/*! \endcond */
int
ngbde_kapi_intr_mask_write(int kdev, unsigned int irq_num,
uint32_t status_reg, uint32_t mask_val)
{
return ngbde_intr_mask_write(kdev, irq_num, 1, status_reg, mask_val);
}
/*! \cond */
EXPORT_SYMBOL(ngbde_kapi_intr_mask_write);
/*! \endcond */

View File

@ -0,0 +1,297 @@
/*! \file ngbde_main.c
*
* NGBDE module entry.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <ngbde.h>
/*! \cond */
MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("NG BDE Module");
MODULE_LICENSE("GPL");
/*! \endcond */
/*! \cond */
static int mmap_debug = 0;
module_param(mmap_debug, int, 0);
MODULE_PARM_DESC(mmap_debug,
"MMAP debug output enable (default 0).");
/*! \endcond */
/*!
* \brief Remap user space DMA memory to non-cached area.
*
* Since we cannot flush and invalidate DMA memory from user space,
* the DMA memory pools need to be cache-coherent, even if this means
* that we need to remap the DMA memory as non-cached.
*
* If undefined, we set this value according to kernel configuration.
*/
#ifndef REMAP_DMA_NONCACHED
# ifdef CONFIG_DMA_NONCOHERENT
# define REMAP_DMA_NONCACHED 1
# else
# define REMAP_DMA_NONCACHED 0
# endif
#endif
static int
ngbde_open(struct inode *inode, struct file *filp)
{
return 0;
}
static int
ngbde_release(struct inode *inode, struct file *filp)
{
return 0;
}
/*!
* \brief Check if memory range is within existing DMA memory pools.
*
* \param [in] paddr Physical start address of memory range.
* \param [in] size Size of memory range.
*
* \retval true Range is valid.
* \retval false Range is not valid.
*/
static bool
ngbde_dma_range_valid(unsigned long paddr, unsigned long size)
{
struct ngbde_dev_s *swdev;
unsigned int num_swdev, idx;
struct ngbde_dmamem_s *dmamem;
unsigned int pool;
ngbde_swdev_get_all(&swdev, &num_swdev);
for (idx = 0; idx < num_swdev; idx++) {
for (pool = 0; pool < NGBDE_NUM_DMAPOOL_MAX; pool++) {
dmamem = &swdev[idx].dmapool[pool].dmamem;
if (paddr >= dmamem->paddr &&
(paddr + size) <= (dmamem->paddr + dmamem->size)) {
return true;
}
}
}
return false;
}
/*!
* \brief Check if memory range is within device I/O ranges.
*
* \param [in] paddr Physical start address of I/O memory range.
* \param [in] size Size of memory range.
*
* \retval true Range is valid.
* \retval false Range is not valid.
*/
static bool
ngbde_pio_range_valid(unsigned long paddr, unsigned long size)
{
struct ngbde_dev_s *swdev;
unsigned int num_swdev, idx;
struct ngbde_memwin_s *iowin;
unsigned long iowin_size;
unsigned int wdx;
ngbde_swdev_get_all(&swdev, &num_swdev);
for (idx = 0; idx < num_swdev; idx++) {
for (wdx = 0; wdx < NGBDE_NUM_IOWIN_MAX; wdx++) {
iowin = &swdev[idx].iowin[wdx];
iowin_size = iowin->size;
if (iowin_size < PAGE_SIZE) {
iowin_size = PAGE_SIZE;
}
if (mmap_debug) {
printk("MMAP: Check 0x%08lx/0x%08lx against "
"0x%08lx/0x%08lx(0x%08lx)\n",
paddr, size,
(unsigned long)iowin->addr,
(unsigned long)iowin->size, iowin_size);
}
if (paddr >= iowin->addr &&
(paddr + size) <= (iowin->addr + iowin_size)) {
return true;
}
}
}
return false;
}
/*!
* \brief Match incomplete address with device base addresses.
*
* Use for physical addresses larger than 44 bits.
*
* \param [in] paddr Physical address from user space.
*
* \return Matched device base addess or 0 if no match.
*/
static unsigned long
ngbde_pio_base_match(unsigned long paddr)
{
struct ngbde_dev_s *swdev;
unsigned int num_swdev, idx;
struct ngbde_memwin_s *iowin;
unsigned int wdx;
ngbde_swdev_get_all(&swdev, &num_swdev);
for (idx = 0; idx < num_swdev; idx++) {
for (wdx = 0; wdx < NGBDE_NUM_IOWIN_MAX; wdx++) {
iowin = &swdev[idx].iowin[wdx];
if (((paddr ^ iowin->addr) & 0xfffffffffffULL) == 0) {
if (mmap_debug) {
printk("MMAP: Matched 0x%08lx to 0x%08lx\n",
(unsigned long)paddr,
(unsigned long)iowin->addr);
}
return iowin->addr;
}
}
}
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 mapping the DMA pool to
* user space via the BDE device file.
*/
static int
ngbde_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 map_noncached = REMAP_DMA_NONCACHED;
int range_valid = 0;
if (mmap_debug) {
printk("MMAP: Mapping %lu Kbytes at 0x%08lx (0x%lx)\n",
size / 1024, paddr, vma->vm_pgoff);
}
if (ngbde_dma_range_valid(paddr, size)) {
range_valid = 1;
} else {
map_noncached = 1;
if (ngbde_pio_range_valid(paddr, size)) {
range_valid = 1;
} else {
paddr = ngbde_pio_base_match(paddr);
if (ngbde_pio_range_valid(paddr, size)) {
range_valid = 1;
}
}
}
if (!range_valid) {
printk("BDE: Invalid mmap range 0x%08lx/0x%lx\n", paddr, size);
return -EINVAL;
}
if (map_noncached) {
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)) {
printk("BDE: 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;
}
static struct file_operations fops = {
.open = ngbde_open,
.release = ngbde_release,
.unlocked_ioctl = ngbde_ioctl,
.compat_ioctl = ngbde_ioctl,
.mmap = ngbde_mmap,
};
/*!
* \brief Standard module cleanup.
*
* \return Nothing.
*/
void __exit
cleanup_module(void)
{
ngbde_intr_cleanup();
ngbde_iio_cleanup();
ngbde_paxb_cleanup();
ngbde_pio_cleanup();
ngbde_dma_cleanup();
ngbde_procfs_cleanup();
unregister_chrdev(MOD_MAJOR, MOD_NAME);
ngbde_pci_cleanup();
ngbde_iproc_cleanup();
printk(KERN_INFO "Broadcom NGBDE unloaded successfully\n");
}
/*!
* \brief Standard module initialization.
*
* \return Nothing.
*/
int __init
init_module(void)
{
int rv;
rv = register_chrdev(MOD_MAJOR, MOD_NAME, &fops);
if (rv < 0) {
printk(KERN_WARNING "%s: can't get major %d\n",
MOD_NAME, MOD_MAJOR);
return rv;
}
rv = ngbde_iproc_probe();
if (rv < 0) {
printk(KERN_WARNING "%s: Error probing for AXI bus devices.\n",
MOD_NAME);
return rv;
}
rv = ngbde_pci_probe();
if (rv < 0) {
printk(KERN_WARNING "%s: Error probing for PCI bus devices.\n",
MOD_NAME);
return rv;
}
rv = ngbde_procfs_init();
if (rv < 0) {
printk(KERN_WARNING "%s: Unable to initialize proc files\n",
MOD_NAME);
return rv;
}
printk(KERN_INFO "Broadcom NGBDE loaded successfully\n");
return 0;
}

View File

@ -0,0 +1,211 @@
/*! \file ngbde_pci_probe.c
*
* NG BDE probe for PCI devices.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <ngbde.h>
/*! \cond */
static int use_msi = 1;
module_param(use_msi, int, 0);
MODULE_PARM_DESC(use_msi,
"Use MSI interrupts if supported by the kernel (default 1).");
/*! \endcond */
/*! \cond */
static int pci_debug = 0;
module_param(pci_debug, int, 0);
MODULE_PARM_DESC(pci_debug,
"PCI debug output enable (default 0).");
/*! \endcond */
/*!
* Use BCMDRD_DEVLIST_ENTRY macro to generate a device list based on
* supported/installed devices.
*/
#define BCMDRD_DEVLIST_ENTRY(_nm,_vn,_dv,_rv,_md,_pi,_bd,_bc,_fn,_cn,_pf,_pd,_r0,_r1) \
{ _vn, _dv, PCI_ANY_ID, PCI_ANY_ID },
/*! Include all chip variants in the list of supported devices. */
#define BCMDRD_DEVLIST_INCLUDE_ALL
static struct pci_device_id pci_id_table[] = {
#include <bcmdrd/bcmdrd_devlist.h>
{ BROADCOM_VENDOR_ID, 0xb524, PCI_ANY_ID, PCI_ANY_ID },
{ BROADCOM_VENDOR_ID, 0xb684, PCI_ANY_ID, PCI_ANY_ID },
{ 0, 0, 0, 0 }
};
static int
pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *ent)
{
int rv;
int bdx;
int cmic_bar = 0;
uint8_t rev;
struct ngbde_dev_s ngbde_dev, *nd = &ngbde_dev;
int bus_no = pci_dev->bus ? pci_dev->bus->number : 0;
int slot_no = PCI_SLOT(pci_dev->devfn);
if (PCI_FUNC(pci_dev->devfn) > 0) {
return 0;
}
if (pci_debug) {
printk("PCI: pci_probe: bus %d slot %d: %04x:%04x\n",
bus_no, slot_no,
pci_dev->vendor, pci_dev->device);
}
memset(nd, 0, sizeof(*nd));
nd->pci_dev = pci_dev;
nd->dma_dev = &pci_dev->dev;
nd->vendor_id = pci_dev->vendor;
nd->device_id = pci_dev->device;
nd->bus_no = bus_no;
nd->slot_no = slot_no;
/* PCI revision must extracted "manually */
pci_read_config_byte(pci_dev, PCI_REVISION_ID, &rev);
nd->revision = rev;
if (pci_enable_device(pci_dev)) {
printk(KERN_WARNING "%s: Cannot enable PCI device: "
"vendor_id = %x, device_id = %x\n",
MOD_NAME, pci_dev->vendor, pci_dev->device);
}
pci_set_master(pci_dev);
/* IRQ number is only valid if PCI device is enabled */
nd->irq_line = pci_dev->irq;
/* Check for iProc */
if (pci_resource_len(pci_dev, 2)) {
nd->iowin[1].addr = pci_resource_start(pci_dev, 0);
nd->iowin[1].size = pci_resource_len(pci_dev, 0);
cmic_bar = 2;
}
nd->iowin[0].addr = pci_resource_start(pci_dev, cmic_bar);
nd->iowin[0].size = pci_resource_len(pci_dev, cmic_bar);
/* Verify basic I/O access by reading first word of each BAR window */
for (bdx = 0; bdx < 2; bdx++) {
if (nd->iowin[bdx].size == 0) {
continue;
}
if (ngbde_pio_map(nd, nd->iowin[bdx].addr, nd->iowin[bdx].size)) {
if (pci_debug) {
printk("PCI: BAR %d adddress 0 = 0x%x\n",
bdx, (unsigned int)ngbde_pio_read32(nd, 0));
}
ngbde_pio_unmap(nd);
} else {
printk(KERN_WARNING "%s: Cannot map PCI BAR %d: "
"start = %08lx, len = %lx\n",
MOD_NAME, bdx,
(unsigned long)nd->iowin[bdx].addr,
(unsigned long)nd->iowin[bdx].size);
}
}
spin_lock_init(&nd->lock);
/* Determine MSI configuration by enabling MSI on the device */
nd->use_msi = use_msi;
if (nd->use_msi) {
if (pci_enable_msi(nd->pci_dev) == 0) {
pci_disable_msi(nd->pci_dev);
} else {
nd->use_msi = 0;
}
}
rv = ngbde_swdev_add(nd);
if (rv == 0) {
/* Update DMA pools for all devices */
rv = ngbde_dma_init();
if (rv < 0) {
printk(KERN_WARNING "%s: Error initializing DMA memory\n",
MOD_NAME);
/* Mark device as inactive */
nd->inactive = 1;
}
}
return rv;
}
static void
pci_remove(struct pci_dev* pci_dev)
{
struct ngbde_dev_s *swdev;
unsigned int num_swdev, idx;
int bus_no = pci_dev->bus ? pci_dev->bus->number : 0;
int slot_no = PCI_SLOT(pci_dev->devfn);
if (pci_debug) {
printk("PCI: pci_remove: bus %d slot %d: %04x:%04x\n",
bus_no, slot_no,
pci_dev->vendor, pci_dev->device);
}
ngbde_swdev_get_all(&swdev, &num_swdev);
for (idx = 0; idx < num_swdev; idx++) {
if (swdev[idx].bus_no == bus_no &&
swdev[idx].slot_no == slot_no) {
if (swdev[idx].inactive) {
printk(KERN_WARNING "%s: Device already removed\n",
MOD_NAME);
}
/* Active device in this slot already? */
swdev[idx].inactive = 1;
}
}
/* Update DMA pools for all devices */
ngbde_dma_cleanup();
}
static struct pci_driver pci_driver = {
.name = MOD_NAME,
.probe = pci_probe,
.remove = pci_remove,
.id_table = pci_id_table,
/* The rest are dynamic */
};
int
ngbde_pci_probe(void)
{
if (pci_register_driver(&pci_driver) < 0) {
return -ENODEV;
}
return 0;
}
int
ngbde_pci_cleanup(void)
{
pci_unregister_driver(&pci_driver);
return 0;
}

View File

@ -0,0 +1,472 @@
/*! \file ngbde_pgmem.c
*
* \brief PGMEM allocator.
*
* This module is used to allocate large physically contiguous memory
* blocks using the Linux kernel page allocator.
*
* The Linux page allocator can allocate contiguous memory up until a
* certain size, which depends on the kernel version and the CPU
* architecture.
*
* If a larger contiguous memory block is requested, then we need to
* allocate multiple blocks from the Linux page allocator and then
* check if which ones are contiguous.
*
* The smaller memory blocks from which the larger block is assembled
* are referred to as "chunks".
*
* The PGMEM allocator will continue to allocate chunks from the Linux
* page allocator, until a contiguous memory block of the requested
* size has been assembled, or until a predefined maximum number of
* chunks have been allocated. Obviously the process is also stopped
* if the Linux page allocator returns an error.
*
* A physically contiguous memory block assembled from smaller memory
* chunks are referred to as "cmblocks".
*
* The chance of success depends on the requested memory block size as
* well as the fragmentation level of the system memory, i.e. the
* sooner after system boot these memory block are requested, the more
* likely these requests are to succeed.
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <ngbde.h>
/*******************************************************************************
* Local definitions
******************************************************************************/
/*! Maximum size the kernel can allocate in a single allocation. */
#define MEM_CHUNK_SIZE_MAX (1 << (MAX_ORDER - 1 + PAGE_SHIFT))
/*! Default block size we wil request from the kernel. */
#define MEM_CHUNK_SIZE_DEFAULT (512 * ONE_KB)
/*! \cond */
static int pgmem_chunk_size = 0;
module_param(pgmem_chunk_size, int, 0);
MODULE_PARM_DESC(pgmem_chunk_size,
"Memory chunk size in KB used by page allocator (default auto).");
/*! \endcond */
/*! \cond */
static int pgmem_debug = 0;
module_param(pgmem_debug, int, 0);
MODULE_PARM_DESC(pgmem_debug,
"Enable page memory allocator debug output (default 0).");
/*! \endcond */
/*! Helper macro for debug trace output. */
#define PGMEM_TRACE(_s) \
do { \
if (pgmem_debug) { \
printk(_s); \
} \
} while (0)
/*!
* Chunk memory block descriptor.
*/
typedef struct cmblock_desc_s {
/*! Linked-list handle. */
struct list_head list;
/*! Requested cmblock size. */
unsigned long req_size;
/*! Memory chunk size. */
unsigned long chunk_size;
/*! Memory chunk size in alternate format (2^x). */
unsigned long chunk_order;
/*! Current cmblock size. */
unsigned long cmblk_size;
/*! Logical address of cmblock. */
unsigned long cmblk_begin;
/*! Logical end address of cmblock. */
unsigned long cmblk_end;
/*! Array of logical chunk addresses. */
unsigned long *chunk_ptr;
/*! Maximum number of chunks to allocate. */
int chunk_cnt_max;
/*! Current number of chunks allocated. */
int chunk_cnt;
} cmblock_desc_t;
static LIST_HEAD(cmblocks_list);
/*!
* \name Chunk tag mask.
* \anchor CT_xxx
*
* The lower two bits of the chunk address is used to tag the chunk
* with its current state.
*/
#define CT_MASK 0x3
/*! Chunk is untagged. */
#define CT_UNTAGGED 0
/*! Chunk was discarded. */
#define CT_DISCARDED 1
/*! Chunk is part of largest cmblock. */
#define CT_LARGEST 2
/*! Chunk is part of current cmblock. */
#define CT_CURRENT 3
/*! Set block as untagged. */
#define CTAG_SET(_a, _t) \
do { \
(_a) &= ~CT_MASK; \
(_a) |= _t; \
} while (0)
/*! Set block as untagged. */
#define CTAG_GET(_a) \
((_a) & CT_MASK)
/*******************************************************************************
* Private Functions
******************************************************************************/
/*!
* \brief Find largest contiguous memory block.
*
* Find largest contiguous memory block from a pool of memory chunks.
*
* Assembly stops if a cmblock of the requested cmblock size has been
* obtained.
*
* The lower two address bits of the memory chunks are encoded as a
* tag according to \ref CT_xxx.
*
* \param [in] cmbd cmblock descriptor.
*
* \return Always 0.
*/
static int
find_largest_cmblock(cmblock_desc_t *cmbd)
{
int i, j, chunks, found;
unsigned long b, e, a;
unsigned long *cptr;
/* Convenience variable */
chunks = cmbd->chunk_cnt;
cptr = cmbd->chunk_ptr;
/* Clear all chunk tags */
for (i = 0; i < chunks; i++) {
CTAG_SET(cptr[i], CT_UNTAGGED);
}
for (i = 0; i < chunks && cmbd->cmblk_size < cmbd->req_size; i++) {
/* First chunk must be an untagged chunk */
if (CTAG_GET(cptr[i]) == CT_UNTAGGED) {
/* Initial cmblock size is the chunk size */
b = cptr[i];
e = b + cmbd->chunk_size;
CTAG_SET(cptr[i], CT_CURRENT);
/* Loop looking for adjacent chunks */
do {
found = 0;
for (j = i + 1; j < chunks && (e - b) < cmbd->req_size; j++) {
a = cptr[j];
/* Check untagged chunks only */
if (CTAG_GET(a) == CT_UNTAGGED) {
if (a == (b - cmbd->chunk_size)) {
/* Found adjacent chunk below current cmblock */
CTAG_SET(cptr[j], CT_CURRENT);
b = a;
found = 1;
} else if (a == e) {
/* Found adjacent chunk above current cmblock */
CTAG_SET(cptr[j], CT_CURRENT);
e += cmbd->chunk_size;
found = 1;
}
}
}
} while (found);
/* Now check the size of the assembled memory block */
if ((e - b) > cmbd->cmblk_size) {
/* The current block is largest so far */
cmbd->cmblk_begin = b;
cmbd->cmblk_end = e;
cmbd->cmblk_size = e - b;
/* Re-tag current and previous largest cmblock */
for (j = 0; j < chunks; j++) {
if (CTAG_GET(cptr[j]) == CT_CURRENT) {
/* Tag current cmblock as the largest */
CTAG_SET(cptr[j], CT_LARGEST);
} else if (CTAG_GET(cptr[j]) == CT_LARGEST) {
/* Discard previous largest cmblock */
CTAG_SET(cptr[j], CT_DISCARDED);
}
}
} else {
/* Discard all chunks in current cmblock */
for (j = 0; j < chunks; j++) {
if (CTAG_GET(cptr[j]) == CT_CURRENT) {
CTAG_SET(cptr[j], CT_DISCARDED);
}
}
}
}
}
return 0;
}
/*!
* \brief Allocate memory chunks and add them to the pool.
*
* Memory chunks are allocated using the kernel page allocator.
*
* \param [in] cmbd - cmblock descriptor.
* \param [in] chunks - Number of memory chunks to allocate.
*
* \return 0 if no errors, otherwise -1.
*/
static int
alloc_mem_chunks(cmblock_desc_t *cmbd, int chunks)
{
int i, start;
unsigned long addr;
if (cmbd->chunk_cnt + chunks > cmbd->chunk_cnt_max) {
printk("PGMEM: No more memory chunks\n");
return -1;
}
start = cmbd->chunk_cnt;
cmbd->chunk_cnt += chunks;
for (i = start; i < cmbd->chunk_cnt; i++) {
/* Get chunk from kernel allocator */
addr = __get_free_pages(GFP_KERNEL | GFP_DMA32, cmbd->chunk_order);
PGMEM_TRACE(".");
if (addr) {
cmbd->chunk_ptr[i] = addr;
} else {
printk("PGMEM: Page memory allocation failed\n");
return -1;
}
}
return 0;
}
/*!
* \brief Allocate large physically contiguous memory block.
*
* If we cannot allocate a sufficiently large block of contiguous
* memory from the kernel, then we simply keep allocating smaller
* chunks until we can assemble a contiguous block of the desired
* size.
*
* When maximum amount of system memory has been allocated without the
* successful assembly of a contiguous memory block, the allocation
* function will return the largest contiguous block found so far. It
* is then up to the calling function to decide whether this amount is
* sufficient to proceed.
*
* \param [in] size Requested memory block size.
* \param [in] chunk_size Assemble cmblock from chunks of this size.
*
* \return Pointer to cmblock descriptor, or NULL if error.
*/
static cmblock_desc_t *
cmblock_alloc(size_t size, size_t chunk_size)
{
cmblock_desc_t *cmbd;
int i, chunk_ptr_size;
unsigned long page_addr;
struct sysinfo si;
/* Sanity check */
if (size == 0 || chunk_size == 0) {
return NULL;
}
/* Allocate an initialize memory cmblock descriptor */
if ((cmbd = kmalloc(sizeof(cmblock_desc_t), GFP_KERNEL)) == NULL) {
return NULL;
}
memset(cmbd, 0, sizeof(*cmbd));
cmbd->req_size = size;
cmbd->chunk_size = PAGE_ALIGN(chunk_size);
while ((PAGE_SIZE << cmbd->chunk_order) < cmbd->chunk_size) {
cmbd->chunk_order++;
}
/* Determine the maximum possible number of memory chunks */
si_meminfo(&si);
cmbd->chunk_cnt_max = (si.totalram << PAGE_SHIFT) / cmbd->chunk_size;
chunk_ptr_size = cmbd->chunk_cnt_max * sizeof(unsigned long);
/* Allocate an initialize memory chunk pool */
cmbd->chunk_ptr = kmalloc(chunk_ptr_size, GFP_KERNEL);
if (cmbd->chunk_ptr == NULL) {
kfree(cmbd);
return NULL;
}
memset(cmbd->chunk_ptr, 0, chunk_ptr_size);
/* Allocate minimum number of memory chunks */
(void)alloc_mem_chunks(cmbd, cmbd->req_size / cmbd->chunk_size);
/* Allocate more chunks until we have a complete cmblock */
do {
find_largest_cmblock(cmbd);
PGMEM_TRACE("o");
if (cmbd->cmblk_size >= cmbd->req_size) {
break;
}
} while (alloc_mem_chunks(cmbd, 8) == 0);
/* Reserve all pages in the cmblock and free unused chunks */
for (i = 0; i < cmbd->chunk_cnt; i++) {
if (CTAG_GET(cmbd->chunk_ptr[i]) == CT_LARGEST) {
CTAG_SET(cmbd->chunk_ptr[i], CT_UNTAGGED);
for (page_addr = cmbd->chunk_ptr[i];
page_addr < cmbd->chunk_ptr[i] + cmbd->chunk_size;
page_addr += PAGE_SIZE) {
SetPageReserved(virt_to_page((void *)page_addr));
}
} else if (cmbd->chunk_ptr[i]) {
CTAG_SET(cmbd->chunk_ptr[i], CT_UNTAGGED);
free_pages(cmbd->chunk_ptr[i], cmbd->chunk_order);
PGMEM_TRACE("x");
cmbd->chunk_ptr[i] = 0;
}
}
PGMEM_TRACE("O\n");
return cmbd;
}
/*!
* \brief Free cmblock and associated resources.
*
* Free all memory chunks and other associated resources associated
* with a contiguous memory block.
*
* See alse \ref cmblock_alloc.
*
* \param [in] cmbd Command block descriptor to free.
*
* \return Nothing.
*/
static void
cmblock_free(cmblock_desc_t *cmbd)
{
int i;
unsigned long page_addr;
if (cmbd->chunk_ptr) {
for (i = 0; i < cmbd->chunk_cnt; i++) {
if (cmbd->chunk_ptr[i]) {
for (page_addr = cmbd->chunk_ptr[i];
page_addr < cmbd->chunk_ptr[i] + cmbd->chunk_size;
page_addr += PAGE_SIZE) {
ClearPageReserved(virt_to_page((void *)page_addr));
}
free_pages(cmbd->chunk_ptr[i], cmbd->chunk_order);
PGMEM_TRACE("X");
}
}
kfree(cmbd->chunk_ptr);
kfree(cmbd);
}
}
/*******************************************************************************
* Public Functions
******************************************************************************/
void *
ngbde_pgmem_alloc(size_t size, gfp_t flags)
{
cmblock_desc_t *cmbd;
size_t chunk_size;
chunk_size = size;
if (pgmem_chunk_size > 0) {
chunk_size = pgmem_chunk_size * ONE_KB;
}
if (chunk_size > MEM_CHUNK_SIZE_MAX) {
chunk_size = MEM_CHUNK_SIZE_DEFAULT;
}
if (pgmem_debug) {
printk("PGMEM: Allocate %d MB in %d KB chunks\n",
(int)(size / ONE_MB), (int)(chunk_size / ONE_KB));
}
if ((cmbd = cmblock_alloc(size, chunk_size)) == NULL) {
return NULL;
}
if (cmbd->cmblk_size < size) {
/* If we didn't get the full size then forget it */
cmblock_free(cmbd);
return NULL;
}
list_add(&cmbd->list, &cmblocks_list);
return (void *)cmbd->cmblk_begin;
}
int
ngbde_pgmem_free(void *ptr)
{
struct list_head *pos;
list_for_each(pos, &cmblocks_list) {
cmblock_desc_t *cmbd = list_entry(pos, cmblock_desc_t, list);
if (ptr == (void *)cmbd->cmblk_begin) {
list_del(&cmbd->list);
cmblock_free(cmbd);
return 0;
}
}
return -1;
}
void
ngbde_pgmem_free_all(void)
{
struct list_head *pos, *tmp;
list_for_each_safe(pos, tmp, &cmblocks_list) {
cmblock_desc_t *cmbd = list_entry(pos, cmblock_desc_t, list);
list_del(&cmbd->list);
cmblock_free(cmbd);
}
}

View File

@ -0,0 +1,97 @@
/*! \file ngbde_pio.c
*
* API for managing and accessing memory-mapped I/O for switch
* registers.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <ngbde.h>
void *
ngbde_pio_map(void *devh, phys_addr_t addr, phys_addr_t size)
{
struct ngbde_dev_s *sd = (struct ngbde_dev_s *)devh;
if (sd->pio_mem) {
if (addr == sd->pio_win.addr && size == sd->pio_win.size) {
/* Already mapped */
return sd->pio_mem;
}
ngbde_pio_unmap(devh);
}
sd->pio_mem = ioremap_nocache(addr, size);
if (sd->pio_mem) {
/* Save mapped resources */
sd->pio_win.addr = addr;
sd->pio_win.size = size;
} else {
printk(KERN_WARNING "%s: Unable to map address 0x%08lu\n",
MOD_NAME, (unsigned long)addr);
}
return sd->pio_mem;
}
void
ngbde_pio_unmap(void *devh)
{
struct ngbde_dev_s *sd = (struct ngbde_dev_s *)devh;
if (sd->pio_mem) {
iounmap(sd->pio_mem);
sd->pio_mem = NULL;
}
}
void
ngbde_pio_cleanup(void)
{
struct ngbde_dev_s *swdev, *sd;
unsigned int num_swdev, idx;
ngbde_swdev_get_all(&swdev, &num_swdev);
for (idx = 0; idx < num_swdev; idx++) {
sd = ngbde_swdev_get(idx);
ngbde_pio_unmap(sd);
}
}
void
ngbde_pio_write32(void *devh, uint32_t offs, uint32_t val)
{
struct ngbde_dev_s *sd = (struct ngbde_dev_s *)devh;
if (sd->pio_mem) {
NGBDE_IOWRITE32(val, sd->pio_mem + offs);
}
}
uint32_t
ngbde_pio_read32(void *devh, uint32_t offs)
{
struct ngbde_dev_s *sd = (struct ngbde_dev_s *)devh;
if (sd->pio_mem) {
return NGBDE_IOREAD32(sd->pio_mem + offs);
}
return 0;
}

View File

@ -0,0 +1,120 @@
/*! \file ngbde_procfs.c
*
* <description>
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <ngbde.h>
static int
proc_show(struct seq_file *m, void *v)
{
struct ngbde_dev_s *swdev;
unsigned int num_swdev, idx;
struct ngbde_dmamem_s *dmamem;
unsigned int pool;
unsigned int dma_pools;
char *dma_str;
ngbde_swdev_get_all(&swdev, &num_swdev);
seq_printf(m, "Broadcom Device Enumerator (%s)\n", MOD_NAME);
seq_printf(m, "Found %d switch device(s):\n", num_swdev);
for (idx = 0; idx < num_swdev; idx++) {
if (swdev->inactive) {
seq_printf(m, "%d:removed\n", idx);
continue;
}
seq_printf(m, "%d:%04x:%04x:%02x,%s(%d)\n", idx,
swdev->vendor_id, swdev->device_id, swdev->revision,
swdev->use_msi ? "MSI" : "IRQ", swdev->irq_line);
}
seq_printf(m, "DMA pools:\n");
for (idx = 0; idx < num_swdev; idx++) {
seq_printf(m, "%d", idx);
dma_pools = 0;
for (pool = 0; pool < NGBDE_NUM_DMAPOOL_MAX; pool++) {
dmamem = &swdev[idx].dmapool[pool].dmamem;
dma_str = "unknown";
if (dmamem->type == NGBDE_DMA_T_NONE) {
/* Skip empty DMA pools */
continue;
} else if (dmamem->type == NGBDE_DMA_T_KAPI) {
dma_str = "kapi";
} else if (dmamem->type == NGBDE_DMA_T_PGMEM) {
dma_str = "pgmem";
}
seq_printf(m, ":%dMB@0x%08lx(%s)",
(int)(dmamem->size / ONE_MB),
(unsigned long)dmamem->baddr, dma_str);
dma_pools++;
}
if (dma_pools == 0) {
seq_printf(m, ":none");
}
seq_printf(m, "\n");
}
return 0;
}
static int
proc_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_show, NULL);
}
static int
proc_release(struct inode *inode, struct file *file)
{
return single_release(inode, file);
}
static struct file_operations proc_fops = {
owner: THIS_MODULE,
open: proc_open,
read: seq_read,
llseek: seq_lseek,
release: proc_release,
};
int
ngbde_procfs_init(void)
{
struct proc_dir_entry *entry;
PROC_CREATE(entry, MOD_NAME, 0666, NULL, &proc_fops);
if (entry == NULL) {
printk(KERN_ERR "ngbde: proc_create failed\n");
return -1;
}
return 0;
}
int
ngbde_procfs_cleanup(void)
{
remove_proc_entry(MOD_NAME, NULL);
return 0;
}

View File

@ -0,0 +1,79 @@
/*! \file ngbde_swdev.c
*
* <description>
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <ngbde.h>
/* Switch devices */
static struct ngbde_dev_s swdevs[NGBDE_NUM_SWDEV_MAX];
/* Number of probed switch devices */
static unsigned int num_swdev;
int
ngbde_swdev_add(struct ngbde_dev_s *nd)
{
unsigned int idx;
/* Look for existing slot */
for (idx = 0; idx < num_swdev; idx++) {
if (swdevs[idx].bus_no == nd->bus_no &&
swdevs[idx].slot_no == nd->slot_no) {
if (swdevs[idx].inactive) {
memcpy(&swdevs[idx], nd, sizeof(swdevs[0]));
return 0;
}
/* Active device in this slot already? */
printk(KERN_WARNING "%s: Device exists\n",
MOD_NAME);
return -EBUSY;
}
}
/* Add new device */
if (num_swdev >= NGBDE_NUM_SWDEV_MAX) {
return -ENOMEM;
}
memcpy(&swdevs[num_swdev], nd, sizeof(swdevs[0]));
++num_swdev;
return 0;
}
struct ngbde_dev_s *
ngbde_swdev_get(int kdev)
{
if ((unsigned int)kdev < num_swdev) {
return &swdevs[kdev];
}
return NULL;
}
int
ngbde_swdev_get_all(struct ngbde_dev_s **nd, unsigned int *num_nd)
{
if (nd) {
*nd = swdevs;
}
if (num_nd) {
*num_nd = num_swdev;
}
return 0;
}

View File

@ -0,0 +1,126 @@
/*! \file lkm.h
*
* <description>
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef LKM_H
#define LKM_H
#include <linux/init.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
#error Kernel too old
#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>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/fcntl.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/hardirq.h>
#ifdef CONFIG_DEVFS_FS
#include <linux/devfs_fs_kernel.h>
#endif
/* Compatibility Macros */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
#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
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)
#define timer_arg(var, context, timer_fieldname) \
(typeof(var))(context)
#define timer_context_t unsigned long
#else
#define timer_context_t struct timer_list *
#define timer_arg(var, context, timer_fieldname) \
from_timer(var, context, timer_fieldname)
#endif
#ifndef setup_timer
#define setup_timer(timer, fn, data) \
timer_setup(timer, fn, 0)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0)
static inline void page_ref_inc(struct page *page)
{
atomic_inc(&page->_count);
}
static inline void page_ref_dec(struct page *page)
{
atomic_dec(&page->_count);
}
#endif
#endif /* LKM_H */

View File

@ -0,0 +1,345 @@
/*! \file ngbde_ioctl.h
*
* NGBDE device I/O control definitions.
*
* This file is intended for use in both kernel mode and user mode.
*
* IMPORTANT!
* All shared structures must be properly 64-bit aligned.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef NGBDE_IOCTL_H
#define NGBDE_IOCTL_H
#include <linux/types.h>
#include <linux/ioctl.h>
/*! Must be updated if backward compatibility is broken. */
#define NGBDE_IOC_VERSION 2
/*! LUBDE IOCTL command magic. */
#define NGBDE_IOC_MAGIC 'L'
/*!
* \name IOCTL commands for the NGBDE kernel module.
* \anchor NGBDE_IOC_xxx
*
* Note that we use __u64 for the IOCTL parameter size because
* sizeof(void *) is different between 32-bit and 64-bit code, and we
* need a 32-bit user mode application to generate the same IOCTL
* command codes as a 64-bit kernel when using the _IOW macro.
*/
/*! \{ */
/*! Get kernel module information. */
#define NGBDE_IOC_MOD_INFO _IOW(NGBDE_IOC_MAGIC, 0, __u64)
/*! Get information about registered devices. */
#define NGBDE_IOC_PROBE_INFO _IOW(NGBDE_IOC_MAGIC, 1, __u64)
/*! Get detailed switch device information. */
#define NGBDE_IOC_DEV_INFO _IOW(NGBDE_IOC_MAGIC, 2, __u64)
/*! Get a physical memory address associated with a switch device. */
#define NGBDE_IOC_PHYS_ADDR _IOW(NGBDE_IOC_MAGIC, 3, __u64)
/*! Interrupt control command (see \ref NGBDE_ICTL_xxx). */
#define NGBDE_IOC_INTR_CTRL _IOW(NGBDE_IOC_MAGIC, 4, __u64)
/*! Add interrupt status/mask register for kernel to control. */
#define NGBDE_IOC_IRQ_REG_ADD _IOW(NGBDE_IOC_MAGIC, 5, __u64)
/*! Write to a shared interrupt mask register. */
#define NGBDE_IOC_IRQ_MASK_WR _IOW(NGBDE_IOC_MAGIC, 6, __u64)
/*! Map device registers in kernel space. */
#define NGBDE_IOC_PIO_WIN_MAP _IOW(NGBDE_IOC_MAGIC, 7, __u64)
/*! Map interrupt controller registers in kernel space. */
#define NGBDE_IOC_IIO_WIN_MAP _IOW(NGBDE_IOC_MAGIC, 8, __u64)
/*! Map PCI bridge registers in kernel space. */
#define NGBDE_IOC_PAXB_WIN_MAP _IOW(NGBDE_IOC_MAGIC, 9, __u64)
/*! Add interrupt ACK register for kernel to control. */
#define NGBDE_IOC_INTR_ACK_REG_ADD _IOW(NGBDE_IOC_MAGIC, 10, __u64)
/*! \} */
/*! IOCTL command return code for success. */
#define NGBDE_IOC_SUCCESS 0
/*! IOCTL command return code for failure. */
#define NGBDE_IOC_FAIL ((__u32)-1)
/*!
* \name Device flags.
* \anchor NGBDE_DEV_F_xxx
*/
/*! \{ */
/*! Message-signaled interrupts, PCI interrupts are operating in MSI mode. */
#define NGBDE_DEV_F_MSI (1 << 0)
/*! \} */
/*!
* \name Interrupt control commands.
* \anchor NGBDE_ICTL_xxx
*/
/*! \{ */
/*! Connect interrupt handler. */
#define NGBDE_ICTL_INTR_CONN 0
/*! Disconnect interrupt handler. */
#define NGBDE_ICTL_INTR_DISC 1
/*! Wait for interrupt. */
#define NGBDE_ICTL_INTR_WAIT 2
/*! Force waiting thread to return. */
#define NGBDE_ICTL_INTR_STOP 3
/*! Clear list of interrupt status/mask registers. */
#define NGBDE_ICTL_REGS_CLR 4
/*! \} */
/*! Kernel module information. */
struct ngbde_ioc_mod_info_s {
/*! IOCTL version used by kernel module. */
__u16 version;
};
/*! Probing results. */
struct ngbde_ioc_probe_info_s {
/*! Number of switch devices. */
__u16 num_swdev;
};
/*! Device information. */
struct ngbde_ioc_dev_info_s {
/*! Device type. */
__u16 type;
/*! Device flags (\ref NGBDE_DEV_F_xxx). */
__u16 flags;
/*! Vendor ID (typically the PCI vendor ID). */
__u16 vendor_id;
/*! Device ID (typically the PCI vendor ID). */
__u16 device_id;
/*! Device revision (typically the PCI device revision). */
__u16 revision;
/*! Device model (device-identification beyond PCI generic ID). */
__u16 model;
};
/*!
* \name I/O resource types.
* \anchor NGBDE_IO_RSRC_xxx
*/
/*! \{ */
/*! Memory-mapped I/O. */
#define NGBDE_IO_RSRC_DEV_IO 0
/*! DMA memory pool. */
#define NGBDE_IO_RSRC_DMA_MEM 1
/*! DMA memory pool as mapped by IOMMU. */
#define NGBDE_IO_RSRC_DMA_BUS 2
/*! \} */
/*!
* \brief Resource ID (IOCTL input).
*
* This structure is used to query a physical address resource in the
* kernel module. The caller must provide a resource type (device I/O,
* DMA memory, etc.) and a resource instance number (e.g. a PCI BAR
* address will have multiple instances).
*
* Also see \ref ngbde_ioc_phys_addr_s.
*/
struct ngbde_ioc_rsrc_id_s {
/*! Resource type (\ref NGBDE_IO_RSRC_xxx). */
__u32 type;
/*! Resource instance number. */
__u32 inst;
};
/*!
* \brief Physical device address.
*
* This structure is returned in response to the \ref
* NGBDE_IOC_PHYS_ADDR command. The caller must identify the requested
* physical address using the \ref ngbde_ioc_rsrc_id_s structure.
*/
struct ngbde_ioc_phys_addr_s {
/*! Physical address. */
__u64 addr;
/*! Resource size (in bytes). */
__u32 size;
};
/*! Interrupt control operation */
struct ngbde_ioc_intr_ctrl_s {
/*! Interrupt instance for this device. */
__u32 irq_num;
/*! Interrupt control command. */
__u32 cmd;
};
/*! Add interrupt register information. */
struct ngbde_ioc_irq_reg_add_s {
/*! Interrupt instance for this device. */
__u32 irq_num;
/*! Interrupt status register address offset. */
__u32 status_reg;
/*! Interrupt mask register address offset. */
__u32 mask_reg;
/*! Interrupt mask for interrupts handled by the kernel. */
__u32 kmask;
/*! Reserved for future use. */
__u32 flags;
};
/*!
* \name Interrupt ACK register access flags.
* \anchor NGBDE_DEV_INTR_ACK_F_xxx
*/
/*! \{ */
/*! ACK registers resides in PCI bridge I/O window. */
#define NGBDE_DEV_INTR_ACK_F_PAXB (1 << 0)
/*! \} */
/*! Add interrupt ACK register information. */
struct ngbde_ioc_intr_ack_reg_add_s {
/*! Interrupt instance for this device. */
__u32 irq_num;
/*! Interrupt ACK register address offset. */
__u32 ack_reg;
/*! Interrupt ACK value. */
__u32 ack_val;
/*! Flags to indicate ack_reg resides in PCI bridge window. */
__u32 flags;
};
/*! Memory-mapped I/O window */
struct ngbde_ioc_pio_win_s {
/*! Physical address */
__u64 addr;
/*! Resource size */
__u32 size;
};
/*! Interrupt mask register write */
struct ngbde_ioc_irq_mask_wr_s {
/*! Interrupt instance for this device. */
__u32 irq_num;
/*! Register offset. */
__u32 offs;
/*! Value to write. */
__u32 val;
};
/*! IOCTL operation data. */
union ngbde_ioc_op_s {
/*! Get kernel module information. */
struct ngbde_ioc_mod_info_s mod_info;
/*! Get information about registered devices. */
struct ngbde_ioc_probe_info_s probe_info;
/*! Get detailed switch device information. */
struct ngbde_ioc_dev_info_s dev_info;
/*! Resource ID (input). */
struct ngbde_ioc_rsrc_id_s rsrc_id;
/*! Get a physical memory address associated with a switch device. */
struct ngbde_ioc_phys_addr_s phys_addr;
/*! Interrupt control command (see \ref NGBDE_ICTL_xxx). */
struct ngbde_ioc_intr_ctrl_s intr_ctrl;
/*! Add interrupt status/mask register for kernel to control. */
struct ngbde_ioc_irq_reg_add_s irq_reg_add;
/*! Add interrupt ACK register for kernel to control. */
struct ngbde_ioc_intr_ack_reg_add_s intr_ack_reg_add;
/*! Write to a shared interrupt mask register. */
struct ngbde_ioc_irq_mask_wr_s irq_mask_wr;
/*! Map device registers in kernel space. */
struct ngbde_ioc_pio_win_s pio_win;
};
/*! IOCTL command message. */
typedef struct ngbde_ioc_cmd_s {
/*! Device handle. */
__u32 devid;
/*! Return code (0 means success). */
__u32 rc;
/*! IOCTL operation. */
union ngbde_ioc_op_s op;
} ngbde_ioc_cmd_t;
#endif /* NGBDE_IOCTL_H */

View File

@ -0,0 +1,169 @@
/*! \file ngbde_kapi.h
*
* NGBDE kernel API.
*
* This file is intended for use by other kernel modules relying on the BDE.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef NGBDE_KAPI_H
#define NGBDE_KAPI_H
#include <linux/types.h>
/*! Maximum number of switch devices supported. */
#ifndef NGBDE_NUM_SWDEV_MAX
#define NGBDE_NUM_SWDEV_MAX 16
#endif
/*!
* \brief Get Linux PCI device handle for a switch device.
*
* \param [in] kdev Device number.
*
* \return Linux PCI device handle or NULL if unavailable.
*/
extern struct pci_dev *
ngbde_kapi_pci_dev_get(int kdev);
/*!
* \brief Get Linux kernel device handle for a switch device.
*
* \param [in] kdev Device number.
*
* \return Linux kernel device handle or NULL if unavailable.
*/
extern struct device *
ngbde_kapi_dma_dev_get(int kdev);
/*!
* \brief Convert DMA bus address to virtual address.
*
* This API will convert a physical DMA bus address to a kernel
* virtual address for a memory location that belongs to one of the
* DMA memory pools allocated by the BDE module.
*
* \param [in] kdev Device number.
* \param [in] baddr Physical DMA bus address for this device.
*
* \return Virtual kernel address or NULL on error.
*/
void *
ngbde_kapi_dma_bus_to_virt(int kdev, dma_addr_t baddr);
/*!
* \brief Convert virtual address to DMA bus address.
*
* This API will convert a kernel virtual address to a physical DMA
* bus address for a memory location that belongs to one of the DMA
* memory pools allocated by the BDE module.
*
* \param [in] kdev Device number.
* \param [in] vaddr Virtual kernel address.
*
* \return Physical DMA bus address for this device or 0 on error.
*/
dma_addr_t
ngbde_kapi_dma_virt_to_bus(int kdev, void *vaddr);
/*!
* \brief Write a memory-mapped register from kernel driver.
*
* \param [in] kdev Device number.
* \param [in] offs Register address offset.
* \param [in] val Value to write to register.
*
* \return Nothing.
*/
extern void
ngbde_kapi_pio_write32(int kdev, uint32_t offs, uint32_t val);
/*!
* \brief Read a memory-mapped register from kernel driver.
*
* \param [in] kdev Device number.
* \param [in] offs Register address offset.
*
* \return Value read from register.
*/
extern uint32_t
ngbde_kapi_pio_read32(int kdev, uint32_t offs);
/*!
* \brief Get base address fo memory-mapped I/O memory.
*
* The lgical base address returned can be used with ioread32, etc.
*
* \param [in] kdev Device number.
*
* \return Logical base address or NULL if unavailable.
*/
extern void *
ngbde_kapi_pio_membase(int kdev);
/*!
* \brief Install kernel mode interrupt handler.
*
* \param [in] kdev Device number.
* \param [in] irq_num MSI interrupt number.
* \param [in] isr_func Interrupt handler function.
* \param [in] isr_data Interrupt handler context.
*
* \retval 0 No errors
*/
extern int
ngbde_kapi_intr_connect(int kdev, unsigned int irq_num,
int (*isr_func)(void *), void *isr_data);
/*!
* \brief Uninstall kernel mode interrupt handler.
*
* \param [in] kdev Device number.
* \param [in] irq_num MSI interrupt number.
*
* \retval 0 No errors
*/
extern int
ngbde_kapi_intr_disconnect(int kdev, unsigned int irq_num);
/*!
* \brief Write shared interrupt mask register.
*
* This function is used by an interrupt handler when a shared
* interrupt mask register needs to be updated.
*
* Note that the mask register to access is referenced by the
* corrsponding status register. This is because the mask register may
* be different depending on the host CPU interface being used
* (e.g. PCI vs. AXI). On the other hand, the status register is the
* same irrespective of the host CPU interface.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
* \param [in] status_reg Corresponding interrupt status register offset.
* \param [in] mask_val New value to write to mask register.
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_kapi_intr_mask_write(int kdev, unsigned int irq_num,
uint32_t status_reg, uint32_t mask_val);
#endif /* NGBDE_KAPI_H */

View File

@ -0,0 +1,408 @@
/*! \file ngknet_dev.h
*
* NGKNET device definitions.
*
* This file is intended for use in both kernel mode and user mode.
*
* IMPORTANT!
* All shared structures must be properly 64-bit aligned.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef NGKNET_DEV_H
#define NGKNET_DEV_H
#include <bcmcnet/bcmcnet_types.h>
/*! Device name length */
#define NGKNET_DEV_NAME_MAX 16
/*! Maximum number of virtual network devices */
#ifndef NGKNET_NETIF_MAX
#define NUM_VDEV_MAX 128
#else
#define NUM_VDEV_MAX NGKNET_NETIF_MAX
#endif
/*! Maximum number of filters */
#ifndef NGKNET_FILTER_MAX
#define NUM_FILTER_MAX 128
#else
#define NUM_FILTER_MAX NGKNET_FILTER_MAX
#endif
/*!
* \brief System network interface
*
* Network interface types:
*
* NGKNET_NETIF_T_VLAN
* Transmits to this interface will go to ingress PIPE of switch
* CPU port using specified VLAN ID. Packet will be switched.
*
* NGKNET_NETIF_T_PORT
* Transmits to this interface will go to unmodified to specified
* physical switch port. All switching logic is bypassed. Meta data
* should be provided when this interface is created.
*
* NGKNET_NETIF_T_META
* Transmits to this interface will be done using raw meta data
* as DMA descriptors.
*
* Network interface flags:
*
* NGKNET_NETIF_F_RCPU_ENCAP
* Use RCPU encapsulation for packets that enter and exit this
* interface.
*
* NGKNET_NETIF_F_ADD_TAG
* Add VLAN tag to packets sent directly to physical port.
*
* NGKNET_NETIF_F_BIND_CHAN
* Bind this interface to a Rx channel.
*/
/*! Max network interface name length */
#define NGKNET_NETIF_NAME_MAX 16
/*! Max network interface meta bytes */
#define NGKNET_NETIF_META_MAX 16
/*! Max netif user data in bytes */
#define NGKNET_NETIF_USER_DATA 64
/*! Send packets to switch */
#define NGKNET_NETIF_T_VLAN 0
/*! Send packets to port */
#define NGKNET_NETIF_T_PORT 1
/*! Send packets with matadata attached */
#define NGKNET_NETIF_T_META 2
/*! Send packets with RCPU encapsulation */
#define NGKNET_NETIF_F_RCPU_ENCAP (1U << 0)
/*! Send packets with vlan tag */
#define NGKNET_NETIF_F_ADD_TAG (1U << 1)
/*! Bind network interface to Rx channel */
#define NGKNET_NETIF_F_BIND_CHAN (1U << 2)
/*!
* \brief Network interface description.
*/
typedef struct ngknet_netif_s {
/*! This network interface ID */
uint16_t id;
/*! Next network interface ID */
uint16_t next;
/*! Network interface type */
uint16_t type;
/*! Network interface flags */
uint16_t flags;
/*! Network interface VLAN ID */
uint16_t vlan;
/*! Network interface MAC address */
uint8_t macaddr[6];
/*! Network interface MTU */
uint32_t mtu;
/*! Network interface bound to channel */
uint32_t chan;
/*! Network interface name */
char name[NGKNET_NETIF_NAME_MAX];
/*! Metadata offset from Ethernet header */
uint16_t meta_off;
/*! Metadata length */
uint16_t meta_len;
/*! Metadata used to send packets to physical port */
uint8_t meta_data[NGKNET_NETIF_META_MAX];
/*! User data gotten back through callbacks */
uint8_t user_data[NGKNET_NETIF_USER_DATA];
} ngknet_netif_t;
/*!
* \brief 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:
*
* NGKNET_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:
*
* NGKNET_FILTER_DEST_T_NULL
* Packet is dropped.
*
* NGKNET_FILTER_DEST_T_NETIF
* Packet is sent to network interface with ID <dest_id>.
*
* NGKNET_FILTER_DEST_T_VNET
* Packet is sent to VNET in user space.
*
* Filter flags:
*
* NGKNET_FILTER_F_ANY_DATA
* When this flags is set the filter will match any packet on
* the associated unit.
*
* NGKNET_FILTER_F_STRIP_TAG
* Strip VLAN tag before packet is sent to destination.
*/
/*! Roundup to word */
#define NGKNET_BYTES2WORDS(bytes) ((bytes + 3) / 4)
/*! Max filter description length */
#define NGKNET_FILTER_DESC_MAX 32
/*! Max filter bytes size */
#define NGKNET_FILTER_BYTES_MAX 256
/*! Max filter words size */
#define NGKNET_FILTER_WORDS_MAX NGKNET_BYTES2WORDS(NGKNET_FILTER_BYTES_MAX)
/*! Max filter user data in bytes */
#define NGKNET_FILTER_USER_DATA 64
/*! Filter to Rx */
#define NGKNET_FILTER_T_RX_PKT 1
/*! Drop packet */
#define NGKNET_FILTER_DEST_T_NULL 0
/*! Send packet to netif */
#define NGKNET_FILTER_DEST_T_NETIF 1
/*! Send packet to VNET */
#define NGKNET_FILTER_DEST_T_VNET 2
/*! Send packet to kernel callback function (BCMPKT_DEST_T_CALLBACK) */
#define NGKNET_FILTER_DEST_T_CB 3
/*! Match any data */
#define NGKNET_FILTER_F_ANY_DATA (1U << 0)
/*! Strip vlan tag */
#define NGKNET_FILTER_F_STRIP_TAG (1U << 1)
/*! Match Rx channel */
#define NGKNET_FILTER_F_MATCH_CHAN (1U << 2)
/*! Filter created with raw metadata */
#define NGKNET_FILTER_F_RAW_PMD (1U << 15)
/*!
* \brief Filter description.
*/
typedef struct ngknet_filter_s {
/*! This filter ID */
uint16_t id;
/*! Next filter ID */
uint16_t next;
/*! Filter type. Refer to \ref NGKNET_FILTER_T_XXX. */
uint16_t type;
/*! Filter flags. Refer to \ref NGKNET_FILTER_F_XXX. */
uint16_t flags;
/*! Filter priority */
uint32_t priority;
/*! Filter belong to */
uint32_t chan;
/*! Filter description */
char desc[NGKNET_FILTER_DESC_MAX];
/*! Destination type. Refer to \ref NGKNET_FILTER_DEST_T_XXX. */
uint16_t dest_type;
/*! Destination network interface ID */
uint16_t dest_id;
/*! Destination network interface protocol type */
uint16_t dest_proto;
/*! Mirror type */
uint16_t mirror_type;
/*! Mirror network interface ID */
uint16_t mirror_id;
/*! Mirror network interface protocol type */
uint16_t mirror_proto;
/*! Out band data offset */
uint16_t oob_data_offset;
/*! Out band data size */
uint16_t oob_data_size;
/*! Packet data offset */
uint16_t pkt_data_offset;
/*! Packet data size */
uint16_t pkt_data_size;
/*! Filtering data */
union {
uint8_t b[NGKNET_FILTER_BYTES_MAX];
uint32_t w[NGKNET_FILTER_WORDS_MAX];
} data;
/*! Filtering mask */
union {
uint8_t b[NGKNET_FILTER_BYTES_MAX];
uint32_t w[NGKNET_FILTER_WORDS_MAX];
} mask;
/*! User data gotten back through callbacks */
uint8_t user_data[NGKNET_FILTER_USER_DATA];
} ngknet_filter_t;
/*!
* \brief Device configure structure.
*/
typedef struct ngknet_dev_cfg_s {
/*! Device name */
char name[NGKNET_DEV_NAME_MAX];
/*! Device type string */
char type_str[NGKNET_DEV_NAME_MAX];
/*! Device ID */
uint32_t dev_id;
/*! Device mode */
dev_mode_t mode;
/*! Number of groups */
uint32_t nb_grp;
/*! Bitmap of groups */
uint32_t bm_grp;
/*! Rx packet header size */
uint32_t rx_ph_size;
/*! Tx packet header size */
uint32_t tx_ph_size;
/*! Base network interface */
ngknet_netif_t base_netif;
} ngknet_dev_cfg_t;
/*!
* \brief Channel configure structure.
*/
typedef struct ngknet_chan_cfg_s {
/*! Channel number */
int chan;
/*! Number of descriptors */
uint32_t nb_desc;
/*! Rx buffer size */
uint32_t rx_buf_size;
/*! Channel control */
uint32_t chan_ctrl;
/*! Packet_byte_swap */
#define NGKNET_PKT_BYTE_SWAP (1 << 0)
/*! Non packet_byte_swap */
#define NGKNET_OTH_BYTE_SWAP (1 << 1)
/*! Header_byte_swap */
#define NGKNET_HDR_BYTE_SWAP (1 << 2)
/*! Rx or Tx */
int dir;
/*! Rx channel */
#define NGKNET_RX_CHAN 0
/*! Tx channel */
#define NGKNET_TX_CHAN 1
} ngknet_chan_cfg_t;
/*!
* \brief RCPU header structure.
*/
struct ngknet_rcpu_hdr {
/*! Destination MAC address */
uint8_t dst_mac[6];
/*! Source MAC address */
uint8_t src_mac[6];
/*! VLAN TPID */
uint16_t vlan_tpid;
/*! VLAN TCI */
uint16_t vlan_tci;
/*! Ethernet type */
uint16_t eth_type;
/*! Packet signature */
uint16_t pkt_sig;
/*! Operation code */
uint8_t op_code;
/*! Flags */
uint8_t flags;
/*! Transaction number */
uint16_t trans_id;
/*! Packet data length */
uint16_t data_len;
/*! Reserved must be 0 */
uint16_t rsvd0;
/*! packet meta data length */
uint8_t meta_len;
/*! Transmission queue number */
uint8_t queue_id;
/*! Reserved must be 0 */
uint16_t rsvd1;
};
/*! RCPU Rx operation */
#define RCPU_OPCODE_RX 0x10
/*! RCPU Tx operation */
#define RCPU_OPCODE_TX 0x20
/*! RCPU purge flag */
#define RCPU_FLAG_PURGE (1 << 0)
/*! RCPU pause flag */
#define RCPU_FLAG_PAUSE (1 << 1)
/*! RCPU modhdr flag */
#define RCPU_FLAG_MODHDR (1 << 2)
/*! RCPU bind queue flag */
#define RCPU_FLAG_BIND_QUE (1 << 3)
#endif /* NGKNET_DEV_H */

View File

@ -0,0 +1,112 @@
/*! \file ngknet_ioctl.h
*
* NGKNET I/O control definitions.
*
* This file is intended for use in both kernel mode and user mode.
*
* IMPORTANT!
* All shared structures must be properly 64-bit aligned.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef NGKNET_IOCTL_H
#define NGKNET_IOCTL_H
/*! Module information */
#define NGKNET_MODULE_NAME "linux_ngknet"
#define NGKNET_MODULE_MAJOR 121
/*! Must be updated if backward compatibility is broken */
#define NGKNET_IOC_VERSION 2
/*! Max number of input arguments */
#define NGKNET_IOC_IARG_MAX 2
#define NGKNET_IOC_MAGIC 'K'
#define NGKNET_VERSION_GET _IOR(NGKNET_IOC_MAGIC, 0xa0, unsigned int)
#define NGKNET_RX_RATE_LIMIT _IOWR(NGKNET_IOC_MAGIC, 0xa1, unsigned int)
#define NGKNET_DEV_INIT _IOWR(NGKNET_IOC_MAGIC, 0xb0, unsigned int)
#define NGKNET_DEV_DEINIT _IOWR(NGKNET_IOC_MAGIC, 0xb1, unsigned int)
#define NGKNET_DEV_SUSPEND _IOWR(NGKNET_IOC_MAGIC, 0xb2, unsigned int)
#define NGKNET_DEV_RESUME _IOWR(NGKNET_IOC_MAGIC, 0xb3, unsigned int)
#define NGKNET_DEV_VNET_WAIT _IOWR(NGKNET_IOC_MAGIC, 0xb4, unsigned int)
#define NGKNET_DEV_HNET_WAKE _IOWR(NGKNET_IOC_MAGIC, 0xb5, unsigned int)
#define NGKNET_DEV_VNET_DOCK _IOWR(NGKNET_IOC_MAGIC, 0xb6, unsigned int)
#define NGKNET_DEV_VNET_UNDOCK _IOWR(NGKNET_IOC_MAGIC, 0xb7, unsigned int)
#define NGKNET_QUEUE_CONFIG _IOWR(NGKNET_IOC_MAGIC, 0xc0, unsigned int)
#define NGKNET_QUEUE_QUERY _IOR(NGKNET_IOC_MAGIC, 0xc1, unsigned int)
#define NGKNET_RCPU_CONFIG _IOWR(NGKNET_IOC_MAGIC, 0xc2, unsigned int)
#define NGKNET_RCPU_GET _IOR(NGKNET_IOC_MAGIC, 0xc3, unsigned int)
#define NGKNET_NETIF_CREATE _IOWR(NGKNET_IOC_MAGIC, 0xd0, unsigned int)
#define NGKNET_NETIF_DESTROY _IOWR(NGKNET_IOC_MAGIC, 0xd1, unsigned int)
#define NGKNET_NETIF_GET _IOR(NGKNET_IOC_MAGIC, 0xd2, unsigned int)
#define NGKNET_NETIF_NEXT _IOR(NGKNET_IOC_MAGIC, 0xd3, unsigned int)
#define NGKNET_NETIF_LINK_SET _IOW(NGKNET_IOC_MAGIC, 0xd4, unsigned int)
#define NGKNET_FILT_CREATE _IOWR(NGKNET_IOC_MAGIC, 0xe0, unsigned int)
#define NGKNET_FILT_DESTROY _IOWR(NGKNET_IOC_MAGIC, 0xe1, unsigned int)
#define NGKNET_FILT_GET _IOR(NGKNET_IOC_MAGIC, 0xe2, unsigned int)
#define NGKNET_FILT_NEXT _IOR(NGKNET_IOC_MAGIC, 0xe3, unsigned int)
#define NGKNET_INFO_GET _IOR(NGKNET_IOC_MAGIC, 0xf0, unsigned int)
#define NGKNET_STATS_GET _IOR(NGKNET_IOC_MAGIC, 0xf1, unsigned int)
#define NGKNET_STATS_RESET _IOWR(NGKNET_IOC_MAGIC, 0xf2, unsigned int)
#define NGKNET_PTP_DEV_CTRL _IOWR(NGKNET_IOC_MAGIC, 0x90, unsigned int)
/*! Kernel module information. */
struct ngknet_ioc_mod_info {
/*! IOCTL version used by kernel module */
uint32_t version;
};
/*! Data transmission */
struct ngknet_ioc_data_xmit {
/*! Data buffer address */
uint64_t buf;
/*! Data buffer length */
uint32_t len;
};
/*! IOCTL operations */
union ngknet_ioc_op {
/*! Get module info */
struct ngknet_ioc_mod_info info;
/*! Transmit data */
struct ngknet_ioc_data_xmit data;
};
/*!
* \brief NGKNET IOCTL command message.
*/
struct ngknet_ioctl {
/*! Device number */
uint32_t unit;
/*! Return code (0 means success) */
uint32_t rc;
/*! Input arguments */
int iarg[NGKNET_IOC_IARG_MAX];
/*! IOCTL operation */
union ngknet_ioc_op op;
};
#endif /* NGKNET_IOCTL_H */

View File

@ -0,0 +1,24 @@
#ifndef __NET_PSAMPLE_H
#define __NET_PSAMPLE_H
#include <lkm/lkm.h>
#include <uapi/linux/psample.h>
#include <linux/module.h>
#include <linux/list.h>
struct psample_group {
struct list_head list;
struct net *net;
u32 group_num;
u32 refcount;
u32 seq;
};
extern struct psample_group *psample_group_get(struct net *net, u32 group_num);
extern void psample_group_put(struct psample_group *group);
extern void psample_sample_packet(struct psample_group *group, struct sk_buff *skb,
u32 trunc_size, int in_ifindex, int out_ifindex,
u32 sample_rate);
#endif /* __NET_PSAMPLE_H */

View File

@ -0,0 +1,35 @@
#ifndef __UAPI_PSAMPLE_H
#define __UAPI_PSAMPLE_H
enum {
/* sampled packet metadata */
PSAMPLE_ATTR_IIFINDEX,
PSAMPLE_ATTR_OIFINDEX,
PSAMPLE_ATTR_ORIGSIZE,
PSAMPLE_ATTR_SAMPLE_GROUP,
PSAMPLE_ATTR_GROUP_SEQ,
PSAMPLE_ATTR_SAMPLE_RATE,
PSAMPLE_ATTR_DATA,
/* commands attributes */
PSAMPLE_ATTR_GROUP_REFCOUNT,
__PSAMPLE_ATTR_MAX
};
enum psample_command {
PSAMPLE_CMD_SAMPLE,
PSAMPLE_CMD_GET_GROUP,
PSAMPLE_CMD_NEW_GROUP,
PSAMPLE_CMD_DEL_GROUP,
};
/* Can be overridden at runtime by module option */
#define PSAMPLE_ATTR_MAX (__PSAMPLE_ATTR_MAX - 1)
#define PSAMPLE_NL_MCGRP_CONFIG_NAME "config"
#define PSAMPLE_NL_MCGRP_SAMPLE_NAME "packets"
#define PSAMPLE_GENL_NAME "psample"
#define PSAMPLE_GENL_VERSION 1
#endif

View File

@ -0,0 +1,44 @@
# -*- Kbuild -*-
#
# Linux KNET module.
#
# $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
# The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# A copy of the GNU General Public License version 2 (GPLv2) can
# be found in the LICENSES folder.$
#
obj-m := linux_ngknet.o
ccflags-y := $(KNET_CPPFLAGS) $(LKM_CFLAGS) \
-I$(SDK)/shr/include \
-I$(SDK)/bcmdrd/include \
-I$(SDK)/linux/include \
-I$(SDK)/linux/knet/include \
-I$(SDK)/linux/knet
linux_ngknet-y := $(CHIP_OBJS) \
bcmcnet_cmicd_pdma_hw.o \
bcmcnet_cmicd_pdma_rxtx.o \
bcmcnet_cmicx_pdma_hw.o \
bcmcnet_cmicx_pdma_rxtx.o \
bcmcnet_core.o \
bcmcnet_dev.o \
bcmcnet_rxtx.o \
ngknet_buff.o \
ngknet_callback.o \
ngknet_extra.o \
ngknet_linux.o \
ngknet_main.o \
ngknet_procfs.o \
ngknet_ptp.o

View File

@ -0,0 +1,105 @@
# -*- Makefile -*-
#
# Linux KNET module.
#
# $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
# The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# A copy of the GNU General Public License version 2 (GPLv2) can
# be found in the LICENSES folder.$
#
CNETDIR = $(SDK)/bcmcnet
KNETDIR = $(SDK)/linux/knet
SRCIDIR = $(CNETDIR)/include/bcmcnet
DSTIDIR = $(KNETDIR)/include/bcmcnet
# Change comma-separated list to space-separated list
comma = ,
empty =
space = $(empty) $(empty)
spc_sep = $(subst $(comma),$(space),$1)
# Convert chip name to uppercase
chip_uc = $(subst a,A,$(subst b,B,$(subst c,C,$(subst m,M,$1))))
# Convert chip name to lowercase
chip_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst M,m,$1))))
#
# If SDK_CHIPS is defined, then exclude any chip directory which is
# not part of this list.
#
KNET_CHIPS := $(subst $(CNETDIR)/chip/,,$(wildcard $(CNETDIR)/chip/bcm*))
ifdef SDK_CHIPS
# Create space-separated lowercase version of chip list
SDK_CHIPS_SPC := $(call spc_sep,$(SDK_CHIPS))
SDK_CHIPS_LC := $(call chip_lc,$(SDK_CHIPS_SPC))
# Configure build flags according to chip list
KNET_CHIPS := $(filter $(SDK_CHIPS_LC),$(KNET_CHIPS))
KNET_CPPFLAGS := CHIP_DEFAULT=0 $(addsuffix =1,$(call chip_uc,$(KNET_CHIPS)))
KNET_CPPFLAGS := $(addprefix -DBCMDRD_CONFIG_INCLUDE_,$(KNET_CPPFLAGS))
export KNET_CPPFLAGS
endif
.PHONY: mklinks rmlinks
knet: mklinks
$(MAKE) all
#
# Suppress symlink error messages.
#
# Note that we do not use "ln -f" as this may cause failures if
# multiple builds are done in parallel on the same source tree.
#
R = 2>/dev/null
mklinks:
mkdir -p $(DSTIDIR)
-ln -s $(KNETDIR)/ngknet_dep.h $(DSTIDIR)/bcmcnet_dep.h $(R)
-ln -s $(KNETDIR)/ngknet_buff.h $(DSTIDIR)/bcmcnet_buff.h $(R)
-ln -s $(SRCIDIR)/bcmcnet_types.h $(DSTIDIR) $(R)
-ln -s $(SRCIDIR)/bcmcnet_internal.h $(DSTIDIR) $(R)
-ln -s $(SRCIDIR)/bcmcnet_core.h $(DSTIDIR) $(R)
-ln -s $(SRCIDIR)/bcmcnet_dev.h $(DSTIDIR) $(R)
-ln -s $(SRCIDIR)/bcmcnet_rxtx.h $(DSTIDIR) $(R)
-ln -s $(SRCIDIR)/bcmcnet_cmicd.h $(DSTIDIR) $(R)
-ln -s $(SRCIDIR)/bcmcnet_cmicx.h $(DSTIDIR) $(R)
-ln -s $(CNETDIR)/chip/*/*attach.c $(KNETDIR) $(R)
-ln -s $(CNETDIR)/hmi/cmicd/*.c $(KNETDIR) $(R)
-ln -s $(CNETDIR)/hmi/cmicx/*.c $(KNETDIR) $(R)
-ln -s $(CNETDIR)/main/bcmcnet_core.c $(KNETDIR) $(R)
-ln -s $(CNETDIR)/main/bcmcnet_dev.c $(KNETDIR) $(R)
-ln -s $(CNETDIR)/main/bcmcnet_rxtx.c $(KNETDIR) $(R)
rmlinks:
-rm -f bcm*
-rm -rf include
CHIP_SRCS := $(addsuffix _pdma_attach.c,$(KNET_CHIPS))
CHIP_OBJS ?= $(patsubst %.c, %.o, $(CHIP_SRCS))
export CHIP_OBJS
include Kbuild
ifeq ($(KERNELRELEASE),)
MOD_NAME = linux_ngknet
include $(SDK)/make/lkm.mk
endif
.PHONY: distclean
distclean: rmlinks

View File

@ -0,0 +1,326 @@
/*! \file ngknet_buff.c
*
* Utility routines for NGKNET packet buffer management in Linux kernel mode.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <bcmcnet/bcmcnet_core.h>
#include <bcmcnet/bcmcnet_dev.h>
#include <bcmcnet/bcmcnet_rxtx.h>
#include "ngknet_main.h"
#include "ngknet_buff.h"
/*!
* Allocate coherent memory
*/
static void *
bcmcnet_ring_buf_alloc(struct pdma_dev *dev, uint32_t size, dma_addr_t *dma)
{
struct ngknet_dev *kdev = (struct ngknet_dev *)dev->priv;
return dma_alloc_coherent(kdev->dev, size, dma, GFP_KERNEL);
}
/*!
* Free coherent memory
*/
static void
bcmcnet_ring_buf_free(struct pdma_dev *dev, uint32_t size, void *addr, dma_addr_t dma)
{
struct ngknet_dev *kdev = (struct ngknet_dev *)dev->priv;
dma_free_coherent(kdev->dev, size, addr, dma);
}
/*!
* Allocate Rx buffer
*/
static int
bcmcnet_rx_buf_alloc(struct pdma_dev *dev, struct pdma_rx_queue *rxq,
struct pdma_rx_buf *pbuf)
{
struct ngknet_dev *kdev = (struct ngknet_dev *)dev->priv;
dma_addr_t dma;
struct page *page;
struct sk_buff *skb;
if (rxq->mode == PDMA_BUF_MODE_PAGE) {
page = kal_dev_alloc_page();
if (unlikely(!page)) {
return SHR_E_MEMORY;
}
dma = dma_map_page(kdev->dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(kdev->dev, dma))) {
__free_page(page);
return SHR_E_MEMORY;
}
pbuf->dma = dma;
pbuf->page = page;
pbuf->page_offset = 0;
} else {
skb = netdev_alloc_skb(kdev->net_dev, PDMA_RXB_RESV + pbuf->adj + rxq->buf_size);
if (unlikely(!skb)) {
return SHR_E_MEMORY;
}
skb_reserve(skb, PDMA_RXB_ALIGN - (((unsigned long)skb->data) & (PDMA_RXB_ALIGN - 1)));
pbuf->skb = skb;
pbuf->pkb = (struct pkt_buf *)skb->data;
dma = dma_map_single(kdev->dev, &pbuf->pkb->data + pbuf->adj, rxq->buf_size, DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(kdev->dev, dma))) {
dev_kfree_skb_any(skb);
return SHR_E_MEMORY;
}
pbuf->dma = dma;
}
return SHR_E_NONE;
}
/*!
* Get Rx buffer DMA address
*/
static void
bcmcnet_rx_buf_dma(struct pdma_dev *dev, struct pdma_rx_queue *rxq,
struct pdma_rx_buf *pbuf, dma_addr_t *addr)
{
if (rxq->mode == PDMA_BUF_MODE_PAGE) {
*addr = pbuf->dma + pbuf->page_offset + PDMA_RXB_RESV + pbuf->adj;
} else {
*addr = pbuf->dma;
}
}
/*!
* Check Rx buffer
*/
static int
bcmcnet_rx_buf_avail(struct pdma_dev *dev, struct pdma_rx_queue *rxq,
struct pdma_rx_buf *pbuf)
{
if (rxq->mode == PDMA_BUF_MODE_PAGE) {
pbuf->skb = NULL;
}
return pbuf->dma != 0;
}
/*!
* Get Rx buffer
*/
static struct pkt_hdr *
bcmcnet_rx_buf_get(struct pdma_dev *dev, struct pdma_rx_queue *rxq,
struct pdma_rx_buf *pbuf, int len)
{
struct ngknet_dev *kdev = (struct ngknet_dev *)dev->priv;
struct sk_buff *skb;
if (rxq->mode == PDMA_BUF_MODE_PAGE) {
if (pbuf->skb) {
return &pbuf->pkb->pkh;
}
skb = kal_build_skb(page_address(pbuf->page) + pbuf->page_offset,
PDMA_SKB_RESV + pbuf->adj + rxq->buf_size);
if (unlikely(!skb)) {
return NULL;
}
skb_reserve(skb, PDMA_RXB_ALIGN);
dma_sync_single_range_for_cpu(kdev->dev, pbuf->dma, pbuf->page_offset,
PDMA_PAGE_BUF_MAX, DMA_FROM_DEVICE);
pbuf->skb = skb;
pbuf->pkb = (struct pkt_buf *)skb->data;
/* Try to reuse this page */
if (unlikely(page_count(pbuf->page) != 1)) {
dma_unmap_page(kdev->dev, pbuf->dma, PAGE_SIZE, DMA_FROM_DEVICE);
pbuf->dma = 0;
} else {
pbuf->page_offset ^= PDMA_PAGE_BUF_MAX;
page_ref_inc(pbuf->page);
dma_sync_single_range_for_device(kdev->dev, pbuf->dma, pbuf->page_offset,
PDMA_PAGE_BUF_MAX, DMA_FROM_DEVICE);
}
} else {
if (!pbuf->dma) {
return &pbuf->pkb->pkh;
}
skb = pbuf->skb;
dma_unmap_single(kdev->dev, pbuf->dma, rxq->buf_size, DMA_FROM_DEVICE);
pbuf->dma = 0;
}
skb_put(skb, PKT_HDR_SIZE + pbuf->adj + len);
return &pbuf->pkb->pkh;
}
/*!
* Put Rx buffer
*/
static int
bcmcnet_rx_buf_put(struct pdma_dev *dev, struct pdma_rx_queue *rxq,
struct pdma_rx_buf *pbuf, int len)
{
struct ngknet_dev *kdev = (struct ngknet_dev *)dev->priv;
dma_addr_t dma;
struct sk_buff *skb;
if (rxq->mode == PDMA_BUF_MODE_PAGE) {
dev_kfree_skb_any(pbuf->skb);
} else {
skb = pbuf->skb;
dma = dma_map_single(kdev->dev, &pbuf->pkb->data + pbuf->adj,
rxq->buf_size, DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(kdev->dev, dma))) {
dev_kfree_skb_any(skb);
pbuf->dma = 0;
return SHR_E_MEMORY;
}
pbuf->dma = dma;
skb_trim(skb, skb->len - (PKT_HDR_SIZE + pbuf->adj + len));
}
return SHR_E_NONE;
}
/*!
* Free Rx buffer
*/
static void
bcmcnet_rx_buf_free(struct pdma_dev *dev, struct pdma_rx_queue *rxq,
struct pdma_rx_buf *pbuf)
{
struct ngknet_dev *kdev = (struct ngknet_dev *)dev->priv;
if (rxq->mode == PDMA_BUF_MODE_PAGE) {
dma_unmap_single(kdev->dev, pbuf->dma, PAGE_SIZE, DMA_FROM_DEVICE);
__free_page(pbuf->page);
} else {
dma_unmap_single(kdev->dev, pbuf->dma, rxq->buf_size, DMA_FROM_DEVICE);
dev_kfree_skb_any(pbuf->skb);
}
pbuf->dma = 0;
pbuf->page = NULL;
pbuf->page_offset = 0;
pbuf->skb = NULL;
pbuf->pkb = NULL;
pbuf->adj = 0;
}
/*!
* Get Rx buffer mode
*/
static enum buf_mode
bcmcnet_rx_buf_mode(struct pdma_dev *dev, struct pdma_rx_queue *rxq)
{
uint32_t len;
len = dev->rx_ph_size ? rxq->buf_size : rxq->buf_size + PDMA_RXB_META;
if (PDMA_RXB_SIZE(len) <= PDMA_PAGE_BUF_MAX && PAGE_SIZE < 8192 &&
kal_support_paged_skb()) {
return PDMA_BUF_MODE_PAGE;
}
return PDMA_BUF_MODE_SKB;
}
/*!
* Get Tx buffer
*/
static struct pkt_hdr *
bcmcnet_tx_buf_get(struct pdma_dev *dev, struct pdma_tx_queue *txq,
struct pdma_tx_buf *pbuf, void *buf)
{
struct ngknet_dev *kdev = (struct ngknet_dev *)dev->priv;
struct sk_buff *skb = (struct sk_buff *)buf;
struct pkt_buf *pkb = (struct pkt_buf *)skb->data;
dma_addr_t dma;
pbuf->len = pkb->pkh.data_len + (pbuf->adj ? pkb->pkh.meta_len : 0);
dma = dma_map_single(kdev->dev, &pkb->data + (pbuf->adj ? 0 : pkb->pkh.meta_len),
pbuf->len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(kdev->dev, dma))) {
dev_kfree_skb_any(skb);
return NULL;
}
pbuf->dma = dma;
pbuf->skb = skb;
pbuf->pkb = pkb;
return &pkb->pkh;
}
/*!
* Get Tx buffer DMA address
*/
static void
bcmcnet_tx_buf_dma(struct pdma_dev *dev, struct pdma_tx_queue *txq,
struct pdma_tx_buf *pbuf, dma_addr_t *addr)
{
*addr = pbuf->dma;
}
/*!
* Free Tx buffer
*/
static void
bcmcnet_tx_buf_free(struct pdma_dev *dev, struct pdma_tx_queue *txq,
struct pdma_tx_buf *pbuf)
{
struct ngknet_dev *kdev = (struct ngknet_dev *)dev->priv;
dma_unmap_single(kdev->dev, pbuf->dma, pbuf->len, DMA_TO_DEVICE);
if (skb_shinfo(pbuf->skb)->tx_flags & SKBTX_IN_PROGRESS) {
skb_queue_tail(&kdev->ptp_tx_queue, pbuf->skb);
schedule_work(&kdev->ptp_tx_work);
} else {
dev_kfree_skb_any(pbuf->skb);
}
pbuf->dma = 0;
pbuf->len = 0;
pbuf->skb = NULL;
pbuf->pkb = NULL;
pbuf->adj = 0;
}
static const struct pdma_buf_mngr buf_mngr = {
.ring_buf_alloc = bcmcnet_ring_buf_alloc,
.ring_buf_free = bcmcnet_ring_buf_free,
.rx_buf_alloc = bcmcnet_rx_buf_alloc,
.rx_buf_dma = bcmcnet_rx_buf_dma,
.rx_buf_avail = bcmcnet_rx_buf_avail,
.rx_buf_get = bcmcnet_rx_buf_get,
.rx_buf_put = bcmcnet_rx_buf_put,
.rx_buf_free = bcmcnet_rx_buf_free,
.rx_buf_mode = bcmcnet_rx_buf_mode,
.tx_buf_get = bcmcnet_tx_buf_get,
.tx_buf_dma = bcmcnet_tx_buf_dma,
.tx_buf_free = bcmcnet_tx_buf_free,
};
/*!
* Open a device
*/
void
bcmcnet_buf_mngr_init(struct pdma_dev *dev)
{
dev->ctrl.buf_mngr = (struct pdma_buf_mngr *)&buf_mngr;
}

View File

@ -0,0 +1,83 @@
/*! \file ngknet_buff.h
*
* Generic data structure definitions for NGKNET packet buffer management.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef NGKNET_BUFF_H
#define NGKNET_BUFF_H
/*! Rx buffer align size */
#define PDMA_RXB_ALIGN 32
/*! Rx buffer reserved size */
#define PDMA_RXB_RESV (PDMA_RXB_ALIGN + PKT_HDR_SIZE)
/*! Rx SKB reserved size */
#define PDMA_SKB_RESV (PDMA_RXB_RESV + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
/*! Rx buffer size */
#define PDMA_RXB_SIZE(len) (SKB_DATA_ALIGN(len + NET_SKB_PAD) + PDMA_SKB_RESV)
/*! Rx reserved meta size */
#define PDMA_RXB_META 64
/*! Max page buffer size */
#define PDMA_PAGE_BUF_MAX 2048
/*!
* \brief Rx buffer.
*/
struct pdma_rx_buf {
/*! DMA address */
dma_addr_t dma;
/*! Buffer page */
struct page *page;
/*! Buffer page offset */
unsigned int page_offset;
/*! Rx SKB */
struct sk_buff *skb;
/*! Packet buffer point */
struct pkt_buf *pkb;
/*! Packet buffer adjustment */
uint32_t adj;
};
/*!
* \brief Tx buffer.
*/
struct pdma_tx_buf {
/*! DMA address */
dma_addr_t dma;
/*! Tx buffer length */
uint32_t len;
/*! Tx SKB */
struct sk_buff *skb;
/*! Packet buffer point */
struct pkt_buf *pkb;
/*! Packet buffer adjustment */
uint32_t adj;
};
#endif /* NGKNET_BUFF_H */

View File

@ -0,0 +1,315 @@
/*! \file ngknet_callback.c
*
* Utility routines for NGKNET callbacks.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include "ngknet_callback.h"
static struct ngknet_callback_ctrl callback_ctrl;
int
ngknet_callback_control_get(struct ngknet_callback_ctrl **cbc)
{
*cbc = &callback_ctrl;
return 0;
}
/*!
* Call-back interfaces for other Linux kernel drivers.
*
* The Rx call-back allows an external module to modify packet contents
* before it is handed off to the Linux network stack.
*
* The Tx call-back allows an external module to modify packet contents
* before it is injected into the switch.
*/
int
ngknet_rx_cb_register(ngknet_rx_cb_f rx_cb)
{
if (callback_ctrl.rx_cb != NULL) {
return -1;
}
callback_ctrl.rx_cb = rx_cb;
return 0;
}
int
ngknet_rx_cb_unregister(ngknet_rx_cb_f rx_cb)
{
if (rx_cb == NULL || callback_ctrl.rx_cb != rx_cb) {
return -1;
}
callback_ctrl.rx_cb = NULL;
return 0;
}
int
ngknet_tx_cb_register(ngknet_tx_cb_f tx_cb)
{
if (callback_ctrl.tx_cb != NULL) {
return -1;
}
callback_ctrl.tx_cb = tx_cb;
return 0;
}
int
ngknet_tx_cb_unregister(ngknet_tx_cb_f tx_cb)
{
if (tx_cb == NULL || callback_ctrl.tx_cb != tx_cb) {
return -1;
}
callback_ctrl.tx_cb = NULL;
return 0;
}
int
ngknet_ptp_rx_config_set_cb_register(ngknet_ptp_config_set_cb_f ptp_rx_config_set_cb)
{
if (callback_ctrl.ptp_rx_config_set_cb != NULL) {
return -1;
}
callback_ctrl.ptp_rx_config_set_cb = ptp_rx_config_set_cb;
return 0;
}
int
ngknet_ptp_rx_config_set_cb_unregister(ngknet_ptp_config_set_cb_f ptp_rx_config_set_cb)
{
if (ptp_rx_config_set_cb == NULL ||
callback_ctrl.ptp_rx_config_set_cb != ptp_rx_config_set_cb) {
return -1;
}
callback_ctrl.ptp_rx_config_set_cb = NULL;
return 0;
}
int
ngknet_ptp_tx_config_set_cb_register(ngknet_ptp_config_set_cb_f ptp_tx_config_set_cb)
{
if (callback_ctrl.ptp_tx_config_set_cb != NULL) {
return -1;
}
callback_ctrl.ptp_tx_config_set_cb = ptp_tx_config_set_cb;
return 0;
}
int
ngknet_ptp_tx_config_set_cb_unregister(ngknet_ptp_config_set_cb_f ptp_tx_config_set_cb)
{
if (ptp_tx_config_set_cb == NULL ||
callback_ctrl.ptp_tx_config_set_cb != ptp_tx_config_set_cb) {
return -1;
}
callback_ctrl.ptp_tx_config_set_cb = NULL;
return 0;
}
int
ngknet_ptp_rx_hwts_get_cb_register(ngknet_ptp_hwts_get_cb_f ptp_rx_hwts_get_cb)
{
if (callback_ctrl.ptp_rx_hwts_get_cb != NULL) {
return -1;
}
callback_ctrl.ptp_rx_hwts_get_cb = ptp_rx_hwts_get_cb;
return 0;
}
int
ngknet_ptp_rx_hwts_get_cb_unregister(ngknet_ptp_hwts_get_cb_f ptp_rx_hwts_get_cb)
{
if (ptp_rx_hwts_get_cb == NULL ||
callback_ctrl.ptp_rx_hwts_get_cb != ptp_rx_hwts_get_cb) {
return -1;
}
callback_ctrl.ptp_rx_hwts_get_cb = NULL;
return 0;
}
int
ngknet_ptp_tx_hwts_get_cb_register(ngknet_ptp_hwts_get_cb_f ptp_tx_hwts_get_cb)
{
if (callback_ctrl.ptp_tx_hwts_get_cb != NULL) {
return -1;
}
callback_ctrl.ptp_tx_hwts_get_cb = ptp_tx_hwts_get_cb;
return 0;
}
int
ngknet_ptp_tx_hwts_get_cb_unregister(ngknet_ptp_hwts_get_cb_f ptp_tx_hwts_get_cb)
{
if (ptp_tx_hwts_get_cb == NULL ||
callback_ctrl.ptp_tx_hwts_get_cb != ptp_tx_hwts_get_cb) {
return -1;
}
callback_ctrl.ptp_tx_hwts_get_cb = NULL;
return 0;
}
int
ngknet_ptp_tx_meta_set_cb_register(ngknet_ptp_meta_set_cb_f ptp_tx_meta_set_cb)
{
if (callback_ctrl.ptp_tx_meta_set_cb != NULL) {
return -1;
}
callback_ctrl.ptp_tx_meta_set_cb = ptp_tx_meta_set_cb;
return 0;
}
int
ngknet_ptp_tx_meta_set_cb_unregister(ngknet_ptp_meta_set_cb_f ptp_tx_meta_set_cb)
{
if (ptp_tx_meta_set_cb == NULL ||
callback_ctrl.ptp_tx_meta_set_cb != ptp_tx_meta_set_cb) {
return -1;
}
callback_ctrl.ptp_tx_meta_set_cb = NULL;
return 0;
}
int
ngknet_ptp_phc_index_get_cb_register(ngknet_ptp_phc_index_get_cb_f ptp_phc_index_get_cb)
{
if (callback_ctrl.ptp_phc_index_get_cb != NULL) {
return -1;
}
callback_ctrl.ptp_phc_index_get_cb = ptp_phc_index_get_cb;
return 0;
}
int
ngknet_ptp_phc_index_get_cb_unregister(ngknet_ptp_phc_index_get_cb_f ptp_phc_index_get_cb)
{
if (ptp_phc_index_get_cb == NULL ||
callback_ctrl.ptp_phc_index_get_cb != ptp_phc_index_get_cb) {
return -1;
}
callback_ctrl.ptp_phc_index_get_cb = NULL;
return 0;
}
int
ngknet_ptp_dev_ctrl_cb_register(ngknet_ptp_dev_ctrl_cb_f ptp_dev_ctrl_cb)
{
if (callback_ctrl.ptp_dev_ctrl_cb != NULL) {
return -1;
}
callback_ctrl.ptp_dev_ctrl_cb = ptp_dev_ctrl_cb;
return 0;
}
int
ngknet_ptp_dev_ctrl_cb_unregister(ngknet_ptp_dev_ctrl_cb_f ptp_dev_ctrl_cb)
{
if (ptp_dev_ctrl_cb == NULL ||
callback_ctrl.ptp_dev_ctrl_cb != ptp_dev_ctrl_cb) {
return -1;
}
callback_ctrl.ptp_dev_ctrl_cb = NULL;
return 0;
}
int
ngknet_netif_create_cb_register(ngknet_netif_cb_f netif_cb)
{
if (callback_ctrl.netif_create_cb != NULL) {
return -1;
}
callback_ctrl.netif_create_cb = netif_cb;
return 0;
}
int
ngknet_netif_create_cb_unregister(ngknet_netif_cb_f netif_cb)
{
if (netif_cb == NULL || callback_ctrl.netif_create_cb != netif_cb) {
return -1;
}
callback_ctrl.netif_create_cb = NULL;
return 0;
}
int
ngknet_netif_destroy_cb_register(ngknet_netif_cb_f netif_cb)
{
if (callback_ctrl.netif_destroy_cb != NULL) {
return -1;
}
callback_ctrl.netif_destroy_cb = netif_cb;
return 0;
}
int
ngknet_netif_destroy_cb_unregister(ngknet_netif_cb_f netif_cb)
{
if (netif_cb == NULL || callback_ctrl.netif_destroy_cb != netif_cb) {
return -1;
}
callback_ctrl.netif_destroy_cb = NULL;
return 0;
}
EXPORT_SYMBOL(ngknet_rx_cb_register);
EXPORT_SYMBOL(ngknet_rx_cb_unregister);
EXPORT_SYMBOL(ngknet_tx_cb_register);
EXPORT_SYMBOL(ngknet_tx_cb_unregister);
EXPORT_SYMBOL(ngknet_ptp_rx_config_set_cb_register);
EXPORT_SYMBOL(ngknet_ptp_rx_config_set_cb_unregister);
EXPORT_SYMBOL(ngknet_ptp_tx_config_set_cb_register);
EXPORT_SYMBOL(ngknet_ptp_tx_config_set_cb_unregister);
EXPORT_SYMBOL(ngknet_ptp_rx_hwts_get_cb_register);
EXPORT_SYMBOL(ngknet_ptp_rx_hwts_get_cb_unregister);
EXPORT_SYMBOL(ngknet_ptp_tx_hwts_get_cb_register);
EXPORT_SYMBOL(ngknet_ptp_tx_hwts_get_cb_unregister);
EXPORT_SYMBOL(ngknet_ptp_tx_meta_set_cb_register);
EXPORT_SYMBOL(ngknet_ptp_tx_meta_set_cb_unregister);
EXPORT_SYMBOL(ngknet_ptp_phc_index_get_cb_register);
EXPORT_SYMBOL(ngknet_ptp_phc_index_get_cb_unregister);
EXPORT_SYMBOL(ngknet_ptp_dev_ctrl_cb_register);
EXPORT_SYMBOL(ngknet_ptp_dev_ctrl_cb_unregister);
EXPORT_SYMBOL(ngknet_netif_create_cb_register);
EXPORT_SYMBOL(ngknet_netif_create_cb_unregister);
EXPORT_SYMBOL(ngknet_netif_destroy_cb_register);
EXPORT_SYMBOL(ngknet_netif_destroy_cb_unregister);

View File

@ -0,0 +1,364 @@
/*! \file ngknet_callback.h
*
* Data structure definitions for NGKNET callbacks.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef NGKNET_CALLBACK_H
#define NGKNET_CALLBACK_H
#include <linux/skbuff.h>
#include "ngknet_main.h"
/*!
* \brief NGKNET callback description.
*/
struct ngknet_callback_desc {
/*! Device number */
int dev_no;
/*! Device ID */
uint32_t dev_id;
/*! Device type string */
const char *type_str;
/*! Network interface private data */
struct ngknet_private *priv;
/*! Matched filter */
struct ngknet_filter_s *filt;
/*! Packet meta data */
uint8_t *pmd;
/*! Packet meta data length */
int pmd_len;
/*! Packet data length */
int pkt_len;
/*! Matched callback filter */
struct ngknet_filter_s *filt_cb;
};
#define NGKNET_SKB_CB(_skb) ((struct ngknet_callback_desc *)_skb->cb)
/*! Handle Rx packet */
typedef struct sk_buff *
(*ngknet_rx_cb_f)(struct sk_buff *skb);
/*! Handle Tx packet */
typedef struct sk_buff *
(*ngknet_tx_cb_f)(struct sk_buff *skb);
/*! PTP Rx/Tx config set */
typedef int
(*ngknet_ptp_config_set_cb_f)(struct ngknet_private *priv, int *value);
/*! PTP Rx/Tx HW timestamp get */
typedef int
(*ngknet_ptp_hwts_get_cb_f)(struct sk_buff *skb, uint64_t *ts);
/*! PTP Tx meta set */
typedef int
(*ngknet_ptp_meta_set_cb_f)(struct sk_buff *skb);
/*! PTP PHC index get */
typedef int
(*ngknet_ptp_phc_index_get_cb_f)(struct ngknet_private *priv, int *index);
/*! PTP device control */
typedef int
(*ngknet_ptp_dev_ctrl_cb_f)(struct ngknet_dev *dev, int cmd, char *data, int len);
/*! Netif callback */
typedef int
(*ngknet_netif_cb_f)(struct net_device *dev);
/*!
* \brief NGKNET callback control.
*/
struct ngknet_callback_ctrl {
/*! Handle Rx packet */
ngknet_rx_cb_f rx_cb;
/*! Handle Tx packet */
ngknet_tx_cb_f tx_cb;
/*! PTP Rx config set */
ngknet_ptp_config_set_cb_f ptp_rx_config_set_cb;
/*! PTP Tx config set */
ngknet_ptp_config_set_cb_f ptp_tx_config_set_cb;
/*! PTP Rx HW timestamp get */
ngknet_ptp_hwts_get_cb_f ptp_rx_hwts_get_cb;
/*! PTP Tx HW timestamp get */
ngknet_ptp_hwts_get_cb_f ptp_tx_hwts_get_cb;
/*! PTP Tx meta set */
ngknet_ptp_meta_set_cb_f ptp_tx_meta_set_cb;
/*! PTP PHC index get */
ngknet_ptp_phc_index_get_cb_f ptp_phc_index_get_cb;
/*! PTP device control */
ngknet_ptp_dev_ctrl_cb_f ptp_dev_ctrl_cb;
/*! Handle Netif create */
ngknet_netif_cb_f netif_create_cb;
/*! Handle Netif destroy */
ngknet_netif_cb_f netif_destroy_cb;
};
/*!
* \brief Get callback control.
*
* \param [in] cbc Pointer to callback control.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_callback_control_get(struct ngknet_callback_ctrl **cbc);
/*!
* \brief Register Rx callback.
*
* \param [in] rx_cb Rx callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_rx_cb_register(ngknet_rx_cb_f rx_cb);
/*!
* \brief Unregister Rx callback.
*
* \param [in] rx_cb Rx callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_rx_cb_unregister(ngknet_rx_cb_f rx_cb);
/*!
* \brief Register Tx callback.
*
* \param [in] tx_cb Tx callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_tx_cb_register(ngknet_tx_cb_f tx_cb);
/*!
* \brief Unregister Tx callback.
*
* \param [in] tx_cb Tx callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_tx_cb_unregister(ngknet_tx_cb_f tx_cb);
/*!
* \brief Register PTP Rx config set callback.
*
* \param [in] ptp_rx_config_set_cb Rx config set callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_rx_config_set_cb_register(ngknet_ptp_config_set_cb_f ptp_rx_config_set_cb);
/*!
* \brief Unregister PTP Rx config set callback.
*
* \param [in] ptp_rx_config_set_cb Rx config set callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_rx_config_set_cb_unregister(ngknet_ptp_config_set_cb_f ptp_rx_config_set_cb);
/*!
* \brief Register PTP Tx config set callback.
*
* \param [in] ptp_tx_config_set_cb Tx config set callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_tx_config_set_cb_register(ngknet_ptp_config_set_cb_f ptp_tx_config_set_cb);
/*!
* \brief Unregister PTP Tx config set callback.
*
* \param [in] ptp_tx_config_set_cb Tx config set callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_tx_config_set_cb_unregister(ngknet_ptp_config_set_cb_f ptp_tx_config_set_cb);
/*!
* \brief Register PTP Rx HW timestamp get callback.
*
* \param [in] ptp_rx_hwts_get_cb Rx HW timestamp get callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_rx_hwts_get_cb_register(ngknet_ptp_hwts_get_cb_f ptp_rx_hwts_get_cb);
/*!
* \brief Unregister PTP Rx HW timestamp get callback.
*
* \param [in] ptp_rx_hwts_get_cb Rx HW timestamp get callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_rx_hwts_get_cb_unregister(ngknet_ptp_hwts_get_cb_f ptp_rx_hwts_get_cb);
/*!
* \brief Register PTP Tx HW timestamp get callback.
*
* \param [in] ptp_tx_hwts_get_cb Tx HW timestamp get callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_tx_hwts_get_cb_register(ngknet_ptp_hwts_get_cb_f ptp_tx_hwts_get_cb);
/*!
* \brief Unregister PTP Tx HW timestamp get callback.
*
* \param [in] ptp_tx_hwts_get_cb Tx HW timestamp get callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_tx_hwts_get_cb_unregister(ngknet_ptp_hwts_get_cb_f ptp_tx_hwts_get_cb);
/*!
* \brief Register PTP Tx meta set callback.
*
* \param [in] ptp_tx_meta_set_cb Tx meta set callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_tx_meta_set_cb_register(ngknet_ptp_meta_set_cb_f ptp_tx_meta_set_cb);
/*!
* \brief Unregister PTP Tx meta set callback.
*
* \param [in] ptp_tx_meta_set_cb Tx meta set callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_tx_meta_set_cb_unregister(ngknet_ptp_meta_set_cb_f ptp_tx_meta_set_cb);
/*!
* \brief Register PTP PHC index get callback.
*
* \param [in] ptp_phc_index_get_cb PHC index get callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_phc_index_get_cb_register(ngknet_ptp_phc_index_get_cb_f ptp_phc_index_get_cb);
/*!
* \brief Unregister PTP PHC index get callback.
*
* \param [in] ptp_phc_index_get_cb PHC index get callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_phc_index_get_cb_unregister(ngknet_ptp_phc_index_get_cb_f ptp_phc_index_get_cb);
/*!
* \brief Register PTP device control callback.
*
* \param [in] ptp_dev_ctrl_cb Device control callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_dev_ctrl_cb_register(ngknet_ptp_dev_ctrl_cb_f ptp_dev_ctrl_cb);
/*!
* \brief Unregister PTP device control callback.
*
* \param [in] ptp_dev_ctrl_cb Device control callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_dev_ctrl_cb_unregister(ngknet_ptp_dev_ctrl_cb_f ptp_dev_ctrl_cb);
/*!
* \brief Register Netif Create callback.
*
* \param [netif_cb] netif_cb create callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_netif_create_cb_register(ngknet_netif_cb_f netif_cb);
/*!
* \brief Unregister Netif Create callback.
*
* \param [netif_cb] netif_cb destroy callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_netif_create_cb_unregister(ngknet_netif_cb_f netif_cb);
/*!
* \brief Register Netif Destroy callback.
*
* \param [netif_cb] netif_cb destroy callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_netif_destroy_cb_register(ngknet_netif_cb_f netif_cb);
/*!
* \brief Unregister Netif Destroy callback.
*
* \param [netif_cb] netif_cb destroy callback function.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_netif_destroy_cb_unregister(ngknet_netif_cb_f netif_cb);
#endif /* NGKNET_CALLBACK_H */

View File

@ -0,0 +1,61 @@
/*! \file ngknet_dep.h
*
* Macro definitions for NGKNET dependence.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef NGKNET_DEP_H
#define NGKNET_DEP_H
#include <shr/shr_error.h>
#include <ngknet_linux.h>
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/*! Memorry barrier */
#define MEMORY_BARRIER smp_mb()
/*! CNET print uitility */
#define CNET_PR(fmt, args...) printk(fmt, ##args)
struct pdma_dev;
/*! Externs for the required functions. */
#define BCMDRD_DEVLIST_ENTRY(_nm,_vn,_dv,_rv,_md,_pi,_bd,_bc,_fn,_cn,_pf,_pd,_r0,_r1) \
extern int _bd##_cnet_pdma_attach(struct pdma_dev *dev); \
extern int _bd##_cnet_pdma_detach(struct pdma_dev *dev);
#include <bcmdrd/bcmdrd_devlist.h>
/*! Create enumeration values from list of supported devices. */
#define BCMDRD_DEVLIST_ENTRY(_nm,_vn,_dv,_rv,_md,_pi,_bd,_bc,_fn,_cn,_pf,_pd,_r0,_r1) \
NGKNET_DEV_T_##_bd,
/*! Enumeration for all base device types. */
typedef enum {
NGKNET_DEV_T_NONE = 0,
#include <bcmdrd/bcmdrd_devlist.h>
NGKNET_DEV_T_COUNT
} ngknet_dev_type_t;
#endif /* NGKNET_DEP_H */

View File

@ -0,0 +1,505 @@
/*! \file ngknet_extra.c
*
* Utility routines for NGKNET enhancement.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <linux/kconfig.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <asm/io.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if.h>
#include <linux/if_vlan.h>
#include <linux/net_tstamp.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/time.h>
#include <lkm/ngknet_dev.h>
#include <bcmcnet/bcmcnet_core.h>
#include "ngknet_main.h"
#include "ngknet_extra.h"
#include "ngknet_callback.h"
static struct ngknet_rl_ctrl rl_ctrl;
int
ngknet_filter_create(struct ngknet_dev *dev, ngknet_filter_t *filter)
{
struct filt_ctrl *fc = NULL;
struct list_head *list = NULL;
ngknet_filter_t *filt = NULL;
unsigned long flags;
int num, id, done = 0;
switch (filter->type) {
case NGKNET_FILTER_T_RX_PKT:
break;
default:
return SHR_E_UNAVAIL;
}
switch (filter->dest_type) {
case NGKNET_FILTER_DEST_T_NULL:
case NGKNET_FILTER_DEST_T_NETIF:
case NGKNET_FILTER_DEST_T_VNET:
case NGKNET_FILTER_DEST_T_CB: /* SDKLT-26907: support NGKNET_FILTER_DEST_T_CB */
break;
default:
return SHR_E_UNAVAIL;
}
spin_lock_irqsave(&dev->lock, flags);
num = (long)dev->fc[0];
for (id = 1; id < num + 1; id++) {
if (!dev->fc[id]) {
break;
}
}
if (id > NUM_FILTER_MAX) {
spin_unlock_irqrestore(&dev->lock, flags);
return SHR_E_RESOURCE;
}
fc = kzalloc(sizeof(*fc), GFP_KERNEL);
if (!fc) {
spin_unlock_irqrestore(&dev->lock, flags);
return SHR_E_MEMORY;
}
dev->fc[id] = fc;
num += id == (num + 1) ? 1 : 0;
dev->fc[0] = (void *)(long)num;
memcpy(&fc->filt, filter, sizeof(fc->filt));
fc->filt.id = id;
list_for_each(list, &dev->filt_list) {
filt = &((struct filt_ctrl *)list)->filt;
if (filt->flags & NGKNET_FILTER_F_MATCH_CHAN) {
if (!(fc->filt.flags & NGKNET_FILTER_F_MATCH_CHAN) ||
fc->filt.chan > filt->chan) {
continue;
}
if (fc->filt.chan < filt->chan ||
fc->filt.priority < filt->priority) {
list_add_tail(&fc->list, list);
done = 1;
break;
}
} else {
if (fc->filt.flags & NGKNET_FILTER_F_MATCH_CHAN ||
fc->filt.priority < filt->priority) {
list_add_tail(&fc->list, list);
done = 1;
break;
}
}
}
if (!done) {
list_add_tail(&fc->list, &dev->filt_list);
}
filter->id = fc->filt.id;
spin_unlock_irqrestore(&dev->lock, flags);
return SHR_E_NONE;
}
int
ngknet_filter_destroy(struct ngknet_dev *dev, int id)
{
struct filt_ctrl *fc = NULL;
unsigned long flags;
int num;
if (id <= 0 || id > NUM_FILTER_MAX) {
return SHR_E_PARAM;
}
spin_lock_irqsave(&dev->lock, flags);
fc = (struct filt_ctrl *)dev->fc[id];
if (!fc) {
spin_unlock_irqrestore(&dev->lock, flags);
return SHR_E_NOT_FOUND;
}
list_del(&fc->list);
kfree(fc);
dev->fc[id] = NULL;
num = (long)dev->fc[0];
while (num-- == id--) {
if (dev->fc[id]) {
dev->fc[0] = (void *)(long)num;
break;
}
}
spin_unlock_irqrestore(&dev->lock, flags);
return SHR_E_NONE;
}
int
ngknet_filter_destroy_all(struct ngknet_dev *dev)
{
int id;
int rv;
for (id = 1; id <= NUM_FILTER_MAX; id++) {
rv = ngknet_filter_destroy(dev, id);
if (SHR_FAILURE(rv)) {
return rv;
}
}
return SHR_E_NONE;
}
int
ngknet_filter_get(struct ngknet_dev *dev, int id, ngknet_filter_t *filter)
{
struct filt_ctrl *fc = NULL;
unsigned long flags;
int num;
if (id <= 0 || id > NUM_FILTER_MAX) {
return SHR_E_PARAM;
}
spin_lock_irqsave(&dev->lock, flags);
fc = (struct filt_ctrl *)dev->fc[id];
if (!fc) {
spin_unlock_irqrestore(&dev->lock, flags);
return SHR_E_NOT_FOUND;
}
memcpy(filter, &fc->filt, sizeof(*filter));
num = (long)dev->fc[0];
for (id++; id < num + 1; id++) {
if (dev->fc[id]) {
break;
}
}
filter->next = id == (num + 1) ? 0 : id;
spin_unlock_irqrestore(&dev->lock, flags);
return SHR_E_NONE;
}
int
ngknet_filter_get_next(struct ngknet_dev *dev, ngknet_filter_t *filter)
{
int id;
int rv;
if (!filter->next) {
for (id = 1; id <= NUM_FILTER_MAX; id++) {
rv = ngknet_filter_get(dev, id, filter);
if (SHR_SUCCESS(rv)) {
return rv;
}
}
if (id > NUM_FILTER_MAX) {
return SHR_E_NOT_FOUND;
}
}
return ngknet_filter_get(dev, filter->next, filter);
}
int
ngknet_rx_pkt_filter(struct ngknet_dev *dev, struct sk_buff *skb, struct net_device **ndev,
struct net_device **mndev, struct sk_buff **mskb)
{
struct pkt_buf *pkb = (struct pkt_buf *)skb->data;
struct net_device *dest_ndev = NULL, *mirror_ndev = NULL;
struct sk_buff *mirror_skb = NULL;
struct ngknet_private *priv = NULL;
struct filt_ctrl *fc = NULL;
struct list_head *list = NULL;
ngknet_filter_t scratch, *filt = NULL, *filt_cb = NULL;
uint8_t *oob = &pkb->data, *data = NULL;
uint16_t tpid;
unsigned long flags;
int wsize;
int chan_id;
int idx, match = 0, match_cb = 0;
bcmcnet_pdma_dev_queue_to_chan(&dev->pdma_dev, pkb->pkh.queue_id,
PDMA_Q_RX, &chan_id);
spin_lock_irqsave(&dev->lock, flags);
dest_ndev = dev->bdev[chan_id];
if (dest_ndev) {
skb->dev = dest_ndev;
priv = netdev_priv(dest_ndev);
priv->users++;
*ndev = dest_ndev;
spin_unlock_irqrestore(&dev->lock, flags);
return SHR_E_NONE;
}
if (list_empty(&dev->filt_list)) {
spin_unlock_irqrestore(&dev->lock, flags);
return SHR_E_NONE;
}
list_for_each(list, &dev->filt_list) {
fc = (struct filt_ctrl *)list;
filt = &fc->filt;
if (filt->flags & NGKNET_FILTER_F_ANY_DATA) {
match = 1;
break;
}
if (filt->flags & NGKNET_FILTER_F_MATCH_CHAN && filt->chan != chan_id) {
continue;
}
memcpy(&scratch.data.b[0],
&oob[filt->oob_data_offset], filt->oob_data_size);
memcpy(&scratch.data.b[filt->oob_data_size],
&pkb->data + pkb->pkh.meta_len + filt->pkt_data_offset,
filt->pkt_data_size);
wsize = NGKNET_BYTES2WORDS(filt->oob_data_size + filt->pkt_data_size);
for (idx = 0; idx < wsize; idx++) {
scratch.data.w[idx] &= filt->mask.w[idx];
if (scratch.data.w[idx] != filt->data.w[idx]) {
break;
}
}
if (idx == wsize) {
if (NGKNET_FILTER_DEST_T_CB == filt->dest_type) {
match_cb = 1;
filt_cb = filt;
continue;
}
match = 1;
break;
}
}
if (match) {
fc->hits++;
switch (filt->dest_type) {
case NGKNET_FILTER_DEST_T_NETIF:
if (filt->dest_id == 0) {
dest_ndev = dev->net_dev;
} else {
dest_ndev = dev->vdev[filt->dest_id];
}
if (dest_ndev) {
skb->dev = dest_ndev;
if (filt->dest_proto) {
pkb->pkh.attrs |= PDMA_RX_SET_PROTO;
skb->protocol = filt->dest_proto;
}
priv = netdev_priv(dest_ndev);
priv->users++;
}
break;
case NGKNET_FILTER_DEST_T_VNET:
pkb->pkh.attrs |= PDMA_RX_TO_VNET;
spin_unlock_irqrestore(&dev->lock, flags);
return SHR_E_NO_HANDLER;
case NGKNET_FILTER_DEST_T_NULL:
default:
spin_unlock_irqrestore(&dev->lock, flags);
return SHR_E_UNAVAIL;
}
}
spin_unlock_irqrestore(&dev->lock, flags);
if (!dest_ndev) {
return SHR_E_NONE;
} else {
*ndev = dest_ndev;
}
if (filt->flags & NGKNET_FILTER_F_STRIP_TAG) {
pkb->pkh.attrs |= PDMA_RX_STRIP_TAG;
data = skb->data + PKT_HDR_SIZE + pkb->pkh.meta_len;
tpid = data[12] << 8 | data[13];
if (tpid == ETH_P_8021Q || tpid == ETH_P_8021AD) {
pkb->pkh.data_len -= VLAN_HLEN;
memmove(skb->data + VLAN_HLEN, skb->data,
PKT_HDR_SIZE + pkb->pkh.meta_len + 2 * ETH_ALEN);
skb_pull(skb, VLAN_HLEN);
}
}
if (dev->cbc->rx_cb) {
NGKNET_SKB_CB(skb)->filt = filt;
/* Add callback filter if matched */
if (match_cb) {
NGKNET_SKB_CB(skb)->filt_cb = filt_cb;
}
}
if (filt->mirror_type == NGKNET_FILTER_DEST_T_NETIF) {
spin_lock_irqsave(&dev->lock, flags);
if (filt->mirror_id == 0) {
mirror_ndev = dev->net_dev;
} else {
mirror_ndev = dev->vdev[filt->mirror_id];
}
if (mirror_ndev) {
mirror_skb = pskb_copy(skb, GFP_ATOMIC);
if (mirror_skb) {
mirror_skb->dev = mirror_ndev;
if (filt->mirror_proto) {
pkb->pkh.attrs |= PDMA_RX_SET_PROTO;
mirror_skb->protocol = filt->mirror_proto;
}
if (dev->cbc->rx_cb) {
NGKNET_SKB_CB(mirror_skb)->filt = filt;
}
priv = netdev_priv(mirror_ndev);
priv->users++;
*mndev = mirror_ndev;
*mskb = mirror_skb;
}
}
spin_unlock_irqrestore(&dev->lock, flags);
}
return SHR_E_NONE;
}
static void
ngknet_rl_process(timer_context_t data)
{
struct ngknet_rl_ctrl *rc = timer_arg(rc, data, timer);
struct ngknet_dev *dev;
unsigned long flags;
int idx;
spin_lock_irqsave(&rc->lock, flags);
rc->rx_pkts = 0;
for (idx = 0; idx < NUM_PDMA_DEV_MAX; idx++) {
dev = &rc->devs[idx];
if (rc->dev_active[idx] && rc->dev_paused[idx]) {
bcmcnet_pdma_dev_rx_resume(&dev->pdma_dev);
rl_ctrl.dev_paused[dev->dev_no] = 0;
}
}
spin_unlock_irqrestore(&rc->lock, flags);
rc->timer.expires = jiffies + HZ / rc->rx_ticks;
add_timer(&rc->timer);
}
void
ngknet_rx_rate_limit_init(struct ngknet_dev *devs)
{
sal_memset(&rl_ctrl, 0, sizeof(rl_ctrl));
rl_ctrl.rx_ticks = 10;
setup_timer(&rl_ctrl.timer, ngknet_rl_process, (timer_context_t)&rl_ctrl);
spin_lock_init(&rl_ctrl.lock);
rl_ctrl.devs = devs;
}
void
ngknet_rx_rate_limit_cleanup(void)
{
del_timer_sync(&rl_ctrl.timer);
}
int
ngknet_rx_rate_limit_started(void)
{
return rl_ctrl.started;
}
void
ngknet_rx_rate_limit_start(struct ngknet_dev *dev)
{
unsigned long flags;
spin_lock_irqsave(&rl_ctrl.lock, flags);
rl_ctrl.dev_active[dev->dev_no] = 1;
spin_unlock_irqrestore(&rl_ctrl.lock, flags);
if (!rl_ctrl.started) {
rl_ctrl.started = 1;
rl_ctrl.timer.expires = jiffies + HZ / rl_ctrl.rx_ticks;
add_timer(&rl_ctrl.timer);
}
}
void
ngknet_rx_rate_limit_stop(struct ngknet_dev *dev)
{
unsigned long flags;
spin_lock_irqsave(&rl_ctrl.lock, flags);
rl_ctrl.dev_active[dev->dev_no] = 0;
spin_unlock_irqrestore(&rl_ctrl.lock, flags);
}
void
ngknet_rx_rate_limit(struct ngknet_dev *dev, int limit)
{
unsigned long flags;
spin_lock_irqsave(&rl_ctrl.lock, flags);
if ((++rl_ctrl.rx_pkts + rl_ctrl.rx_overruns > limit / rl_ctrl.rx_ticks) &&
!rl_ctrl.dev_paused[dev->dev_no] && rl_ctrl.dev_active[dev->dev_no]) {
rl_ctrl.dev_paused[dev->dev_no] = 1;
rl_ctrl.rx_overruns = 0;
bcmcnet_pdma_dev_rx_suspend(&dev->pdma_dev);
}
if (rl_ctrl.dev_paused[dev->dev_no]) {
rl_ctrl.rx_overruns++;
}
spin_unlock_irqrestore(&rl_ctrl.lock, flags);
}
void
ngknet_tx_queue_schedule(struct ngknet_dev *dev, struct sk_buff *skb, int *queue)
{
struct pkt_buf *pkb = (struct pkt_buf *)skb->data;
if (pkb->pkh.attrs & PDMA_TX_BIND_QUE) {
*queue = pkb->pkh.queue_id;
}
}

View File

@ -0,0 +1,218 @@
/*! \file ngknet_extra.h
*
* Generic data structure definitions for NGKNET enhancement.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef NGKNET_EXTRA_H
#define NGKNET_EXTRA_H
/*!
* \brief Filter control.
*/
struct filt_ctrl {
/*! List head */
struct list_head list;
/*! Device number */
int dev_no;
/*! Number of hits */
uint64_t hits;
/*! Filter description */
ngknet_filter_t filt;
};
/*!
* \brief Create filter.
*
* \param [in] dev Device structure point.
* \param [in] filter Filter structure point.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
ngknet_filter_create(struct ngknet_dev *dev, ngknet_filter_t *filter);
/*!
* \brief Destroy filter.
*
* \param [in] dev Device structure point.
* \param [in] id Filter ID.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
ngknet_filter_destroy(struct ngknet_dev *dev, int id);
/*!
* \brief Destroy all the filters.
*
* \param [in] dev Device structure point.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
ngknet_filter_destroy_all(struct ngknet_dev *dev);
/*!
* \brief Get filter.
*
* \param [in] dev Device structure point.
* \param [in] id Filter ID.
* \param [out] filter Filter structure point.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
ngknet_filter_get(struct ngknet_dev *dev, int id, ngknet_filter_t *filter);
/*!
* \brief Get the next filter.
*
* \param [in] dev Device structure point.
* \param [out] filter Filter structure point.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
ngknet_filter_get_next(struct ngknet_dev *dev, ngknet_filter_t *filter);
/*!
* \brief Filter packet.
*
* \param [in] dev Device structure point.
* \param [in] skb Rx packet SKB.
* \param [out] mndev Mirror network interface.
* \param [out] mskb Mirror Rx packet SKB.
*
* \retval Matched network interface.
* \retval NULL No matched network interface.
*/
extern int
ngknet_rx_pkt_filter(struct ngknet_dev *dev, struct sk_buff *skb, struct net_device **ndev,
struct net_device **mndev, struct sk_buff **mskb);
/*!
* \brief Rx rate limit control.
*
* This contains all the control information for Rx rate limit such as
* the number of Rx packets, status related to Rx rate limit, etc.
*
* The rate limit is kernel-oriented, i.e. all the Rx packets from any
* device/channel will be accounted for. Once the received packets reach
* the limit value in an 1-Sec interval, the driver API XXXX_rx_suspend()
* will be called to suspend Rx. The 1-Sec basis timer will call the driver
* API XXXX_rx_resume() to resume Rx and reset rate-related status/counters
* at the begin of the next 1-Sec interval.
*
* The NGKNET module parameter 'rx_rate_limit' is used to decide the maximum
* Rx rate. Disable Rx rate limit if set 0. It can be set when inserting
* NGKNET module or modified using its SYSFS attributions.
*/
struct ngknet_rl_ctrl {
/*! Rx packets */
int rx_pkts;
/*! Rx overruns */
int rx_overruns;
/*! Rx ticks */
int rx_ticks;
/*! Active devices under rate control */
int dev_active[NUM_PDMA_DEV_MAX];
/*! Paused devices due to no Rx credit */
int dev_paused[NUM_PDMA_DEV_MAX];
/*! Rate limit timer */
struct timer_list timer;
/*! Rate limit lock */
spinlock_t lock;
/*! Devices */
struct ngknet_dev *devs;
/*! Rate limit status indicator */
int started;
};
/*!
* \brief Initialize Rx rate limit.
*
* \param [in] devs Devices array.
*/
extern void
ngknet_rx_rate_limit_init(struct ngknet_dev *devs);
/*!
* \brief Cleanup Rx rate limit.
*/
extern void
ngknet_rx_rate_limit_cleanup(void);
/*!
* \brief Get Rx rate limit state.
*/
extern int
ngknet_rx_rate_limit_started(void);
/*!
* \brief Start Rx rate limit.
*
* \param [in] dev Device structure point.
*/
extern void
ngknet_rx_rate_limit_start(struct ngknet_dev *dev);
/*!
* \brief Stop Rx rate limit.
*
* \param [in] dev Device structure point.
*/
extern void
ngknet_rx_rate_limit_stop(struct ngknet_dev *dev);
/*!
* \brief Limit Rx rate.
*
* \param [in] dev Device structure point.
*/
extern void
ngknet_rx_rate_limit(struct ngknet_dev *dev, int limit);
/*!
* \brief Schedule Tx queue.
*
* \param [in] dev Device structure point.
* \param [in] queue Tx queue number.
*/
extern void
ngknet_tx_queue_schedule(struct ngknet_dev *dev, struct sk_buff *skb, int *queue);
#endif /* NGKNET_EXTRA_H */

View File

@ -0,0 +1,173 @@
/*! \file ngknet_linux.c
*
* Utility routines for Linux kernel APIs abstraction.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <linux/kconfig.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include "ngknet_linux.h"
/*!
* Time
*/
unsigned long
sal_time_usecs(void)
{
struct timeval tv;
kal_time_val_get(&tv);
return tv.tv_sec * 1000000 + tv.tv_usec;
}
void
sal_usleep(unsigned long usec)
{
unsigned long then, now, hz;
hz = usec * HZ / 1000000;
if (hz) {
schedule_timeout(hz);
}
usec = usec * HZ % 1000000 / HZ;
if (usec) {
then = sal_time_usecs();
do {
schedule();
now = sal_time_usecs();
} while (now > then && (now - then) < usec);
}
}
/*!
* Synchronization
*/
typedef struct {
struct semaphore sem;
char *desc;
int binary;
} sem_ctrl_t;
sal_sem_t
sal_sem_create(char *desc, int binary, int count)
{
sem_ctrl_t *sc = kmalloc(sizeof(*sc), GFP_KERNEL);
if (sc != NULL) {
sema_init(&sc->sem, count);
sc->desc = desc;
sc->binary = binary;
}
return (sal_sem_t)sc;
}
void
sal_sem_destroy(sal_sem_t sem)
{
sem_ctrl_t *sc = (sem_ctrl_t *)sem;
kfree(sc);
}
int
sal_sem_take(sal_sem_t sem, int usec)
{
sem_ctrl_t *sc = (sem_ctrl_t *)sem;
int rv;
if (usec == SAL_SEM_FOREVER) {
do {
rv = down_interruptible(&sc->sem);
} while (rv == -EINTR);
return rv ? -1 : 0;
}
return -1;
}
int
sal_sem_give(sal_sem_t sem)
{
sem_ctrl_t *sc = (sem_ctrl_t *)sem;
up(&sc->sem);
return 0;
}
typedef struct spinlock_ctrl_s {
spinlock_t spinlock;
unsigned long flags;
char *desc;
} *spinlock_ctrl_t;
sal_spinlock_t
sal_spinlock_create(char *desc)
{
spinlock_ctrl_t sl = kmalloc(sizeof(*sl), GFP_KERNEL);
if (sl != NULL) {
spin_lock_init(&sl->spinlock);
sl->flags = 0;
sl->desc = desc;
}
return (sal_spinlock_t)sl;
}
void
sal_spinlock_destroy(sal_spinlock_t lock)
{
spinlock_ctrl_t sl = (spinlock_ctrl_t)lock;
kfree(sl);
}
int
sal_spinlock_lock(sal_spinlock_t lock)
{
spinlock_ctrl_t sl = (spinlock_ctrl_t)lock;
spin_lock_irqsave(&sl->spinlock, sl->flags);
return 0;
}
int
sal_spinlock_unlock(sal_spinlock_t lock)
{
spinlock_ctrl_t sl = (spinlock_ctrl_t)lock;
spin_unlock_irqrestore(&sl->spinlock, sl->flags);
return 0;
}

View File

@ -0,0 +1,240 @@
/*! \file ngknet_linux.h
*
* Data structure and macro definitions for Linux kernel APIs abstraction.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef NGKNET_LINUX_H
#define NGKNET_LINUX_H
#include <linux/version.h>
#include <linux/skbuff.h>
#include <linux/kthread.h>
#include <linux/netdevice.h>
/*!
* Kernel abstraction
*/
#define MODULE_PARAM(n, t, p) module_param(n, t, p)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
#define kal_vlan_hwaccel_put_tag(skb, proto, tci) \
__vlan_hwaccel_put_tag(skb, tci)
#define NETIF_F_HW_VLAN_CTAG_RX NETIF_F_HW_VLAN_RX
#define NETIF_F_HW_VLAN_CTAG_TX NETIF_F_HW_VLAN_TX
#else
#define kal_vlan_hwaccel_put_tag(skb, proto, tci) \
__vlan_hwaccel_put_tag(skb, htons(proto), tci)
#endif /* KERNEL_VERSION(3,10,0) */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)
static inline int
kal_support_paged_skb(void)
{
return false;
}
#else
static inline int
kal_support_paged_skb(void)
{
return true;
}
#endif /* KERNEL_VERSION(3,6,0) */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)
static inline struct page *
kal_dev_alloc_page(void)
{
return NULL;
}
#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
static inline struct page *
kal_dev_alloc_page(void)
{
return alloc_pages(GFP_ATOMIC | __GFP_ZERO | __GFP_COLD |
__GFP_COMP | __GFP_MEMALLOC, 0);
}
#else
static inline struct page *
kal_dev_alloc_page(void)
{
return dev_alloc_page();
}
#endif /* KERNEL_VERSION(3,6,0) */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)
static inline struct sk_buff *
kal_build_skb(void *data, unsigned int frag_size)
{
return NULL;
}
#else
static inline struct sk_buff *
kal_build_skb(void *data, unsigned int frag_size)
{
return build_skb(data, frag_size);
}
#endif /* KERNEL_VERSION(3,6,0) */
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)
static inline void
kal_netif_trans_update(struct net_device *dev)
{
dev->trans_start = jiffies;
}
#else
static inline void
kal_netif_trans_update(struct net_device *dev)
{
netif_trans_update(dev);
}
#endif /* KERNEL_VERSION(4,7,0) */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0)
static inline void
kal_time_val_get(struct timeval *tv)
{
do_gettimeofday(tv);
}
#else
static inline void
kal_time_val_get(struct timeval *tv)
{
struct timespec64 ts;
ktime_get_real_ts64(&ts);
tv->tv_sec = ts.tv_sec;
tv->tv_usec = ts.tv_nsec / 1000;
}
#endif /* KERNEL_VERSION(3,17,0) */
static inline unsigned long
kal_copy_from_user(void *to, const void __user *from,
unsigned int dl, unsigned int sl)
{
unsigned int len = dl;
if (unlikely(len != sl)) {
printk(KERN_WARNING "Unmatched linux_ngknet.ko, please use the latest.\n");
len = min(dl, sl);
}
return copy_from_user(to, from, len);
}
static inline unsigned long
kal_copy_to_user(void __user *to, const void *from,
unsigned int dl, unsigned int sl)
{
unsigned int len = dl;
if (unlikely(len != sl)) {
printk(KERN_WARNING "Unmatched linux_ngknet.ko, please use the latest.\n");
len = min(dl, sl);
}
return copy_to_user(to, from, len);
}
/*!
* System abstraction
*/
static inline void *
sal_alloc(unsigned int sz, char *s)
{
return kmalloc(sz, GFP_KERNEL);
}
static inline void
sal_free(void *addr)
{
kfree(addr);
}
static inline void *
sal_memset(void *dest, int c, size_t cnt)
{
return memset(dest, c, cnt);
}
static inline void *
sal_memcpy(void *dest, const void *src, size_t cnt)
{
return memcpy(dest, src, cnt);
}
static inline char *
sal_strncpy(char *dest, const char *src, size_t cnt)
{
return strncpy(dest, src, cnt);
}
/*!
* Time
*/
extern unsigned long
sal_time_usecs(void);
extern void
sal_usleep(unsigned long usec);
/*!
* Synchronization
*/
typedef struct sal_sem_s {
char semaphore_opaque_type;
} *sal_sem_t;
typedef struct sal_spinlock_s {
char spinlock_opaque_type;
} *sal_spinlock_t;
#define SAL_SEM_FOREVER -1
#define SAL_SEM_BINARY 1
#define SAL_SEM_COUNTING 0
extern sal_sem_t
sal_sem_create(char *desc, int binary, int count);
extern void
sal_sem_destroy(sal_sem_t sem);
extern int
sal_sem_take(sal_sem_t sem, int usec);
extern int
sal_sem_give(sal_sem_t sem);
extern sal_spinlock_t
sal_spinlock_create(char *desc);
extern void
sal_spinlock_destroy(sal_spinlock_t lock);
extern int
sal_spinlock_lock(sal_spinlock_t lock);
extern int
sal_spinlock_unlock(sal_spinlock_t lock);
#endif /* NGKNET_LINUX_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,278 @@
/*! \file ngknet_main.h
*
* Data structure and macro definitions for NGKNET kernel module.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef NGKNET_MAIN_H
#define NGKNET_MAIN_H
#include <linux/netdevice.h>
#include <lkm/lkm.h>
#include <lkm/ngknet_dev.h>
#include <bcmcnet/bcmcnet_core.h>
/*! Maximum number of PDMA devices supported */
#ifdef NGBDE_NUM_SWDEV_MAX
#define NUM_PDMA_DEV_MAX NGBDE_NUM_SWDEV_MAX
#else
#define NUM_PDMA_DEV_MAX 16
#endif
/*!
* Debug levels
*/
#define DBG_LVL_VERB 0x0001
#define DBG_LVL_PKT 0x0002
#define DBG_LVL_CMD 0x0004
#define DBG_LVL_IRQ 0x0008
#define DBG_LVL_NAPI 0x0010
#define DBG_LVL_NDEV 0x0020
#define DBG_LVL_FILT 0x0040
#define DBG_LVL_RCPU 0x0080
#define DBG_LVL_WARN 0x0100
#define DBG_LVL_PDMP 0x0200
#define DBG_LVL_RATE 0x0400
#define DBG_LVL_LINK 0x0800
#define DBG_VERB(_s) do { if (debug & DBG_LVL_VERB) printk _s; } while (0)
#define DBG_PKT(_s) do { if (debug & DBG_LVL_PKT) printk _s; } while (0)
#define DBG_CMD(_s) do { if (debug & DBG_LVL_CMD) printk _s; } while (0)
#define DBG_IRQ(_s) do { if (debug & DBG_LVL_IRQ) printk _s; } while (0)
#define DBG_NAPI(_s) do { if (debug & DBG_LVL_NAPI) printk _s; } while (0)
#define DBG_NDEV(_s) do { if (debug & DBG_LVL_NDEV) printk _s; } while (0)
#define DBG_FILT(_s) do { if (debug & DBG_LVL_FILT) printk _s; } while (0)
#define DBG_RCPU(_s) do { if (debug & DBG_LVL_RCPU) printk _s; } while (0)
#define DBG_WARN(_s) do { if (debug & DBG_LVL_WARN) printk _s; } while (0)
#define DBG_PDMP(_s) do { if (debug & DBG_LVL_PDMP) printk _s; } while (0)
#define DBG_RATE(_s) do { if (debug & DBG_LVL_RATE) printk _s; } while (0)
#define DBG_LINK(_s) do { if (debug & DBG_LVL_LINK) printk _s; } while (0)
/*!
* Device description
*/
struct ngknet_dev {
/*! Base address for PCI register access */
volatile void *base_addr;
/*! Required for DMA memory control */
struct device *dev;
/*! Required for PCI memory control */
struct pci_dev *pci_dev;
/*! Base network device */
struct net_device *net_dev;
/*! PDMA device */
struct pdma_dev pdma_dev;
/*! Device number (from BDE) */
int dev_no;
/*! Vitual network devices, 0 is reserved */
struct net_device *vdev[NUM_VDEV_MAX + 1];
/*! Vitual network devices bound to queue */
struct net_device *bdev[NUM_QUE_MAX];
/*! Filter list */
struct list_head filt_list;
/*! Filter control, 0 is reserved */
void *fc[NUM_FILTER_MAX + 1];
/*! Callback control */
struct ngknet_callback_ctrl *cbc;
/*! RCPU control */
struct ngknet_rcpu_hdr rcpu_ctrl;
/*! NGKNET lock */
spinlock_t lock;
/*! NGKNET wait queue */
wait_queue_head_t wq;
/*! VNET wait queue */
wait_queue_head_t vnet_wq;
/*! VNET is active */
atomic_t vnet_active;
/*! HNET wait queue */
wait_queue_head_t hnet_wq;
/*! HNET is active */
atomic_t hnet_active;
/*! HNET deamon */
struct task_struct *hnet_task;
/*! HNET work */
struct work_struct hnet_work;
/*! PTP Tx queue */
struct sk_buff_head ptp_tx_queue;
/*! PTP Tx work */
struct work_struct ptp_tx_work;
/*! Flags */
int flags;
/*! NGKNET device is active */
#define NGKNET_DEV_ACTIVE (1 << 0)
};
/*!
* Network interface specific private data
*/
struct ngknet_private {
/*! Network device */
struct net_device *net_dev;
/*! Network stats */
struct net_device_stats stats;
/*! NGKNET device */
struct ngknet_dev *bkn_dev;
/*! Network interface ID */
int id;
/*! Network interface type */
int type;
/*! Network interface flags */
uint32_t flags;
/*! Network interface vlan */
uint32_t vlan;
/*! Network interface bound to */
uint32_t chan;
/*! Metadata offset from Ethernet header */
uint32_t meta_off;
/*! Metadata length */
uint32_t meta_len;
/*! Metadata used to send packets to physical port */
uint8_t meta_data[NGKNET_NETIF_META_MAX];
/*! User data gotten back through callbacks */
uint8_t user_data[NGKNET_NETIF_USER_DATA];
/*! Users of this network interface */
int users;
/*! Wait for this network interface free */
int wait;
/*! HW timestamp Rx filter */
int hwts_rx_filter;
/*! HW timestamp Tx type */
int hwts_tx_type;
};
/*!
* \brief Create network interface.
*
* \param [in] dev NGKNET device structure point.
* \param [in] netif Network interface structure point.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
ngknet_netif_create(struct ngknet_dev *dev, ngknet_netif_t *netif);
/*!
* \brief Destroy network interface.
*
* \param [in] dev NGKNET device structure point.
* \param [in] id Network interface ID.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
ngknet_netif_destroy(struct ngknet_dev *dev, int id);
/*!
* \brief Get network interface.
*
* \param [in] dev NGKNET device structure point.
* \param [in] id Network interface ID.
* \param [out] netif Network interface structure point.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
ngknet_netif_get(struct ngknet_dev *dev, int id, ngknet_netif_t *netif);
/*!
* \brief Get the next network interface.
*
* \param [in] dev NGKNET device structure point.
* \param [out] netif Network interface structure point.
*
* \retval SHR_E_NONE No errors.
* \retval SHR_E_XXXX Operation failed.
*/
extern int
ngknet_netif_get_next(struct ngknet_dev *dev, ngknet_netif_t *netif);
/*!
* \brief Get debug level.
*
* \retval Current debug level.
*/
extern int
ngknet_debug_level_get(void);
/*!
* \brief Set debug level.
*
* \param [in] debug_level Debug level to be set.
*/
extern void
ngknet_debug_level_set(int debug_level);
/*!
* \brief Get Rx rate limit.
*
* \retval Current Rx rate limit.
*/
extern int
ngknet_rx_rate_limit_get(void);
/*!
* \brief Set Rx rate limit.
*
* \param [in] rate_limit Rx rate limit to be set.
*/
extern void
ngknet_rx_rate_limit_set(int rate_limit);
#endif /* NGKNET_MAIN_H */

View File

@ -0,0 +1,655 @@
/*! \file ngknet_procfs.c
*
* <description>
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <lkm/lkm.h>
#include <lkm/ngknet_ioctl.h>
#include "ngknet_main.h"
#include "ngknet_extra.h"
extern struct ngknet_dev ngknet_devices[];
static struct proc_dir_entry *proc_root = NULL;
static void
proc_data_show(struct seq_file *m, const unsigned char *buf, size_t len)
{
uint32_t i;
if (!buf || !len) {
seq_printf(m, "\n");
return;
}
for (i = 0; i < len; i++) {
seq_printf(m, "%02x ", buf[i]);
if ((i + 1) % 32 == 0 || (i + 1) == len) {
seq_printf(m, "\n");
if ((i + 1) < len) {
seq_printf(m, " ");
}
}
}
}
static int
proc_debug_level_show(struct seq_file *m, void *v)
{
seq_printf(m, "Debug level: 0x%x\n", ngknet_debug_level_get());
return 0;
}
static int
proc_debug_level_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_debug_level_show, NULL);
}
static ssize_t
proc_debug_level_write(struct file *file, const char *buf,
size_t count, loff_t *loff)
{
char level_str[11] = {0};
int debug_level;
if (copy_from_user(level_str, buf, sizeof(level_str) - 1)) {
return -EFAULT;
}
debug_level = simple_strtol(level_str, NULL, 16);
ngknet_debug_level_set(debug_level);
printk("Debug level set to: 0x%x\n", debug_level);
return count;
}
static int
proc_debug_level_release(struct inode *inode, struct file *file)
{
return single_release(inode, file);
}
static struct file_operations proc_debug_level_fops = {
owner: THIS_MODULE,
open: proc_debug_level_open,
read: seq_read,
write: proc_debug_level_write,
llseek: seq_lseek,
release: proc_debug_level_release,
};
static int
proc_device_info_show(struct seq_file *m, void *v)
{
struct ngknet_dev *dev;
struct bcmcnet_dev_info *info;
int di, qi, ai = 0;
int rv;
for (di = 0; di < NUM_PDMA_DEV_MAX; di++) {
dev = &ngknet_devices[di];
if (!(dev->flags & NGKNET_DEV_ACTIVE)) {
continue;
}
ai++;
rv = bcmcnet_pdma_dev_info_get(&dev->pdma_dev);
if (SHR_FAILURE(rv)) {
printk("ngknet: get device%d info failed\n", di);
break;
}
info = &dev->pdma_dev.info;
seq_printf(m, "dev_no: %d\n", di);
seq_printf(m, "dev_name: %s\n", info->dev_name);
seq_printf(m, "dev_id: 0x%x\n", info->dev_id);
seq_printf(m, "dev_type: %d\n", info->dev_type);
seq_printf(m, "max_groups: %d\n", info->max_groups);
seq_printf(m, "max_queues: %d\n", info->max_queues);
seq_printf(m, "bm_groups: 0x%x\n", info->bm_groups);
seq_printf(m, "bm_rx_queues: 0x%x\n", info->bm_rx_queues);
seq_printf(m, "bm_tx_queues: 0x%x\n", info->bm_tx_queues);
seq_printf(m, "nb_groups: %d\n", info->nb_groups);
seq_printf(m, "nb_rx_queues: %d\n", info->nb_rx_queues);
seq_printf(m, "nb_tx_queues: %d\n", info->nb_tx_queues);
seq_printf(m, "rx_desc_size: %d\n", info->rx_desc_size);
seq_printf(m, "tx_desc_size: %d\n", info->tx_desc_size);
seq_printf(m, "rx_ph_size: %d\n", info->rx_ph_size);
seq_printf(m, "tx_ph_size: %d\n", info->tx_ph_size);
for (qi = 0; qi < info->nb_rx_queues; qi++) {
seq_printf(m, "rx_buf_sz[%d]: %d\n", qi, info->rx_buf_size[qi]);
}
for (qi = 0; qi < info->nb_rx_queues; qi++) {
seq_printf(m, "nb_rx_desc[%d]: %d\n", qi, info->nb_rx_desc[qi]);
}
for (qi = 0; qi < info->nb_tx_queues; qi++) {
seq_printf(m, "nb_tx_desc[%d]: %d\n", qi, info->nb_tx_desc[qi]);
}
}
if (!ai) {
seq_printf(m, "%s\n", "No active device");
} else {
seq_printf(m, "------------------------\n");
seq_printf(m, "Total %d devices\n", ai);
}
return 0;
}
static int
proc_device_info_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_device_info_show, NULL);
}
static int
proc_device_info_release(struct inode *inode, struct file *file)
{
return single_release(inode, file);
}
static struct file_operations proc_device_info_fops = {
owner: THIS_MODULE,
open: proc_device_info_open,
read: seq_read,
llseek: seq_lseek,
release: proc_device_info_release,
};
static int
proc_filter_info_show(struct seq_file *m, void *v)
{
struct ngknet_dev *dev;
ngknet_filter_t filt = {0};
int di, dn = 0, fn = 0;
int rv;
for (di = 0; di < NUM_PDMA_DEV_MAX; di++) {
dev = &ngknet_devices[di];
if (!(dev->flags & NGKNET_DEV_ACTIVE)) {
continue;
}
dn++;
do {
rv = ngknet_filter_get_next(dev, &filt);
if (SHR_FAILURE(rv)) {
printk("ngknet: get device%d filter failed\n", di);
break;
}
fn++;
seq_printf(m, "\n");
seq_printf(m, "dev_no: %d\n", di);
seq_printf(m, "id: %d\n", filt.id);
seq_printf(m, "next: %d\n", filt.next);
seq_printf(m, "type: %d\n", filt.type);
seq_printf(m, "flags: 0x%x\n", filt.flags);
seq_printf(m, "prio: %d\n", filt.priority);
seq_printf(m, "chan: %d\n", filt.chan);
seq_printf(m, "desc: %s\n", filt.desc);
seq_printf(m, "dest_type: %d\n", filt.dest_type);
seq_printf(m, "dest_id: %d\n", filt.dest_id);
seq_printf(m, "dest_proto: 0x%x\n", filt.dest_proto);
seq_printf(m, "mirror_type: %d\n", filt.mirror_type);
seq_printf(m, "mirror_id: %d\n", filt.mirror_id);
seq_printf(m, "mirror_proto: 0x%x\n", filt.mirror_proto);
seq_printf(m, "oob_offset: %d\n", filt.oob_data_offset);
seq_printf(m, "oob_size: %d\n", filt.oob_data_size);
seq_printf(m, "pkt_offset: %d\n", filt.pkt_data_offset);
seq_printf(m, "pkt_size: %d\n", filt.pkt_data_size);
seq_printf(m, "filt_data: ");
proc_data_show(m, filt.data.b, filt.oob_data_size + filt.pkt_data_size);
seq_printf(m, "filt_mask: ");
proc_data_show(m, filt.mask.b, filt.oob_data_size + filt.pkt_data_size);
seq_printf(m, "user_data: ");
proc_data_show(m, filt.user_data, NGKNET_FILTER_USER_DATA);
seq_printf(m, "hits: %llu\n", ((struct filt_ctrl *)dev->fc[filt.id])->hits);
} while (filt.next);
}
if (!dn) {
seq_printf(m, "%s\n", "No active device");
} else {
seq_printf(m, "--------------------------------\n");
seq_printf(m, "Total %d devices, %d filters\n", dn, fn);
}
return 0;
}
static int
proc_filter_info_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_filter_info_show, NULL);
}
static int
proc_filter_info_release(struct inode *inode, struct file *file)
{
return single_release(inode, file);
}
static struct file_operations proc_filter_info_fops = {
owner: THIS_MODULE,
open: proc_filter_info_open,
read: seq_read,
llseek: seq_lseek,
release: proc_filter_info_release,
};
static int
proc_netif_info_show(struct seq_file *m, void *v)
{
struct ngknet_dev *dev;
struct net_device *ndev;
struct ngknet_private *priv;
ngknet_netif_t netif = {0};
int di, ma, dn = 0, nn = 0;
int rv;
for (di = 0; di < NUM_PDMA_DEV_MAX; di++) {
dev = &ngknet_devices[di];
if (!(dev->flags & NGKNET_DEV_ACTIVE)) {
continue;
}
dn++;
do {
rv = ngknet_netif_get_next(dev, &netif);
if (SHR_FAILURE(rv)) {
printk("ngknet: get device%d netif failed\n", di);
break;
}
nn++;
ndev = netif.id == 0 ? dev->net_dev : dev->vdev[netif.id];
priv = netdev_priv(ndev);
seq_printf(m, "\n");
seq_printf(m, "dev_no: %d\n", di);
seq_printf(m, "id: %d\n", netif.id);
seq_printf(m, "next: %d\n", netif.next);
seq_printf(m, "type: %d\n", netif.type);
seq_printf(m, "flags: 0x%x\n", netif.flags);
seq_printf(m, "vlan: %d\n", netif.vlan);
seq_printf(m, "mac: ");
for (ma = 0; ma < 6; ma++) {
if (ma == 5) {
seq_printf(m, "%02x\n", netif.macaddr[ma]);
} else {
seq_printf(m, "%02x:", netif.macaddr[ma]);
}
}
seq_printf(m, "mtu: %d\n", netif.mtu);
seq_printf(m, "chan: %d\n", netif.chan);
seq_printf(m, "name: %s\n", netif.name);
seq_printf(m, "meta_off: %d\n", netif.meta_off);
seq_printf(m, "meta_len: %d\n", netif.meta_len);
seq_printf(m, "meta_data: ");
proc_data_show(m, netif.meta_data, netif.meta_len);
seq_printf(m, "user_data: ");
proc_data_show(m, netif.user_data, NGKNET_NETIF_USER_DATA);
seq_printf(m, "rx_packets: %lu\n", priv->stats.rx_packets);
seq_printf(m, "rx_bytes: %lu\n", priv->stats.rx_bytes);
seq_printf(m, "rx_dropped: %lu\n", priv->stats.rx_dropped);
seq_printf(m, "rx_errors: %lu\n", priv->stats.rx_errors);
seq_printf(m, "tx_packets: %lu\n", priv->stats.tx_packets);
seq_printf(m, "tx_bytes: %lu\n", priv->stats.tx_bytes);
seq_printf(m, "tx_dropped: %lu\n", priv->stats.tx_dropped);
seq_printf(m, "tx_errors: %lu\n", priv->stats.tx_errors);
} while (netif.next);
}
if (!dn) {
seq_printf(m, "%s\n", "No active device");
} else {
seq_printf(m, "--------------------------------\n");
seq_printf(m, "Total %d devices, %d netifs\n", dn, nn);
}
return 0;
}
static int
proc_netif_info_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_netif_info_show, NULL);
}
static int
proc_netif_info_release(struct inode *inode, struct file *file)
{
return single_release(inode, file);
}
static struct file_operations proc_netif_info_fops = {
owner: THIS_MODULE,
open: proc_netif_info_open,
read: seq_read,
llseek: seq_lseek,
release: proc_netif_info_release,
};
static int
proc_pkt_stats_show(struct seq_file *m, void *v)
{
struct ngknet_dev *dev;
struct bcmcnet_dev_stats *stats;
int di, qi, ai = 0;
int rv;
for (di = 0; di < NUM_PDMA_DEV_MAX; di++) {
dev = &ngknet_devices[di];
if (!(dev->flags & NGKNET_DEV_ACTIVE)) {
continue;
}
ai++;
rv = bcmcnet_pdma_dev_stats_get(&dev->pdma_dev);
if (SHR_FAILURE(rv)) {
printk("ngknet: get device%d stats failed\n", di);
break;
}
stats = &dev->pdma_dev.stats;
seq_printf(m, "rx_packets: %llu\n", (unsigned long long)stats->rx_packets);
seq_printf(m, "rx_bytes: %llu\n", (unsigned long long)stats->rx_bytes);
for (qi = 0; qi < dev->pdma_dev.ctrl.nb_rxq; qi++) {
seq_printf(m, "rx_packets[%d]: %llu\n", qi, (unsigned long long)stats->rxq_packets[qi]);
seq_printf(m, "rx_bytes[%d]: %llu\n", qi, (unsigned long long)stats->rxq_bytes[qi]);
}
seq_printf(m, "rx_dropped: %llu\n", (unsigned long long)stats->rx_dropped);
seq_printf(m, "rx_errors: %llu\n", (unsigned long long)stats->rx_errors);
seq_printf(m, "rx_nomems: %llu\n", (unsigned long long)stats->rx_nomems);
seq_printf(m, "tx_packets: %llu\n", (unsigned long long)stats->tx_packets);
seq_printf(m, "tx_bytes: %llu\n", (unsigned long long)stats->tx_bytes);
for (qi = 0; qi < dev->pdma_dev.ctrl.nb_txq; qi++) {
seq_printf(m, "tx_packets[%d]: %llu\n", qi, (unsigned long long)stats->txq_packets[qi]);
seq_printf(m, "tx_bytes[%d]: %llu\n", qi, (unsigned long long)stats->txq_bytes[qi]);
}
seq_printf(m, "tx_dropped: %llu\n", (unsigned long long)stats->tx_dropped);
seq_printf(m, "tx_errors: %llu\n", (unsigned long long)stats->tx_errors);
seq_printf(m, "tx_xoffs: %llu\n", (unsigned long long)stats->tx_xoffs);
seq_printf(m, "interrupts: %llu\n", (unsigned long long)stats->intrs);
}
if (!ai) {
seq_printf(m, "%s\n", "No active device");
} else {
seq_printf(m, "------------------------\n");
seq_printf(m, "Total %d devices\n", ai);
}
return 0;
}
static int
proc_pkt_stats_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_pkt_stats_show, NULL);
}
static int
proc_pkt_stats_release(struct inode *inode, struct file *file)
{
return single_release(inode, file);
}
static struct file_operations proc_pkt_stats_fops = {
owner: THIS_MODULE,
open: proc_pkt_stats_open,
read: seq_read,
llseek: seq_lseek,
release: proc_pkt_stats_release,
};
static int
proc_rate_limit_show(struct seq_file *m, void *v)
{
seq_printf(m, "Rx rate limit: %d pps\n", ngknet_rx_rate_limit_get());
return 0;
}
static int
proc_rate_limit_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_rate_limit_show, NULL);
}
static ssize_t
proc_rate_limit_write(struct file *file, const char *buf,
size_t count, loff_t *loff)
{
char limit_str[9] = {0};
int rate_limit;
if (copy_from_user(limit_str, buf, sizeof(limit_str) - 1)) {
return -EFAULT;
}
rate_limit = simple_strtol(limit_str, NULL, 10);
ngknet_rx_rate_limit_set(rate_limit);
printk("Rx rate limit set to: %d pps\n", rate_limit);
return count;
}
static int
proc_rate_limit_release(struct inode *inode, struct file *file)
{
return single_release(inode, file);
}
static struct file_operations proc_rate_limit_fops = {
owner: THIS_MODULE,
open: proc_rate_limit_open,
read: seq_read,
write: proc_rate_limit_write,
llseek: seq_lseek,
release: proc_rate_limit_release,
};
static int
proc_reg_status_show(struct seq_file *m, void *v)
{
struct ngknet_dev *dev;
int di, qi, ai = 0;
for (di = 0; di < NUM_PDMA_DEV_MAX; di++) {
dev = &ngknet_devices[di];
if (!(dev->flags & NGKNET_DEV_ACTIVE)) {
continue;
}
ai++;
for (qi = 0; qi < dev->pdma_dev.ctrl.nb_rxq; qi++) {
bcmcnet_pdma_rx_queue_reg_dump(&dev->pdma_dev, qi);
}
for (qi = 0; qi < dev->pdma_dev.ctrl.nb_txq; qi++) {
bcmcnet_pdma_tx_queue_reg_dump(&dev->pdma_dev, qi);
}
}
if (!ai) {
seq_printf(m, "%s\n", "No active device");
} else {
seq_printf(m, "------------------------\n");
seq_printf(m, "Total %d devices\n", ai);
}
return 0;
}
static int
proc_reg_status_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_reg_status_show, NULL);
}
static int
proc_reg_status_release(struct inode *inode, struct file *file)
{
return single_release(inode, file);
}
static struct file_operations proc_reg_status_fops = {
owner: THIS_MODULE,
open: proc_reg_status_open,
read: seq_read,
llseek: seq_lseek,
release: proc_reg_status_release,
};
static int
proc_ring_status_show(struct seq_file *m, void *v)
{
struct ngknet_dev *dev;
int di, qi, ai = 0;
for (di = 0; di < NUM_PDMA_DEV_MAX; di++) {
dev = &ngknet_devices[di];
if (!(dev->flags & NGKNET_DEV_ACTIVE)) {
continue;
}
ai++;
seq_printf(m, "%s-%d, ", "Unit", di);
for (qi = 0; qi < dev->pdma_dev.ctrl.nb_rxq; qi++) {
bcmcnet_pdma_rx_ring_dump(&dev->pdma_dev, qi);
}
seq_printf(m, "%s%d, ", "Rx queues: ", qi);
for (qi = 0; qi < dev->pdma_dev.ctrl.nb_txq; qi++) {
bcmcnet_pdma_tx_ring_dump(&dev->pdma_dev, qi);
}
seq_printf(m, "%s%d. ", "Tx queues: ", qi);
seq_printf(m, "\n");
}
if (!ai) {
seq_printf(m, "%s\n", "No active device");
} else {
seq_printf(m, "------------------------\n");
seq_printf(m, "Total %d devices\n", ai);
}
return 0;
}
static int
proc_ring_status_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_ring_status_show, NULL);
}
static int
proc_ring_status_release(struct inode *inode, struct file *file)
{
return single_release(inode, file);
}
static struct file_operations proc_ring_status_fops = {
owner: THIS_MODULE,
open: proc_ring_status_open,
read: seq_read,
llseek: seq_lseek,
release: proc_ring_status_release,
};
int
ngknet_procfs_init(void)
{
struct proc_dir_entry *entry = NULL;
proc_root = proc_mkdir(NGKNET_MODULE_NAME, NULL);
if (proc_root == NULL) {
printk(KERN_ERR "ngknet: proc_mkdir failed\n");
return -1;
}
PROC_CREATE(entry, "debug_level", 0666, proc_root, &proc_debug_level_fops);
if (entry == NULL) {
printk(KERN_ERR "ngknet: proc_create failed\n");
return -1;
}
PROC_CREATE(entry, "device_info", 0444, proc_root, &proc_device_info_fops);
if (entry == NULL) {
printk(KERN_ERR "ngknet: proc_create failed\n");
return -1;
}
PROC_CREATE(entry, "filter_info", 0444, proc_root, &proc_filter_info_fops);
if (entry == NULL) {
printk(KERN_ERR "ngknet: proc_create failed\n");
return -1;
}
PROC_CREATE(entry, "netif_info", 0444, proc_root, &proc_netif_info_fops);
if (entry == NULL) {
printk(KERN_ERR "ngknet: proc_create failed\n");
return -1;
}
PROC_CREATE(entry, "pkt_stats", 0444, proc_root, &proc_pkt_stats_fops);
if (entry == NULL) {
printk(KERN_ERR "ngknet: proc_create failed\n");
return -1;
}
PROC_CREATE(entry, "rate_limit", 0666, proc_root, &proc_rate_limit_fops);
if (entry == NULL) {
printk(KERN_ERR "ngknet: proc_create failed\n");
return -1;
}
PROC_CREATE(entry, "reg_status", 0444, proc_root, &proc_reg_status_fops);
if (entry == NULL) {
printk(KERN_ERR "ngknet: proc_create failed\n");
return -1;
}
PROC_CREATE(entry, "ring_status", 0444, proc_root, &proc_ring_status_fops);
if (entry == NULL) {
printk(KERN_ERR "ngknet: proc_create failed\n");
return -1;
}
return 0;
}
int
ngknet_procfs_cleanup(void)
{
remove_proc_entry("debug_level", proc_root);
remove_proc_entry("device_info", proc_root);
remove_proc_entry("filter_info", proc_root);
remove_proc_entry("netif_info", proc_root);
remove_proc_entry("pkt_stats", proc_root);
remove_proc_entry("rate_limit", proc_root);
remove_proc_entry("reg_status", proc_root);
remove_proc_entry("ring_status", proc_root);
remove_proc_entry(NGKNET_MODULE_NAME, NULL);
return 0;
}

View File

@ -0,0 +1,47 @@
/*! \file ngknet_procfs.h
*
* Procfs-related definitions and APIs for NGKNET module.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef NGKNET_PROCFS_H
#define NGKNET_PROCFS_H
/*!
* \brief Initialize procfs for KNET driver.
*
* Create procfs read/write interfaces.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngknet_procfs_init(void);
/*!
* \brief Clean up procfs for KNET driver.
*
* Clean up resources allocated by \ref ngknet_procfs_init.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngknet_procfs_cleanup(void);
#endif /* NGKNET_PROCFS_H */

View File

@ -0,0 +1,194 @@
/*! \file ngknet_ptp.c
*
* Utility routines for PTP.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include "ngknet_callback.h"
#include "ngknet_ptp.h"
int
ngknet_ptp_rx_config_set(struct net_device *ndev, int *filter)
{
struct ngknet_private *priv = netdev_priv(ndev);
struct ngknet_dev *dev = priv->bkn_dev;
if (!dev->cbc->ptp_rx_config_set_cb) {
return SHR_E_UNAVAIL;
}
/*
* The expected Rx filter value is passed to the callback. The callback
* should pass back the actual filter value by the paramter <filter>.
* The callback can use priv->user_data to get other private parameters
* such as phys_port, dev_type, etc, which should be introduced when the
* netif is created.
*/
return dev->cbc->ptp_rx_config_set_cb(priv, filter);
}
int
ngknet_ptp_tx_config_set(struct net_device *ndev, int type)
{
struct ngknet_private *priv = netdev_priv(ndev);
struct ngknet_dev *dev = priv->bkn_dev;
if (!dev->cbc->ptp_tx_config_set_cb) {
return SHR_E_UNAVAIL;
}
/*
* The Tx type value is passed to the callback by the parameter <type>.
* The callback should do the configuration according to the type.
* The callback can use priv->user_data to get other private parameters
* such as phys_port, dev_type, etc, which should be introduced when the
* netif is created.
*/
return dev->cbc->ptp_tx_config_set_cb(priv, &type);
}
int
ngknet_ptp_rx_hwts_get(struct net_device *ndev, struct sk_buff *skb, uint64_t *ts)
{
struct ngknet_private *priv = netdev_priv(ndev);
struct ngknet_dev *dev = priv->bkn_dev;
struct ngknet_callback_desc *cbd = NGKNET_SKB_CB(skb);
struct pkt_hdr *pkh = (struct pkt_hdr *)skb->data;
if (!dev->cbc->ptp_rx_hwts_get_cb) {
return SHR_E_UNAVAIL;
}
cbd->dev_no = dev->dev_no;
cbd->dev_id = dev->pdma_dev.dev_id;
cbd->priv = priv;
cbd->pmd = skb->data + PKT_HDR_SIZE;
cbd->pmd_len = pkh->meta_len;
cbd->pkt_len = pkh->data_len;
/*
* The callback should get timestamp value for a Rx packet and return
* by the parameter <ts>.
* Some parameters have been consolidated to SKB as above. They can be
* achieved by NGKNET_SKB_CB(skb). Specially more private paramters are
* in NGKNET_SKB_CB(skb)->priv->user_data[].
*/
return dev->cbc->ptp_rx_hwts_get_cb(skb, ts);
}
int
ngknet_ptp_tx_hwts_get(struct net_device *ndev, struct sk_buff *skb, uint64_t *ts)
{
struct ngknet_private *priv = netdev_priv(ndev);
struct ngknet_dev *dev = priv->bkn_dev;
struct ngknet_callback_desc *cbd = NGKNET_SKB_CB(skb);
struct pkt_hdr *pkh = (struct pkt_hdr *)skb->data;
if (!dev->cbc->ptp_tx_hwts_get_cb) {
return SHR_E_UNAVAIL;
}
cbd->dev_no = dev->dev_no;
cbd->dev_id = dev->pdma_dev.dev_id;
cbd->priv = priv;
cbd->pmd = skb->data + PKT_HDR_SIZE;
cbd->pmd_len = pkh->meta_len;
cbd->pkt_len = pkh->data_len;
/*
* The callback should get timestamp value for a Tx packet and return
* by the parameter <ts>.
* For HWTSTAMP_TX_ONESTEP_SYNC type, the time value can be achieved and
* returned immediately. Otherwise, for HWTSTAMP_TX_ON type, the callback
* should wait till the time value can be available, i.e. the packet has
* been tranmitted out from port.
* Some parameters have been consolidated to SKB as above. They can be
* achieved by NGKNET_SKB_CB(skb). Specially more private paramters are
* in NGKNET_SKB_CB(skb)->priv->user_data[] such as phys_port, dev_type,
* and so on.
*/
return dev->cbc->ptp_tx_hwts_get_cb(skb, ts);
}
int
ngknet_ptp_tx_meta_set(struct net_device *ndev, struct sk_buff *skb)
{
struct ngknet_private *priv = netdev_priv(ndev);
struct ngknet_dev *dev = priv->bkn_dev;
struct ngknet_callback_desc *cbd = NGKNET_SKB_CB(skb);
struct pkt_hdr *pkh = (struct pkt_hdr *)skb->data;
if (!dev->cbc->ptp_tx_meta_set_cb) {
return SHR_E_UNAVAIL;
}
cbd->dev_no = dev->dev_no;
cbd->dev_id = dev->pdma_dev.dev_id;
cbd->priv = priv;
cbd->pmd = skb->data + PKT_HDR_SIZE;
cbd->pmd_len = pkh->meta_len;
cbd->pkt_len = pkh->data_len;
/*
* The callback should configure the metadata <NGKNET_SKB_CB(skb)->pmd>
* for HW timestamping according to the corresponding switch device.
* Some parameters have been consolidated to SKB as above. They can be
* achieved by NGKNET_SKB_CB(skb). Specially more private paramters are
* in NGKNET_SKB_CB(skb)->priv->user_data[] such as phys_port, dev_type,
* and so on.
*/
return dev->cbc->ptp_tx_meta_set_cb(skb);
}
int
ngknet_ptp_phc_index_get(struct net_device *ndev, int *index)
{
struct ngknet_private *priv = netdev_priv(ndev);
struct ngknet_dev *dev = priv->bkn_dev;
if (!dev->cbc->ptp_phc_index_get_cb) {
return SHR_E_UNAVAIL;
}
/*
* The callback should return the HPC index by the parameter <index>.
* priv->user_data[] can be used to get other private parameters such as
* phys_port, dev_type, etc, which should be introduced when the netif is
* created.
*/
return dev->cbc->ptp_phc_index_get_cb(priv, index);
}
int
ngknet_ptp_dev_ctrl(struct ngknet_dev *dev, int cmd, char *data, int len)
{
if (!dev->cbc->ptp_dev_ctrl_cb) {
return SHR_E_UNAVAIL;
}
/*
* The callback is IOCTL dispatcher for PTP driver/module.
* The parameter <cmd> is the command defined by the user. The parameter
* <data> and <len> are used for interactions between the user application
* and the driver for PTP device start/stop, enable/disable, set/get, and
* so on.
*/
return dev->cbc->ptp_dev_ctrl_cb(dev, cmd, data, len);
}

View File

@ -0,0 +1,111 @@
/*! \file ngknet_ptp.h
*
* Definitions and APIs declaration for PTP.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef NGKNET_PTP_H
#define NGKNET_PTP_H
#include <linux/skbuff.h>
#include "ngknet_main.h"
/*!
* \brief PTP Rx config set.
*
* \param [in] ndev Network device structure point.
* \param [in] filter Rx filter.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_rx_config_set(struct net_device *ndev, int *filter);
/*!
* \brief PTP Tx config set.
*
* \param [in] ndev Network device structure point.
* \param [in] type Tx type.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_tx_config_set(struct net_device *ndev, int type);
/*!
* \brief PTP Rx HW timestamping get.
*
* \param [in] ndev Network device structure point.
* \param [in] skb Rx packet SKB.
* \param [out] ts Timestamp value.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_rx_hwts_get(struct net_device *ndev, struct sk_buff *skb, uint64_t *ts);
/*!
* \brief PTP Tx HW timestamping get.
*
* \param [in] ndev Network device structure point.
* \param [in] skb Tx packet SKB.
* \param [out] ts Timestamp value.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_tx_hwts_get(struct net_device *ndev, struct sk_buff *skb, uint64_t *ts);
/*!
* \brief PTP Tx meta set.
*
* \param [in] ndev Network device structure point.
* \param [in] skb Tx packet SKB.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_tx_meta_set(struct net_device *ndev, struct sk_buff *skb);
/*!
* \brief PTP PHC index get.
*
* \param [in] ndev Network device structure point.
* \param [out] index PHC index.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_phc_index_get(struct net_device *ndev, int *index);
/*!
* \brief PTP device control.
*
* \param [in] dev NGKNET device structure point.
* \param [in] cmd Command.
* \param [in] data Data buffer.
* \param [in] len Data length.
*
* \retval SHR_E_NONE No errors.
*/
extern int
ngknet_ptp_dev_ctrl(struct ngknet_dev *dev, int cmd, char *data, int len);
#endif /* NGKNET_PTP_H */

View File

@ -0,0 +1,36 @@
# -*- Kbuild -*-
#
# Linux KNET Callback module.
#
# $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
# The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# A copy of the GNU General Public License version 2 (GPLv2) can
# be found in the LICENSES folder.$
#
ifeq ($(BUILD_PSAMPLE),1)
PSAMPLE_CFLAGS=-DPSAMPLE_SUPPORT
PSAMPLE_CB_OBJS=psample-cb.o
endif
obj-m := linux_ngknetcb.o
ccflags-y := $(LKM_CFLAGS) \
-I$(SDK)/shr/include \
-I$(SDK)/bcmdrd/include \
-I$(SDK)/linux/include \
-I$(SDK)/linux/knet/include \
-I$(SDK)/linux/knet \
$(PSAMPLE_CFLAGS)
linux_ngknetcb-y := ngknetcb_main.o \
$(PSAMPLE_CB_OBJS)

View File

@ -0,0 +1,33 @@
# -*- Makefile -*-
#
# Linux KNET Callback module.
#
# $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
# The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# A copy of the GNU General Public License version 2 (GPLv2) can
# be found in the LICENSES folder.$
#
include Kbuild
ifeq ($(KERNELRELEASE),)
MOD_NAME = linux_ngknetcb
include $(SDK)/make/lkm.mk
endif
.PHONY: distclean
distclean:

Some files were not shown because too many files have changed in this diff Show More