From 4d37c2f3c7b5df45520fff722b1db3955a3320ce Mon Sep 17 00:00:00 2001 From: Mahesh Maddikayala Date: Wed, 20 Jan 2021 21:32:49 +0000 Subject: [PATCH 01/10] update SAI GPL modules to 6.5.21 --- .../broadcom/saibcm-modules/include/ibde.h | 13 +- .../broadcom/saibcm-modules/include/kcom.h | 15 +- .../saibcm-modules/include/sal/core/sync.h | 13 +- .../saibcm-modules/include/sal/core/thread.h | 13 +- .../saibcm-modules/include/sal/types.h | 13 +- .../saibcm-modules/include/sdk_config.h | 13 +- .../saibcm-modules/include/soc/devids.h | 149 +++- .../broadcom/saibcm-modules/make/Make.config | 15 +- .../broadcom/saibcm-modules/make/Make.depend | 13 +- .../broadcom/saibcm-modules/make/Make.kernlib | 13 +- .../broadcom/saibcm-modules/make/Make.lib | 15 +- .../broadcom/saibcm-modules/make/Make.linux | 15 +- .../broadcom/saibcm-modules/make/Make.subdirs | 13 +- .../broadcom/saibcm-modules/make/Make.tools | 13 +- .../saibcm-modules/make/Makefile.linux-gts | 24 +- .../saibcm-modules/make/Makefile.linux-iproc | 13 +- .../make/Makefile.linux-iproc-3_14 | 13 +- .../make/Makefile.linux-iproc-4_4 | 13 +- .../make/Makefile.linux-iproc_64 | 13 +- .../saibcm-modules/make/Makefile.linux-kernel | 13 +- .../make/Makefile.linux-kernel-2_6 | 13 +- .../make/Makefile.linux-kernel-3_6 | 13 +- .../make/Makefile.linux-kernel-4_4 | 13 +- .../make/Makefile.linux-kmodule | 20 +- .../saibcm-modules/make/Makefile.linux-slk | 17 +- .../make/Makefile.linux-x86-common-2_6 | 13 +- .../Makefile.linux-x86-generic-common-2_6 | 14 +- .../Makefile.linux-x86-smp_generic_64-2_6 | 20 +- .../saibcm-modules/make/Makefile.linux-xlr | 24 +- .../systems/bde/linux/include/linux-bde.h | 59 +- .../systems/bde/linux/include/linux_dma.h | 15 +- .../systems/bde/linux/include/mpool.h | 13 +- .../systems/bde/linux/kernel/Makefile | 13 +- .../bde/linux/kernel/linux-kernel-bde.c | 210 ++++-- .../systems/bde/linux/kernel/linux_dma.c | 228 +++++- .../systems/bde/linux/kernel/linux_shbde.c | 13 +- .../systems/bde/linux/kernel/linux_shbde.h | 13 +- .../systems/bde/linux/shared/mpool.c | 122 ++-- .../systems/bde/linux/user/kernel/Makefile | 13 +- .../bde/linux/user/kernel/linux-user-bde.c | 607 ++++++++++++---- .../bde/linux/user/kernel/linux-user-bde.h | 78 +- .../systems/bde/shared/include/shbde.h | 13 +- .../systems/bde/shared/include/shbde_iproc.h | 13 +- .../systems/bde/shared/include/shbde_mdio.h | 13 +- .../systems/bde/shared/include/shbde_pci.h | 13 +- .../systems/bde/shared/shbde_iproc.c | 24 +- .../systems/bde/shared/shbde_mdio.c | 13 +- .../systems/bde/shared/shbde_pci.c | 13 +- .../systems/linux/kernel/modules/Makefile | 13 +- .../linux/kernel/modules/bcm-knet/Makefile | 13 +- .../linux/kernel/modules/bcm-knet/bcm-knet.c | 199 ++++-- .../kernel/modules/bcm-ptp-clock/Makefile | 6 +- .../modules/bcm-ptp-clock/bcm-ptp-clock.c | 676 +++++++++--------- .../linux/kernel/modules/include/bcm-knet.h | 14 +- .../linux/kernel/modules/include/gmodule.h | 22 +- .../linux/kernel/modules/include/lkm.h | 16 +- .../linux/kernel/modules/knet-cb/Makefile | 13 +- .../linux/kernel/modules/knet-cb/knet-cb.c | 22 +- .../linux/kernel/modules/knet-cb/psample-cb.c | 22 +- .../linux/kernel/modules/psample/psample.c | 2 +- .../linux/kernel/modules/shared/Makefile | 13 +- .../linux/kernel/modules/shared/gmodule.c | 28 +- .../linux/kernel/modules/shared/ksal.c | 13 +- .../systems/linux/user/common/Makefile | 63 +- .../systems/linux/user/gts/Makefile | 13 +- .../systems/linux/user/iproc-3_14/Makefile | 13 +- .../systems/linux/user/iproc-4_4/Makefile | 13 +- .../systems/linux/user/iproc/Makefile | 13 +- .../systems/linux/user/iproc_64/Makefile | 13 +- .../systems/linux/user/slk/Makefile | 13 +- .../user/x86-smp_generic_64-2_6/Makefile | 13 +- .../systems/linux/user/xlr/Makefile | 13 +- .../broadcom/saibcm-modules/tools/mktool.pl | 13 +- 73 files changed, 2407 insertions(+), 893 deletions(-) diff --git a/platform/broadcom/saibcm-modules/include/ibde.h b/platform/broadcom/saibcm-modules/include/ibde.h index 5f371b2667c3..fb9d13d1d5fe 100644 --- a/platform/broadcom/saibcm-modules/include/ibde.h +++ b/platform/broadcom/saibcm-modules/include/ibde.h @@ -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 $ diff --git a/platform/broadcom/saibcm-modules/include/kcom.h b/platform/broadcom/saibcm-modules/include/kcom.h index eb41e1a5aaf2..5129400ca8cd 100644 --- a/platform/broadcom/saibcm-modules/include/kcom.h +++ b/platform/broadcom/saibcm-modules/include/kcom.h @@ -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; diff --git a/platform/broadcom/saibcm-modules/include/sal/core/sync.h b/platform/broadcom/saibcm-modules/include/sal/core/sync.h index 75dd6ce68312..03fd2facc907 100644 --- a/platform/broadcom/saibcm-modules/include/sal/core/sync.h +++ b/platform/broadcom/saibcm-modules/include/sal/core/sync.h @@ -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 $ diff --git a/platform/broadcom/saibcm-modules/include/sal/core/thread.h b/platform/broadcom/saibcm-modules/include/sal/core/thread.h index b7ecb722489f..86713d1e0742 100644 --- a/platform/broadcom/saibcm-modules/include/sal/core/thread.h +++ b/platform/broadcom/saibcm-modules/include/sal/core/thread.h @@ -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 $ diff --git a/platform/broadcom/saibcm-modules/include/sal/types.h b/platform/broadcom/saibcm-modules/include/sal/types.h index 7ed68f43e5e5..43d64dbcc6b9 100644 --- a/platform/broadcom/saibcm-modules/include/sal/types.h +++ b/platform/broadcom/saibcm-modules/include/sal/types.h @@ -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 $ diff --git a/platform/broadcom/saibcm-modules/include/sdk_config.h b/platform/broadcom/saibcm-modules/include/sdk_config.h index 9d781114bdf3..6ce7d77d52d0 100644 --- a/platform/broadcom/saibcm-modules/include/sdk_config.h +++ b/platform/broadcom/saibcm-modules/include/sdk_config.h @@ -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 $ diff --git a/platform/broadcom/saibcm-modules/include/soc/devids.h b/platform/broadcom/saibcm-modules/include/soc/devids.h index bb91d90be03f..89fabac44537 100644 --- a/platform/broadcom/saibcm-modules/include/soc/devids.h +++ b/platform/broadcom/saibcm-modules/include/soc/devids.h @@ -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 diff --git a/platform/broadcom/saibcm-modules/make/Make.config b/platform/broadcom/saibcm-modules/make/Make.config index 409a6a49b3f3..88bf1740ea0b 100644 --- a/platform/broadcom/saibcm-modules/make/Make.config +++ b/platform/broadcom/saibcm-modules/make/Make.config @@ -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. @@ -161,8 +172,6 @@ CFLAGS += ${INCFLAGS} CXXFLAGS += ${INCFLAGS} CPPFLAGS += ${INCFLAGS} -CFLAGS += -DSAI_FIXUP -UKCOM_FILTER_MAX -DKCOM_FILTER_MAX=1024 - # # Debug #ifdef control # diff --git a/platform/broadcom/saibcm-modules/make/Make.depend b/platform/broadcom/saibcm-modules/make/Make.depend index de7099387666..802f5f4483c2 100644 --- a/platform/broadcom/saibcm-modules/make/Make.depend +++ b/platform/broadcom/saibcm-modules/make/Make.depend @@ -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. diff --git a/platform/broadcom/saibcm-modules/make/Make.kernlib b/platform/broadcom/saibcm-modules/make/Make.kernlib index 6ec8a1c8df77..94801acd4a69 100644 --- a/platform/broadcom/saibcm-modules/make/Make.kernlib +++ b/platform/broadcom/saibcm-modules/make/Make.kernlib @@ -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. diff --git a/platform/broadcom/saibcm-modules/make/Make.lib b/platform/broadcom/saibcm-modules/make/Make.lib index d67325c5dd2f..ac81cc134f6d 100644 --- a/platform/broadcom/saibcm-modules/make/Make.lib +++ b/platform/broadcom/saibcm-modules/make/Make.lib @@ -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 diff --git a/platform/broadcom/saibcm-modules/make/Make.linux b/platform/broadcom/saibcm-modules/make/Make.linux index 81e88daf16bc..ad18872a34eb 100644 --- a/platform/broadcom/saibcm-modules/make/Make.linux +++ b/platform/broadcom/saibcm-modules/make/Make.linux @@ -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 diff --git a/platform/broadcom/saibcm-modules/make/Make.subdirs b/platform/broadcom/saibcm-modules/make/Make.subdirs index 1033e296c0a3..374d817d212d 100644 --- a/platform/broadcom/saibcm-modules/make/Make.subdirs +++ b/platform/broadcom/saibcm-modules/make/Make.subdirs @@ -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. diff --git a/platform/broadcom/saibcm-modules/make/Make.tools b/platform/broadcom/saibcm-modules/make/Make.tools index 8ed77727fef2..0d55eb2e653a 100644 --- a/platform/broadcom/saibcm-modules/make/Make.tools +++ b/platform/broadcom/saibcm-modules/make/Make.tools @@ -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. diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-gts b/platform/broadcom/saibcm-modules/make/Makefile.linux-gts index ddc94afa13fe..726dfdf505bd 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-gts +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-gts @@ -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) diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc b/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc index 7d8adb98de38..fa4911185aa8 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc @@ -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. diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc-3_14 b/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc-3_14 index 723fea6c73cf..8d9f66aa50a0 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc-3_14 +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc-3_14 @@ -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. diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc-4_4 b/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc-4_4 index df31f84e9d8f..bcef1ff69dd4 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc-4_4 +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc-4_4 @@ -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. diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc_64 b/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc_64 index dbccd7e25734..247da7386370 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc_64 +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-iproc_64 @@ -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. diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel b/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel index 7cbf8451f91e..ccb0c30d2acc 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel @@ -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. diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-2_6 b/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-2_6 index 559f2ae5e5e5..08461e4c4b7c 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-2_6 +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-2_6 @@ -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. diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-3_6 b/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-3_6 index 0d54c4474fc8..528522ec4bd3 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-3_6 +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-3_6 @@ -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. diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-4_4 b/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-4_4 index 0e8e22e1b32d..c02fc0edd89b 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-4_4 +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-kernel-4_4 @@ -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. diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-kmodule b/platform/broadcom/saibcm-modules/make/Makefile.linux-kmodule index 540c497ea258..46caf00f20b5 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-kmodule +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-kmodule @@ -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). diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-slk b/platform/broadcom/saibcm-modules/make/Makefile.linux-slk index 00131c2f2af9..656835019a05 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-slk +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-slk @@ -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 diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-common-2_6 b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-common-2_6 index 25e953136bc0..dbd51ee1f627 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-common-2_6 +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-common-2_6 @@ -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. diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-generic-common-2_6 b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-generic-common-2_6 index b443a3d4733d..4b02aa53cda8 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-generic-common-2_6 +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-generic-common-2_6 @@ -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 diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-smp_generic_64-2_6 b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-smp_generic_64-2_6 index 8a97f3954301..5a4cc6a805cf 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-smp_generic_64-2_6 +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-smp_generic_64-2_6 @@ -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,14 +36,9 @@ 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) - KFLAGS += -fPIC -mcmodel=small -else - KFLAGS += -fno-pie -mcmodel=kernel -endif LINUX_UAPI = $(LINUX_INCLUDE)/uapi ifneq (,$(shell ls $(LINUX_UAPI) 2>/dev/null)) diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-xlr b/platform/broadcom/saibcm-modules/make/Makefile.linux-xlr index ddc94afa13fe..726dfdf505bd 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-xlr +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-xlr @@ -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) diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux-bde.h b/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux-bde.h index bdf7a56dcabb..c4d31579bfdf 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux-bde.h +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux-bde.h @@ -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 */ /*********************************************************************** * @@ -58,7 +69,6 @@ #define __LINUX_BDE_H__ #include - #include @@ -104,12 +114,17 @@ /* Max devices */ /* 16 switch chips + 2 out-of-band Ethernet + 2 CPUs */ +#ifndef LINUX_BDE_MAX_SWITCH_DEVICES #define LINUX_BDE_MAX_SWITCH_DEVICES 16 +#endif #define LINUX_BDE_MAX_ETHER_DEVICES 2 #define LINUX_BDE_MAX_CPU_DEVICES 2 #define LINUX_BDE_MAX_DEVICES (LINUX_BDE_MAX_SWITCH_DEVICES + \ LINUX_BDE_MAX_ETHER_DEVICES + \ - LINUX_BDE_MAX_CPU_DEVICES) + LINUX_BDE_MAX_CPU_DEVICES) +#define LINUX_BDE_NOF_DEVICE_BITMAP_WORDS ((LINUX_BDE_MAX_DEVICES+31)/32) +#define LINUX_BDE_MAX_IPROC_UC_CORES 12 /* Maximum number of R5 cores per device */ +typedef uint32 linux_bde_device_bitmap_t[LINUX_BDE_NOF_DEVICE_BITMAP_WORDS]; /* * PCI devices will be initialized by the Linux Kernel, @@ -148,14 +163,24 @@ typedef struct linux_bde_bus_s { */ #define BDE_DEV_STATE_CHANGED (2) +/* + * BDE_DEV_INST_ID_INVALID : The invalid instance identifier. + */ +#define BDE_DEV_INST_ID_INVALID ((uint32)-1) + extern int linux_bde_create(linux_bde_bus_t* bus, ibde_t** bde); extern int linux_bde_destroy(ibde_t* bde); #ifdef BCM_INSTANCE_SUPPORT extern int linux_bde_instance_attach(unsigned int dev_mask,unsigned int dma_size); +extern int linux_bde_instance_config(linux_bde_device_bitmap_t dev_mask,unsigned int dma_size); #endif #ifdef __KERNEL__ +#ifdef INCLUDE_EDK +#define BDE_EDK_SUPPORT +#endif + /* * Backdoors provided by the kernel bde * @@ -171,6 +196,10 @@ extern int linux_bde_instance_attach(unsigned int dev_mask,unsigned int dma_size extern int lkbde_get_dma_info(phys_addr_t *cpu_pbase, phys_addr_t *dma_pbase, ssize_t *size); extern uint32 lkbde_get_dev_phys(int d); extern uint32 lkbde_get_dev_phys_hi(int d); +#ifdef BDE_EDK_SUPPORT +extern int lkbde_edk_get_dma_info(int dev_id, phys_addr_t* cpu_pbase, + phys_addr_t* dma_pbase, ssize_t* size); +#endif /* * Virtual device address needed by kernel space @@ -183,8 +212,8 @@ extern void *lkbde_get_dev_virt(int d); * the userland code to mmap. The following functions * supports multiple resources for a single device. */ -extern int lkbde_get_dev_resource(int d, int rsrc, uint32 *flags, - uint32 *phys_lo, uint32 *phys_hi); +extern int lkbde_get_dev_resource(int d, int rsrc, uint32_t *phys_lo, + uint32_t *phys_hi, uint32_t *size); /* * Backdoor to retrieve OS device structure to be used for @@ -215,6 +244,19 @@ extern int lkbde_dev_state_set(int d, uint32 state); extern int lkbde_dev_instid_get(int d, uint32 *instid); extern int lkbde_dev_instid_set(int d, uint32 instid); + +/* + * Return none-zero if the SDK instance with the given instance ID + * manages the given device. + */ +extern int lkbde_is_dev_managed_by_instance(uint32 dev, uint32 inst_id); + +/* + * Return a pointer to the bitmap of the SDK instance managed devices. + */ +extern linux_bde_device_bitmap_t* lkbde_get_inst_devs(uint32 inst_id); + + /* * Functions that allow an interrupt handler in user mode to * coexist with interrupt handler in kernel module. @@ -256,13 +298,6 @@ extern int lkbde_cpu_pci_register(int d); #endif #endif -/* Don't use _SIMPLE_MEMORY_ALLOCATION_ method for newer kernel than 3.10.0 */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) -#ifndef _SIMPLE_MEMORY_ALLOCATION_ -#define _SIMPLE_MEMORY_ALLOCATION_ 0 -#endif -#endif - /* Allocation via dma_alloc_coherent is turned off by default */ #ifndef _SIMPLE_MEMORY_ALLOCATION_ #define _SIMPLE_MEMORY_ALLOCATION_ 9 /* compile in the allocation method, but do not use it by default */ diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux_dma.h b/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux_dma.h index 3bf7488abce9..23eb3fa33e9e 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux_dma.h +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/include/linux_dma.h @@ -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 */ /*********************************************************************** * @@ -60,7 +71,7 @@ extern void _dma_init(int dev_index); extern int _dma_cleanup(void); -extern void _dma_pprint(void); +extern void _dma_pprint(struct seq_file *m); extern uint32_t *_salloc(int d, int size, const char *name); extern void _sfree(int d, void *ptr); extern int _sinval(int d, void *ptr, int length); diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/include/mpool.h b/platform/broadcom/saibcm-modules/systems/bde/linux/include/mpool.h index be4d436f8da9..15d496ff623d 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/include/mpool.h +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/include/mpool.h @@ -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: mpool.h,v 1.2 Broadcom SDK $ diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/Makefile b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/Makefile index cfd72d3a9216..2aa3bec11d73 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/Makefile +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/Makefile @@ -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 # # -*- Makefile -*- # $Id: Makefile,v 1.18 Broadcom SDK $ diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux-kernel-bde.c b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux-kernel-bde.c index 3a60ac4dd54e..9029b3b51477 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux-kernel-bde.c +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux-kernel-bde.c @@ -339,10 +339,19 @@ typedef struct bde_ctrl_s { uint32 dev_state; /* inst_id */ - uint32 inst_id; + uint32 inst_id; /* The instance ID of the instance controlling the device */ } bde_ctrl_t; static bde_ctrl_t _devices[LINUX_BDE_MAX_DEVICES]; + +/* information stored per SDK instance, curently the devices it manages */ +typedef struct { + linux_bde_device_bitmap_t devices; /* The devices controlled by this instance */ +} lkbde_inst_info_t; + +/* Information for each SDK instance (array index), the device that it manages */ +static lkbde_inst_info_t _instance_info[LINUX_BDE_MAX_DEVICES] = {{ .devices = {0}}}; + static int _ndevices = 0; static int _switch_ndevices = 0; static int _ether_ndevices = 0; @@ -810,6 +819,25 @@ iproc_cmicd_probe(struct platform_device *pldev) static int iproc_cmicd_remove(struct platform_device *pldev) { + int i; + uint32 mask = BDE_SWITCH_DEV_TYPE | BDE_AXI_DEV_TYPE; + bde_ctrl_t *ctrl; + + for (i = 0; i < _ndevices; i++) { + ctrl = _devices + i; + if ((ctrl->dev_type & mask) == mask) { + if (ctrl->bde_dev.base_address1) { + iounmap((void *)ctrl->bde_dev.base_address1); + ctrl->bde_dev.base_address1 = 0; + } + + if (ctrl->bde_dev.base_address) { + iounmap((void *)ctrl->bde_dev.base_address); + ctrl->bde_dev.base_address = 0; + } + } + } + return 0; } #ifdef CONFIG_OF @@ -1429,6 +1457,7 @@ static const struct pci_device_id _id_table[] = { { BROADCOM_VENDOR_ID, BCM53575_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56070_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56071_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56072_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9656, PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9056, PCI_ANY_ID, PCI_ANY_ID }, { BCM53000_VENDOR_ID, BCM53000PCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, @@ -1474,9 +1503,11 @@ static const struct pci_device_id _id_table[] = { { BROADCOM_VENDOR_ID, BCM88270_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88271_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88272_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88273_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88274_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88276_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88278_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88279_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, @@ -1496,7 +1527,6 @@ static const struct pci_device_id _id_table[] = { { BROADCOM_VENDOR_ID, BCM88687_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88380_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88381_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM88202_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88360_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88361_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88363_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, @@ -1527,18 +1557,37 @@ static const struct pci_device_id _id_table[] = { { BROADCOM_VENDOR_ID, BCM8869E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM8869F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88800_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM88821_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM88826_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88801_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88802_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88803_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88804_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88805_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88806_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88807_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88808_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88809_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8880A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8880B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8880C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8880D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8880E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8880F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88820_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88821_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88822_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88823_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88824_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88825_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88826_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88827_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88828_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88829_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8882A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8882B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8882C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8882D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8882E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8882F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88480_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88481_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88482_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, @@ -1555,12 +1604,40 @@ static const struct pci_device_id _id_table[] = { { BROADCOM_VENDOR_ID, BCM8848D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM8848E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM8848F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88280_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88281_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88282_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88283_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88284_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88285_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88286_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88287_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88288_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88289_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8828A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8828B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8828C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8828D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8828E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8828F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88850_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88851_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88852_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88853_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88854_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88855_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88856_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88857_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88858_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM88859_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8885A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8885B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8885C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8885D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8885E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM8885F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, #endif /* BCM_DNX_SUPPORT */ #ifdef BCM_DFE_SUPPORT - { BROADCOM_VENDOR_ID, BCM88750_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM88753_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM88755_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88770_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88773_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88774_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, @@ -1574,7 +1651,6 @@ static const struct pci_device_id _id_table[] = { { BROADCOM_VENDOR_ID, BCM88954_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88955_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88956_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM88752_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88772_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM88952_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, #endif @@ -1613,6 +1689,10 @@ static const struct pci_device_id _id_table[] = { { BROADCOM_VENDOR_ID, BCM56276_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56277_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56278_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56279_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56575_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56175_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56176_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56370_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56371_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56372_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, @@ -1638,6 +1718,7 @@ static const struct pci_device_id _id_table[] = { { BROADCOM_VENDOR_ID, BCM56470_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56471_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56472_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56475_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { 0, 0, 0, 0 } };; @@ -2540,9 +2621,6 @@ _pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) #if defined(BCM_DFE_SUPPORT) switch (dev->device) { - case BCM88750_DEVICE_ID: - case BCM88753_DEVICE_ID: - case BCM88755_DEVICE_ID: case BCM88770_DEVICE_ID: case BCM88773_DEVICE_ID: case BCM88774_DEVICE_ID: @@ -2554,7 +2632,6 @@ _pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) case BCM88954_DEVICE_ID: case BCM88955_DEVICE_ID: case BCM88956_DEVICE_ID: - case BCM88752_DEVICE_ID: case BCM88772_DEVICE_ID: case BCM88952_DEVICE_ID: @@ -2801,9 +2878,10 @@ _pci_remove(struct pci_dev* dev) } static struct pci_driver _device_driver = { - probe: _pci_probe, - remove: _pci_remove, - id_table: _id_table, + .name = LINUX_KERNEL_BDE_NAME, + .probe = _pci_probe, + .remove = _pci_remove, + .id_table = _id_table, /* The rest are dynamic */ }; @@ -2978,7 +3056,13 @@ probe_plx_local_bus(void) static int _init(void) { + unsigned i; #ifdef IPROC_CMICD + /* + * Adjust the PCI driver name to prevent our device file from + * getting removed when the module is unloaded. + */ + _device_driver.name = LINUX_KERNEL_BDE_NAME ".iproc"; #ifdef CONFIG_OF if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { iproc_platform_driver_register(&iproc_cmicd_driver); @@ -3000,9 +3084,6 @@ _init(void) #ifdef BCM_ICS _ics_bde_create(); #else /* PCI */ - /* Register our goodies */ - _device_driver.name = LINUX_KERNEL_BDE_NAME; - /* Configure MSI interrupt support */ use_msi = usemsi; @@ -3078,6 +3159,10 @@ _init(void) } } + for (i = 0; i < LINUX_BDE_MAX_DEVICES; ++i) { + _devices[i].inst_id = BDE_DEV_INST_ID_INVALID; + } + return 0; } @@ -3150,45 +3235,45 @@ _cleanup(void) * Always 0 */ static int -_pprint(void) +_pprint(struct seq_file *m) { int i = 0; - pprintf("Broadcom Device Enumerator (%s)\n", LINUX_KERNEL_BDE_NAME); + pprintf(m, "Broadcom Device Enumerator (%s)\n", LINUX_KERNEL_BDE_NAME); - pprintf("Module parameters:\n"); - pprintf("\tmaxpayload=%d\n", maxpayload); - pprintf("\tusemsi=%d\n", usemsi); + pprintf(m, "Module parameters:\n"); + pprintf(m, "\tmaxpayload=%d\n", maxpayload); + pprintf(m, "\tusemsi=%d\n", usemsi); - _dma_pprint(); + _dma_pprint(m); if (_ndevices == 0) { - pprintf("No devices found\n"); + pprintf(m, "No devices found\n"); } else { - pprintf("Devices:\n"); + pprintf(m, "Devices:\n"); } for (i = 0; i < _ndevices; i++) { bde_ctrl_t *ctrl = _devices + i; if (ctrl->dev_type & BDE_SWITCH_DEV_TYPE) { - pprintf("\t%d (swi) : ", i); + pprintf(m, "\t%d (swi) : ", i); } else if (ctrl->dev_type & BDE_ETHER_DEV_TYPE) { - pprintf("\t%d (eth) : ", i); + pprintf(m, "\t%d (eth) : ", i); } else if (ctrl->dev_type & BDE_CPU_DEV_TYPE) { - pprintf("\t%d (cpu) : ", i); + pprintf(m, "\t%d (cpu) : ", i); } else { - pprintf("\t%d (?) : ", i); + pprintf(m, "\t%d (?) : ", i); } if (ctrl->dev_state == BDE_DEV_STATE_REMOVED) { - pprintf("PCI device 0x%x:0x%x:%d REMOVED\n", + pprintf(m, "PCI device 0x%x:0x%x:%d REMOVED\n", ctrl->pci_device->vendor, ctrl->pci_device->device, ctrl->bde_dev.rev); continue; } if (ctrl->dev_type & BDE_PCI_DEV_TYPE) { - pprintf("PCI device %02x:%02x.%x 0x%x:0x%x:%d:0x%.8lx:0x%.8lx:%d%s\n", + pprintf(m, "PCI device %02x:%02x.%x 0x%x:0x%x:%d:0x%.8lx:0x%.8lx:%d%s\n", (unsigned int)ctrl->pci_device->bus->number, PCI_SLOT(ctrl->pci_device->devfn), PCI_FUNC(ctrl->pci_device->devfn), @@ -3200,7 +3285,7 @@ _pprint(void) ctrl->pci_device->irq, ctrl->use_msi ? " (MSI)" : ""); } else if (ctrl->dev_type & BDE_SPI_DEV_TYPE) { - pprintf("SPI Device %d:%x:%x:0x%x:0x%x:%d\n", + pprintf(m, "SPI Device %d:%x:%x:0x%x:0x%x:%d\n", ctrl->spi_device->cid, ctrl->spi_device->part, ctrl->spi_device->rev, @@ -3208,26 +3293,35 @@ _pprint(void) ctrl->spi_device->phyid_low, ctrl->bde_dev.rev); } else if (ctrl->dev_type & BDE_ICS_DEV_TYPE) { - pprintf("ICS Device 0x%x:0x%x\n", + pprintf(m, "ICS Device 0x%x:0x%x\n", ctrl->bde_dev.device, ctrl->bde_dev.rev); } else if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { - pprintf("AXI Device 0x%x:0x%x:0x%.8lx:%d\n", + pprintf(m, "AXI Device 0x%x:0x%x:0x%.8lx:%d\n", ctrl->bde_dev.device, ctrl->bde_dev.rev, (unsigned long)ctrl->iowin[0].addr, ctrl->iLine); } else if (ctrl->dev_type & BDE_EB_DEV_TYPE) { - pprintf("EB Bus Device 0x%x:0x%x\n", + pprintf(m, "EB Bus Device 0x%x:0x%x\n", ctrl->bde_dev.device, ctrl->bde_dev.rev); } if (debug >= 1) { - pprintf("\t\timask:imask2:fmask 0x%x:0x%x:0x%x\n", + pprintf(m, "\t\timask:imask2:fmask 0x%x:0x%x:0x%x\n", ctrl->imask, ctrl->imask2, ctrl->fmask); } + if (debug >= 1) { + if (ctrl->inst_id == BDE_DEV_INST_ID_INVALID) { + pprintf(m, "\t\tinst_id INVALID\n"); + } else { + pprintf(m, "\t\tinst_id %u%s\n", + ctrl->inst_id, + ctrl->inst_id < LINUX_BDE_MAX_DEVICES ? "":"(Illegal)"); + } + } } return 0; } @@ -3952,9 +4046,6 @@ lkbde_cpu_pci_register(int d) pci_write_config_byte(ctrl->pci_device, 0x88, 0x2f); pci_write_config_byte(ctrl->pci_device, 0x89, 0x10); break; - case BCM88750_DEVICE_ID: - case BCM88753_DEVICE_ID: - case BCM88755_DEVICE_ID: case BCM88770_DEVICE_ID: case BCM88773_DEVICE_ID: case BCM88774_DEVICE_ID: @@ -3966,7 +4057,6 @@ lkbde_cpu_pci_register(int d) case BCM88954_DEVICE_ID: case BCM88955_DEVICE_ID: case BCM88956_DEVICE_ID: - case BCM88752_DEVICE_ID: case BCM88772_DEVICE_ID: case BCM88952_DEVICE_ID: case ACP_PCI_DEVICE_ID: @@ -4013,9 +4103,11 @@ lkbde_cpu_pci_register(int d) case BCM88476_DEVICE_ID: case BCM88477_DEVICE_ID: case BCM88270_DEVICE_ID: + case BCM88271_DEVICE_ID: case BCM88272_DEVICE_ID: case BCM88273_DEVICE_ID: case BCM88274_DEVICE_ID: + case BCM88276_DEVICE_ID: case BCM88278_DEVICE_ID: case BCM8206_DEVICE_ID: case BCM88350_DEVICE_ID: @@ -4061,6 +4153,7 @@ lkbde_cpu_pci_register(int d) case J2C_DEVICE_ID: case J2C_2ND_DEVICE_ID: case Q2A_DEVICE_ID: + case Q2U_DEVICE_ID: case J2P_DEVICE_ID: #endif #ifdef BCM_DNXF_SUPPORT @@ -4277,14 +4370,14 @@ lkbde_get_dev_virt(int d) } int -lkbde_get_dev_resource(int d, int rsrc, uint32_t *flags, - uint32_t *phys_lo, uint32_t *phys_hi) +lkbde_get_dev_resource(int d, int rsrc, uint32_t *phys_lo, + uint32_t *phys_hi, uint32_t *size) { if (!VALID_DEVICE(d)) { return -1; } - *flags = 0; + *size = 0; *phys_lo = 0; *phys_hi = 0; @@ -4300,12 +4393,14 @@ lkbde_get_dev_resource(int d, int rsrc, uint32_t *flags, #ifdef PHYS_ADDR_IS_64BIT *phys_hi = (uint32_t)(_devices[d].iowin[0].addr >> 32); #endif + *size = _devices[d].iowin[0].size; break; case 1: *phys_lo = (uint32_t)(_devices[d].iowin[1].addr); #ifdef PHYS_ADDR_IS_64BIT *phys_hi = (uint32_t)(_devices[d].iowin[1].addr >> 32); #endif + *size = _devices[d].iowin[1].size; break; default: break; @@ -4431,7 +4526,7 @@ lkbde_irq_mask_set(int d, uint32_t addr, uint32_t mask, uint32_t fmask) if (iproc_reg) { _iproc_write(d, addr, ctrl->imask | ctrl->imask2); } else { - _write(d, addr, ctrl->imask | ctrl->imask2); + _write(d, addr, ctrl->imask | ctrl->imask2); } spin_unlock_irqrestore(&ctrl->lock, flags); @@ -4481,6 +4576,29 @@ lkbde_get_num_devices(int type) return _num_devices(type); } +/* + * Return none-zero if the SDK instance with the given instance ID + * manages the given device. + */ +int lkbde_is_dev_managed_by_instance(uint32 dev, uint32 inst_id) +{ + if (inst_id >= LINUX_BDE_MAX_DEVICES || dev >= _ndevices) { + return 0; + } + return _instance_info[inst_id].devices[dev / 32] & (1 << (dev % 32)) ? 1 : 0; +} + +/* + * Return a pointer to the bitmap of the SDK instance managed devices. + */ +linux_bde_device_bitmap_t* lkbde_get_inst_devs(uint32 inst_id) +{ + if (inst_id >= LINUX_BDE_MAX_DEVICES) { + return NULL; + } + return &_instance_info[inst_id].devices; +} + /* * Export functions */ @@ -4503,3 +4621,5 @@ LKM_EXPORT_SYM(lkbde_cpu_write); LKM_EXPORT_SYM(lkbde_cpu_read); LKM_EXPORT_SYM(lkbde_cpu_pci_register); #endif +LKM_EXPORT_SYM(lkbde_is_dev_managed_by_instance); +LKM_EXPORT_SYM(lkbde_get_inst_devs); diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_dma.c b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_dma.c index 4f9518e9f4a9..52711964a533 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_dma.c +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_dma.c @@ -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: linux_dma.c,v 1.414 Broadcom SDK $ @@ -78,9 +89,10 @@ /* allocation types/methods for the DMA memory pool */ #define ALLOC_TYPE_CHUNK 0 /* use small allocations and join them */ #define ALLOC_TYPE_API 1 /* use one allocation */ + #if _SIMPLE_MEMORY_ALLOCATION_ #include -#if defined(IPROC_CMICD) && defined(CONFIG_CMA) && defined(CONFIG_CMA_SIZE_MBYTES) +#if defined(CONFIG_CMA) && defined(CONFIG_CMA_SIZE_MBYTES) #define DMA_MAX_ALLOC_SIZE (CONFIG_CMA_SIZE_MBYTES * 1024 * 1024) #else #define DMA_MAX_ALLOC_SIZE (1 << (MAX_ORDER - 1 + PAGE_SHIFT)) /* Maximum size the kernel can allocate in one allocation */ @@ -88,6 +100,7 @@ #endif /* _SIMPLE_MEMORY_ALLOCATION_ */ #if _SIMPLE_MEMORY_ALLOCATION_ == 1 +/* Use Linux DMA API to allocate contiguous memory */ #define ALLOC_METHOD_DEFAULT ALLOC_TYPE_API #if defined(__arm__) #define USE_DMA_MMAP_COHERENT @@ -196,6 +209,17 @@ MODULE_PARM_DESC(himemaddr, #define DMA_MEM_DEFAULT (8 * ONE_MB) #endif +#ifdef BDE_EDK_SUPPORT +typedef struct { + phys_addr_t cpu_pbase; /* CPU physical base address of the DMA pool */ + phys_addr_t dma_pbase; /* Bus base address of the DMA pool */ + void __iomem *dma_vbase; + uint32 size; /* Total size of the pool */ +}_edk_dma_pool_t; +static _edk_dma_pool_t _edk_dma_pool[LINUX_BDE_MAX_DEVICES]; +static int _edk_use_dma_mapping = 0; +#endif + /* We try to assemble a contiguous segment from chunks of this size */ #define DMA_BLOCK_SIZE (512 * ONE_KB) @@ -552,18 +576,145 @@ _pgfree(void *ptr) return -1; } +#ifdef BDE_EDK_SUPPORT +/* + * Function: _edk_mpool_free + * + * Purpose: + * Free all memory allocated by _adk_mpool_alloc + * Parameters: + * None + * Returns: + * Nothing. + */ +static void +_edk_mpool_free(void) +{ + int i, ndevices; + + ndevices = BDE_NUM_DEVICES(BDE_SWITCH_DEVICES); + for (i = 0; i < ndevices && DMA_DEV(i); i ++) { + if (_edk_dma_pool[i].dma_vbase) { + if (_edk_use_dma_mapping) { + dma_unmap_single(DMA_DEV(i), (dma_addr_t)_edk_dma_pool[i].dma_pbase, + _edk_dma_pool[i].size, DMA_BIDIRECTIONAL); + } + _pgfree(_edk_dma_pool[i].dma_vbase); + _edk_dma_pool[i].dma_vbase = NULL; + } + } + _edk_use_dma_mapping = 0; +} + +/* + * Function: edk_mpool_alloc + * + * Purpose: + * Allocate DMA memory pool for EDK + * Parameters: + * size - size of DMA memory pool + * Returns: + * Nothing. + */ +static void +_edk_mpool_alloc(int dev_id, size_t size) +{ + static void __iomem *dma_vbase = NULL; + static phys_addr_t cpu_pbase = 0; + static phys_addr_t dma_pbase = 0; + + struct device *dev = DMA_DEV(DMA_DEV_INDEX); + unsigned long pbase = 0; + + dma_vbase = _pgalloc(size); + if (!dma_vbase) { + gprintk("Failed to allocate memory pool of size 0x%lx for EDK\n", + (unsigned long)size); + return; + } + cpu_pbase = virt_to_bus(dma_vbase); + + /* Use dma_map_single to obtain DMA bus address or IOVA if IOMMU is present. */ + if (dev) { + pbase = dma_map_single(dev, dma_vbase, size, DMA_BIDIRECTIONAL); + if (BDE_DMA_MAPPING_ERROR(dev, pbase)) { + gprintk("Failed to map memory at %p for EDK\n", dma_vbase); + _pgfree(dma_vbase); + dma_vbase = NULL; + return; + } + _edk_use_dma_mapping = 1; + } else { + pbase = cpu_pbase; + } + + dma_pbase = pbase; + +#ifdef REMAP_DMA_NONCACHED + _dma_vbase = IOREMAP(dma_pbase, size); +#endif + _edk_dma_pool[dev_id].cpu_pbase = cpu_pbase; + _edk_dma_pool[dev_id].dma_pbase = dma_pbase; + _edk_dma_pool[dev_id].dma_vbase = dma_vbase; + _edk_dma_pool[dev_id].size = size; +} + +int +lkbde_edk_get_dma_info(int dev_id, phys_addr_t* cpu_pbase, phys_addr_t* dma_pbase, ssize_t* size) +{ + if (_edk_dma_pool[dev_id].dma_vbase == NULL) { + _edk_mpool_alloc(dev_id, *size * ONE_MB); + } + + if (cpu_pbase) { + *cpu_pbase = _edk_dma_pool[dev_id].cpu_pbase; + } + + if (dma_pbase) { + *dma_pbase = _edk_dma_pool[dev_id].dma_pbase; + } + + *size = (_edk_dma_pool[dev_id].dma_vbase) ? _edk_dma_pool[dev_id].size : 0; + return 0; +} + /* - * Function: _pgcleanup + * The below function validates the memory to the EDK allocated DMA pool, + * required to user space via the BDE device file. + */ +static int +_edk_vm_is_valid(struct file *filp, struct vm_area_struct *vma) +{ + unsigned long phys_addr = vma->vm_pgoff << PAGE_SHIFT; + unsigned long size = vma->vm_end - vma->vm_start; + int i, ndevices; + + ndevices = BDE_NUM_DEVICES(BDE_SWITCH_DEVICES); + for (i = 0; i < ndevices; i++) { + if (phys_addr < (unsigned long )_edk_dma_pool[i].cpu_pbase || + (phys_addr + size) > ((unsigned long )_edk_dma_pool[i].cpu_pbase + + _edk_dma_pool[i].size)) { + continue; + } + return 1; + } + + return 0; +} +#endif + +/* + * Function: _mpool_free * * Purpose: - * Free all memory allocated by _pgalloc + * Free all memory allocated by _mpool_alloc * Parameters: * None * Returns: * Nothing. */ static void -_pgcleanup(void) +_mpool_free(void) { switch (dmaalloc) { #if _SIMPLE_MEMORY_ALLOCATION_ @@ -599,7 +750,7 @@ _pgcleanup(void) } /* - * Function: _alloc_mpool + * Function: _mpool_alloc * * Purpose: * Allocate DMA memory pool @@ -613,7 +764,7 @@ _pgcleanup(void) * It is assumed there is only one pool. */ static void -_alloc_mpool(size_t size) +_mpool_alloc(size_t size) { unsigned long pbase = 0; struct device *dev = DMA_DEV(DMA_DEV_INDEX); @@ -643,7 +794,22 @@ _alloc_mpool(size_t size) gprintk("DMA in high memory at 0x%lx size 0x%lx is beyond the 4GB limit and not supported.\n", pbase, (unsigned long)size); return; } - _cpu_pbase = _dma_pbase = pbase; + _cpu_pbase = pbase; + if (dev) { + /* Use dma_map_single to obtain DMA bus address or I/O virtual address, if + IOMMU is present. */ + pbase = dma_map_single(dev, bus_to_virt(_cpu_pbase), size, DMA_BIDIRECTIONAL); + if (BDE_DMA_MAPPING_ERROR(dev, pbase)) { + gprintk("Error !! Failed to map memory at phys base 0x%lx\n", + (unsigned long)_cpu_pbase); + _cpu_pbase = 0; + return; + } + _use_dma_mapping = 1; + } else { + pbase = _cpu_pbase; + } + _dma_pbase = pbase; _dma_vbase = IOREMAP(_dma_pbase, size); } else { /* Get DMA memory from kernel */ @@ -684,14 +850,13 @@ _alloc_mpool(size_t size) return; } _cpu_pbase = virt_to_bus(_dma_vbase); - /* Use dma_map_single to obtain DMA bus address or IOVA if iommu is present. */ + /* Use dma_map_single to obtain DMA bus address or IOVA if IOMMU is present. */ if (dev) { pbase = dma_map_single(dev, _dma_vbase, size, DMA_BIDIRECTIONAL); if (BDE_DMA_MAPPING_ERROR(dev, pbase)) { gprintk("Failed to map memory at %p\n", _dma_vbase); - _pgcleanup(); + _mpool_free(); _dma_vbase = NULL; - _cpu_pbase = 0; return; } _use_dma_mapping = 1; @@ -709,7 +874,7 @@ _alloc_mpool(size_t size) if (!dma64_support && ((pbase + (size - 1)) >> 16) > DMA_BIT_MASK(16)) { gprintk("DMA memory allocated at 0x%lx size 0x%lx is beyond the 4GB limit and not supported.\n", pbase, (unsigned long)size); - _pgcleanup(); + _mpool_free(); _dma_vbase = NULL; _dma_pbase = 0; return; @@ -739,15 +904,27 @@ _alloc_mpool(size_t size) int _dma_cleanup(void) { +#ifdef BDE_EDK_SUPPORT + _edk_mpool_free(); +#endif if (_dma_vbase) { mpool_destroy(_dma_pool); if (_use_himem) { + int i, ndevices; iounmap(_dma_vbase); + if (_use_dma_mapping) { + ndevices = BDE_NUM_DEVICES(BDE_SWITCH_DEVICES); + for (i = 0; i < ndevices && DMA_DEV(i); i ++) { + dma_unmap_single(DMA_DEV(i), (dma_addr_t)_dma_pbase, _dma_mem_size, + DMA_BIDIRECTIONAL); + } + _use_dma_mapping = 0; + } } else { #ifdef REMAP_DMA_NONCACHED iounmap(_dma_vbase); #endif - _pgcleanup(); + _mpool_free(); } _dma_vbase = NULL; _dma_pbase = 0; @@ -811,7 +988,7 @@ void _dma_init(int dev_index) } if (_dma_mem_size) { - _alloc_mpool(_dma_mem_size); + _mpool_alloc(_dma_mem_size); if (_dma_vbase == NULL) { gprintk("no DMA memory available\n"); } else { @@ -835,10 +1012,17 @@ int _dma_mmap(struct file *filp, struct vm_area_struct *vma) if (phys_addr < (unsigned long )_cpu_pbase || (phys_addr + size) > ((unsigned long )_cpu_pbase + _dma_mem_size)) { +#ifdef BDE_EDK_SUPPORT + if(!_edk_vm_is_valid(filp, vma)) { + gprintk("range 0x%lx-0x%lx outside DMA pool\n", phys_addr, phys_addr + size); + return -EINVAL; + } +#else gprintk("range 0x%lx-0x%lx outside DMA pool 0x%lx-0x%lx\n", phys_addr, phys_addr + size, (unsigned long )_cpu_pbase, (unsigned long )_cpu_pbase + _dma_mem_size); return -EINVAL; +#endif } #ifdef USE_DMA_MMAP_COHERENT @@ -995,7 +1179,7 @@ lkbde_get_dma_info(phys_addr_t* cpu_pbase, phys_addr_t* dma_pbase, ssize_t* size if (_dma_mem_size == 0) { _dma_mem_size = DMA_MEM_DEFAULT; } - _alloc_mpool(_dma_mem_size); + _mpool_alloc(_dma_mem_size); } *cpu_pbase = _cpu_pbase; *dma_pbase = _dma_pbase; @@ -1004,12 +1188,12 @@ lkbde_get_dma_info(phys_addr_t* cpu_pbase, phys_addr_t* dma_pbase, ssize_t* size } void -_dma_pprint(void) +_dma_pprint(struct seq_file *m) { - pprintf("\tdmasize=%s\n", dmasize); - pprintf("\thimem=%s\n", himem); - pprintf("\thimemaddr=%s\n", himemaddr); - pprintf("DMA Memory (%s): %d bytes, %d used, %d free%s\n", + pprintf(m, "\tdmasize=%s\n", dmasize); + pprintf(m, "\thimem=%s\n", himem); + pprintf(m, "\thimemaddr=%s\n", himemaddr); + pprintf(m, "DMA Memory (%s): %d bytes, %d used, %d free%s\n", (_use_himem) ? "high" : "kernel", (_dma_vbase) ? _dma_mem_size : 0, (_dma_vbase) ? mpool_usage(_dma_pool) : 0, @@ -1020,6 +1204,10 @@ _dma_pprint(void) /* * Export functions */ + +#ifdef BDE_EDK_SUPPORT +LKM_EXPORT_SYM(lkbde_edk_get_dma_info); +#endif LKM_EXPORT_SYM(kmalloc_giant); LKM_EXPORT_SYM(kfree_giant); LKM_EXPORT_SYM(lkbde_get_dma_info); diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_shbde.c b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_shbde.c index a2d58858a5a5..dd003e1f9297 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_shbde.c +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_shbde.c @@ -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: $ diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_shbde.h b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_shbde.h index 5e8a70119e85..ef4b49dc2124 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_shbde.h +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux_shbde.h @@ -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: $ diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/shared/mpool.c b/platform/broadcom/saibcm-modules/systems/bde/linux/shared/mpool.c index 13206596ee26..4c2db5e4de6c 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/shared/mpool.c +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/shared/mpool.c @@ -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: mpool.c,v 1.18 Broadcom SDK $ @@ -71,7 +82,7 @@ static sal_sem_t _mpool_lock; #endif #define MPOOL_BUF_SIZE 1024 -#define MPOOL_BUF_ALLOC_COUNT_MAX 16 +#define MPOOL_BUF_ALLOC_COUNT_MAX 128 typedef struct mpool_mem_s { unsigned char *address; @@ -80,20 +91,42 @@ typedef struct mpool_mem_s { struct mpool_mem_s *next; } mpool_mem_t; +static int _mpool_count; static int _buf_alloc_count; static mpool_mem_t *mpool_buf[MPOOL_BUF_ALLOC_COUNT_MAX]; static mpool_mem_t *free_list; -#define ALLOC_INIT_MPOOL_BUF(ptr) \ - ptr = MALLOC((sizeof(mpool_mem_t) * MPOOL_BUF_SIZE)); \ - if (ptr) { \ - int i; \ - for (i = 0; i < MPOOL_BUF_SIZE - 1; i++) { \ - ptr[i].next = &ptr[i+1]; \ - } \ - ptr[MPOOL_BUF_SIZE - 1].next = NULL; \ - free_list = &ptr[0]; \ - } +static mpool_mem_t * +_mpool_buf_create(void) +{ + int i; + mpool_mem_t *ptr; + + if (_buf_alloc_count == MPOOL_BUF_ALLOC_COUNT_MAX) { + return NULL; + } + + mpool_buf[_buf_alloc_count] = MALLOC((sizeof(mpool_mem_t) * MPOOL_BUF_SIZE)); + if (!mpool_buf[_buf_alloc_count]) { + return NULL; + } + + ptr = mpool_buf[_buf_alloc_count]; + for (i = 0; i < MPOOL_BUF_SIZE - 1; i++) { + ptr[i].next = &ptr[i+1]; + } + + ptr[MPOOL_BUF_SIZE - 1].next = NULL; + + if (free_list) { + free_list->next = &ptr[0]; + } else { + free_list = &ptr[0]; + } + + _buf_alloc_count++; + return ptr; +} /* * Function: mpool_init @@ -108,7 +141,15 @@ static mpool_mem_t *free_list; int mpool_init(void) { + int i; + MPOOL_LOCK_INIT(); + _buf_alloc_count = 0; + _mpool_count = 0; + for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) { + mpool_buf[i] = NULL; + } + free_list = NULL; return 0; } @@ -140,7 +181,7 @@ mpool_alloc(mpool_handle_t pool, int size) } mod = size & (BCM_CACHE_LINE_BYTES - 1); - if (mod != 0 ) { + if (mod != 0) { size += (BCM_CACHE_LINE_BYTES - mod); } while (ptr && ptr->next) { @@ -155,20 +196,9 @@ mpool_alloc(mpool_handle_t pool, int size) return NULL; } - if (!free_list) { - if (_buf_alloc_count == MPOOL_BUF_ALLOC_COUNT_MAX) { - MPOOL_UNLOCK(); - return NULL; - } - - ALLOC_INIT_MPOOL_BUF(mpool_buf[_buf_alloc_count]); - - if (mpool_buf[_buf_alloc_count] == NULL) { - MPOOL_UNLOCK(); - return NULL; - } - - _buf_alloc_count++; + if (!free_list && !_mpool_buf_create()) { + MPOOL_UNLOCK(); + return NULL; } newptr = free_list; @@ -251,25 +281,16 @@ mpool_create(void *base_ptr, int size) { mpool_mem_t *head, *tail; int mod = (int)(((unsigned long)base_ptr) & (BCM_CACHE_LINE_BYTES - 1)); - int i; MPOOL_LOCK(); - for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) { - mpool_buf[i] = NULL; - } - - _buf_alloc_count = 0; - - ALLOC_INIT_MPOOL_BUF(mpool_buf[_buf_alloc_count]); - - if (mpool_buf[_buf_alloc_count] == NULL) { - MPOOL_UNLOCK(); - return NULL; + if (!free_list || !(free_list->next)) { + if (!_mpool_buf_create()) { + MPOOL_UNLOCK(); + return NULL; + } } - _buf_alloc_count++; - if (mod) { base_ptr = (char*)base_ptr + (BCM_CACHE_LINE_BYTES - mod); size -= (BCM_CACHE_LINE_BYTES - mod); @@ -288,6 +309,7 @@ mpool_create(void *base_ptr, int size) head->next = tail; tail->prev = head; tail->next = NULL; + _mpool_count++; MPOOL_UNLOCK(); return head; @@ -307,19 +329,27 @@ int mpool_destroy(mpool_handle_t pool) { int i; + mpool_mem_t *head = pool; MPOOL_LOCK(); - if ((mpool_mem_t *)pool != mpool_buf[0]) { + if (!(head && head->prev)) { MPOOL_UNLOCK(); return 0; } - for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) { - if (mpool_buf[i]) { - FREE(mpool_buf[i]); - mpool_buf[i] = NULL; + head->prev->next = free_list; + free_list = head; + _mpool_count--; + + if (_mpool_count == 0) { + for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) { + if (mpool_buf[i]) { + FREE(mpool_buf[i]); + mpool_buf[i] = NULL; + } } + free_list = NULL; } MPOOL_UNLOCK(); diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/Makefile b/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/Makefile index 424f2fe24bee..2cc96df02d0a 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/Makefile +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/Makefile @@ -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 # # -*- Makefile -*- # $Id: Makefile,v 1.1 Broadcom SDK $ diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.c b/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.c index 46f60c8a3ae9..4e6186e2d80d 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.c +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.c @@ -24,14 +24,13 @@ #include #include #include - +#include #include "linux-user-bde.h" #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) #include #endif - MODULE_AUTHOR("Broadcom Corporation"); MODULE_DESCRIPTION("User BDE Helper Module"); MODULE_LICENSE("GPL"); @@ -71,7 +70,7 @@ MODULE_LICENSE("GPL"); /* CMICX defines */ #define INTC_INTR_REG_NUM (8) - +#define PAXB_INTRCLR_DELAY_REG_NUM (16) /* TODO:HX5 The INTR base address values are changed for HX5, @@ -80,15 +79,27 @@ be made. */ #define PAXB_0_PAXB_IC_INTRCLR_0 (0x180123a0) #define PAXB_0_PAXB_IC_INTRCLR_1 (0x180123a4) - #define PAXB_0_PAXB_IC_INTRCLR_MODE_0 (0x180123a8) #define PAXB_0_PAXB_IC_INTRCLR_MODE_1 (0x180123ac) +#define PAXB_0_PAXB_INTR_STATUS (0x18012f38) +#define PAXB_0_PAXB_IC_INTR_PACING_CTRL (0x18012398) +#define PAXB_0_PAXB_INTRCLR_DELAY_UNIT (0x1801239c) +#define PAXB_0_PAXB_IC_INTRCLR_DELAY_REG0 (0x180123b0) +#define PAXB_0_PCIE_ERROR_STATUS (0x18012024) #define HX5_PAXB_0_PAXB_IC_INTRCLR_0 (0x102303a0) #define HX5_PAXB_0_PAXB_IC_INTRCLR_1 (0x102303a4) #define HX5_PAXB_0_PAXB_IC_INTRCLR_MODE_0 (0x102303a8) #define HX5_PAXB_0_PAXB_IC_INTRCLR_MODE_1 (0x102303ac) +#define HX5_PAXB_0_PAXB_INTR_STATUS (0x10230f38) +#define HX5_PAXB_0_PAXB_IC_INTR_PACING_CTRL (0x10230398) +#define HX5_PAXB_0_PAXB_INTRCLR_DELAY_UNIT (0x1023039c) +#define HX5_PAXB_0_PAXB_IC_INTRCLR_DELAY_REG0 (0x102303b0) +#define HX5_PAXB_0_PCIE_ERROR_STATUS (0x10230024) + +#define PAXB_0_PAXB_IC_INTRCLR_DELAY_BASE (PAXB_0_PAXB_IC_INTRCLR_DELAY_REG0) +#define HX5_PAXB_0_PAXB_IC_INTRCLR_DELAY_BASE (HX5_PAXB_0_PAXB_IC_INTRCLR_DELAY_REG0) #define INTC_INTR_ENABLE_REG0 (0x180130f0) #define INTC_INTR_STATUS_REG0 (0x18013190) @@ -129,9 +140,9 @@ be made. #define INTC_LOW_PRIORITY_INTR_REG_IND IRQ_MASK_INDEX(HX5_CHIP_INTR_LOW_PRIORITY) #define INTC_PDMA_INTR_REG_IND 4 -#define READ_INTC_INTR(d, reg, v) \ +#define IPROC_READ(d, reg, v) \ (v = user_bde->iproc_read(d, reg)) -#define WRITE_INTC_INTR(d, reg, v) \ +#define IPROC_WRITE(d, reg, v) \ (user_bde->iproc_write(d, reg, v)) #define IHOST_READ_INTR(d, reg, v) \ @@ -155,6 +166,22 @@ be made. static uint32 *ihost_intr_status_base = NULL; static uint32 *ihost_intr_enable_base = NULL; +/* Module parameter for Interruptible timeout */ +static int intr_timeout = 0; +LKM_MOD_PARAM(intr_timeout, "i", int, (S_IRUGO | S_IWUSR)); +MODULE_PARM_DESC(intr_timeout, +"Interruptible wait timeout in milliseconds for Interrupt to be triggered."); + +static ulong intr_count = 0; +LKM_MOD_PARAM(intr_count, "intr_count", ulong, (S_IRUGO | S_IWUSR)); +MODULE_PARM_DESC(intr_count, +"Interrupt count provides information about the number of times the ISR is called."); + +static ulong intr_timeout_count = 0; +LKM_MOD_PARAM(intr_timeout_count, "intr_timeout_count", ulong, (S_IRUGO | S_IWUSR)); +MODULE_PARM_DESC(intr_timeout_count, +"Interrupt timeout count provides information about the number of times the interrupt wait is timeed out."); + /* Debug output */ static int debug; LKM_MOD_PARAM(debug, "i", int, (S_IRUGO | S_IWUSR)); @@ -168,10 +195,16 @@ typedef void (*isr_f)(void *); typedef struct _intr_regs_s { uint32 intc_intr_status_base; uint32 intc_intr_enable_base; + uint32 intc_intr_raw_status_base; uint32 intc_intr_clear_0; uint32 intc_intr_clear_1; uint32 intc_intr_clear_mode_0; uint32 intc_intr_clear_mode_1; + uint32 intc_intr_status; + uint32 intc_intr_pacing_ctrl; + uint32 intc_intr_clear_delay_unit; + uint32 intc_intr_clear_delay_base; + uint32 intc_intr_pcie_err_status; } _intr_regs_t; typedef struct bde_ctrl_s { @@ -181,7 +214,8 @@ typedef struct bde_ctrl_s { int devid; isr_f isr; uint32 *ba; - int inst; /* associate to _bde_inst_resource[] */ + uint32 inst; /* the resource/instance index in _bde_inst_resource[] */ + int edk_irq_enabled; _intr_regs_t intr_regs; } bde_ctrl_t; @@ -199,20 +233,37 @@ static atomic_t _ether_interrupt_has_taken_place = ATOMIC_INIT(0); */ static int _bde_multi_inst = 0; +#define MAX_UC_CORES LINUX_BDE_MAX_IPROC_UC_CORES + +/* Structure to hold info about interrupts handled by EDK */ typedef struct { - unsigned int inst_id; - unsigned int dma_offset; - unsigned int dma_size; + uint32_t timer_intrc_offset; /* Timer interrupts INTC offset */ + uint32_t timer_intrc_mask; /* Timer interrupts mask */ + uint32_t sw_intr_intrc_offset; /* SW Programmable Interrupt's offset */ + uint32_t sw_intr_intrc_mask; /* SW interrupt's mask */ + uint32_t sw_intr_src_bitmap; /* SW interrupt's bitmask to navigate ICFG registers */ + uint32_t sw_intr_icfg_reg[MAX_UC_CORES]; /* ICFG registers for each core */ +} bde_edk_intr_t; + +typedef struct { + int is_active; /* Is the instance active */ + unsigned int dma_offset; /* offset of the instance's DMA memory in the DMA buffer pool */ + unsigned int dma_size; /* size of the instance's DMA memory (in the DMA buffer pool) */ wait_queue_head_t intr_wq; + wait_queue_head_t edk_intr_wq; atomic_t intr; + atomic_t edk_intr; + bde_edk_intr_t edk_irqs; } bde_inst_resource_t; +/* This array contains information for SDK instance, the index in the array is the instance ID */ static bde_inst_resource_t _bde_inst_resource[LINUX_BDE_MAX_DEVICES]; /* * Lock used to protect changes to _bde_inst_resource */ static spinlock_t bde_resource_lock; + typedef struct { phys_addr_t cpu_pbase; /* CPU physical base address of the DMA pool */ phys_addr_t dma_pbase; /* Bus base address of the DMA pool */ @@ -291,23 +342,98 @@ _cmic_interrupt(bde_ctrl_t *ctrl) #endif } -static void -_cmicx_interrupt(bde_ctrl_t *ctrl) +void +dump_interrupt_regs(bde_ctrl_t *ctrl , int dev) +{ + int ind; + uint32_t val; + + if (debug >= 2) { + gprintk("Interrupt timeout count = %lu\n", intr_timeout_count); + gprintk("Interrupt count = %lu\n", intr_count); + for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) { + IPROC_READ(dev, ctrl->intr_regs.intc_intr_status_base + 4 * ind, val); + gprintk("INTC_INTR_STATUS_REG_%d = 0x%x\n", ind, val); + IPROC_READ(dev, ctrl->intr_regs.intc_intr_raw_status_base + 4 * ind, val); + gprintk("INTC_INTR_RAW_STATUS_REG_%d = 0x%x\n", ind, val); + IPROC_READ(dev, ctrl->intr_regs.intc_intr_enable_base + 4 * ind, val); + gprintk("INTC_INTR_ENABLE_REG_%d = 0x%x\n", ind, val); + } + /* Dump PAXB Register */ + IPROC_READ(dev, ctrl->intr_regs.intc_intr_status, val); + gprintk("PAXB_0_PAXB_INTR_STATUS = 0x%x\n", val); + IPROC_READ(dev, ctrl->intr_regs.intc_intr_pacing_ctrl, val); + gprintk("PAXB_0_PAXB_IC_INTR_PACING_CTRL = 0x%x\n", val); + IPROC_READ(dev, ctrl->intr_regs.intc_intr_clear_delay_unit, val); + gprintk("PAXB_0_PAXB_INTRCLR_DELAY_UNIT = 0x%x\n", val); + IPROC_READ(dev, ctrl->intr_regs.intc_intr_pcie_err_status, val); + gprintk("PAXB_0_PCIE_ERROR_STATUS = 0x%x\n", val); + + for (ind = 0; ind < PAXB_INTRCLR_DELAY_REG_NUM; ind++) { + IPROC_READ(dev, ctrl->intr_regs.intc_intr_clear_delay_base + 4 * ind, val); + gprintk("PAXB_0_PAXB_IC_INTRCLR_DELAY_REG_%d = 0x%x\n", ind, val); + } + } + /* Clear interrupt enable registers */ + for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) { + IPROC_WRITE(dev, ctrl->intr_regs.intc_intr_enable_base + 4 * ind, 0); + } +} + +#ifdef BDE_EDK_SUPPORT +static int +_cmicx_edk_interrupt_check(bde_ctrl_t *ctrl, int d) { - int d, ind; - uint32 stat, iena, mask, fmask; bde_inst_resource_t *res; + uint32 stat, mask = 0, bitmap = 0; + int idx; + + res = &_bde_inst_resource[ctrl->inst]; + bitmap = res->edk_irqs.sw_intr_src_bitmap; + + /* Explicitly reading raw_status so as to not clear the status on read */ + IPROC_READ(d, ctrl->intr_regs.intc_intr_raw_status_base + + (res->edk_irqs.sw_intr_intrc_offset * 4), stat); + /* Check whether Software Programmable Interrupt is set */ + if (stat & res->edk_irqs.sw_intr_intrc_mask) { + for (idx = 0; (bitmap && (idx < MAX_UC_CORES)); idx++) { + if (bitmap & 1) { + IPROC_READ(d, res->edk_irqs.sw_intr_icfg_reg[idx], stat); + mask |= (stat & 1) << idx; + } + bitmap = (bitmap >> 1); + } + if (mask) + return 1; + } + + /* EDK uses timer interrupt as watchdog to indicate the the firmware has crashed */ + IPROC_READ(d, ctrl->intr_regs.intc_intr_raw_status_base + + (res->edk_irqs.timer_intrc_offset * 4), stat); + if (stat & res->edk_irqs.timer_intrc_mask) { + return 1; + } + return 0; +} +#endif + +static int +_cmicx_interrupt_prepare(bde_ctrl_t *ctrl) +{ + int d, ind, ret = 0; + uint32 stat, iena, mask, fmask; d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t)); if (ctrl->dev_type & BDE_PCI_DEV_TYPE) { + IPROC_READ(d, ctrl->intr_regs.intc_intr_clear_mode_0, stat); /* Clear MSI interrupts immediately to prevent spurious interrupts */ - WRITE_INTC_INTR(d, ctrl->intr_regs.intc_intr_clear_0, 0xFFFFFFFF); - WRITE_INTC_INTR(d, ctrl->intr_regs.intc_intr_clear_1, 0xFFFFFFFF); + if (stat == 0) { + IPROC_WRITE(d, ctrl->intr_regs.intc_intr_clear_0, 0xFFFFFFFF); + IPROC_WRITE(d, ctrl->intr_regs.intc_intr_clear_1, 0xFFFFFFFF); + } } - res = &_bde_inst_resource[ctrl->inst]; - lkbde_irq_mask_get(d, &mask, &fmask); if (fmask) { @@ -315,15 +441,15 @@ _cmicx_interrupt(bde_ctrl_t *ctrl) IHOST_READ_INTR(d, ihost_intr_status_base + INTC_PDMA_INTR_REG_IND, stat); IHOST_READ_INTR(d, ihost_intr_enable_base + INTC_PDMA_INTR_REG_IND, iena); } else { - READ_INTC_INTR(d, ctrl->intr_regs.intc_intr_status_base + 4 * INTC_PDMA_INTR_REG_IND, stat); - READ_INTC_INTR(d, ctrl->intr_regs.intc_intr_enable_base + 4 * INTC_PDMA_INTR_REG_IND, iena); + IPROC_READ(d, ctrl->intr_regs.intc_intr_status_base + 4 * INTC_PDMA_INTR_REG_IND, stat); + IPROC_READ(d, ctrl->intr_regs.intc_intr_enable_base + 4 * INTC_PDMA_INTR_REG_IND, iena); } if (stat & iena) { if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { IHOST_WRITE_INTR(d, ihost_intr_enable_base + INTC_PDMA_INTR_REG_IND + HX5_IHOST_IRQ_MASK_OFFSET, ~0); } else { - WRITE_INTC_INTR(d, ctrl->intr_regs.intc_intr_enable_base + 4 * INTC_PDMA_INTR_REG_IND, 0); + IPROC_WRITE(d, ctrl->intr_regs.intc_intr_enable_base + 4 * INTC_PDMA_INTR_REG_IND, 0); } for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) { @@ -344,16 +470,16 @@ _cmicx_interrupt(bde_ctrl_t *ctrl) } } } else { - READ_INTC_INTR(d, ctrl->intr_regs.intc_intr_status_base + 4 * ind, stat); - READ_INTC_INTR(d, ctrl->intr_regs.intc_intr_enable_base + 4 * ind, iena); + IPROC_READ(d, ctrl->intr_regs.intc_intr_status_base + 4 * ind, stat); + IPROC_READ(d, ctrl->intr_regs.intc_intr_enable_base + 4 * ind, iena); } if (stat & iena) { break; } } - + /* No pending interrupts */ if (ind >= INTC_INTR_REG_NUM) { - return; + return -1; } } } @@ -362,6 +488,11 @@ _cmicx_interrupt(bde_ctrl_t *ctrl) * So as to avoid getting new interrupts until the user level driver * enumerates the interrupts to be serviced */ +#ifdef BDE_EDK_SUPPORT + if (ctrl->edk_irq_enabled) + ret = _cmicx_edk_interrupt_check(ctrl, d); +#endif + for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) { if (fmask && ind == INTC_PDMA_INTR_REG_IND) { continue; @@ -381,17 +512,42 @@ _cmicx_interrupt(bde_ctrl_t *ctrl) HX5_IHOST_IRQ_MASK_OFFSET, ~0); } } else { - WRITE_INTC_INTR(d, ctrl->intr_regs.intc_intr_enable_base + 4*ind, 0); + IPROC_WRITE(d, ctrl->intr_regs.intc_intr_enable_base + (4 * ind), 0); } } - /* Notify */ - atomic_set(&res->intr, 1); + return ret; +} + +static void +_cmicx_interrupt(bde_ctrl_t *ctrl) +{ + bde_inst_resource_t *res; + int ret; + + intr_count++; + + res = &_bde_inst_resource[ctrl->inst]; + ret = _cmicx_interrupt_prepare(ctrl); + if (ret < 0) { + return; + } else if (ret > 0) { + /* Notify */ + atomic_set(&res->edk_intr, 1); #ifdef BDE_LINUX_NON_INTERRUPTIBLE - wake_up(&res->intr_wq); + wake_up(&res->edk_intr_wq); #else - wake_up_interruptible(&res->intr_wq); + wake_up_interruptible(&res->edk_intr_wq); #endif + } else { + /* Notify */ + atomic_set(&res->intr, 1); +#ifdef BDE_LINUX_NON_INTERRUPTIBLE + wake_up(&res->intr_wq); +#else + wake_up_interruptible(&res->intr_wq); +#endif + } } static void @@ -695,25 +851,6 @@ _cmicd_interrupt(bde_ctrl_t *ctrl) #endif } -static void -_bcm88750_interrupt(bde_ctrl_t *ctrl) -{ - int d; - bde_inst_resource_t *res; - - d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t)); - res = &_bde_inst_resource[ctrl->inst]; - lkbde_irq_mask_set(d, CMIC_IRQ_MASK, 0, 0); - - lkbde_irq_mask_set(d, CMIC_IRQ_MASK_1, 0, 0); - lkbde_irq_mask_set(d, CMIC_IRQ_MASK_2, 0, 0); - atomic_set(&res->intr, 1); -#ifdef BDE_LINUX_NON_INTERRUPTIBLE - wake_up(&res->intr_wq); -#else - wake_up_interruptible(&res->intr_wq); -#endif -} /* The actual interrupt handler of ethernet devices */ static void @@ -738,7 +875,6 @@ static struct _intr_mode_s { { (isr_f)_cmicm_interrupt, "CMICm" }, { (isr_f)_cmicd_interrupt, "CMICd" }, { (isr_f)_cmicd_cmc0_interrupt, "CMICd CMC0" }, - { (isr_f)_bcm88750_interrupt, "BCM88750" }, { (isr_f)_cmicx_interrupt, "CMICx" }, { NULL, NULL } }; @@ -764,17 +900,31 @@ _intr_regs_init(bde_ctrl_t *ctrl, int hx5_intr) if (hx5_intr) { ctrl->intr_regs.intc_intr_status_base = HX5_INTC_INTR_STATUS_BASE; ctrl->intr_regs.intc_intr_enable_base = HX5_INTC_INTR_ENABLE_BASE; + ctrl->intr_regs.intc_intr_raw_status_base = HX5_INTC_INTR_RAW_STATUS_BASE; ctrl->intr_regs.intc_intr_clear_0 = HX5_PAXB_0_PAXB_IC_INTRCLR_0; ctrl->intr_regs.intc_intr_clear_1 = HX5_PAXB_0_PAXB_IC_INTRCLR_1; ctrl->intr_regs.intc_intr_clear_mode_0 = HX5_PAXB_0_PAXB_IC_INTRCLR_MODE_0; ctrl->intr_regs.intc_intr_clear_mode_1 = HX5_PAXB_0_PAXB_IC_INTRCLR_MODE_1; + ctrl->intr_regs.intc_intr_status = HX5_PAXB_0_PAXB_INTR_STATUS; + ctrl->intr_regs.intc_intr_pacing_ctrl = HX5_PAXB_0_PAXB_IC_INTR_PACING_CTRL; + ctrl->intr_regs.intc_intr_clear_delay_unit = HX5_PAXB_0_PAXB_INTRCLR_DELAY_UNIT; + ctrl->intr_regs.intc_intr_clear_delay_base = HX5_PAXB_0_PAXB_IC_INTRCLR_DELAY_BASE; + ctrl->intr_regs.intc_intr_pcie_err_status = HX5_PAXB_0_PCIE_ERROR_STATUS; + } else { ctrl->intr_regs.intc_intr_status_base = INTC_INTR_STATUS_BASE; + ctrl->intr_regs.intc_intr_raw_status_base = INTC_INTR_RAW_STATUS_BASE; ctrl->intr_regs.intc_intr_enable_base = INTC_INTR_ENABLE_BASE; ctrl->intr_regs.intc_intr_clear_0 = PAXB_0_PAXB_IC_INTRCLR_0; ctrl->intr_regs.intc_intr_clear_1 = PAXB_0_PAXB_IC_INTRCLR_1; ctrl->intr_regs.intc_intr_clear_mode_0 = PAXB_0_PAXB_IC_INTRCLR_MODE_0; ctrl->intr_regs.intc_intr_clear_mode_1 = PAXB_0_PAXB_IC_INTRCLR_MODE_1; + ctrl->intr_regs.intc_intr_status = PAXB_0_PAXB_INTR_STATUS; + ctrl->intr_regs.intc_intr_pacing_ctrl = PAXB_0_PAXB_IC_INTR_PACING_CTRL; + ctrl->intr_regs.intc_intr_clear_delay_unit = PAXB_0_PAXB_INTRCLR_DELAY_UNIT; + ctrl->intr_regs.intc_intr_clear_delay_base = PAXB_0_PAXB_IC_INTRCLR_DELAY_BASE; + ctrl->intr_regs.intc_intr_pcie_err_status = PAXB_0_PCIE_ERROR_STATUS; + } } @@ -804,13 +954,6 @@ _devices_init(int d) } if (ctrl->dev_type & BDE_SWITCH_DEV_TYPE) { switch (user_bde->get_dev(d)->device) { - case BCM88750_DEVICE_ID: - case BCM88753_DEVICE_ID: - case BCM88754_DEVICE_ID: - case BCM88755_DEVICE_ID: - case BCM88752_DEVICE_ID: - ctrl->isr = (isr_f)_bcm88750_interrupt; - break; case BCM53540_DEVICE_ID: case BCM53547_DEVICE_ID: case BCM53548_DEVICE_ID: @@ -894,6 +1037,10 @@ _devices_init(int d) case BCM56276_DEVICE_ID: case BCM56277_DEVICE_ID: case BCM56278_DEVICE_ID: + case BCM56279_DEVICE_ID: + case BCM56575_DEVICE_ID: + case BCM56175_DEVICE_ID: + case BCM56176_DEVICE_ID: ctrl->isr = (isr_f)_cmicx_interrupt; if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { if (!ihost_intr_enable_base) { @@ -944,6 +1091,7 @@ _devices_init(int d) case J2C_DEVICE_ID: case J2C_2ND_DEVICE_ID: case Q2A_DEVICE_ID: + case Q2U_DEVICE_ID: case J2P_DEVICE_ID: #endif #ifdef BCM_DNXF_SUPPORT @@ -974,10 +1122,11 @@ _devices_init(int d) static int _init(void) { - int i; + int i, nof_devices; phys_addr_t cpu_pbase, dma_pbase; ssize_t dmasize; bde_inst_resource_t *res; + uint32 *bitmap_ptr; /* Connect to the kernel bde */ if ((linux_bde_create(NULL, &user_bde) < 0) || user_bde == NULL) { @@ -1002,16 +1151,30 @@ _init(void) res->dma_offset = 0; res->dma_size = _dma_pool.total_size; init_waitqueue_head(&res->intr_wq); + init_waitqueue_head(&res->edk_intr_wq); atomic_set(&res->intr, 0); + atomic_set(&res->edk_intr, 0); ihost_intr_enable_base = NULL; ihost_intr_status_base = NULL; - for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) { - res->inst_id |= (1 << i); + nof_devices = user_bde->num_devices(BDE_ALL_DEVICES); + /* for no BDE instances, mark the single SDK as controlling all devices */ + bitmap_ptr = *lkbde_get_inst_devs(0); + for (i = nof_devices; i >=32; i -= 32) { + *(bitmap_ptr++) = 0xffffffff; + } + *bitmap_ptr = (((uint32)1) << i) - 1; + res->is_active = 1; + + for (i = 0; i < nof_devices; i++) { /* init all devices */ _devices_init(i); } + if (intr_timeout > 0) { + gprintk("Interruptible wait timeout = %d msecs\n", intr_timeout); + } + return 0; } @@ -1036,7 +1199,7 @@ _cleanup(void) BDE_DEV_MEM_MAPPED(_devices[i].dev_type)) { user_bde->interrupt_disconnect(i); } - lkbde_dev_instid_set(i, 0); + lkbde_dev_instid_set(i, BDE_DEV_INST_ID_INVALID); } linux_bde_destroy(user_bde); user_bde = NULL; @@ -1065,48 +1228,53 @@ _cleanup(void) * Always 0 */ static int -_pprint(void) +_pprint(struct seq_file *m) { int idx; const char *name; bde_inst_resource_t *res; uint32 state, instid; - pprintf("Broadcom Device Enumerator (%s)\n", LINUX_USER_BDE_NAME); + pprintf(m, "Broadcom Device Enumerator (%s)\n", LINUX_USER_BDE_NAME); for (idx = 0; idx < user_bde->num_devices(BDE_ALL_DEVICES); idx++) { name = _intr_mode_str(_devices[idx].isr); if (name == NULL) { name = "unknown"; } - pprintf("\t%d: Interrupt mode %s ",idx, name); + pprintf(m, "\t%d: Interrupt mode %s ",idx, name); (void)lkbde_dev_state_get(idx, &state); if (state == BDE_DEV_STATE_REMOVED) { - pprintf(" Device REMOVED ! \n"); + pprintf(m, " Device REMOVED ! \n"); } else { (void)lkbde_dev_instid_get(idx, &instid); - if (instid) { - pprintf("Inst id 0x%x\n",instid); + if (instid != BDE_DEV_INST_ID_INVALID) { + pprintf(m, "Inst id 0x%x\n",instid); } else { - pprintf("\n"); + pprintf(m, "\n"); } } } - pprintf("Instance resource \n"); + pprintf(m, "Instance resource \n"); for (idx = 0; idx < user_bde->num_devices(BDE_ALL_DEVICES); idx++) { res = &_bde_inst_resource[idx]; - if (res->inst_id) { - pprintf("\tDev mask 0x%x : " - "DMA offset %d size %d MB\n", - res->inst_id, + if (res->is_active) { + linux_bde_device_bitmap_t* bitmap_p = lkbde_get_inst_devs(idx); + pprintf(m, "\t%d: DMA offset %d size %d MB Dev mask 0x", + idx, res->dma_offset, res->dma_size); + for (state = 0; state * 32 < user_bde->num_devices(BDE_ALL_DEVICES); ++state) { + pprintf(m,"%.8x ", (*bitmap_p)[state]); + } + pprintf(m,"\n"); } } return 0; } +#ifdef BCM_INSTANCE_SUPPORT /* * Allocate the DMA resource from DMA pool * Parameter : @@ -1127,22 +1295,21 @@ _dma_resource_alloc(unsigned int dma_size, unsigned int *dma_offset) _dma_pool.offset += dma_size; return 0; } +#endif static int -_dma_resource_get(int inst_id, phys_addr_t *cpu_pbase, phys_addr_t *dma_pbase, ssize_t* size) +_dma_resource_get(unsigned inst_id, phys_addr_t *cpu_pbase, phys_addr_t *dma_pbase, ssize_t* size) { - int i; unsigned int dma_size = 0, dma_offset = 0; bde_inst_resource_t *res; - for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) { - res = &_bde_inst_resource[i]; - if (res->inst_id == inst_id) { - dma_size = res->dma_size; - dma_offset = res->dma_offset; - break; - } + if (inst_id >= user_bde->num_devices(BDE_ALL_DEVICES)) { + gprintk("ERROR: requested DMA resources for an instance number out of range: %u\n", inst_id); + return -1; } + res = &_bde_inst_resource[inst_id]; + dma_size = res->dma_size; + dma_offset = res->dma_offset; *cpu_pbase = _dma_pool.cpu_pbase + dma_offset * ONE_MB; *dma_pbase = _dma_pool.dma_pbase + dma_offset * ONE_MB; @@ -1151,28 +1318,49 @@ _dma_resource_get(int inst_id, phys_addr_t *cpu_pbase, phys_addr_t *dma_pbase, s return 0; } +#ifdef BCM_INSTANCE_SUPPORT +/* + * Checks if we have the instance in _bde_inst_resource. If not, return LUBDE_SUCCESS==0 (considered a new instance). + * If it exists with the same dmasize, return 1 (It is considered already in use) + * Otherwise if the device with the same index of the resource, has resource/instance index 0, return LUBDE_SUCCESS==0. (bug) + * Otherwise return LUBDE_FAIL==-1 (It is considered to exist with a different dmasize). + */ static int -_instance_validate(unsigned int inst_id, unsigned int dmasize) +_instance_validate(unsigned int inst_id, unsigned int dmasize, linux_bde_device_bitmap_t inst_devices) { - int i; - bde_inst_resource_t *res; + unsigned i; + uint32 bits; + bde_inst_resource_t *res = _bde_inst_resource + inst_id; + linux_bde_device_bitmap_t* bitmap_p; - for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) { - res = &_bde_inst_resource[i]; - if (res->inst_id == inst_id) { - if (res->dma_size != dmasize) { - if(_devices[i].inst == 0){ - /* Skip _instance_validate (not init yet) */ - return LUBDE_SUCCESS; - } - gprintk("ERROR: dma_size mismatch\n"); - return LUBDE_FAIL; - } - return (1); + if (inst_id >= user_bde->num_devices(BDE_ALL_DEVICES)) { + gprintk("ERROR: instance number out of range: %u\n", inst_id); + return LUBDE_FAIL; + } + + if (res->is_active == 0) { + /* FIXME SDK-225233 check that the devices are not used by another active instance */ + return LUBDE_SUCCESS; + } + + bitmap_p = lkbde_get_inst_devs(inst_id); + for (i = 0; i < LINUX_BDE_NOF_DEVICE_BITMAP_WORDS; ++i) { + bits = inst_devices[i] ^ (*bitmap_p)[i]; + if (bits != 0) { + for (i *= 32; (bits & 1) == 0; bits >>= 1, ++i); + gprintk("ERROR: existing instance number %u does not control the same devices, see device %u\n", inst_id, i); + return LUBDE_FAIL; } } - return LUBDE_SUCCESS; + + if (res->dma_size == dmasize) { + return 1; /* For an existing same instance with the same DMA size, do nothing */ + } + /* with a different DMS size */ + gprintk("ERROR: dma_size mismatch\n"); + return LUBDE_FAIL; } +#endif static int _device_reprobe(void) @@ -1187,33 +1375,49 @@ _device_reprobe(void) return 0; } +#ifdef BCM_INSTANCE_SUPPORT +/* + * Attach an SDK instance: + * _device_reprobe(); + * Check If an instance with the same bitmap exists, if yes with the same dmasize, return, if yes a different dmasize return an error, if no: + * Allocate DMA for the instance. + * This loop finds the first free resource in _bde_inst_resource[] and configure it for the instance. + * Store the resource/instance index in _bde_inst_resource for every device in the instance. + */ static int -_instance_attach(unsigned int inst_id, unsigned int dma_size) +_instance_attach(unsigned int inst_id, unsigned int dma_size, linux_bde_device_bitmap_t inst_devices) { unsigned int dma_offset; int i, exist; bde_inst_resource_t *res; - int inst_idx = -1; - uint32 instid; + uint32 previous_inst_id; /* Reprobe the system for hot-plugged device */ _device_reprobe(); if (debug >= 2) { - gprintk("INFO: Request to attach to instance_id %d with dma size %d!\n", inst_id, dma_size); + gprintk("INFO: Request to attach to instance_id %u with dma size %d!\n", inst_id, dma_size); } spin_lock(&bde_resource_lock); - /* Validate the resource with inst_id */ - exist = _instance_validate(inst_id, dma_size); - if (exist < 0) { + /* If not in multi instance mode, move to the mode and fix the first instance that represented all devices */ + if (_bde_multi_inst == 0) { + _bde_multi_inst = 1; + _bde_inst_resource->is_active = 0; + /*_bde_inst_resource->dev will not be used when _bde_inst_resource->is_active == 0 */ + } + + /* Validate the resource with inst_devices */ + exist = _instance_validate(inst_id, dma_size, inst_devices); + + if (exist == LUBDE_FAIL) { spin_unlock(&bde_resource_lock); return LUBDE_FAIL; } if (exist > 0) { if (debug >= 2) { - gprintk("INFO: Already attached to instance_id %d with dma size %d!\n", inst_id, dma_size); + gprintk("INFO: Already attached to instance_id %u with dma size %d!\n", inst_id, dma_size); } spin_unlock(&bde_resource_lock); return LUBDE_SUCCESS; @@ -1222,38 +1426,59 @@ _instance_attach(unsigned int inst_id, unsigned int dma_size) spin_unlock(&bde_resource_lock); return LUBDE_FAIL; } - for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) { - res = &_bde_inst_resource[i]; - if ((_bde_multi_inst == 0) || (res->inst_id == 0)) { - res->inst_id = inst_id; - res->dma_offset = dma_offset; - res->dma_size = dma_size; - _bde_multi_inst++; - inst_idx = i; - init_waitqueue_head(&res->intr_wq); - atomic_set(&res->intr, 0); - break; - } + + /* configure the instance ID resources */ + res = _bde_inst_resource + inst_id; + res->is_active = 1; + res->dma_offset = dma_offset; + res->dma_size = dma_size; +#ifdef SAI_FIXUP /* SDK-240875 */ + /* skip instance 0, WQ for instance 0 has been initialized in user_bde init, see _init() */ + if (inst_id != 0) { + init_waitqueue_head(&res->intr_wq); + init_waitqueue_head(&res->edk_intr_wq); + atomic_set(&res->intr, 0); + atomic_set(&res->edk_intr, 0); } +#endif + memcpy(*lkbde_get_inst_devs(inst_id), inst_devices, sizeof(linux_bde_device_bitmap_t)); /* SDK-225233 */ + /* store the resource/instance index in _bde_inst_resource for every device in the instance */ for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) { - if (inst_id & (1 << i)) { - _devices[i].inst = inst_idx; - /* Pass the instid to the kernel BDE */ - if (lkbde_dev_instid_get(i, &instid) == 0) { - if (!instid) { + if (inst_devices[i / 32] & (1 << (i % 32))) { + _devices[i].inst = inst_id; + /* Pass the inst_id to the kernel BDE */ + if (lkbde_dev_instid_get(i, &previous_inst_id) == 0) { /* If the linux-kernel-bde inst_id is not set for the device, set it to the instance ID */ + if (previous_inst_id == BDE_DEV_INST_ID_INVALID) { lkbde_dev_instid_set(i, inst_id); } - } + } /* TODO handle the case where the device is marked belonging to a different instance */ } } spin_unlock(&bde_resource_lock); if (debug >= 2) { - gprintk("INFO: Attached to instance_id %d with dma size %d! SUCCESS\n", inst_id, dma_size); + gprintk("INFO: Attached to instance_id %lu with dma size %d! SUCCESS\n", (unsigned long)inst_devices, dma_size); } return LUBDE_SUCCESS; } +#endif /* BCM_INSTANCE_SUPPORT */ + +#ifdef BDE_EDK_SUPPORT +static int +_edk_instance_attach(unsigned int inst_id, unsigned int dma_size) +{ + ssize_t size = (ssize_t)dma_size; + if (size) { + lkbde_edk_get_dma_info(inst_id, NULL, NULL, &size); + if (!size) { + gprintk("Error: EDK Attached to instance_id %lu failed\n", (unsigned long)inst_id); + return LUBDE_FAIL; + } + } + return LUBDE_SUCCESS; +} +#endif /* * Function: _ioctl @@ -1273,7 +1498,7 @@ _ioctl(unsigned int cmd, unsigned long arg) phys_addr_t cpu_pbase, dma_pbase; ssize_t size; const ibde_dev_t *bde_dev; - int inst_id; + int inst_id, idx; bde_inst_resource_t *res; uint32_t *mapaddr; @@ -1341,10 +1566,19 @@ _ioctl(unsigned int cmd, unsigned long arg) case LUBDE_GET_DMA_INFO: inst_id = io.dev; if (_bde_multi_inst){ - _dma_resource_get(inst_id, &cpu_pbase, &dma_pbase, &size); + if (_dma_resource_get(inst_id, &cpu_pbase, &dma_pbase, &size)) { + io.rc = LUBDE_FAIL; + } } else { lkbde_get_dma_info(&cpu_pbase, &dma_pbase, &size); } +#ifdef BDE_EDK_SUPPORT + case LUBDE_GET_EDK_DMA_INFO: + if (cmd == LUBDE_GET_EDK_DMA_INFO) { + inst_id = io.dev; + lkbde_edk_get_dma_info(inst_id, &cpu_pbase, &dma_pbase, &size); + } +#endif io.d0 = dma_pbase; io.d1 = size; /* Optionally enable DMA mmap via /dev/linux-kernel-bde */ @@ -1365,14 +1599,6 @@ _ioctl(unsigned int cmd, unsigned long arg) } if (_devices[io.dev].dev_type & BDE_SWITCH_DEV_TYPE) { if (_devices[io.dev].isr && !_devices[io.dev].enabled) { - bde_ctrl_t *ctrl; - ctrl = &_devices[io.dev]; - if ((ctrl->isr == (isr_f)_cmicx_interrupt) && - (ctrl->dev_type & BDE_PCI_DEV_TYPE)) { - /* Set MSI mode to SW clear vs auto clear */ - WRITE_INTC_INTR(io.dev, ctrl->intr_regs.intc_intr_clear_mode_0, 0x0); - WRITE_INTC_INTR(io.dev, ctrl->intr_regs.intc_intr_clear_mode_1, 0x0); - } user_bde->interrupt_connect(io.dev, _devices[io.dev].isr, _devices+io.dev); @@ -1398,6 +1624,32 @@ _ioctl(unsigned int cmd, unsigned long arg) _devices[io.dev].enabled = 0; } break; + case LUBDE_SET_EDK_INTERRUPTS: + if (!VALID_DEVICE(io.dev)) { + return -EINVAL; + } + res = &_bde_inst_resource[_devices[io.dev].inst]; + res->edk_irqs.timer_intrc_offset = io.d0; + res->edk_irqs.timer_intrc_mask = io.d1; + res->edk_irqs.sw_intr_intrc_offset = io.d2; + res->edk_irqs.sw_intr_intrc_mask = io.d3; + res->edk_irqs.sw_intr_src_bitmap = io.dx.dw[0]; + for (idx = 0; idx < MAX_UC_CORES; idx++) { + res->edk_irqs.sw_intr_icfg_reg[idx] = io.dx.dw[idx + 1]; + } + break; + case LUBDE_ENABLE_EDK_INTERRUPTS: + if (!VALID_DEVICE(io.dev)) { + return -EINVAL; + } + _devices[io.dev].edk_irq_enabled = 1; + break; + case LUBDE_DISABLE_EDK_INTERRUPTS: + if (!VALID_DEVICE(io.dev)) { + return -EINVAL; + } + _devices[io.dev].edk_irq_enabled = 0; + break; case LUBDE_WAIT_FOR_INTERRUPT: if (!VALID_DEVICE(io.dev)) { return -EINVAL; @@ -1409,8 +1661,34 @@ _ioctl(unsigned int cmd, unsigned long arg) atomic_read(&res->intr) != 0, 100); #else - wait_event_interruptible(res->intr_wq, - atomic_read(&res->intr) != 0); + /* CMICX Devices */ + if ((_devices[io.dev].dev_type & BDE_PCI_DEV_TYPE) && + (_devices[io.dev].isr == (isr_f)_cmicx_interrupt) && + (intr_timeout > 0)) { + unsigned long t_jiffies; + int err=0; + t_jiffies = msecs_to_jiffies(intr_timeout); + err = wait_event_interruptible_timeout(res->intr_wq, + atomic_read(&res->intr) != 0, + t_jiffies); + /* Timeout happend and condition not set */ + if (err == 0) { + bde_ctrl_t *ctrl; + ctrl = &_devices[io.dev]; + intr_timeout_count++; + if (debug >= 1) { + gprintk("Timeout happend and condition not set\n"); + } + dump_interrupt_regs(ctrl, io.dev); + } else if (err == -ERESTARTSYS) { + if (debug >= 1) { + gprintk("Interrupted by Signal\n"); + } + } + } else { + wait_event_interruptible(res->intr_wq, + atomic_read(&res->intr) != 0); + } #endif /* * Even if we get multiple interrupts, we @@ -1424,14 +1702,56 @@ _ioctl(unsigned int cmd, unsigned long arg) #else wait_event_interruptible(_ether_interrupt_wq, atomic_read(&_ether_interrupt_has_taken_place) != 0); + #endif /* - * Even if we get multiple interrupts, we + * Even if we get multiple interrupts, we * only run the interrupt handler once. */ atomic_set(&_ether_interrupt_has_taken_place, 0); } break; + case LUBDE_WAIT_FOR_EDK_INTERRUPT: + if (!VALID_DEVICE(io.dev)) { + return -EINVAL; + } + res = &_bde_inst_resource[_devices[io.dev].inst]; +#ifdef BDE_LINUX_NON_INTERRUPTIBLE + wait_event_timeout(res->edk_intr_wq, + atomic_read(&res->edk_intr) != 0, 100); + +#else + /* CMICX Devices */ + if ((_devices[io.dev].dev_type & BDE_PCI_DEV_TYPE) && + (_devices[io.dev].isr == (isr_f)_cmicx_interrupt) && + (intr_timeout > 0)) { + unsigned long t_jiffies; + int err = 0; + t_jiffies = msecs_to_jiffies(intr_timeout); + err = wait_event_interruptible_timeout(res->edk_intr_wq, + atomic_read(&res->edk_intr) != 0, t_jiffies); + /* Timeout happend and condition not set */ + if (err == 0) { + bde_ctrl_t *ctrl; + ctrl = &_devices[io.dev]; + intr_timeout_count++; + if (debug >= 1) { + gprintk("EDK Interrrupt: Timeout happened\n"); + } + dump_interrupt_regs(ctrl, io.dev); + } else if (err == -ERESTARTSYS) { + if (debug >= 1) { + gprintk("EDK Interrrupt: Interrupted by Signal\n"); + } + } + } else { + wait_event_interruptible(res->edk_intr_wq, atomic_read(&res->edk_intr) != 0); + } +#endif + /* Even if we get multiple interrupts, we + * only run the interrupt handler once. */ + atomic_set(&res->edk_intr, 0); + break; case LUBDE_USLEEP: case LUBDE_UDELAY: case LUBDE_SEM_OP: @@ -1487,7 +1807,7 @@ _ioctl(unsigned int cmd, unsigned long arg) if (BDE_DEV_MEM_MAPPED(_devices[io.dev].dev_type)) { /* Get physical address to map */ io.rc = lkbde_get_dev_resource(io.dev, io.d0, - &io.d1, &io.d2, &io.d3); + &io.d2, &io.d3, &io.d1); } } else { io.rc = LUBDE_FAIL; @@ -1517,9 +1837,16 @@ _ioctl(unsigned int cmd, unsigned long arg) io.rc = LUBDE_FAIL; } break; +#ifdef BDE_EDK_SUPPORT + case LUBDE_ATTACH_EDK_INSTANCE: + io.rc = _edk_instance_attach(io.d0, io.d1); + break; +#endif +#ifdef BCM_INSTANCE_SUPPORT case LUBDE_ATTACH_INSTANCE: - io.rc = _instance_attach(io.d0, io.d1); + io.rc = _instance_attach(io.d0, io.d1, io.dx.dw); break; +#endif case LUBDE_GET_DEVICE_STATE: io.rc = lkbde_dev_state_get(io.dev, &io.d0); break; diff --git a/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.h b/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.h index 535ccac9fad9..4bd4b746c521 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.h +++ b/platform/broadcom/saibcm-modules/systems/bde/linux/user/kernel/linux-user-bde.h @@ -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: linux-user-bde.h,v 1.23 Broadcom SDK $ @@ -45,7 +56,7 @@ typedef struct { unsigned int d3; bde_kernel_addr_t p0; union { - unsigned int dw[2]; + uint32_t dw[16]; unsigned char buf[64]; } dx; } lubde_ioctl_t; @@ -54,34 +65,41 @@ typedef struct { /* LUBDE ioctls */ #define LUBDE_MAGIC 'L' -#define LUBDE_VERSION _IO(LUBDE_MAGIC, 0) -#define LUBDE_GET_NUM_DEVICES _IO(LUBDE_MAGIC, 1) -#define LUBDE_GET_DEVICE _IO(LUBDE_MAGIC, 2) -#define LUBDE_PCI_CONFIG_PUT32 _IO(LUBDE_MAGIC, 3) -#define LUBDE_PCI_CONFIG_GET32 _IO(LUBDE_MAGIC, 4) -#define LUBDE_GET_DMA_INFO _IO(LUBDE_MAGIC, 5) -#define LUBDE_ENABLE_INTERRUPTS _IO(LUBDE_MAGIC, 6) -#define LUBDE_DISABLE_INTERRUPTS _IO(LUBDE_MAGIC, 7) -#define LUBDE_USLEEP _IO(LUBDE_MAGIC, 8) -#define LUBDE_WAIT_FOR_INTERRUPT _IO(LUBDE_MAGIC, 9) -#define LUBDE_SEM_OP _IO(LUBDE_MAGIC, 10) -#define LUBDE_UDELAY _IO(LUBDE_MAGIC, 11) -#define LUBDE_GET_DEVICE_TYPE _IO(LUBDE_MAGIC, 12) -#define LUBDE_SPI_READ_REG _IO(LUBDE_MAGIC, 13) -#define LUBDE_SPI_WRITE_REG _IO(LUBDE_MAGIC, 14) -#define LUBDE_READ_REG_16BIT_BUS _IO(LUBDE_MAGIC, 19) -#define LUBDE_WRITE_REG_16BIT_BUS _IO(LUBDE_MAGIC, 20) -#define LUBDE_GET_BUS_FEATURES _IO(LUBDE_MAGIC, 21) -#define LUBDE_WRITE_IRQ_MASK _IO(LUBDE_MAGIC, 22) -#define LUBDE_CPU_WRITE_REG _IO(LUBDE_MAGIC, 23) -#define LUBDE_CPU_READ_REG _IO(LUBDE_MAGIC, 24) -#define LUBDE_CPU_PCI_REGISTER _IO(LUBDE_MAGIC, 25) -#define LUBDE_DEV_RESOURCE _IO(LUBDE_MAGIC, 26) -#define LUBDE_IPROC_READ_REG _IO(LUBDE_MAGIC, 27) -#define LUBDE_IPROC_WRITE_REG _IO(LUBDE_MAGIC, 28) -#define LUBDE_ATTACH_INSTANCE _IO(LUBDE_MAGIC, 29) -#define LUBDE_GET_DEVICE_STATE _IO(LUBDE_MAGIC, 30) -#define LUBDE_REPROBE _IO(LUBDE_MAGIC, 31) +#define LUBDE_VERSION _IO(LUBDE_MAGIC, 0) +#define LUBDE_GET_NUM_DEVICES _IO(LUBDE_MAGIC, 1) +#define LUBDE_GET_DEVICE _IO(LUBDE_MAGIC, 2) +#define LUBDE_PCI_CONFIG_PUT32 _IO(LUBDE_MAGIC, 3) +#define LUBDE_PCI_CONFIG_GET32 _IO(LUBDE_MAGIC, 4) +#define LUBDE_GET_DMA_INFO _IO(LUBDE_MAGIC, 5) +#define LUBDE_ENABLE_INTERRUPTS _IO(LUBDE_MAGIC, 6) +#define LUBDE_DISABLE_INTERRUPTS _IO(LUBDE_MAGIC, 7) +#define LUBDE_USLEEP _IO(LUBDE_MAGIC, 8) +#define LUBDE_WAIT_FOR_INTERRUPT _IO(LUBDE_MAGIC, 9) +#define LUBDE_SEM_OP _IO(LUBDE_MAGIC, 10) +#define LUBDE_UDELAY _IO(LUBDE_MAGIC, 11) +#define LUBDE_GET_DEVICE_TYPE _IO(LUBDE_MAGIC, 12) +#define LUBDE_SPI_READ_REG _IO(LUBDE_MAGIC, 13) +#define LUBDE_SPI_WRITE_REG _IO(LUBDE_MAGIC, 14) +#define LUBDE_READ_REG_16BIT_BUS _IO(LUBDE_MAGIC, 19) +#define LUBDE_WRITE_REG_16BIT_BUS _IO(LUBDE_MAGIC, 20) +#define LUBDE_GET_BUS_FEATURES _IO(LUBDE_MAGIC, 21) +#define LUBDE_WRITE_IRQ_MASK _IO(LUBDE_MAGIC, 22) +#define LUBDE_CPU_WRITE_REG _IO(LUBDE_MAGIC, 23) +#define LUBDE_CPU_READ_REG _IO(LUBDE_MAGIC, 24) +#define LUBDE_CPU_PCI_REGISTER _IO(LUBDE_MAGIC, 25) +#define LUBDE_DEV_RESOURCE _IO(LUBDE_MAGIC, 26) +#define LUBDE_IPROC_READ_REG _IO(LUBDE_MAGIC, 27) +#define LUBDE_IPROC_WRITE_REG _IO(LUBDE_MAGIC, 28) +#define LUBDE_ATTACH_INSTANCE _IO(LUBDE_MAGIC, 29) +#define LUBDE_GET_DEVICE_STATE _IO(LUBDE_MAGIC, 30) +#define LUBDE_REPROBE _IO(LUBDE_MAGIC, 31) +#define LUBDE_SET_EDK_INTERRUPTS _IO(LUBDE_MAGIC, 32) +#define LUBDE_ENABLE_EDK_INTERRUPTS _IO(LUBDE_MAGIC, 33) +#define LUBDE_DISABLE_EDK_INTERRUPTS _IO(LUBDE_MAGIC, 34) +#define LUBDE_WAIT_FOR_EDK_INTERRUPT _IO(LUBDE_MAGIC, 35) +#define LUBDE_ATTACH_EDK_INSTANCE _IO(LUBDE_MAGIC, 36) +#define LUBDE_GET_EDK_DMA_INFO _IO(LUBDE_MAGIC, 37) + #define LUBDE_SEM_OP_CREATE 1 #define LUBDE_SEM_OP_DESTROY 2 diff --git a/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde.h b/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde.h index 53003a40ce53..2d0651191fbb 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde.h +++ b/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde.h @@ -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: $ diff --git a/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_iproc.h b/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_iproc.h index 4b614ba53139..4b71b8f16ee3 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_iproc.h +++ b/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_iproc.h @@ -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: $ diff --git a/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_mdio.h b/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_mdio.h index 5f8fa63533f4..a51dd2ac6f5f 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_mdio.h +++ b/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_mdio.h @@ -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: $ diff --git a/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_pci.h b/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_pci.h index 1f045d7b02c8..a0b88494823f 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_pci.h +++ b/platform/broadcom/saibcm-modules/systems/bde/shared/include/shbde_pci.h @@ -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: $ diff --git a/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_iproc.c b/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_iproc.c index 087720a20a8b..ca8024c78a32 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_iproc.c +++ b/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_iproc.c @@ -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: $ @@ -292,12 +303,19 @@ shbde_iproc_paxb_init(shbde_hal_t *shbde, void *iproc_regs, /* Configure MSIX interrupt page, need for iproc ver 0x10 and 0x12 */ if ((icfg->use_msi == 2) && - ((icfg->iproc_ver == 0x10) || (icfg->iproc_ver == 0x12))){ + ((icfg->iproc_ver == 0x10) + || (icfg->iproc_ver == 0x12) + || (icfg->iproc_ver == 0x11))){ unsigned int mask = (0x1 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT) - 1; reg = ROFFS(iproc_regs, PAXB_0_FUNC0_IMAP1_3); data = iproc32_read(shbde, reg); data &= mask; - data |= 0x410 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT; + if (icfg->iproc_ver == 0x11) { + data |= 0x400 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT; + } else { + data |= 0x410 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT; + } + iproc32_write(shbde, reg, data); } diff --git a/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_mdio.c b/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_mdio.c index ef4a72071b33..1e38eb024adc 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_mdio.c +++ b/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_mdio.c @@ -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: $ diff --git a/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_pci.c b/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_pci.c index 5cc46d0d463d..8e64b475a41f 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_pci.c +++ b/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_pci.c @@ -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: $ diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/Makefile b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/Makefile index 448b4b9a9310..b599580ae861 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/Makefile @@ -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 # # -*- Makefile -*- # $Id: Makefile,v 1.10 Broadcom SDK $ diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/Makefile b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/Makefile index a3f430a6a903..9879be69b0b6 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/Makefile @@ -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 # # -*- Makefile -*- # $Id: Makefile,v 1.3 Broadcom SDK $ diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c index a9eda27ad4d5..a3f92b17584b 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c @@ -60,10 +60,6 @@ #include #include -#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,16,0) -#include -#endif - #include #include #include @@ -222,6 +218,7 @@ MODULE_PARM_DESC(ft_vid, #define DBG_LVL_DCB_RX 0x20000 #define DBG_LVL_PDMP_TX 0x40000 #define DBG_LVL_PDMP_RX 0x80000 +#define DBG_LVL_PTP 0x100000 #define DBG_VERB(_s) do { if (debug & DBG_LVL_VERB) gprintk _s; } while (0) #define DBG_PKT(_s) do { if (debug & DBG_LVL_PKT) gprintk _s; } while (0) @@ -245,6 +242,7 @@ MODULE_PARM_DESC(ft_vid, #define DBG_DCB(_s) do { if (debug & (DBG_LVL_DCB|DBG_LVL_DCB_TX| \ DBG_LVL_DCB_RX)) \ gprintk _s; } while (0) +#define DBG_PTP(_s) do { if (debug & DBG_LVL_PTP) gprintk _s; } while (0) /* This flag is used to indicate if debugging packet function is open or closed */ @@ -499,6 +497,12 @@ static inline void bkn_skb_tx_timestamp(struct sk_buff *skb) #define BKN_DMA_MAPPING_ERROR(d,a) bkn_pci_dma_mapping_error(d,a) #endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) +#define BKN_NETDEV_TX_BUSY NETDEV_TX_BUSY +#else +#define BKN_NETDEV_TX_BUSY 1 +#endif + /* * Get a 16-bit value from packet offset * _data Pointer to packet @@ -672,6 +676,8 @@ typedef struct bkn_switch_info_s { } rx[NUM_RX_CHAN]; } bkn_switch_info_t; +#define INVALID_INSTANCE_ID BDE_DEV_INST_ID_INVALID + /* 0x1 - Jericho 2 mode */ #define BKN_DNX_JR2_MODE 1 /* PTCH_2 */ @@ -936,13 +942,6 @@ typedef struct bkn_filter_s { kcom_filter_t kf; } bkn_filter_t; -#ifdef SAI_FIXUP /* SDK-224448 */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) -#define BKN_NETDEV_TX_BUSY NETDEV_TX_BUSY -#else -#define BKN_NETDEV_TX_BUSY 1 -#endif -#endif /* SDK-224448 */ /* * Multiple instance support in KNET @@ -1071,6 +1070,7 @@ bkn_sleep(int clicks) #define DEV_IS_CMICX(_sinfo) ((_sinfo)->cmic_type == 'x') #define DEV_IS_CMICM(_sinfo) ((_sinfo)->cmic_type == 'm') +#define DEV_IS_CMIC(_sinfo) ((_sinfo)->cmic_type != 0) #define CDMA_CH(_d, _ch) ((_d)->cdma_channels & (1 << (_ch))) /* @@ -2125,12 +2125,13 @@ bkn_api_rx_chain_done(bkn_switch_info_t *sinfo, int chan) static int bkn_api_rx_copy_from_skb(bkn_switch_info_t *sinfo, - int chan, bkn_desc_info_t *desc) + int chan, bkn_desc_info_t *desc, int rx_hwts) { bkn_dcb_chain_t *dcb_chain; uint32_t *dcb; uint32_t dcb_stat; uint8_t *pkt; + uint8_t *skb_pkt; uint64_t pkt_dma; int pktlen; int i; @@ -2168,8 +2169,18 @@ bkn_api_rx_copy_from_skb(bkn_switch_info_t *sinfo, return -1; } + skb_pkt = desc->skb->data; + + /* Strip custom header from KNETSync packets. */ + if ((rx_hwts) && + ((skb_pkt[0] == 'B') && (skb_pkt[1] == 'C') && + (skb_pkt[2] == 'M') && (skb_pkt[3] == 'C'))) { + + skb_pkt = skb_pkt + skb_pkt[4]; + } + /* Copy packet data */ - memcpy(pkt, desc->skb->data, pktlen); + memcpy(pkt, skb_pkt, pktlen); /* Copy packet metadata and mark as done */ if (sinfo->cmic_type != 'x') { @@ -2235,11 +2246,11 @@ bkn_rx_refill(bkn_switch_info_t *sinfo, int chan) while (sinfo->rx[chan].free < MAX_RX_DCBS) { desc = &sinfo->rx[chan].desc[sinfo->rx[chan].cur]; if (desc->skb == NULL) { - skb = dev_alloc_skb(rx_buffer_size + RCPU_RX_ENCAP_SIZE); + skb = dev_alloc_skb(rx_buffer_size + SKB_DATA_ALIGN(resv_size)); if (skb == NULL) { break; } - skb_reserve(skb, resv_size); + skb_reserve(skb, SKB_DATA_ALIGN(resv_size)); desc->skb = skb; } else { DBG_DCB_RX(("Refill Rx%d SKB in DCB %d recycled.\n", @@ -3832,6 +3843,11 @@ bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget) while (dcbs_done < budget) { char str[32]; + + if (!sinfo->rx[chan].running) { + /* DCBs might be cleaned up when bkn_knet_hw_reset is triggered. */ + return 0; + } sprintf(str, "Rx DCB (%d)", sinfo->rx[chan].dirty); desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty]; dcb = desc->dcb_mem; @@ -3850,6 +3866,12 @@ bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget) sinfo->rx[chan].pkts++; skb = desc->skb; + DBG_DCB_RX(("Rx%d SKB DMA done (%d).\n", chan, sinfo->rx[chan].dirty)); + BKN_DMA_UNMAP_SINGLE(sinfo->dma_dev, + desc->skb_dma, desc->dma_size, + BKN_DMA_FROMDEV); + desc->skb_dma = 0; + if (device_is_sand(sinfo)) { err_woff = BKN_SAND_SCRATCH_DATA_SIZE - 1; sand_scratch_data[err_woff] = dcb[sinfo->dcb_wsize-1]; @@ -3868,11 +3890,6 @@ bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget) pktlen = dcb[sinfo->dcb_wsize-1] & 0xffff; priv = netdev_priv(sinfo->dev); - DBG_DCB_RX(("Rx%d SKB DMA done (%d).\n", chan, sinfo->rx[chan].dirty)); - BKN_DMA_UNMAP_SINGLE(sinfo->dma_dev, - desc->skb_dma, desc->dma_size, - BKN_DMA_FROMDEV); - desc->skb_dma = 0; bkn_dump_pkt(skb->data, pktlen, XGS_DMA_RX_CHAN); if (device_is_sand(sinfo)) { @@ -3945,7 +3962,7 @@ bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget) case KCOM_DEST_T_API: DBG_FLTR(("Send to Rx API\n")); sinfo->rx[chan].pkts_f_api++; - bkn_api_rx_copy_from_skb(sinfo, chan, desc); + bkn_api_rx_copy_from_skb(sinfo, chan, desc, 0); break; case KCOM_DEST_T_NETIF: priv = bkn_netif_lookup(sinfo, filter->kf.dest_id); @@ -3961,7 +3978,7 @@ bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget) if ((filter->kf.mirror_type == KCOM_DEST_T_API) || dbg_pkt_enable) { sinfo->rx[chan].pkts_m_api++; - bkn_api_rx_copy_from_skb(sinfo, chan, desc); + bkn_api_rx_copy_from_skb(sinfo, chan, desc, priv->rx_hwts); } if (device_is_sand(sinfo)) { @@ -4095,6 +4112,9 @@ bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget) } } + /* Ensure that we reallocate SKB for this DCB */ + desc->skb = NULL; + /* Unlock while calling up network stack */ spin_unlock(&sinfo->lock); if (use_napi) { @@ -4104,8 +4124,6 @@ bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget) } spin_lock(&sinfo->lock); - /* Ensure that we reallocate SKB for this DCB */ - desc->skb = NULL; } else { DBG_FLTR(("Unknown netif %d\n", filter->kf.dest_id)); @@ -4299,11 +4317,28 @@ bkn_hw_tstamp_tx_work(struct work_struct *work) { bkn_switch_info_t *sinfo = container_of(work, bkn_switch_info_t, tx_ptp_work); struct sk_buff *skb; + int ret; while (skb_queue_len(&sinfo->tx_ptp_queue)) { skb = skb_dequeue(&sinfo->tx_ptp_queue); - if (bkn_hw_tstamp_tx_set(sinfo, skb) < 0) { - gprintk("Timestamp has not been taken for the current skb.\n"); + ret = bkn_hw_tstamp_tx_set(sinfo, skb); + if (ret < 0) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)) + ktime_t now; + now = ktime_get(); + DBG_PTP(("2Step TX Timestamp has not been taken for the current skb (%lld us)\n", + ktime_us_delta(now, skb->tstamp))); + } else { + ktime_t now; + now = ktime_get(); + /* Timeout 20 should be same as configured by PTP4L */ + if (ktime_us_delta(now, skb->tstamp) >= 20000) { + DBG_PTP(("2Step TX Timestamp fetch took long time %lld us\n", + ktime_us_delta(now, skb->tstamp))); + } +#else + DBG_PTP(("2Step TX Timestamp has not been taken for the current skb\n")); +#endif } dev_kfree_skb_any(skb); } @@ -4346,6 +4381,9 @@ bkn_do_tx(bkn_switch_info_t *sinfo) } if (bkn_skb_tx_flags(desc->skb) & SKBTX_IN_PROGRESS) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)) + desc->skb->tstamp = ktime_get(); +#endif skb_queue_tail(&sinfo->tx_ptp_queue, desc->skb); schedule_work(&sinfo->tx_ptp_work); } else { @@ -5310,6 +5348,7 @@ bkn_hw_tstamp_tx_config(bkn_switch_info_t *sinfo, case 26: case 32: case 33: + case 35: meta[2] |= md[0]; meta[3] |= md[1]; meta[4] |= md[2]; @@ -5342,6 +5381,7 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) uint32_t *metadata; unsigned long flags; uint32_t cpu_channel = 0; + int headroom, tailroom; DBG_VERB(("Netif Tx: Len=%d priv->id=%d\n", skb->len, priv->id)); @@ -5449,7 +5489,16 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) if (skb_header_cloned(skb)) { /* Current SKB cannot be modified */ DBG_SKB(("Realloc Tx SKB\n")); - new_skb = dev_alloc_skb(pktlen + TAG_SZ + FCS_SZ); + /* + * New SKB needs extra TAG_SZ for VLAN tag + * and extra FCS_SZ for Ethernet FCS. + */ + headroom = TAG_SZ; + tailroom = FCS_SZ; + new_skb = skb_copy_expand(skb, + headroom + skb_headroom(skb), + tailroom + skb_tailroom(skb), + GFP_ATOMIC); if (new_skb == NULL) { DBG_WARN(("Tx drop: No SKB memory\n")); priv->stats.tx_dropped++; @@ -5458,9 +5507,12 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&sinfo->lock, flags); return 0; } + /* Remove rcpulen from buffer. */ + skb_pull(new_skb, rcpulen); + /* Extended by TAG_SZ at the start of buffer. */ + skb_push(new_skb, TAG_SZ); + /* Restore the data before the tag. */ memcpy(new_skb->data, pktdata, 12); - memcpy(&new_skb->data[16], &pktdata[12], pktlen - 12); - skb_put(new_skb, pktlen + TAG_SZ); bkn_skb_tstamp_copy(new_skb, skb); dev_kfree_skb_any(skb); skb = new_skb; @@ -5489,7 +5541,16 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) if (skb_header_cloned(skb) || skb_headroom(skb) < hdrlen + 4) { /* Current SKB cannot be modified */ DBG_SKB(("Realloc Tx SKB\n")); - new_skb = dev_alloc_skb(pktlen + hdrlen + 4 + FCS_SZ); + if (device_is_sand(sinfo)) { + headroom = hdrlen; + } else { + headroom = hdrlen + 4; + } + tailroom = FCS_SZ; + new_skb = skb_copy_expand(skb, + headroom + skb_headroom(skb), + tailroom + skb_tailroom(skb), + GFP_ATOMIC); if (new_skb == NULL) { DBG_WARN(("Tx drop: No SKB memory\n")); priv->stats.tx_dropped++; @@ -5498,12 +5559,7 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&sinfo->lock, flags); return 0; } - if (!device_is_sand(sinfo)) - { - skb_reserve(new_skb, 4); - } - memcpy(new_skb->data + hdrlen, skb->data, pktlen); - skb_put(new_skb, pktlen + hdrlen); + skb_push(new_skb, hdrlen); bkn_skb_tstamp_copy(new_skb, skb); dev_kfree_skb_any(skb); skb = new_skb; @@ -5526,7 +5582,12 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) if (skb_header_cloned(skb) || skb_headroom(skb) < 4) { /* Current SKB cannot be modified */ DBG_SKB(("Realloc Tx SKB\n")); - new_skb = dev_alloc_skb(pktlen + TAG_SZ + FCS_SZ); + headroom = TAG_SZ; + tailroom = FCS_SZ; + new_skb = skb_copy_expand(skb, + headroom + skb_headroom(skb), + tailroom + skb_tailroom(skb), + GFP_ATOMIC); if (new_skb == NULL) { DBG_WARN(("Tx drop: No SKB memory\n")); priv->stats.tx_dropped++; @@ -5535,10 +5596,8 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&sinfo->lock, flags); return 0; } - memcpy(new_skb->data, skb->data, hdrlen + 12); - memcpy(&new_skb->data[hdrlen + 16], &skb->data[hdrlen + 12], - pktlen - hdrlen - 12); - skb_put(new_skb, pktlen + TAG_SZ); + skb_push(new_skb, TAG_SZ); + memcpy(new_skb->data, pktdata, hdrlen + 12); bkn_skb_tstamp_copy(new_skb, skb); dev_kfree_skb_any(skb); skb = new_skb; @@ -5868,24 +5927,11 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) priv->stats.tx_bytes += pktlen; sinfo->tx.pkts++; } else { -#ifdef SAI_FIXUP /* SDK-224448 */ DBG_VERB(("Tx busy: No DMA resources\n")); sinfo->tx.pkts_d_dma_resrc++; -#else - DBG_WARN(("Tx drop: No DMA resources\n")); - priv->stats.tx_dropped++; - sinfo->tx.pkts_d_dma_resrc++; - dev_kfree_skb_any(skb); - } - - /* Check our Tx resources */ - if (sinfo->tx.free <= 1) { -#endif /* SDK-224448 */ bkn_suspend_tx(sinfo); -#ifdef SAI_FIXUP /* SDK-224448 */ spin_unlock_irqrestore(&sinfo->lock, flags); return BKN_NETDEV_TX_BUSY; -#endif /* SDK-224448 */ } NETDEV_UPDATE_TRANS_START_TIME(dev); @@ -6105,6 +6151,7 @@ bkn_create_sinfo(int dev_no) sinfo->dma_dev = lkbde_get_dma_dev(dev_no); sinfo->pdev = lkbde_get_hw_dev(dev_no); sinfo->dev_no = dev_no; + sinfo->inst_id = INVALID_INSTANCE_ID; sinfo->evt_idx = -1; spin_lock_init(&sinfo->lock); @@ -6196,6 +6243,7 @@ bkn_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) case 26: case 32: case 33: + case 35: case 36: case 38: case 40: @@ -6292,10 +6340,6 @@ bkn_init_ndev(u8 *mac, char *name) if (dev->mtu == 0) { dev->mtu = rx_buffer_size; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)) - dev->min_mtu = 68; - dev->max_mtu = rx_buffer_size; -#endif /* Device vectors */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) @@ -7296,9 +7340,9 @@ bkn_proc_cleanup(void) */ static int -_pprint(void) +_pprint(struct seq_file *m) { - pprintf("Broadcom BCM KNET Linux Network Driver\n"); + pprintf(m, "Broadcom BCM KNET Linux Network Driver\n"); return 0; } @@ -7460,7 +7504,7 @@ bkn_create_inst(uint32 inst_id) DBG_INST(("%s evt_idx %d inst_id 0x%x\n",__FUNCTION__, i, inst_id)); break; } - if ((_bkn_multi_inst == 0) || (evt->inst_id == 0)) { + if ((_bkn_multi_inst == 0) || (evt->inst_id == INVALID_INSTANCE_ID)) { _bkn_multi_inst ++; evt_idx = i; init_waitqueue_head(&evt->evt_wq); @@ -7475,7 +7519,7 @@ bkn_create_inst(uint32 inst_id) return -1; } for (i = 0; i < kernel_bde->num_devices(BDE_ALL_DEVICES); i++) { - if (inst_id & (1 << i)) { + if (lkbde_is_dev_managed_by_instance(i, inst_id)) { sinfo = bkn_sinfo_from_unit(i); spin_lock_irqsave(&sinfo->lock, flags); sinfo->evt_idx = evt_idx; @@ -7519,23 +7563,28 @@ bkn_knet_dev_inst_set(kcom_msg_reprobe_t *kmsg) { bkn_switch_info_t *sinfo; int d = kmsg->hdr.unit; - uint32 inst = 0; + uint32 inst = INVALID_INSTANCE_ID; unsigned long flags; struct list_head *list; sinfo = bkn_sinfo_from_unit(d); +#ifdef BCM_INSTANCE_SUPPORT lkbde_dev_instid_get(d, &inst); +#else + inst = INVALID_INSTANCE_ID; +#endif + DBG_INST(("%s sinfo->inst_id %d d %d inst %d\n",__FUNCTION__,sinfo->inst_id, d, inst)); spin_lock_irqsave(&sinfo->lock, flags); if (sinfo->inst_id != inst) { /* Instance database changed, reinit the inst_id */ - sinfo->inst_id = 0; + sinfo->inst_id = INVALID_INSTANCE_ID; sinfo->evt_idx = -1; } spin_unlock_irqrestore(&sinfo->lock, flags); - if (inst) { - if (sinfo->inst_id == 0) { + if (inst != INVALID_INSTANCE_ID) { + if (sinfo->inst_id == INVALID_INSTANCE_ID) { if (bkn_create_inst(inst) != 0) { return -1; } @@ -7549,7 +7598,7 @@ bkn_knet_dev_inst_set(kcom_msg_reprobe_t *kmsg) sinfo = (bkn_switch_info_t *)list; spin_lock_irqsave(&sinfo->lock, flags); sinfo->evt_idx = 0; - sinfo->inst_id = 0; + sinfo->inst_id = INVALID_INSTANCE_ID; spin_unlock_irqrestore(&sinfo->lock, flags); } } @@ -7880,16 +7929,16 @@ bkn_knet_netif_create(kcom_msg_netif_create_t *kmsg, int len) } } + DBG_VERB(("Assigned ID %d to Ethernet device %s\n", priv->id, dev->name)); kmsg->netif.id = priv->id; memcpy(kmsg->netif.macaddr, dev->dev_addr, 6); memcpy(kmsg->netif.name, dev->name, KCOM_NETIF_NAME_MAX - 1); - if (knet_netif_create_cb != NULL) { int retv = knet_netif_create_cb(kmsg->hdr.unit, &(kmsg->netif), dev); - if (retv) { + if (retv) { gprintk("Warning: knet_netif_create_cb() returned %d for netif '%s'\n", retv, dev->name); } } @@ -7947,6 +7996,7 @@ bkn_knet_netif_destroy(kcom_msg_netif_destroy_t *kmsg, int len) netif.id = priv->id; knet_netif_destroy_cb(kmsg->hdr.unit, &netif, priv->dev); } + list_del(&priv->list); if (priv->id < sinfo->ndev_max) { @@ -8473,8 +8523,8 @@ bkn_get_next_dma_event(kcom_msg_dma_info_t *kmsg) sinfo = bkn_sinfo_from_unit(dev_no); } - if (sinfo && (sinfo->inst_id != 0) && - ((sinfo->inst_id & (1 << dev_evt)) == 0)) { + if (sinfo && (sinfo->inst_id != INVALID_INSTANCE_ID) && + (!lkbde_is_dev_managed_by_instance(dev_evt, sinfo->inst_id))) { DBG_INST((" %s skip dev(%d)\n",__FUNCTION__,dev_no)); continue; } @@ -8540,8 +8590,10 @@ _cleanup(void) del_timer_sync(&sinfo->rxtick); spin_lock_irqsave(&sinfo->lock, flags); - bkn_dma_abort(sinfo); - dev_irq_mask_set(sinfo, 0); + if (DEV_IS_CMIC(sinfo)) { + bkn_dma_abort(sinfo); + dev_irq_mask_set(sinfo, 0); + } spin_unlock_irqrestore(&sinfo->lock, flags); DBG_IRQ(("Unregister ISR.\n")); @@ -8759,6 +8811,7 @@ _init(void) /* Initialize event queue */ for (idx = 0; idx < LINUX_BDE_MAX_DEVICES; idx++) { memset(&_bkn_evt[idx], 0, sizeof(bkn_evt_resource_t)); + _bkn_evt[idx].inst_id = INVALID_INSTANCE_ID; } evt = &_bkn_evt[0]; init_waitqueue_head(&evt->evt_wq); diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-ptp-clock/Makefile b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-ptp-clock/Makefile index 1c9a3209e133..9aa3be686851 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-ptp-clock/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-ptp-clock/Makefile @@ -14,9 +14,9 @@ # version 2 (GPLv2) along with this source code. # # -*- Makefile -*- -# $Id: Makefile,v 1.3 Broadcom SDK $ -# $Copyright: (c) 2020 Broadcom. -# Broadcom Proprietary and Confidential. All rights reserved.$ +# $Id: Makefile,v 1.3 2012/07/17 07:39:51 mlarsen Exp $ +# $Copyright: (c) 2005 Broadcom Corp. +# All Rights Reserved.$ # LOCALDIR = systems/linux/kernel/modules/bcm-ptp-clock diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-ptp-clock/bcm-ptp-clock.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-ptp-clock/bcm-ptp-clock.c index 5b0a6bde738d..edc4a38c741c 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-ptp-clock/bcm-ptp-clock.c +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/bcm-ptp-clock/bcm-ptp-clock.c @@ -76,9 +76,13 @@ MODULE_PARM_DESC(fw_core, /* Debug levels */ #define DBG_LVL_VERB 0x1 #define DBG_LVL_WARN 0x2 +#define DBG_LVL_TXTS 0x4 +#define DBG_LVL_CMDS 0x8 #define DBG_VERB(_s) do { if (debug & DBG_LVL_VERB) gprintk _s; } while (0) #define DBG_WARN(_s) do { if (debug & DBG_LVL_WARN) gprintk _s; } while (0) +#define DBG_TXTS(_s) do { if (debug & DBG_LVL_TXTS) gprintk _s; } while (0) +#define DBG_CMDS(_s) do { if (debug & DBG_LVL_CMDS) gprintk _s; } while (0) #define DBG_ERR(_s) do { if (1) gprintk _s; } while (0) @@ -98,41 +102,37 @@ MODULE_PARM_DESC(fw_core, #define BKSYNC_PACKLEN_U24 3 #define BKSYNC_PACKLEN_U32 4 -#define BKSYNC_UNPACK_U8(_buf, _var) \ +#define BKSYNC_UNPACK_U8(_buf, _var) \ _var = *_buf++ -#define BKSYNC_UNPACK_U16(_buf, _var) \ +#define BKSYNC_UNPACK_U16(_buf, _var) \ do { \ (_var) = (((_buf)[0] << 8) | \ (_buf)[1]); \ - (_buf) += BKSYNC_PACKLEN_U16; \ + (_buf) += BKSYNC_PACKLEN_U16; \ } while (0) -#define BKSYNC_UNPACK_U24(_buf, _var) \ +#define BKSYNC_UNPACK_U24(_buf, _var) \ do { \ (_var) = (((_buf)[0] << 16) | \ ((_buf)[1] << 8) | \ (_buf)[2]); \ - (_buf) += BKSYNC_PACKLEN_U24; \ + (_buf) += BKSYNC_PACKLEN_U24; \ } while (0) -#define BKSYNC_UNPACK_U32(_buf, _var) \ +#define BKSYNC_UNPACK_U32(_buf, _var) \ do { \ (_var) = (((_buf)[0] << 24) | \ ((_buf)[1] << 16) | \ ((_buf)[2] << 8) | \ (_buf)[3]); \ - (_buf) += BKSYNC_PACKLEN_U32; \ + (_buf) += BKSYNC_PACKLEN_U32; \ } while (0) #define CMICX_DEV_TYPE ((ptp_priv->dcb_type == 38) || \ (ptp_priv->dcb_type == 36)) -#define HOSTCMD_USE_REGS ((ptp_priv->dcb_type == 38) || \ - (ptp_priv->dcb_type == 36) || \ - (ptp_priv->dcb_type == 32)) - /* CMIC MCS-0 SCHAN Messaging registers */ /* Core0:CMC1 Core1:CMC2 */ #define CMIC_CMC_BASE \ @@ -154,30 +154,58 @@ MODULE_PARM_DESC(fw_core, u32 hostcmd_regs[5] = { 0 }; -/* TX Timestamp FIFO Access */ -#define BCM_NUM_PORTS 128 +#define BCMKSYNC_NUM_PORTS 128 /* NUM_PORTS where 2-step is supported. */ +#define BCMKSYNC_MAX_NUM_PORTS 256 /* Max ever NUM_PORTS in the system */ +#define BCMKSYNC_MAX_MTP_IDX 8 /* Max number of mtps in the system */ -/* Service request commands to R5 */ +/* Service request commands to Firmware. */ enum { - BCM_KSYNC_DONE = 0x0, - BCM_KSYNC_INIT = 0x1, - BCM_KSYNC_DEINIT = 0x2, - BCM_KSYNC_GETTIME = 0x3, - BCM_KSYNC_SETTIME = 0x4, - BCM_KSYNC_FREQCOR = 0x5, - BCM_KSYNC_PBM_UPDATE = 0x6, - BCM_KSYNC_ADJTIME = 0x7, - BCM_KSYNC_GET_TSTIME = 0x8, + BKSYNC_DONE = (0x0), + BKSYNC_INIT = (0x1), + BKSYNC_DEINIT = (0x2), + BKSYNC_GETTIME = (0x3), + BKSYNC_SETTIME = (0x4), + BKSYNC_FREQCOR = (0x5), + BKSYNC_PBM_UPDATE = (0x6), + BKSYNC_ADJTIME = (0x7), + BKSYNC_GET_TSTIME = (0x8), + BKSYNC_MTP_TS_UPDATE_ENABLE = (0x9), + BKSYNC_MTP_TS_UPDATE_DISABLE = (0xa), + BKSYNC_ACK_TSTIME = (0xb), +}; + + +/* 1588 message types. */ +enum +{ + IEEE1588_MSGTYPE_SYNC = (0x0), + IEEE1588_MSGTYPE_DELREQ = (0x1), + IEEE1588_MSGTYPE_PDELREQ = (0x2), + IEEE1588_MSGTYPE_PDELRESP = (0x3), + /* reserved (0x4) */ + /* reserved (0x5) */ + /* reserved (0x6) */ + /* reserved (0x7) */ + IEEE1588_MSGTYPE_GENERALMASK = (0x8), /* all non-event messages have this bit set */ + IEEE1588_MSGTYPE_FLWUP = (0x8), + IEEE1588_MSGTYPE_DELRESP = (0x9), + IEEE1588_MSGTYPE_PDELRES_FLWUP = (0xA), + IEEE1588_MSGTYPE_ANNOUNCE = (0xB), + IEEE1588_MSGTYPE_SGNLNG = (0xC), + IEEE1588_MSGTYPE_MNGMNT = (0xD) + /* reserved (0xE) */ + /* reserved (0xF) */ }; /* Usage macros */ #define ONE_BILLION (1000000000) #define SKB_U16_GET(_skb, _pkt_offset) \ - ((_skb->data[_pkt_offset] << 8) | _skb->data[_pkt_offset + 1]) + ((_skb->data[_pkt_offset] << 8) | _skb->data[_pkt_offset + 1]) #define BKSYNC_PTP_EVENT_MSG(_ptp_msg_type) \ - ((_ptp_msg_type == DELAY_REQ) || (_ptp_msg_type == SYNC)) + ((_ptp_msg_type == IEEE1588_MSGTYPE_DELREQ) || \ + (_ptp_msg_type == IEEE1588_MSGTYPE_SYNC)) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) @@ -187,10 +215,6 @@ enum { #endif -/* Values for the messageType field */ -#define SYNC 0x0 -#define DELAY_REQ 0x1 - /* * Hardware specific information. * 4 words of information used from this data set. @@ -225,6 +249,19 @@ uint32_t sobmhudpipv6_dcb32[24] = {0x00000000, 0x00013E00, 0x00000000, 0x0000000 0x00000000, 0x000C3E00, 0x00000000, 0x00000000, 0x00000000, 0x000C4200, 0x00000000, 0x00000000, 0x00000000, 0x000C3E00, 0x00000000, 0x00000000, 0x00000000, 0x000C4200, 0x00000000, 0x00000000}; +uint32_t sobmhrawpkts_dcb35[24] = {0x00000000, 0x0020E000, 0x00000000, 0x00000000, 0x00000000, 0x00212000, 0x00000000, 0x00000000, + 0x00000000, 0x0100E000, 0x00000000, 0x00000000, 0x00000000, 0x01012000, 0x00000000, 0x00000000, + 0x00000000, 0x0140E000, 0x00000000, 0x00000000, 0x00000000, 0x01412000, 0x00000000, 0x00000000}; + +uint32_t sobmhudpipv4_dcb35[24] = {0x00000000, 0x0022A000, 0x00000000, 0x00000000, 0x00000000, 0x0022E000, 0x00000000, 0x00000000, + 0x00000000, 0x0102A000, 0x00000000, 0x00000000, 0x00000000, 0x0102E000, 0x00000000, 0x00000000, + 0x00000000, 0x0142A000, 0x00000000, 0x00000000, 0x00000000, 0x0142E000, 0x00000000, 0x00000000}; + +uint32_t sobmhudpipv6_dcb35[24] = {0x00000000, 0x0023E000, 0x00000000, 0x00000000, 0x00000000, 0x00242000, 0x00000000, 0x00000000, + 0x00000000, 0x0103E000, 0x00000000, 0x00000000, 0x00000000, 0x01042000, 0x00000000, 0x00000000, + 0x00000000, 0x0143E000, 0x00000000, 0x00000000, 0x00000000, 0x01442000, 0x00000000, 0x00000000}; + + uint32_t sobmhrawpkts_dcb36[24] = {0x00000000, 0x00010E00, 0x00000000, 0x00000000, 0x00000000, 0x00011200, 0x00000000, 0x00000000, 0x00000000, 0x00080E00, 0x00000000, 0x00000000, 0x00000000, 0x00081200, 0x00000000, 0x00000000, 0x00000000, 0x00080E00, 0x00000000, 0x00000000, 0x00000000, 0x00081200, 0x00000000, 0x00000000}; @@ -267,21 +304,26 @@ typedef struct _bksync_uc_linux_ipc_s u32 ksyncinit; u32 dev_id; s64 freqcorr; - u64 portmap[BCM_NUM_PORTS/64]; + u64 portmap[BCMKSYNC_NUM_PORTS/64]; /* Two-step enabled ports */ u64 ptptime; u64 reftime; s64 phase_offset; - bksync_tx_ts_data_t port_ts_data[BCM_NUM_PORTS]; + bksync_tx_ts_data_t port_ts_data[BCMKSYNC_NUM_PORTS]; } bksync_uc_linux_ipc_t; typedef struct bksync_port_stats_s { u32 pkt_rxctr; /* All ingress packets */ u32 pkt_txctr; /* All egress packets */ + u32 pkt_txonestep; /* 1-step Tx packet counter */ u32 tsts_match; /* 2-Step tstamp req match */ u32 tsts_timeout; /* 2-Step tstamp req timeouts */ u32 tsts_discard; /* 2-Step tstamp req discards */ u32 osts_event_pkts; /* 1-step event packet counter */ u32 osts_tstamp_reqs; /* 1-step events with tstamp request */ + u32 fifo_rxctr; /* 2-Step tstamp req match */ + u64 tsts_best_fetch_time; /* 1-step events with tstamp request */ + u64 tsts_worst_fetch_time; /* 1-step events with tstamp request */ + u32 tsts_avg_fetch_time; /* 1-step events with tstamp request */ } bksync_port_stats_t; /* Clock Private Data */ @@ -296,14 +338,10 @@ struct bksync_ptp_priv { volatile bksync_uc_linux_ipc_t *shared_addr; /* address for shared memory access */ uint64_t dma_mem; int dma_mem_size; - int num_pports; struct DMA_DEV *dma_dev; /* Required for DMA memory control */ - u32 pkt_rxctr[BCM_NUM_PORTS]; - u32 pkt_txctr[BCM_NUM_PORTS]; - u32 ts_match[BCM_NUM_PORTS]; - u32 ts_timeout[BCM_NUM_PORTS]; - u32 ts_discard[BCM_NUM_PORTS]; + int num_pports; int timekeep_status; + u32 mirror_encap_bmp; struct delayed_work time_keep; bksync_port_stats_t *port_stats; }; @@ -311,7 +349,7 @@ struct bksync_ptp_priv { static struct bksync_ptp_priv *ptp_priv; volatile bksync_uc_linux_ipc_t *linuxPTPMemory = (bksync_uc_linux_ipc_t*)(0); static volatile int module_initialized; -static int retry_count = 10; /* Default retry for 10 jiffies */ +static int num_retries = 10; /* Retry count */ static void bksync_ptp_time_keep_init(void); static void bksync_ptp_time_keep_deinit(void); @@ -366,64 +404,6 @@ ptp_sleep(int jiffies) } -static int bksync_cmd_cmicm_go(u32 cmd, void *data0, void *data1) -{ - int ret = -1; - int retry_cnt = retry_count; - u32 cmd_status; - - mutex_lock(&ptp_priv->ptp_lock); - ptp_priv->shared_addr->ksyncinit = cmd; - switch (cmd) { - case BCM_KSYNC_INIT: - ptp_priv->shared_addr->phase_offset = 0; - ret = 0; - break; - case BCM_KSYNC_FREQCOR: - ptp_priv->shared_addr->freqcorr = *((s32 *)data0); - break; - case BCM_KSYNC_ADJTIME: - ptp_priv->shared_addr->phase_offset = *((s64 *)data0); - break; - case BCM_KSYNC_GETTIME: - break; - case BCM_KSYNC_SETTIME: - ptp_priv->shared_addr->ptptime = *((s64 *)data0); - ptp_priv->shared_addr->phase_offset = 0; - break; - default: - break; - } - - do { - cmd_status = ptp_priv->shared_addr->ksyncinit; - if (cmd_status == BCM_KSYNC_DONE) { - switch (cmd) { - case BCM_KSYNC_GETTIME: - *((s64 *)data0) = ptp_priv->shared_addr->ptptime; - *((s64 *)data1) = ptp_priv->shared_addr->reftime; /* ptp counter */ - break; - default: - break; - } - ret = 0; - break; - } - ptp_sleep(1); - retry_cnt--; - } while (retry_cnt); - mutex_unlock(&ptp_priv->ptp_lock); - - if (retry_cnt == 0) { - DBG_ERR(("Timeout on response from R5\n")); - } - - - return ret; -} - - - static void bksync_hostcmd_data_op(int setget, u64 *d1, u64 *d2) { u32 w0, w1; @@ -455,14 +435,28 @@ static void bksync_hostcmd_data_op(int setget, u64 *d1, u64 *d2) } -static int bksync_cmd_cmicx_go(u32 cmd, void *data0, void *data1) +static int bksync_cmd_go(u32 cmd, void *data0, void *data1) { int ret = -1; - int retry_cnt = (retry_count * 100); + int retry_cnt = (1000); /* 1ms default timeout for hostcmd response */ u32 cmd_status; char cmd_str[20]; + int port; + uint32_t seq_id; + ktime_t start, now; + + if (ptp_priv == NULL || ptp_priv->shared_addr == NULL) { + return ret; + } mutex_lock(&ptp_priv->ptp_lock); + + if (cmd == BKSYNC_GET_TSTIME || cmd == BKSYNC_ACK_TSTIME) { + port = *((uint64_t *)data0) & 0xFFF; + seq_id = *((uint64_t*)data0) >> 16; + } + start = ktime_get(); + ptp_priv->shared_addr->ksyncinit = cmd; /* init data */ @@ -472,36 +466,53 @@ static int bksync_cmd_cmicx_go(u32 cmd, void *data0, void *data1) DEV_WRITE32(ptp_priv, hostcmd_regs[4], 0x0); switch (cmd) { - case BCM_KSYNC_INIT: + case BKSYNC_INIT: sprintf(cmd_str, "KSYNC_INIT"); ptp_priv->shared_addr->phase_offset = 0; bksync_hostcmd_data_op(1, (u64 *)&(ptp_priv->shared_addr->phase_offset), 0); break; - case BCM_KSYNC_FREQCOR: + case BKSYNC_FREQCOR: sprintf(cmd_str, "KSYNC_FREQCORR"); ptp_priv->shared_addr->freqcorr = *((s32 *)data0); bksync_hostcmd_data_op(1, (u64 *)&(ptp_priv->shared_addr->freqcorr), 0); break; - case BCM_KSYNC_ADJTIME: + case BKSYNC_ADJTIME: sprintf(cmd_str, "KSYNC_ADJTIME"); ptp_priv->shared_addr->phase_offset = *((s64 *)data0); bksync_hostcmd_data_op(1, (u64 *)&(ptp_priv->shared_addr->phase_offset), 0); break; - case BCM_KSYNC_GETTIME: + case BKSYNC_GETTIME: + retry_cnt = (retry_cnt * 2); sprintf(cmd_str, "KSYNC_GETTIME"); break; - case BCM_KSYNC_GET_TSTIME: + case BKSYNC_GET_TSTIME: retry_cnt = (retry_cnt * 2); sprintf(cmd_str, "KSYNC_GET_TSTIME"); bksync_hostcmd_data_op(1, data0, data1); break; - case BCM_KSYNC_SETTIME: + case BKSYNC_ACK_TSTIME: + retry_cnt = (retry_cnt * 2); + sprintf(cmd_str, "KSYNC_ACK_TSTIME"); + bksync_hostcmd_data_op(1, data0, data1); + break; + case BKSYNC_SETTIME: sprintf(cmd_str, "KSYNC_SETTIME"); ptp_priv->shared_addr->ptptime = *((s64 *)data0); ptp_priv->shared_addr->phase_offset = 0; bksync_hostcmd_data_op(1, (u64 *)&(ptp_priv->shared_addr->ptptime), (u64 *)&(ptp_priv->shared_addr->phase_offset)); break; - case BCM_KSYNC_DEINIT: + case BKSYNC_MTP_TS_UPDATE_ENABLE: + retry_cnt = (retry_cnt * 6); + sprintf(cmd_str, "KSYNC_MTP_TS_UPDATE_ENABLE"); + bksync_hostcmd_data_op(1, (u64 *)data0, 0); + break; + case BKSYNC_MTP_TS_UPDATE_DISABLE: + retry_cnt = (retry_cnt * 6); + sprintf(cmd_str, "KSYNC_MTP_TS_UPDATE_DISABLE"); + bksync_hostcmd_data_op(1, (u64 *)data0, 0); + break; + case BKSYNC_DEINIT: + retry_cnt = (retry_cnt * 4); sprintf(cmd_str, "KSYNC_DEINIT"); break; default: @@ -514,11 +525,11 @@ static int bksync_cmd_cmicx_go(u32 cmd, void *data0, void *data1) DEV_READ32(ptp_priv, hostcmd_regs[0], &cmd_status); ptp_priv->shared_addr->ksyncinit = cmd_status; - if (cmd_status == BCM_KSYNC_DONE) { + if (cmd_status == BKSYNC_DONE) { ret = 0; switch (cmd) { - case BCM_KSYNC_GET_TSTIME: - case BCM_KSYNC_GETTIME: + case BKSYNC_GET_TSTIME: + case BKSYNC_GETTIME: bksync_hostcmd_data_op(0, (u64 *)data0, (u64 *)data1); break; default: @@ -530,37 +541,20 @@ static int bksync_cmd_cmicx_go(u32 cmd, void *data0, void *data1) retry_cnt--; } while (retry_cnt); + now = ktime_get(); mutex_unlock(&ptp_priv->ptp_lock); if (retry_cnt == 0) { - DBG_ERR(("Timeout on response from R5 to cmd %s\n", cmd_str)); + DBG_ERR(("Timeout on response from R5 to cmd %s time taken %lld us\n", cmd_str, ktime_us_delta(now, start))); + if (cmd == BKSYNC_GET_TSTIME) { + DBG_TXTS(("Timeout Port %d SeqId %d\n", port, seq_id)); + } } - - - return ret; -} - - -static int bksync_cmd_go(u32 cmd, void *data0, void *data1) -{ - int ret = -1; - - if (ptp_priv == NULL || ptp_priv->shared_addr == NULL) { - return ret; + if (debug & DBG_LVL_CMDS) { + if (ktime_us_delta(now, start) > 5000) + DBG_CMDS(("R5 Command %s exceeded time expected (%lld us)\n", cmd_str, ktime_us_delta(now, start))); } - switch (ptp_priv->dcb_type) { - case 26: - ret = bksync_cmd_cmicm_go(cmd, data0, data1); - break; - case 32: - case 36: - case 38: - ret = bksync_cmd_cmicx_go(cmd, data0, data1); - break; - default: - break; - } return ret; } @@ -577,7 +571,7 @@ static int bksync_cmd_go(u32 cmd, void *data0, void *data1) static int bksync_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) { int ret = -1; - u32 cmd_status = BCM_KSYNC_FREQCOR; + u32 cmd_status = BKSYNC_FREQCOR; ret = bksync_cmd_go(cmd_status, &ppb, NULL); DBG_VERB(("applying freq correction: %x\n", ppb)); @@ -595,7 +589,7 @@ static int bksync_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) */ static int bksync_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { - u32 cmd_status = BCM_KSYNC_ADJTIME; + u32 cmd_status = BKSYNC_ADJTIME; int ret = -1; ret = bksync_cmd_go(cmd_status, (void *)&delta, NULL); @@ -616,18 +610,20 @@ static int bksync_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) static int bksync_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) { int ret = -1; - u32 cmd_status = BCM_KSYNC_GETTIME; + u32 cmd_status = BKSYNC_GETTIME; s64 reftime = 0; s64 refctr = 0; ret = bksync_cmd_go(cmd_status, (void *)&reftime, (void *)&refctr); - DBG_VERB(("ptp gettime: 0x%llx refctr:0x%llx\n", reftime, refctr)); - mutex_lock(&ptp_priv->ptp_pair_lock); - ptp_priv->shared_addr->ptptime = reftime; - ptp_priv->shared_addr->reftime = refctr; - mutex_unlock(&ptp_priv->ptp_pair_lock); - - *ts = ns_to_timespec64(reftime); + if (ret == 0) { + DBG_VERB(("ptp gettime: 0x%llx refctr:0x%llx\n", reftime, refctr)); + mutex_lock(&ptp_priv->ptp_pair_lock); + ptp_priv->shared_addr->ptptime = reftime; + ptp_priv->shared_addr->reftime = refctr; + mutex_unlock(&ptp_priv->ptp_pair_lock); + + *ts = ns_to_timespec64(reftime); + } return ret; } @@ -646,7 +642,7 @@ static int bksync_ptp_settime(struct ptp_clock_info *ptp, { s64 reftime, phaseadj; int ret = -1; - u32 cmd_status = BCM_KSYNC_SETTIME; + u32 cmd_status = BKSYNC_SETTIME; phaseadj = 0; reftime = timespec64_to_ns(ts); @@ -663,6 +659,38 @@ static int bksync_ptp_enable(struct ptp_clock_info *ptp, return 0; } + +static int bksync_ptp_mirror_encap_update(struct ptp_clock_info *ptp, + int mtp_idx, int start) +{ + int ret = -1; + u64 mirror_encap_idx; + u32 cmd_status; + + if (mtp_idx > BCMKSYNC_MAX_MTP_IDX) { + return ret; + } + + mirror_encap_idx = mtp_idx; + if (start) { + cmd_status = BKSYNC_MTP_TS_UPDATE_ENABLE; + ptp_priv->mirror_encap_bmp |= (1 << mtp_idx); + } else { + if (!(ptp_priv->mirror_encap_bmp & mtp_idx)) { + /* Not running */ + return ret; + } + cmd_status = BKSYNC_MTP_TS_UPDATE_DISABLE; + ptp_priv->mirror_encap_bmp &= ~mtp_idx; + } + + ret = bksync_cmd_go(cmd_status, &mirror_encap_idx, NULL); + DBG_VERB(("ptp mmirror_encap_update: %d, mpt_index: %d, ret:%d \n", start, mtp_idx, ret)); + + return ret; + +} + /* structure describing a PTP hardware clock */ static struct ptp_clock_info bksync_ptp_caps = { .owner = THIS_MODULE, @@ -721,7 +749,7 @@ int bksync_ptp_hw_tstamp_enable(int dev_no, int port, int tx_type) portmap |= (uint64_t)0x1 << port; ptp_priv->shared_addr->portmap[map] = portmap; /* Command to R5 for the update */ - ptp_priv->shared_addr->ksyncinit=BCM_KSYNC_PBM_UPDATE; + ptp_priv->shared_addr->ksyncinit=BKSYNC_PBM_UPDATE; } exit: @@ -769,7 +797,7 @@ int bksync_ptp_hw_tstamp_disable(int dev_no, int port, int tx_type) ptp_priv->shared_addr->portmap[map]= portmap; /* Command to R5 for the update */ - ptp_priv->shared_addr->ksyncinit = BCM_KSYNC_PBM_UPDATE; + ptp_priv->shared_addr->ksyncinit = BKSYNC_PBM_UPDATE; } exit: return ret; @@ -818,23 +846,26 @@ bksync_txpkt_tsts_tsamp_get(int port, uint32_t pkt_seq_id, uint32_t *ts_valid, u { int ret = 0; uint64_t tmp; + u32 fifo_rxctr = 0; tmp = (port & 0xFFFF) | (pkt_seq_id << 16); - if (HOSTCMD_USE_REGS) { - ret = bksync_cmd_go(BCM_KSYNC_GET_TSTIME, &tmp, timestamp); - - if (ret >= 0) { - *seq_id = ((tmp >> 16) & 0xFFFF); - *ts_valid = (tmp & 0x1); + ret = bksync_cmd_go(BKSYNC_GET_TSTIME, &tmp, timestamp); + + if (ret >= 0) { + fifo_rxctr = (tmp >> 32) & 0xFFFF; + *seq_id = ((tmp >> 16) & 0xFFFF); + *ts_valid = (tmp & 0x1); + if (*ts_valid) { + tmp = (port & 0xFFFF) | (pkt_seq_id << 16); + bksync_cmd_go(BKSYNC_ACK_TSTIME, &tmp, 0); + if (fifo_rxctr != 0) { + if (fifo_rxctr != ptp_priv->port_stats[port].fifo_rxctr + 1) { + DBG_ERR(("FW Reset or Lost Timestamp RxSeq:(Prev %d : Current %d)\n", ptp_priv->port_stats[port].fifo_rxctr, fifo_rxctr)); + } + ptp_priv->port_stats[port].fifo_rxctr = fifo_rxctr; + } } -#if 0 - if (tmp & 0x1) gprintk("in_port: %d in_seq_id: %d out_port: %lld ts_valid: %lld seq_id: %lld ts: %llx\n", port, pkt_seq_id, ((tmp & 0xFFFF) >> 1), (tmp & 0x1), (tmp >> 16), *timestamp); -#endif - } else { - *ts_valid = ptp_priv->shared_addr->port_ts_data[port].ts_valid; - *seq_id = ptp_priv->shared_addr->port_ts_data[port].ts_seq_id; - *timestamp = ptp_priv->shared_addr->port_ts_data[port].timestamp; } @@ -861,9 +892,12 @@ int bksync_ptp_hw_tstamp_tx_time_get(int dev_no, int port, uint8_t *pkt, uint64_ uint32_t pktseq_id = 0; uint64_t timestamp = 0; uint16_t tpid = 0; - int retry_cnt = retry_count; + ktime_t start; + u64 delta; + int retry_cnt = num_retries; int seq_id_offset, tpid_offset; int transport = network_transport; + start = ktime_get(); if (!ptp_priv || !pkt || !ts || port < 1 || port > 255 || ptp_priv->shared_addr == NULL) { return -1; @@ -918,25 +952,26 @@ int bksync_ptp_hw_tstamp_tx_time_get(int dev_no, int port, uint8_t *pkt, uint64_ if (seq_id == pktseq_id) { *ts = timestamp; - if (HOSTCMD_USE_REGS) { - ptp_priv->port_stats[port].tsts_match += 1; - } else { - ptp_priv->ts_match[port] += 1; - } + ptp_priv->port_stats[port].tsts_match += 1; - DBG_VERB(("Port: %d Skb_SeqID %d FW_SeqId %d and TS:%llx\n", - port, pktseq_id, seq_id, timestamp)); + delta = ktime_us_delta(ktime_get(), start); + DBG_VERB(("Port: %d Skb_SeqID %d FW_SeqId %d and TS:%llx FetchTime %lld\n", + port, pktseq_id, seq_id, timestamp, delta)); + if (delta < ptp_priv->port_stats[port].tsts_best_fetch_time || ptp_priv->port_stats[port].tsts_best_fetch_time == 0) { + ptp_priv->port_stats[port].tsts_best_fetch_time = delta; + } + if (delta > ptp_priv->port_stats[port].tsts_worst_fetch_time || ptp_priv->port_stats[port].tsts_worst_fetch_time == 0) { + ptp_priv->port_stats[port].tsts_worst_fetch_time = delta; + } + /* Calculate Moving Average*/ + ptp_priv->port_stats[port].tsts_avg_fetch_time = ((u32)delta + ((ptp_priv->port_stats[port].tsts_match - 1) * ptp_priv->port_stats[port].tsts_avg_fetch_time)) / ptp_priv->port_stats[port].tsts_match; break; } else { - DBG_ERR(("discard timestamp on port %d Skb_SeqID %d FW_SeqId %d\n", - port, pktseq_id, seq_id)); + DBG_TXTS(("Discard timestamp on port %d Skb_SeqID %d FW_SeqId %d RetryCnt %d TimeLapsed (%lld us)\n", + port, pktseq_id, seq_id, (num_retries - retry_cnt), ktime_us_delta(ktime_get(),start))); - if (HOSTCMD_USE_REGS) { - ptp_priv->port_stats[port].tsts_discard += 1; - } else { - ptp_priv->ts_discard[port] += 1; - } + ptp_priv->port_stats[port].tsts_discard += 1; continue; } } @@ -945,19 +980,12 @@ int bksync_ptp_hw_tstamp_tx_time_get(int dev_no, int port, uint8_t *pkt, uint64_ } while(retry_cnt); - if (HOSTCMD_USE_REGS) { - ptp_priv->port_stats[port].pkt_txctr += 1; - } else { - ptp_priv->pkt_txctr[port] += 1; - } + ptp_priv->port_stats[port].pkt_txctr += 1; if (retry_cnt == 0) { - if (HOSTCMD_USE_REGS) { - ptp_priv->port_stats[port].tsts_timeout += 1; - } else { - ptp_priv->ts_timeout[port] += 1; - } - DBG_ERR(("FW Response timeout: Tx TS on phy port:%d Skb_SeqID: %d\n", port, seq_id)); + ptp_priv->port_stats[port].tsts_timeout += 1; + DBG_ERR(("FW Response timeout: Tx TS on phy port:%d Skb_SeqID: %d TimeLapsed (%lld us)\n", + port, pktseq_id, ktime_us_delta(ktime_get(), start))); } @@ -1113,6 +1141,7 @@ int bksync_ptp_hw_tstamp_rx_time_upscale(int dev_no, int port, struct sk_buff *s switch (KNET_SKB_CB(skb)->dcb_type) { case 26: case 32: + case 35: if (pci_cos != (meta[4] & 0x3F)) { return -1; } @@ -1142,12 +1171,8 @@ int bksync_ptp_hw_tstamp_rx_time_upscale(int dev_no, int port, struct sk_buff *s } if (port > 0){ - port -= 1; - if (HOSTCMD_USE_REGS) { + port -= 1; ptp_priv->port_stats[port].pkt_rxctr += 1; - } else { - ptp_priv->pkt_rxctr[port] += 1; - } } return ret; @@ -1240,6 +1265,8 @@ int bksync_ptp_hw_tstamp_tx_meta_get(int dev_no, if (md) *md = &sobmhrawpkts_dcb32[md_offset]; } else if(KNET_SKB_CB(skb)->dcb_type == 26) { if (md) *md = &sobmhrawpkts_dcb26[md_offset]; + } else if(KNET_SKB_CB(skb)->dcb_type == 35) { + if (md) *md = &sobmhrawpkts_dcb35[md_offset]; } else if(KNET_SKB_CB(skb)->dcb_type == 36) { if (md) *md = &sobmhrawpkts_dcb36[md_offset]; } else if(KNET_SKB_CB(skb)->dcb_type == 38) { @@ -1252,6 +1279,8 @@ int bksync_ptp_hw_tstamp_tx_meta_get(int dev_no, if (md) *md = &sobmhudpipv4_dcb32[md_offset]; } else if(KNET_SKB_CB(skb)->dcb_type == 26) { if (md) *md = &sobmhudpipv4_dcb26[md_offset]; + } else if(KNET_SKB_CB(skb)->dcb_type == 35) { + if (md) *md = &sobmhudpipv4_dcb35[md_offset]; } else if(KNET_SKB_CB(skb)->dcb_type == 36) { if (md) *md = &sobmhudpipv4_dcb36[md_offset]; } else if(KNET_SKB_CB(skb)->dcb_type == 38) { @@ -1264,6 +1293,8 @@ int bksync_ptp_hw_tstamp_tx_meta_get(int dev_no, if (md) *md = &sobmhudpipv6_dcb32[md_offset]; } else if(KNET_SKB_CB(skb)->dcb_type == 26) { if (md) *md = &sobmhudpipv6_dcb26[md_offset]; + } else if(KNET_SKB_CB(skb)->dcb_type == 35) { + if (md) *md = &sobmhudpipv6_dcb35[md_offset]; } else if(KNET_SKB_CB(skb)->dcb_type == 36) { if (md) *md = &sobmhudpipv6_dcb36[md_offset]; } else if(KNET_SKB_CB(skb)->dcb_type == 38) { @@ -1276,6 +1307,8 @@ int bksync_ptp_hw_tstamp_tx_meta_get(int dev_no, if (md) *md = &sobmhudpipv4_dcb32[md_offset]; } else if(KNET_SKB_CB(skb)->dcb_type == 26) { if (md) *md = &sobmhudpipv4_dcb26[md_offset]; + } else if(KNET_SKB_CB(skb)->dcb_type == 35) { + if (md) *md = &sobmhudpipv4_dcb35[md_offset]; } else if(KNET_SKB_CB(skb)->dcb_type == 36) { if (md) *md = &sobmhudpipv4_dcb36[md_offset]; } else if(KNET_SKB_CB(skb)->dcb_type == 38) { @@ -1285,7 +1318,7 @@ int bksync_ptp_hw_tstamp_tx_meta_get(int dev_no, } - if ((hwts == HWTSTAMP_TX_ONESTEP_SYNC) && + if ((hwts == HWTSTAMP_TX_ONESTEP_SYNC) && BKSYNC_PTP_EVENT_MSG(skb->data[ptp_hdr_offset])) { /* One Step Timestamp Field updation */ int corr_offset = ptp_hdr_offset + 8; @@ -1295,6 +1328,7 @@ int bksync_ptp_hw_tstamp_tx_meta_get(int dev_no, int udp_csum_regen; u32 udp_csum20; u16 udp_csum; + int port; udp_csum = SKB_U16_GET(skb, (ptp_hdr_offset - 2)); @@ -1360,12 +1394,15 @@ int bksync_ptp_hw_tstamp_tx_meta_get(int dev_no, skb->data[ptp_hdr_offset - 1] = ((udp_csum ) & 0xFF); } - if (skb->data[ptp_hdr_offset] == DELAY_REQ) { + if (skb->data[ptp_hdr_offset] == IEEE1588_MSGTYPE_DELREQ) { *tstamp = ptptime; DBG_VERB(("ptp delay req packet tstamp : 0x%llx corrField: 0x%llx\n", ptptime, corrField)); } + port = KNET_SKB_CB(skb)->port; + port -= 1; + ptp_priv->port_stats[port].pkt_txonestep += 1; } return 0; @@ -1425,14 +1462,14 @@ static void bksync_ptp_time_keep_deinit(void) static int bksync_ptp_init(struct ptp_clock_info *ptp) { - return bksync_cmd_go(BCM_KSYNC_INIT, NULL, NULL); + return bksync_cmd_go(BKSYNC_INIT, NULL, NULL); } static int bksync_ptp_deinit(struct ptp_clock_info *ptp) { bksync_ptp_time_keep_deinit(); - return bksync_cmd_go(BCM_KSYNC_DEINIT, NULL, NULL); + return bksync_cmd_go(BKSYNC_DEINIT, NULL, NULL); } /* @@ -1450,14 +1487,15 @@ static void *bksync_proc_seq_start(struct seq_file *s, loff_t *pos) /* beginning a new sequence ? */ if ( (int)*pos == 0 && ptp_priv->shared_addr != NULL) { - seq_printf(s, "Port Bitmap : %08llx%08llx\n", + seq_printf(s, "TwoStep Port Bitmap : %08llx%08llx\n", (uint64_t)(ptp_priv->shared_addr->portmap[1]), (uint64_t)(ptp_priv->shared_addr->portmap[0])); - seq_printf(s,"%4s| %9s| %9s| %9s| %9s| %9s| %9s|\n", - "Port", "RxCounter", "TxCounter", "TSTimeout", "TSRead", "TSMatch", "TSDiscard"); + seq_printf(s,"%4s| %9s| %9s| %9s| %9s| %9s| %9s| %9s| %9s| %9s| %9s| %9s\n", + "Port", "RxCounter", "TxCounter", "TxOneStep", "TSTimeout", "TSRead", "TSMatch", "TSDiscard", + "TimeHi" , "TimeLo", "TimeAvg", "FIFORx"); } - if (ptp_priv->shared_addr != NULL && (int)*pos < (ptp_priv->num_pports)) + if ((int)*pos < (ptp_priv->num_pports)) return (void *)(unsigned long)(*pos + 1); /* End of the sequence, return NULL */ return NULL; @@ -1490,33 +1528,24 @@ static int bksync_proc_seq_show(struct seq_file *s, void *v) { unsigned long port = (unsigned long)v; port = port - 1; - if (HOSTCMD_USE_REGS) { - if (ptp_priv->port_stats[port].pkt_rxctr || ptp_priv->port_stats[port].pkt_txctr || - ptp_priv->port_stats[port].tsts_discard || ptp_priv->port_stats[port].tsts_timeout || - ptp_priv->shared_addr->port_ts_data[port].ts_cnt || ptp_priv->port_stats[port].tsts_match) { - seq_printf(s, "%4lu | %9d| %9d| %9d| %9d| %9d| %9d| %s\n", (port + 1), - ptp_priv->port_stats[port].pkt_rxctr, - ptp_priv->port_stats[port].pkt_txctr, - ptp_priv->port_stats[port].tsts_timeout, - ptp_priv->shared_addr->port_ts_data[port].ts_cnt, - ptp_priv->port_stats[port].tsts_match, - ptp_priv->port_stats[port].tsts_discard, - ptp_priv->port_stats[port].pkt_txctr != ptp_priv->port_stats[port].tsts_match ? "***":""); - } - } else { - if (ptp_priv->pkt_rxctr[port] || ptp_priv->pkt_txctr[port] || - ptp_priv->ts_discard[port] || ptp_priv->ts_timeout[port] || - ptp_priv->shared_addr->port_ts_data[port].ts_cnt || ptp_priv->ts_match[port]) { - seq_printf(s, "%4lu | %9d| %9d| %9d| %9d| %9d| %9d| %s\n", (port + 1), - ptp_priv->pkt_rxctr[port], - ptp_priv->pkt_txctr[port], - ptp_priv->ts_timeout[port], + if (ptp_priv->port_stats[port].pkt_rxctr || ptp_priv->port_stats[port].pkt_txctr || + ptp_priv->port_stats[port].pkt_txonestep|| + ptp_priv->port_stats[port].tsts_discard || ptp_priv->port_stats[port].tsts_timeout || + ptp_priv->shared_addr->port_ts_data[port].ts_cnt || ptp_priv->port_stats[port].tsts_match) { + seq_printf(s, "%4lu | %9d| %9d| %9d| %9d| %9d| %9d| %9d| %9lld| %9lld | %9d|%9d | %s\n", (port + 1), + ptp_priv->port_stats[port].pkt_rxctr, + ptp_priv->port_stats[port].pkt_txctr, + ptp_priv->port_stats[port].pkt_txonestep, + ptp_priv->port_stats[port].tsts_timeout, ptp_priv->shared_addr->port_ts_data[port].ts_cnt, - ptp_priv->ts_match[port], - ptp_priv->ts_discard[port], - ptp_priv->pkt_txctr[port] != ptp_priv->ts_match[port] ? "***":""); + ptp_priv->port_stats[port].tsts_match, + ptp_priv->port_stats[port].tsts_discard, + ptp_priv->port_stats[port].tsts_worst_fetch_time, + ptp_priv->port_stats[port].tsts_best_fetch_time, + ptp_priv->port_stats[port].tsts_avg_fetch_time, + ptp_priv->port_stats[port].fifo_rxctr, + ptp_priv->port_stats[port].pkt_txctr != ptp_priv->port_stats[port].tsts_match ? "***":""); } - } return 0; } @@ -1549,19 +1578,12 @@ bksync_proc_txts_write(struct file *file, const char *buf, if ((ptr = strstr(debug_str, "clear")) != NULL) { for (port = 0; port < ptp_priv->num_pports; port++) { - if (HOSTCMD_USE_REGS) { - ptp_priv->port_stats[port].pkt_rxctr = 0; - ptp_priv->port_stats[port].pkt_txctr = 0; - ptp_priv->port_stats[port].tsts_discard = 0; - ptp_priv->port_stats[port].tsts_timeout = 0; - ptp_priv->port_stats[port].tsts_match = 0; - } else { - ptp_priv->pkt_rxctr[port] = 0; - ptp_priv->pkt_txctr[port] = 0; - ptp_priv->ts_discard[port] = 0; - ptp_priv->ts_timeout[port] = 0; - ptp_priv->ts_match[port] = 0; - } + ptp_priv->port_stats[port].pkt_rxctr = 0; + ptp_priv->port_stats[port].pkt_txctr = 0; + ptp_priv->port_stats[port].pkt_txonestep = 0; + ptp_priv->port_stats[port].tsts_timeout = 0; + ptp_priv->port_stats[port].tsts_match = 0; + ptp_priv->port_stats[port].tsts_discard = 0; if (ptp_priv->shared_addr) ptp_priv->shared_addr->port_ts_data[port].ts_cnt = 0; } @@ -1581,91 +1603,90 @@ struct file_operations bksync_proc_txts_file_ops = { release: seq_release, }; +/* + * Driver Debug Proc Entry + */ static int -bksync_proc_init(void) +bksync_proc_debug_show(struct seq_file *m, void *v) { - struct proc_dir_entry *entry; - - PROC_CREATE(entry, "stats", 0666, bksync_proc_root, &bksync_proc_txts_file_ops); - if (entry == NULL) { - return -1; - } + seq_printf(m, "Configuration:\n"); + seq_printf(m, " debug: 0x%x\n", debug); return 0; } -static int -bksync_proc_cleanup(void) +static ssize_t +bksync_proc_debug_write(struct file *file, const char *buf, + size_t count, loff_t *loff) { - remove_proc_entry("stats", bksync_proc_root); - return 0; -} + char debug_str[40]; + char *ptr; -static void bksync_ptp_cmicm_dma_init(int dcb_type) -{ - int endianess; - int num_pports = 128; - dma_addr_t dma_mem = 0; + if (copy_from_user(debug_str, buf, count)) { + return -EFAULT; + } - /* Initialize the Base address for CMIC and shared Memory access */ - ptp_priv->base_addr = lkbde_get_dev_virt(0); - ptp_priv->dma_dev = lkbde_get_dma_dev(0); + if ((ptr = strstr(debug_str, "debug=")) != NULL) { + ptr += 6; + debug = simple_strtol(ptr, NULL, 0); + } else { + gprintk("Warning: unknown configuration\n"); + } - ptp_priv->dma_mem_size = 16384;/*sizeof(bksync_uc_linux_ipc_t);*/ + return count; +} - if (ptp_priv->shared_addr == NULL) { - DBG_ERR(("Allocate shared memory with R5\n")); - ptp_priv->shared_addr = DMA_ALLOC_COHERENT(ptp_priv->dma_dev, - ptp_priv->dma_mem_size, - &dma_mem); - ptp_priv->dma_mem = (uint64_t)dma_mem; - ptp_priv->num_pports = num_pports; - ptp_priv->port_stats = kzalloc((sizeof(bksync_port_stats_t) * num_pports), GFP_KERNEL); - } +static int bksync_proc_debug_open(struct inode * inode, struct file * file) +{ + return single_open(file, bksync_proc_debug_show, NULL); +} - if (ptp_priv->shared_addr != NULL) { - /* Reset memory */ - memset((void *)ptp_priv->shared_addr, 0, ptp_priv->dma_mem_size); - DBG_ERR(("Shared memory allocation (%d bytes) successful at 0x%016lx.\n", - ptp_priv->dma_mem_size, (long unsigned int)ptp_priv->dma_mem)); -#ifdef __LITTLE_ENDIAN - endianess = 0; -#else - endianess = 1; -#endif - DEV_WRITE32(ptp_priv, CMIC_CMC_SCHAN_MESSAGE_12r(CMIC_CMC_BASE), ((pci_cos << 16) | endianess)); +struct file_operations bksync_proc_debug_file_ops = { + owner: THIS_MODULE, + open: bksync_proc_debug_open, + read: seq_read, + llseek: seq_lseek, + write: bksync_proc_debug_write, + release: single_release, +}; - DEV_WRITE32(ptp_priv, CMIC_CMC_SCHAN_MESSAGE_10r(CMIC_CMC_BASE), - (ptp_priv->dma_mem & 0xffffffff)); - DEV_WRITE32(ptp_priv, CMIC_CMC_SCHAN_MESSAGE_11r(CMIC_CMC_BASE), - (ptp_priv->dma_mem >> 32) & 0xffffffff); - ptp_priv->dcb_type = dcb_type; - } +static int +bksync_proc_init(void) +{ + struct proc_dir_entry *entry; - if (debug & DBG_LVL_VERB) { - printk(KERN_EMERG"%s %p:%p\n",__FUNCTION__, - ptp_priv->base_addr,(void *)ptp_priv->shared_addr); + PROC_CREATE(entry, "stats", 0666, bksync_proc_root, &bksync_proc_txts_file_ops); + if (entry == NULL) { + return -1; + } + PROC_CREATE(entry, "debug", 0666, bksync_proc_root, &bksync_proc_debug_file_ops); + if (entry == NULL) { + return -1; } + return 0; +} - return; +static int +bksync_proc_cleanup(void) +{ + remove_proc_entry("stats", bksync_proc_root); + remove_proc_entry("debug", bksync_proc_root); + return 0; } -static void bksync_ptp_cmicx_dma_init(int dcb_type) +static void bksync_ptp_dma_init(int dcb_type) { int endianess; int num_pports = 256; - /* Initialize the Base address for CMIC and shared Memory access */ - ptp_priv->base_addr = lkbde_get_dev_virt(0); - ptp_priv->dma_dev = lkbde_get_dma_dev(0); + ptp_priv->num_pports = num_pports; ptp_priv->dcb_type = dcb_type; ptp_priv->dma_mem_size = 16384;/*sizeof(bksync_uc_linux_ipc_t);*/ if (ptp_priv->shared_addr == NULL) { ptp_priv->shared_addr = kzalloc(16384, GFP_KERNEL); - ptp_priv->num_pports = num_pports; ptp_priv->port_stats = kzalloc((sizeof(bksync_port_stats_t) * num_pports), GFP_KERNEL); } @@ -1678,10 +1699,10 @@ static void bksync_ptp_cmicx_dma_init(int dcb_type) #else endianess = 1; #endif - DEV_WRITE32(ptp_priv, CMIC_CMC_SCHAN_MESSAGE_12r(CMIC_CMC_BASE), ((pci_cos << 16) | endianess)); + DEV_WRITE32(ptp_priv, CMIC_CMC_SCHAN_MESSAGE_14r(CMIC_CMC_BASE), ((pci_cos << 16) | endianess)); - DEV_WRITE32(ptp_priv, CMIC_CMC_SCHAN_MESSAGE_10r(CMIC_CMC_BASE), 1); - DEV_WRITE32(ptp_priv, CMIC_CMC_SCHAN_MESSAGE_11r(CMIC_CMC_BASE), 1); + DEV_WRITE32(ptp_priv, CMIC_CMC_SCHAN_MESSAGE_15r(CMIC_CMC_BASE), 1); + DEV_WRITE32(ptp_priv, CMIC_CMC_SCHAN_MESSAGE_16r(CMIC_CMC_BASE), 1); } @@ -1690,6 +1711,7 @@ static void bksync_ptp_cmicx_dma_init(int dcb_type) ptp_priv->base_addr,(void *)ptp_priv->shared_addr); } + ptp_priv->mirror_encap_bmp = 0x0; hostcmd_regs[0] = CMIC_CMC_SCHAN_MESSAGE_21r(CMIC_CMC_BASE); hostcmd_regs[1] = CMIC_CMC_SCHAN_MESSAGE_20r(CMIC_CMC_BASE); @@ -1701,28 +1723,6 @@ static void bksync_ptp_cmicx_dma_init(int dcb_type) } -static void bksync_ptp_dma_init(int dcb_type) -{ - switch (dcb_type) { - case 26: - bksync_ptp_cmicm_dma_init(dcb_type); - ptp_priv->dcb_type = dcb_type; - break; - case 32: - case 36: - case 38: - bksync_ptp_cmicx_dma_init(dcb_type); - ptp_priv->dcb_type = dcb_type; - break; - default: - break; - } - - return; -} - - - /** * bksync_ioctl_cmd_handler * @kmsg: kcom message - ptp clock ioctl command. @@ -1732,6 +1732,7 @@ static void bksync_ptp_dma_init(int dcb_type) static int bksync_ioctl_cmd_handler(kcom_msg_clock_cmd_t *kmsg, int len, int dcb_type) { + u32 fw_status; kmsg->hdr.type = KCOM_MSG_TYPE_RSP; if (!module_initialized && kmsg->clock_info.cmd != KSYNC_M_HW_INIT) { @@ -1744,6 +1745,20 @@ bksync_ioctl_cmd_handler(kcom_msg_clock_cmd_t *kmsg, int len, int dcb_type) pci_cos = kmsg->clock_info.data[0]; if (kmsg->clock_info.data[1] == 0 || kmsg->clock_info.data[1] == 1) { fw_core = kmsg->clock_info.data[1]; + DEV_READ32(ptp_priv, CMIC_CMC_SCHAN_MESSAGE_21r(CMIC_CMC_BASE), &fw_status); + + /* Return success if the app is already initialized. */ + if (module_initialized) { + kmsg->hdr.status = KCOM_E_NONE; + return sizeof(kcom_msg_hdr_t); + } + + /* Return error if the app is not ready yet. */ + if (fw_status != 0xBADC0DE1) { + kmsg->hdr.status = KCOM_E_RESOURCE; + return sizeof(kcom_msg_hdr_t); + } + bksync_ptp_dma_init(dcb_type); if (bksync_ptp_init(&(ptp_priv->ptp_caps)) >= 0) { module_initialized = 1; @@ -1757,6 +1772,12 @@ bksync_ioctl_cmd_handler(kcom_msg_clock_cmd_t *kmsg, int len, int dcb_type) case KSYNC_M_HW_TS_DISABLE: bksync_ptp_hw_tstamp_disable(0, kmsg->clock_info.data[0], 0); break; + case KSYNC_M_MTP_TS_UPDATE_ENABLE: + bksync_ptp_mirror_encap_update(0, kmsg->clock_info.data[0], TRUE); + break; + case KSYNC_M_MTP_TS_UPDATE_DISABLE: + bksync_ptp_mirror_encap_update(0, kmsg->clock_info.data[0], FALSE); + break; case KSYNC_M_VERSION: break; default: @@ -1813,6 +1834,10 @@ static int bksync_ptp_register(void) /* Register ptp clock driver with bksync_ptp_caps */ ptp_priv->ptp_clock = ptp_clock_register(&ptp_priv->ptp_caps, NULL); + /* Initialize the Base address for CMIC and shared Memory access */ + ptp_priv->base_addr = lkbde_get_dev_virt(0); + ptp_priv->dma_dev = lkbde_get_dma_dev(0); + if (IS_ERR(ptp_priv->ptp_clock)) { ptp_priv->ptp_clock = NULL; } else if (ptp_priv->ptp_clock) { @@ -1858,8 +1883,8 @@ static int bksync_ptp_remove(void) bkn_hw_tstamp_ioctl_cmd_cb_unregister(bksync_ioctl_cmd_handler); if (module_initialized) { - DEV_WRITE32(ptp_priv, CMIC_CMC_SCHAN_MESSAGE_10r(CMIC_CMC_BASE), 0); - DEV_WRITE32(ptp_priv, CMIC_CMC_SCHAN_MESSAGE_11r(CMIC_CMC_BASE), 0); + DEV_WRITE32(ptp_priv, CMIC_CMC_SCHAN_MESSAGE_15r(CMIC_CMC_BASE), 0); + DEV_WRITE32(ptp_priv, CMIC_CMC_SCHAN_MESSAGE_16r(CMIC_CMC_BASE), 0); } /* Deinitialize the PTP */ bksync_ptp_deinit(&(ptp_priv->ptp_caps)); @@ -1870,12 +1895,7 @@ static int bksync_ptp_remove(void) ptp_priv->port_stats = NULL; } if (ptp_priv->shared_addr != NULL) { - if (HOSTCMD_USE_REGS) { - kfree((void *)ptp_priv->shared_addr); - } else { - DMA_FREE_COHERENT(ptp_priv->dma_dev, ptp_priv->dma_mem_size, - (void *)ptp_priv->shared_addr, (dma_addr_t)ptp_priv->dma_mem); - } + kfree((void *)ptp_priv->shared_addr); ptp_priv->shared_addr = NULL; DBG_ERR(("Free R5 memory\n")); } @@ -1906,13 +1926,13 @@ static int bksync_ptp_remove(void) * Always 0 */ static int -_pprint(void) +_pprint(struct seq_file *m) { #if LINUX_VERSION_CODE > KERNEL_VERSION(3,17,0) /* put some goodies here */ - pprintf("Broadcom BCM PTP Hardware Clock Module\n"); + pprintf(m, "Broadcom BCM PTP Hardware Clock Module\n"); #else - pprintf("Broadcom BCM PTP Hardware Clock Module not supported\n"); + pprintf(m, "Broadcom BCM PTP Hardware Clock Module not supported\n"); #endif return 0; } diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/bcm-knet.h b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/bcm-knet.h index df8874fb1f70..8d710869824f 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/bcm-knet.h +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/bcm-knet.h @@ -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: bcm-knet.h,v 1.4 Broadcom SDK $ @@ -137,7 +148,6 @@ bkn_hw_tstamp_ioctl_cmd_cb_register(knet_hw_tstamp_ioctl_cmd_cb_f hw_tstamp_ioct extern int bkn_hw_tstamp_ioctl_cmd_cb_unregister(knet_hw_tstamp_ioctl_cmd_cb_f hw_tstamp_ioctl_cmd_cb); - typedef struct { uint8 cmic_type; uint8 dcb_type; diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/gmodule.h b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/gmodule.h index 22cef82a8ddc..a9db097f3062 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/gmodule.h +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/gmodule.h @@ -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: gmodule.h,v 1.9 Broadcom SDK $ @@ -23,6 +34,7 @@ #define __COMMON_LINUX_KRN_GMODULE_H__ #include +#include typedef struct gmodule_s { @@ -32,9 +44,7 @@ typedef struct gmodule_s { int (*init)(void); int (*cleanup)(void); - - int (*pprint)(void); - + int (*pprint)(struct seq_file *m); int (*open)(void); int (*ioctl)(unsigned int cmd, unsigned long arg); int (*close)(void); @@ -48,8 +58,8 @@ extern gmodule_t* gmodule_get(void); /* Proc Filesystem information */ -extern int pprintf(const char* fmt, ...) - __attribute__ ((format (printf, 1, 2))); +extern int pprintf(struct seq_file *m, const char* fmt, ...) + __attribute__ ((format (printf, 2, 3))); extern int gmodule_vpprintf(char** page, const char* fmt, va_list args) __attribute__ ((format (printf, 2, 0))); extern int gmodule_pprintf(char** page, const char* fmt, ...) diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/lkm.h b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/lkm.h index 56d641c9c87c..9ea8fc5896d8 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/lkm.h +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/include/lkm.h @@ -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: lkm.h,v 1.22 Broadcom SDK $ @@ -34,7 +45,8 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) #include #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) +/* The version kconfig.h became available in. */ #include #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/Makefile b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/Makefile index 3de3e07080c4..b8697731dd4e 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/Makefile @@ -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 # # -*- Makefile -*- # $Id: Makefile,v 1.3 Broadcom SDK $ diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c index 1626d33c1c5d..650a4ced1d7a 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c @@ -107,7 +107,7 @@ static struct sk_buff *strip_tag_rx_cb(struct sk_buff *skb, int dev_no, void *me static struct sk_buff *strip_tag_tx_cb(struct sk_buff *skb, int dev_no, void *meta); static int strip_tag_filter_cb(uint8_t * pkt, int size, int dev_no, void *meta, int chan, kcom_filter_t * kf); -static int _pprint(void); +static int _pprint(struct seq_file *m); static int _cleanup(void); static int _init(void); @@ -333,11 +333,11 @@ knet_filter_cb(uint8_t * pkt, int size, int dev_no, void *meta, int chan, kcom_filter_t *kf) { /* check for filter callback handler */ -#ifdef PSAMPLE_SUPPORT + #ifdef PSAMPLE_SUPPORT if (strncmp(kf->desc, PSAMPLE_CB_NAME, KCOM_FILTER_DESC_MAX) == 0) { return psample_filter_cb (pkt, size, dev_no, meta, chan, kf); } -#endif + #endif return strip_tag_filter_cb (pkt, size, dev_no, meta, chan, kf); } @@ -366,12 +366,12 @@ knet_netif_destroy_cb(int unit, kcom_netif_t *netif, struct net_device *dev) * % cat /proc/linux-knet-cb */ static int -_pprint(void) +_pprint(struct seq_file *m) { - pprintf("Broadcom Linux KNET Call-Back: Untagged VLAN Stripper\n"); - pprintf(" %lu stripped packets\n", strip_stats.stripped); - pprintf(" %lu packets checked\n", strip_stats.checked); - pprintf(" %lu packets skipped\n", strip_stats.skipped); + pprintf(m, "Broadcom Linux KNET Call-Back: Untagged VLAN Stripper\n"); + pprintf(m, " %lu stripped packets\n", strip_stats.stripped); + pprintf(m ," %lu packets checked\n", strip_stats.checked); + pprintf(m, " %lu packets skipped\n", strip_stats.skipped); return 0; } @@ -395,6 +395,7 @@ _cleanup(void) #ifdef PSAMPLE_SUPPORT psample_cleanup(); #endif + return 0; } @@ -410,9 +411,10 @@ _init(void) bkn_tx_skb_cb_register(strip_tag_tx_cb); } -#ifdef PSAMPLE_SUPPORT + #ifdef PSAMPLE_SUPPORT psample_init(); -#endif + #endif + bkn_filter_cb_register(knet_filter_cb); bkn_netif_create_cb_register(knet_netif_create_cb); diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/psample-cb.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/psample-cb.c index e1a6086a52ae..755955b20fdd 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/psample-cb.c +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/knet-cb/psample-cb.c @@ -967,7 +967,7 @@ psample_proc_stats_open(struct inode * inode, struct file * file) * psample stats Proc Write Entry * * Syntax: - * write any value to clear stats + * write any value to clear stats */ static ssize_t psample_proc_stats_write(struct file *file, const char *buf, @@ -1009,13 +1009,13 @@ int psample_cleanup(void) int psample_init(void) { #define PROCFS_MAX_PATH 1024 + #define PSAMPLE_PROCFS_PATH "bcm/knet-cb" char psample_procfs_path[PROCFS_MAX_PATH]; struct proc_dir_entry *entry; /* create procfs for psample */ - snprintf(psample_procfs_path, PROCFS_MAX_PATH, "bcm/knet-cb"); - knet_cb_proc_root = proc_mkdir(psample_procfs_path, NULL); - snprintf(psample_procfs_path, PROCFS_MAX_PATH, "%s/%s", psample_procfs_path, PSAMPLE_CB_NAME); + proc_mkdir(PSAMPLE_PROCFS_PATH, NULL); + snprintf(psample_procfs_path, sizeof(psample_procfs_path), "%s/%s", PSAMPLE_PROCFS_PATH, PSAMPLE_CB_NAME); psample_proc_root = proc_mkdir(psample_procfs_path, NULL); /* create procfs for psample stats */ @@ -1031,7 +1031,7 @@ int psample_init(void) gprintk("%s: Unable to create procfs entry '/procfs/%s/rate'\n", __func__, psample_procfs_path); return -1; } - + /* create procfs for setting sample size */ PROC_CREATE(entry, "size", 0666, psample_proc_root, &psample_proc_size_file_ops); if (entry == NULL) { @@ -1059,23 +1059,23 @@ int psample_init(void) memset(&g_psample_work, 0, sizeof(psample_work_t)); /* setup psample_info struct */ - INIT_LIST_HEAD(&g_psample_info.netif_list); + INIT_LIST_HEAD(&g_psample_info.netif_list); spin_lock_init(&g_psample_info.lock); /* setup psample work queue */ - spin_lock_init(&g_psample_work.lock); - INIT_LIST_HEAD(&g_psample_work.pkt_list); + spin_lock_init(&g_psample_work.lock); + INIT_LIST_HEAD(&g_psample_work.pkt_list); INIT_WORK(&g_psample_work.wq, psample_task); - /* get net namespace */ + /* get net namespace */ g_psample_info.netns = get_net_ns_by_pid(current->pid); if (!g_psample_info.netns) { gprintk("%s: Could not get network namespace for pid %d\n", __func__, current->pid); return (-1); } - PSAMPLE_CB_DBG_PRINT("%s: current->pid %d, netns 0x%p, sample_size %d\n", __func__, + PSAMPLE_CB_DBG_PRINT("%s: current->pid %d, netns 0x%p, sample_size %d\n", __func__, current->pid, g_psample_info.netns, psample_size); - + return 0; } diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/psample/psample.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/psample/psample.c index 1deccacc5edd..99317cbf30cc 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/psample/psample.c +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/psample/psample.c @@ -224,7 +224,7 @@ void psample_sample_packet(struct psample_group *group, struct sk_buff *skb, data_len = PSAMPLE_MAX_PACKET_SIZE - meta_len - NLA_HDRLEN - NLA_ALIGNTO; - nl_skb = genlmsg_new(meta_len + data_len, GFP_ATOMIC); + nl_skb = genlmsg_new(meta_len + nla_total_size(data_len), GFP_ATOMIC); if (unlikely(!nl_skb)) return; diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/Makefile b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/Makefile index 5e97a3a32123..966f639f6983 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/Makefile @@ -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 # # -*- Makefile -*- # $Id: Makefile,v 1.2 Broadcom SDK $ diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/gmodule.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/gmodule.c index cdfaf089674a..3ef000961837 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/gmodule.c +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/gmodule.c @@ -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: gmodule.c,v 1.20 Broadcom SDK $ @@ -26,8 +37,6 @@ #include #include #include -#include - /* Module Vector Table */ static gmodule_t* _gmodule = NULL; @@ -94,21 +103,18 @@ gdbg(const char* fmt, ...) * Proc FS Utilities */ #if PROC_INTERFACE_KERN_VER_3_10 -static struct seq_file* _proc_buf = NULL; - int -pprintf(const char* fmt, ...) +pprintf(struct seq_file *m, const char* fmt, ...) { va_list args; va_start(args, fmt); - seq_vprintf(_proc_buf, fmt, args); + seq_vprintf(m, fmt, args); va_end(args); return 0; } static int _gmodule_proc_show(struct seq_file *m, void *v){ - _proc_buf = m; - _gmodule->pprint(); + _gmodule->pprint(m); return 0; } @@ -174,7 +180,7 @@ gmodule_pprintf(char** page_ptr, const char* fmt, ...) static char* _proc_buf = NULL; int -pprintf(const char* fmt, ...) +pprintf(struct seq_file *m, const char* fmt, ...) { int rv; @@ -193,7 +199,7 @@ static int _gmodule_pprint(char* buf) { PSTART(buf); - _gmodule->pprint(); + _gmodule->pprint(NULL); return PEND(buf); } diff --git a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/ksal.c b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/ksal.c index d1caf871f0e2..7f90c59c3a39 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/ksal.c +++ b/platform/broadcom/saibcm-modules/systems/linux/kernel/modules/shared/ksal.c @@ -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: ksal.c,v 1.1 Broadcom SDK $ diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/common/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/common/Makefile index f95593a383ce..3dc6425e6ee0 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/user/common/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/user/common/Makefile @@ -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 # # -*- Makefile -*- # $Id: Makefile,v 1.4 Broadcom SDK $ @@ -94,9 +105,6 @@ BCM_KNET=$(DEST_DIR)/$(BCM_KNET_LOCAL) PSAMPLE_LOCAL := psample.$(KOBJ) PSAMPLE := $(DEST_DIR)/$(PSAMPLE_LOCAL) -BCM_LPTP_LOCAL :=linux-bcm-ptp-clock.$(KOBJ) -BCM_LPTP=$(DEST_DIR)/$(BCM_LPTP_LOCAL) - ifeq (,$(findstring DELIVER,$(MAKECMDGOALS))) .DEFAULT_GOAL := all all_targets := kernel_modules $(KERNEL_BDE) $(USER_BDE) @@ -113,11 +121,6 @@ endif ifndef BUILD_KNET BUILD_KNET = 1 endif -# Remove this when LinuxPTP support becomes optional. -ifndef BUILD_LPTP -BUILD_LPTP = 1 -BUILD_KNETSYNC = 1 -endif ifeq ($(BUILD_KNET),1) # Kernel network support @@ -140,31 +143,7 @@ endif ifdef BUILD_PSAMPLE all_targets += $(PSAMPLE) ADD_TO_CFLAGS += -DPSAMPLE_SUPPORT - - -# KnetSync support -ifdef BUILD_KNETSYNC - -KERNEL_TARGETS += $(BCM_PTP_CLOCK) -LOCAL_KERNEL_TARGETS += $(patsubst %,$(realpath ..)/$(platform)/%,$(BCM_PTP_CLOCK_LOCAL)) - -endif # BUILD_KNETSYNC - -ifeq ($(NO_LOCAL_TARGETS),) -LOCAL_TARGETS +=$(patsubst %,../$(platform)/%,$(PSAMPLE_LOCAL)) -all_targets +=$(LOCAL_TARGETS) endif -endif - -ifdef BUILD_LPTP -all_targets += $(BCM_LPTP) - -ifeq ($(NO_LOCAL_TARGETS),) -LOCAL_TARGETS +=$(patsubst %,../$(platform)/%,$(BCM_LPTP_LOCAL)) -all_targets +=$(LOCAL_TARGETS) -endif -endif - ADD_TO_CFLAGS += -I$(SDK)/systems/linux/kernel/modules/include COND_KNET_LIBS = libuser.$(libext) endif @@ -189,18 +168,13 @@ CFLAGS += $(ADD_TO_CFLAGS) #SAI_FIXUP CFLAGS:=$(filter-out -fPIC, $(CFLAGS)) -# KnetSync Support -ifdef BUILD_KNETSYNC -knetsync_subdirs = bcm-ptp-clock -endif # BUILD_KNETSYNC - kernel_modules: $(MAKE) -C $(SDK)/systems/bde/linux/kernel kernel_version=$(kernel_version) $(MAKE) -C $(SDK)/systems/bde/linux/user/kernel kernel_version=$(kernel_version) ifeq ($(BUILD_KNET),1) $(MAKE) -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \ subdirs="shared bcm-knet" override-target=linux-$(platform) CFLAGS="$(CFLAGS)" -ifdef BUILD_PSAMPLE +ifdef BUILD_PSAMPLE $(MAKE) -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \ subdirs="psample" override-target=linux-$(platform) CFLAGS="$(CFLAGS)" endif @@ -208,10 +182,6 @@ ifdef BUILD_KNET_CB $(MAKE) -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \ subdirs="knet-cb" override-target=linux-$(platform) CFLAGS="$(CFLAGS)" endif -ifdef BUILD_LPTP - $(MAKE) -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \ - subdirs="bcm-ptp-clock" override-target=linux-$(platform) CFLAGS="$(CFLAGS)" -endif endif $(KERNEL_BDE): $(KERN_BLDROOT)/linux-kernel-bde.$(KOBJ) @@ -230,8 +200,7 @@ $(KNET_CB): $(KERN_BLDROOT)/linux-knet-cb.$(KOBJ) $(PSAMPLE): $(KERN_BLDROOT)/psample.$(KOBJ) $(OBJCOPY) --strip-debug $< $@ -$(BCM_LPTP): $(KERN_BLDROOT)/linux-bcm-ptp-clock.$(KOBJ) - $(OBJCOPY) --strip-debug $< $@ + ifeq ($(NO_LOCAL_TARGETS),) $(foreach targ,$(LOCAL_TARGETS),$(eval $(call LOCAL_TARGET_DEF,$(targ)))) @@ -241,10 +210,10 @@ clean:: $(MAKE) -C $(SDK)/systems/bde/linux/kernel $@ $(MAKE) -C $(SDK)/systems/bde/linux/user/kernel $@ $(MAKE) -C $(SDK)/systems/linux/kernel/modules \ - subdirs="shared bcm-knet knet-cb psample bcm-ptp-clock" \ + subdirs="shared bcm-knet knet-cb psample" \ override-target=linux-$(platform) $@ $(RM) $(KERNEL_BDE) $(USER_BDE) - $(RM) $(BCM_KNET) $(KNET_CB) $(PSAMPLE) $(BCM_LPTP) + $(RM) $(BCM_KNET) $(KNET_CB) $(PSAMPLE) $(RM) $(KERN_BLDROOT)/linux-kernel-bde.$(KOBJ) $(RM) $(KERN_BLDROOT)/linux-user-bde.$(KOBJ) $(RM) $(KERN_BLDROOT)/linux-bcm-knet.$(KOBJ) diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/gts/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/gts/Makefile index 466faf02a515..5acaeab271cc 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/user/gts/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/user/gts/Makefile @@ -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 # # -*- Makefile -*- # $Id: Makefile,v 0.1 Broadcom SDK $ diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/iproc-3_14/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/iproc-3_14/Makefile index c9f538802f6d..b874340ddec2 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/user/iproc-3_14/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/user/iproc-3_14/Makefile @@ -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 # # -*- Makefile -*- # $Id: Makefile,v 1.7 Broadcom SDK $ diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/iproc-4_4/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/iproc-4_4/Makefile index e8405f5c2a0c..2b724be3202f 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/user/iproc-4_4/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/user/iproc-4_4/Makefile @@ -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 # # -*- Makefile -*- # $Id: Makefile,v 1.7 Broadcom SDK $ diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/iproc/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/iproc/Makefile index 03300ff8a046..f10c5c37a082 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/user/iproc/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/user/iproc/Makefile @@ -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 # # -*- Makefile -*- # $Id: Makefile,v 1.7 Broadcom SDK $ diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/iproc_64/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/iproc_64/Makefile index 778c85a03bed..983b3abbced7 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/user/iproc_64/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/user/iproc_64/Makefile @@ -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 # # -*- Makefile -*- # $Id: Makefile,v 1.7 Broadcom SDK $ diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/slk/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/slk/Makefile index 99d49d285145..6ef360156572 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/user/slk/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/user/slk/Makefile @@ -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 # # -*- Makefile -*- # $Id: Makefile,v 0.1 Broadcom SDK $ diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile index 29717b3af42a..78c2c0cb1702 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile @@ -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 # # -*- Makefile -*- # $Id: Makefile,v 1.2 Broadcom SDK $ diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/xlr/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/xlr/Makefile index 13246d09e78f..e19eeff4aef2 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/user/xlr/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/user/xlr/Makefile @@ -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 # # -*- Makefile -*- # $Id: Makefile,v 0.1 Broadcom SDK $ diff --git a/platform/broadcom/saibcm-modules/tools/mktool.pl b/platform/broadcom/saibcm-modules/tools/mktool.pl index 8800c00613d8..518ab25535c3 100644 --- a/platform/broadcom/saibcm-modules/tools/mktool.pl +++ b/platform/broadcom/saibcm-modules/tools/mktool.pl @@ -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 # # # mktool.pl From e334277251b866c7f9af53862198e5830ddc6487 Mon Sep 17 00:00:00 2001 From: Mahesh Maddikayala Date: Wed, 20 Jan 2021 22:05:21 +0000 Subject: [PATCH 02/10] update Makefile and add default MTU arg for module install --- platform/broadcom/saibcm-modules/debian/opennsl-modules.init | 2 +- platform/broadcom/saibcm-modules/make/Make.config | 2 ++ .../make/Makefile.linux-x86-smp_generic_64-2_6 | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/platform/broadcom/saibcm-modules/debian/opennsl-modules.init b/platform/broadcom/saibcm-modules/debian/opennsl-modules.init index 7def10cbff86..287bc5fec05e 100755 --- a/platform/broadcom/saibcm-modules/debian/opennsl-modules.init +++ b/platform/broadcom/saibcm-modules/debian/opennsl-modules.init @@ -57,7 +57,7 @@ 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 } diff --git a/platform/broadcom/saibcm-modules/make/Make.config b/platform/broadcom/saibcm-modules/make/Make.config index 88bf1740ea0b..b086aa3aa79b 100644 --- a/platform/broadcom/saibcm-modules/make/Make.config +++ b/platform/broadcom/saibcm-modules/make/Make.config @@ -172,6 +172,8 @@ CFLAGS += ${INCFLAGS} CXXFLAGS += ${INCFLAGS} CPPFLAGS += ${INCFLAGS} +CFLAGS += -DSAI_FIXUP -UKCOM_FILTER_MAX -DKCOM_FILTER_MAX=1024 + # # Debug #ifdef control # diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-smp_generic_64-2_6 b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-smp_generic_64-2_6 index 5a4cc6a805cf..9df0bee5a774 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-smp_generic_64-2_6 +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-x86-smp_generic_64-2_6 @@ -39,6 +39,11 @@ ifeq (,$(KFLAGS)) KFLAGS := -nostdinc -isystem $(SYSINC) -I$(KERNDIR)/include -I$(KERNDIR)/arch/x86/include -include $(AUTOCONF) -D__KERNEL__ -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -fno-delete-null-pointer-checks -Os -m64 -mtune=generic -mno-red-zone -fno-pie -mcmodel=kernel -funit-at-a-time -maccumulate-outgoing-args -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -fno-stack-protector -fomit-frame-pointer -g -Wdeclaration-after-statement -Wno-pointer-sign endif +ifeq ($(LINUX_MAKE_SHARED_LIB), 1) + KFLAGS += -fPIC -mcmodel=small +else + KFLAGS += -fno-pie -mcmodel=kernel +endif LINUX_UAPI = $(LINUX_INCLUDE)/uapi ifneq (,$(shell ls $(LINUX_UAPI) 2>/dev/null)) From 7d1622b6152cae906a614ec048b841c18560b8c4 Mon Sep 17 00:00:00 2001 From: Mahesh Maddikayala Date: Thu, 21 Jan 2021 21:55:20 +0000 Subject: [PATCH 03/10] update changelog, update makefile to build psample and PTP clock kernel module --- .../broadcom/saibcm-modules/debian/changelog | 6 +++ .../systems/linux/user/common/Makefile | 48 +++++++++++++++++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/platform/broadcom/saibcm-modules/debian/changelog b/platform/broadcom/saibcm-modules/debian/changelog index f2b0db31e662..ac06f81dcdfa 100644 --- a/platform/broadcom/saibcm-modules/debian/changelog +++ b/platform/broadcom/saibcm-modules/debian/changelog @@ -1,3 +1,9 @@ +opennsl (4.2.1.3-1) unstable; urgency=medium + + * Update to Broadcom SAI 4.3.0.10 + + -- Mahesh Maddikayala 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 diff --git a/platform/broadcom/saibcm-modules/systems/linux/user/common/Makefile b/platform/broadcom/saibcm-modules/systems/linux/user/common/Makefile index 3dc6425e6ee0..8f59a763e314 100644 --- a/platform/broadcom/saibcm-modules/systems/linux/user/common/Makefile +++ b/platform/broadcom/saibcm-modules/systems/linux/user/common/Makefile @@ -105,6 +105,9 @@ BCM_KNET=$(DEST_DIR)/$(BCM_KNET_LOCAL) PSAMPLE_LOCAL := psample.$(KOBJ) PSAMPLE := $(DEST_DIR)/$(PSAMPLE_LOCAL) +BCM_LPTP_LOCAL :=linux-bcm-ptp-clock.$(KOBJ) +BCM_LPTP=$(DEST_DIR)/$(BCM_LPTP_LOCAL) + ifeq (,$(findstring DELIVER,$(MAKECMDGOALS))) .DEFAULT_GOAL := all all_targets := kernel_modules $(KERNEL_BDE) $(USER_BDE) @@ -122,6 +125,12 @@ ifndef BUILD_KNET BUILD_KNET = 1 endif +# Remove this when LinuxPTP support becomes optional. +ifndef BUILD_LPTP +BUILD_LPTP = 1 +BUILD_KNETSYNC = 1 +endif + ifeq ($(BUILD_KNET),1) # Kernel network support all_targets += $(BCM_KNET) @@ -143,7 +152,30 @@ endif ifdef BUILD_PSAMPLE all_targets += $(PSAMPLE) ADD_TO_CFLAGS += -DPSAMPLE_SUPPORT + +# KnetSync support +ifdef BUILD_KNETSYNC + +KERNEL_TARGETS += $(BCM_PTP_CLOCK) +LOCAL_KERNEL_TARGETS += $(patsubst %,$(realpath ..)/$(platform)/%,$(BCM_PTP_CLOCK_LOCAL)) + +endif # BUILD_KNETSYNC + +ifeq ($(NO_LOCAL_TARGETS),) + LOCAL_TARGETS +=$(patsubst %,../$(platform)/%,$(PSAMPLE_LOCAL)) + all_targets +=$(LOCAL_TARGETS) +endif +endif + +ifdef BUILD_LPTP + all_targets += $(BCM_LPTP) + +ifeq ($(NO_LOCAL_TARGETS),) + LOCAL_TARGETS +=$(patsubst %,../$(platform)/%,$(BCM_LPTP_LOCAL)) + all_targets +=$(LOCAL_TARGETS) endif +endif + ADD_TO_CFLAGS += -I$(SDK)/systems/linux/kernel/modules/include COND_KNET_LIBS = libuser.$(libext) endif @@ -168,6 +200,11 @@ CFLAGS += $(ADD_TO_CFLAGS) #SAI_FIXUP CFLAGS:=$(filter-out -fPIC, $(CFLAGS)) +# KnetSync Support +ifdef BUILD_KNETSYNC + knetsync_subdirs = bcm-ptp-clock +endif # BUILD_KNETSYNC + kernel_modules: $(MAKE) -C $(SDK)/systems/bde/linux/kernel kernel_version=$(kernel_version) $(MAKE) -C $(SDK)/systems/bde/linux/user/kernel kernel_version=$(kernel_version) @@ -182,6 +219,10 @@ ifdef BUILD_KNET_CB $(MAKE) -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \ subdirs="knet-cb" override-target=linux-$(platform) CFLAGS="$(CFLAGS)" endif +ifdef BUILD_LPTP + $(MAKE) -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \ + subdirs="bcm-ptp-clock" override-target=linux-$(platform) CFLAGS="$(CFLAGS)" +endif endif $(KERNEL_BDE): $(KERN_BLDROOT)/linux-kernel-bde.$(KOBJ) @@ -200,7 +241,8 @@ $(KNET_CB): $(KERN_BLDROOT)/linux-knet-cb.$(KOBJ) $(PSAMPLE): $(KERN_BLDROOT)/psample.$(KOBJ) $(OBJCOPY) --strip-debug $< $@ - +$(BCM_LPTP): $(KERN_BLDROOT)/linux-bcm-ptp-clock.$(KOBJ) + $(OBJCOPY) --strip-debug $< $@ ifeq ($(NO_LOCAL_TARGETS),) $(foreach targ,$(LOCAL_TARGETS),$(eval $(call LOCAL_TARGET_DEF,$(targ)))) @@ -210,10 +252,10 @@ clean:: $(MAKE) -C $(SDK)/systems/bde/linux/kernel $@ $(MAKE) -C $(SDK)/systems/bde/linux/user/kernel $@ $(MAKE) -C $(SDK)/systems/linux/kernel/modules \ - subdirs="shared bcm-knet knet-cb psample" \ + subdirs="shared bcm-knet knet-cb psample bcm-ptp-clock" \ override-target=linux-$(platform) $@ $(RM) $(KERNEL_BDE) $(USER_BDE) - $(RM) $(BCM_KNET) $(KNET_CB) $(PSAMPLE) + $(RM) $(BCM_KNET) $(KNET_CB) $(PSAMPLE) $(BCM_LPTP) $(RM) $(KERN_BLDROOT)/linux-kernel-bde.$(KOBJ) $(RM) $(KERN_BLDROOT)/linux-user-bde.$(KOBJ) $(RM) $(KERN_BLDROOT)/linux-bcm-knet.$(KOBJ) From 95f70c7d84a16ad9bb6bee991b0f07d76a27d7a8 Mon Sep 17 00:00:00 2001 From: Mahesh Maddikayala Date: Thu, 21 Jan 2021 23:18:47 +0000 Subject: [PATCH 04/10] update BCMSAI link to 4.3.0.10 (with 6.5.21 SDK) --- platform/broadcom/sai.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/broadcom/sai.mk b/platform/broadcom/sai.mk index fcb175d3d0c5..ba2bd8bd4cd5 100644 --- a/platform/broadcom/sai.mk +++ b/platform/broadcom/sai.mk @@ -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)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/4.3/master/libsaibcm_4.3.0.10_amd64.deb?sv=2015-04-05&sr=b&sig=yKic6%2FwJ2mHM6n4lXrR32yqEsLt01EUzqxIuOAvV7uQ%3D&se=2022-01-21T23%3A13%3A54Z&sp=r" BRCM_SAI_DEV = libsaibcm-dev_4.2.1.5-10_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_amd64.deb?sv=2015-04-05&sr=b&sig=IAx7bmd0mgQL8DyF345jQOQHRxwx9wen2AyWdacfmw4%3D&se=2022-01-21T23%3A15%3A30Z&sp=r" SONIC_ONLINE_DEBS += $(BRCM_SAI) $(BRCM_SAI_DEV)_DEPENDS += $(BRCM_SAI) From bfb663b713a2753db83f42b9f4ff93e98c00b609 Mon Sep 17 00:00:00 2001 From: Mahesh Maddikayala Date: Fri, 22 Jan 2021 00:39:06 +0000 Subject: [PATCH 05/10] update opennsl version --- platform/broadcom/saibcm-modules/debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/broadcom/saibcm-modules/debian/changelog b/platform/broadcom/saibcm-modules/debian/changelog index ac06f81dcdfa..0f3906b25a0d 100644 --- a/platform/broadcom/saibcm-modules/debian/changelog +++ b/platform/broadcom/saibcm-modules/debian/changelog @@ -1,4 +1,4 @@ -opennsl (4.2.1.3-1) unstable; urgency=medium +opennsl (6.5.21) unstable; urgency=medium * Update to Broadcom SAI 4.3.0.10 From 14f9213d78be5f892082c67c09063211fdc2cdda Mon Sep 17 00:00:00 2001 From: Mahesh Maddikayala Date: Fri, 22 Jan 2021 04:05:24 +0000 Subject: [PATCH 06/10] update opennsl kernel version --- platform/broadcom/sai-modules.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/broadcom/sai-modules.mk b/platform/broadcom/sai-modules.mk index 84d97c09ac88..4909febc45d9 100644 --- a/platform/broadcom/sai-modules.mk +++ b/platform/broadcom/sai-modules.mk @@ -1,6 +1,6 @@ # Broadcom SAI modules -BRCM_OPENNSL_KERNEL_VERSION = 4.2.1.3-1 +BRCM_OPENNSL_KERNEL_VERSION = 6.5.21 BRCM_OPENNSL_KERNEL = opennsl-modules_$(BRCM_OPENNSL_KERNEL_VERSION)_amd64.deb $(BRCM_OPENNSL_KERNEL)_SRC_PATH = $(PLATFORM_PATH)/saibcm-modules From ccc60bbb975300dffbfe768a7bc22e12e90287ba Mon Sep 17 00:00:00 2001 From: Mahesh Maddikayala Date: Sat, 23 Jan 2021 02:24:16 +0000 Subject: [PATCH 07/10] fix the libsaibcm version --- platform/broadcom/sai.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/broadcom/sai.mk b/platform/broadcom/sai.mk index ba2bd8bd4cd5..37bc2f95b17c 100644 --- a/platform/broadcom/sai.mk +++ b/platform/broadcom/sai.mk @@ -1,6 +1,6 @@ -BRCM_SAI = libsaibcm_4.2.1.5-10_amd64.deb +BRCM_SAI = libsaibcm_4.3.1.10-1_amd64.deb $(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/4.3/master/libsaibcm_4.3.0.10_amd64.deb?sv=2015-04-05&sr=b&sig=yKic6%2FwJ2mHM6n4lXrR32yqEsLt01EUzqxIuOAvV7uQ%3D&se=2022-01-21T23%3A13%3A54Z&sp=r" -BRCM_SAI_DEV = libsaibcm-dev_4.2.1.5-10_amd64.deb +BRCM_SAI_DEV = libsaibcm-dev_4.3.1.10-1_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.3/master/libsaibcm-dev_4.3.0.10_amd64.deb?sv=2015-04-05&sr=b&sig=IAx7bmd0mgQL8DyF345jQOQHRxwx9wen2AyWdacfmw4%3D&se=2022-01-21T23%3A15%3A30Z&sp=r" From 9b73229914fa6168d04d01de507ec3b4f7d8c997 Mon Sep 17 00:00:00 2001 From: Mahesh Maddikayala Date: Tue, 26 Jan 2021 04:58:33 +0000 Subject: [PATCH 08/10] udpate libsaibcm with unresolved symbol fix --- platform/broadcom/sai.mk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/broadcom/sai.mk b/platform/broadcom/sai.mk index 37bc2f95b17c..7fe0e09c1528 100644 --- a/platform/broadcom/sai.mk +++ b/platform/broadcom/sai.mk @@ -1,8 +1,8 @@ -BRCM_SAI = libsaibcm_4.3.1.10-1_amd64.deb -$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/4.3/master/libsaibcm_4.3.0.10_amd64.deb?sv=2015-04-05&sr=b&sig=yKic6%2FwJ2mHM6n4lXrR32yqEsLt01EUzqxIuOAvV7uQ%3D&se=2022-01-21T23%3A13%3A54Z&sp=r" -BRCM_SAI_DEV = libsaibcm-dev_4.3.1.10-1_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=WmZegm2db91OxDM8vA%2FjRAhhAZHJWE7yrTug5S784co%3D&se=2022-06-10T02%3A35%3A42Z&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.3/master/libsaibcm-dev_4.3.0.10_amd64.deb?sv=2015-04-05&sr=b&sig=IAx7bmd0mgQL8DyF345jQOQHRxwx9wen2AyWdacfmw4%3D&se=2022-01-21T23%3A15%3A30Z&sp=r" +$(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=mI3xjiOeQANZweWt115wjSE5q1jLPYLJRC4FYIlJ8nY%3D&se=2022-06-10T02%3A36%3A30Z&sp=r" SONIC_ONLINE_DEBS += $(BRCM_SAI) $(BRCM_SAI_DEV)_DEPENDS += $(BRCM_SAI) From c4a5824d0362060ffec6c60a4e230e78cbe6ad3a Mon Sep 17 00:00:00 2001 From: Mahesh Maddikayala Date: Tue, 26 Jan 2021 21:30:41 +0000 Subject: [PATCH 09/10] updated libsaibcm with premium cancun firmware packages --- platform/broadcom/sai.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/broadcom/sai.mk b/platform/broadcom/sai.mk index 7fe0e09c1528..7a1e6cf99bd1 100644 --- a/platform/broadcom/sai.mk +++ b/platform/broadcom/sai.mk @@ -1,8 +1,8 @@ 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=WmZegm2db91OxDM8vA%2FjRAhhAZHJWE7yrTug5S784co%3D&se=2022-06-10T02%3A35%3A42Z&sp=r" +$(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.3/master/libsaibcm-dev_4.3.0.10-2_amd64.deb?sv=2015-04-05&sr=b&sig=mI3xjiOeQANZweWt115wjSE5q1jLPYLJRC4FYIlJ8nY%3D&se=2022-06-10T02%3A36%3A30Z&sp=r" +$(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) From c1b14a409308abd7dd547668ab53f4f817ca5539 Mon Sep 17 00:00:00 2001 From: Mahesh Maddikayala Date: Thu, 28 Jan 2021 00:13:04 +0000 Subject: [PATCH 10/10] Added sdklt modules, update opennsl version to match BCMSAI version --- platform/broadcom/sai-modules.mk | 2 +- .../broadcom/saibcm-modules/debian/changelog | 3 +- .../debian/opennsl-modules.init | 4 + .../debian/opennsl-modules.install | 1 + platform/broadcom/saibcm-modules/debian/rules | 11 + .../saibcm-modules/sdklt/LICENSES/gpl-2.0.txt | 339 +++ .../broadcom/saibcm-modules/sdklt/Makefile | 83 + .../bcm56780_a0/bcm56780_a0_pdma_attach.c | 38 + .../bcm56880_a0/bcm56880_a0_pdma_attach.c | 38 + .../bcm56990_a0/bcm56990_a0_pdma_attach.c | 38 + .../bcm56990_b0/bcm56990_b0_pdma_attach.c | 38 + .../bcm56996_a0/bcm56996_a0_pdma_attach.c | 38 + .../bcmcnet/hmi/cmicd/bcmcnet_cmicd_pdma_hw.c | 530 ++++ .../hmi/cmicd/bcmcnet_cmicd_pdma_rxtx.c | 1062 +++++++ .../bcmcnet/hmi/cmicx/bcmcnet_cmicx_pdma_hw.c | 604 ++++ .../hmi/cmicx/bcmcnet_cmicx_pdma_rxtx.c | 1094 +++++++ .../bcmcnet/include/bcmcnet/bcmcnet_cmicd.h | 369 +++ .../bcmcnet/include/bcmcnet/bcmcnet_cmicx.h | 379 +++ .../bcmcnet/include/bcmcnet/bcmcnet_core.h | 1323 ++++++++ .../bcmcnet/include/bcmcnet/bcmcnet_dev.h | 544 ++++ .../include/bcmcnet/bcmcnet_internal.h | 305 ++ .../bcmcnet/include/bcmcnet/bcmcnet_rxtx.h | 512 ++++ .../bcmcnet/include/bcmcnet/bcmcnet_types.h | 263 ++ .../sdklt/bcmcnet/main/bcmcnet_core.c | 701 +++++ .../sdklt/bcmcnet/main/bcmcnet_dev.c | 1059 +++++++ .../sdklt/bcmcnet/main/bcmcnet_rxtx.c | 708 +++++ .../bcmdrd/include/bcmdrd/bcmdrd_devlist.h | 337 +++ .../sdklt/bcmdrd/include/bcmdrd_config.h | 166 + .../bcmdrd/include/bcmdrd_config_chips.h | 545 ++++ .../saibcm-modules/sdklt/linux/bde/Kbuild | 39 + .../saibcm-modules/sdklt/linux/bde/Makefile | 33 + .../saibcm-modules/sdklt/linux/bde/ngbde.h | 836 +++++ .../sdklt/linux/bde/ngbde_dma.c | 340 +++ .../sdklt/linux/bde/ngbde_iio.c | 143 + .../sdklt/linux/bde/ngbde_intr.c | 550 ++++ .../sdklt/linux/bde/ngbde_ioctl.c | 237 ++ .../sdklt/linux/bde/ngbde_iproc_probe.c | 164 + .../sdklt/linux/bde/ngbde_kapi.c | 216 ++ .../sdklt/linux/bde/ngbde_main.c | 297 ++ .../sdklt/linux/bde/ngbde_pci_probe.c | 211 ++ .../sdklt/linux/bde/ngbde_pgmem.c | 472 +++ .../sdklt/linux/bde/ngbde_pio.c | 97 + .../sdklt/linux/bde/ngbde_procfs.c | 120 + .../sdklt/linux/bde/ngbde_swdev.c | 79 + .../sdklt/linux/include/lkm/lkm.h | 126 + .../sdklt/linux/include/lkm/ngbde_ioctl.h | 345 +++ .../sdklt/linux/include/lkm/ngbde_kapi.h | 169 ++ .../sdklt/linux/include/lkm/ngknet_dev.h | 408 +++ .../sdklt/linux/include/lkm/ngknet_ioctl.h | 112 + .../sdklt/linux/include/net/psample.h | 24 + .../sdklt/linux/include/uapi/linux/psample.h | 35 + .../saibcm-modules/sdklt/linux/knet/Kbuild | 44 + .../saibcm-modules/sdklt/linux/knet/Makefile | 105 + .../sdklt/linux/knet/ngknet_buff.c | 326 ++ .../sdklt/linux/knet/ngknet_buff.h | 83 + .../sdklt/linux/knet/ngknet_callback.c | 315 ++ .../sdklt/linux/knet/ngknet_callback.h | 364 +++ .../sdklt/linux/knet/ngknet_dep.h | 61 + .../sdklt/linux/knet/ngknet_extra.c | 505 ++++ .../sdklt/linux/knet/ngknet_extra.h | 218 ++ .../sdklt/linux/knet/ngknet_linux.c | 173 ++ .../sdklt/linux/knet/ngknet_linux.h | 240 ++ .../sdklt/linux/knet/ngknet_main.c | 2689 +++++++++++++++++ .../sdklt/linux/knet/ngknet_main.h | 278 ++ .../sdklt/linux/knet/ngknet_procfs.c | 655 ++++ .../sdklt/linux/knet/ngknet_procfs.h | 47 + .../sdklt/linux/knet/ngknet_ptp.c | 194 ++ .../sdklt/linux/knet/ngknet_ptp.h | 111 + .../saibcm-modules/sdklt/linux/knetcb/Kbuild | 36 + .../sdklt/linux/knetcb/Makefile | 33 + .../sdklt/linux/knetcb/ngknetcb_main.c | 444 +++ .../sdklt/linux/knetcb/psample-cb.c | 995 ++++++ .../sdklt/linux/knetcb/psample-cb.h | 57 + .../saibcm-modules/sdklt/linux/psample/Kbuild | 18 + .../sdklt/linux/psample/Makefile | 21 + .../sdklt/linux/psample/psample.c | 302 ++ .../broadcom/saibcm-modules/sdklt/make/lkm.mk | 76 + .../sdklt/shr/include/shr/shr_error.h | 195 ++ 78 files changed, 24770 insertions(+), 2 deletions(-) create mode 100644 platform/broadcom/saibcm-modules/sdklt/LICENSES/gpl-2.0.txt create mode 100644 platform/broadcom/saibcm-modules/sdklt/Makefile create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56780_a0/bcm56780_a0_pdma_attach.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56880_a0/bcm56880_a0_pdma_attach.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56990_a0/bcm56990_a0_pdma_attach.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56990_b0/bcm56990_b0_pdma_attach.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56996_a0/bcm56996_a0_pdma_attach.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/hmi/cmicd/bcmcnet_cmicd_pdma_hw.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/hmi/cmicd/bcmcnet_cmicd_pdma_rxtx.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/hmi/cmicx/bcmcnet_cmicx_pdma_hw.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/hmi/cmicx/bcmcnet_cmicx_pdma_rxtx.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_cmicd.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_cmicx.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_core.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_dev.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_internal.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_rxtx.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_types.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/main/bcmcnet_core.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/main/bcmcnet_dev.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmcnet/main/bcmcnet_rxtx.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmdrd/include/bcmdrd/bcmdrd_devlist.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmdrd/include/bcmdrd_config.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/bcmdrd/include/bcmdrd_config_chips.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/bde/Kbuild create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/bde/Makefile create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_dma.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_iio.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_intr.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_ioctl.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_iproc_probe.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_kapi.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_main.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_pci_probe.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_pgmem.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_pio.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_procfs.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_swdev.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/lkm.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/ngbde_ioctl.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/ngbde_kapi.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/ngknet_dev.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/ngknet_ioctl.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/include/net/psample.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/include/uapi/linux/psample.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/Kbuild create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/Makefile create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_buff.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_buff.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_callback.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_callback.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_dep.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_extra.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_extra.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_linux.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_linux.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_main.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_main.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_procfs.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_procfs.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_ptp.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_ptp.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knetcb/Kbuild create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knetcb/Makefile create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knetcb/ngknetcb_main.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knetcb/psample-cb.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/knetcb/psample-cb.h create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/psample/Kbuild create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/psample/Makefile create mode 100644 platform/broadcom/saibcm-modules/sdklt/linux/psample/psample.c create mode 100644 platform/broadcom/saibcm-modules/sdklt/make/lkm.mk create mode 100644 platform/broadcom/saibcm-modules/sdklt/shr/include/shr/shr_error.h diff --git a/platform/broadcom/sai-modules.mk b/platform/broadcom/sai-modules.mk index 4909febc45d9..2d4262518c68 100644 --- a/platform/broadcom/sai-modules.mk +++ b/platform/broadcom/sai-modules.mk @@ -1,6 +1,6 @@ # Broadcom SAI modules -BRCM_OPENNSL_KERNEL_VERSION = 6.5.21 +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 diff --git a/platform/broadcom/saibcm-modules/debian/changelog b/platform/broadcom/saibcm-modules/debian/changelog index 0f3906b25a0d..87d659d21a61 100644 --- a/platform/broadcom/saibcm-modules/debian/changelog +++ b/platform/broadcom/saibcm-modules/debian/changelog @@ -1,6 +1,7 @@ -opennsl (6.5.21) unstable; urgency=medium +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 Thu, 21 Jan 2021 18:36:38 +0000 diff --git a/platform/broadcom/saibcm-modules/debian/opennsl-modules.init b/platform/broadcom/saibcm-modules/debian/opennsl-modules.init index 287bc5fec05e..09112f5331ce 100755 --- a/platform/broadcom/saibcm-modules/debian/opennsl-modules.init +++ b/platform/broadcom/saibcm-modules/debian/opennsl-modules.init @@ -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 @@ -59,6 +61,7 @@ function load_kernel_modules() 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 diff --git a/platform/broadcom/saibcm-modules/debian/opennsl-modules.install b/platform/broadcom/saibcm-modules/debian/opennsl-modules.install index 0e8051fbbca7..ebb290820f03 100644 --- a/platform/broadcom/saibcm-modules/debian/opennsl-modules.install +++ b/platform/broadcom/saibcm-modules/debian/opennsl-modules.install @@ -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 diff --git a/platform/broadcom/saibcm-modules/debian/rules b/platform/broadcom/saibcm-modules/debian/rules index 64cc9b6c07e0..4fcf2db75a5f 100755 --- a/platform/broadcom/saibcm-modules/debian/rules +++ b/platform/broadcom/saibcm-modules/debian/rules @@ -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= diff --git a/platform/broadcom/saibcm-modules/sdklt/LICENSES/gpl-2.0.txt b/platform/broadcom/saibcm-modules/sdklt/LICENSES/gpl-2.0.txt new file mode 100644 index 000000000000..d159169d1050 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/LICENSES/gpl-2.0.txt @@ -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. + + + Copyright (C) + + 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. + + , 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. diff --git a/platform/broadcom/saibcm-modules/sdklt/Makefile b/platform/broadcom/saibcm-modules/sdklt/Makefile new file mode 100644 index 000000000000..d6f358c55283 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/Makefile @@ -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 diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56780_a0/bcm56780_a0_pdma_attach.c b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56780_a0/bcm56780_a0_pdma_attach.c new file mode 100644 index 000000000000..e06dcb68bfc8 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56780_a0/bcm56780_a0_pdma_attach.c @@ -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 +#include +#include + +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); +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56880_a0/bcm56880_a0_pdma_attach.c b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56880_a0/bcm56880_a0_pdma_attach.c new file mode 100644 index 000000000000..9a2152e99ac0 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56880_a0/bcm56880_a0_pdma_attach.c @@ -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 +#include +#include + +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); +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56990_a0/bcm56990_a0_pdma_attach.c b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56990_a0/bcm56990_a0_pdma_attach.c new file mode 100644 index 000000000000..7827ef25de3d --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56990_a0/bcm56990_a0_pdma_attach.c @@ -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 +#include +#include + +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); +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56990_b0/bcm56990_b0_pdma_attach.c b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56990_b0/bcm56990_b0_pdma_attach.c new file mode 100644 index 000000000000..e34ae1f0b45c --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56990_b0/bcm56990_b0_pdma_attach.c @@ -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 +#include +#include + +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); +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56996_a0/bcm56996_a0_pdma_attach.c b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56996_a0/bcm56996_a0_pdma_attach.c new file mode 100644 index 000000000000..aab5822f68b7 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/chip/bcm56996_a0/bcm56996_a0_pdma_attach.c @@ -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 +#include +#include + +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); +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/hmi/cmicd/bcmcnet_cmicd_pdma_hw.c b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/hmi/cmicd/bcmcnet_cmicd_pdma_hw.c new file mode 100644 index 000000000000..83ce4d11b97f --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/hmi/cmicd/bcmcnet_cmicd_pdma_hw.c @@ -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 +#include +#include +#include + +/*! + * 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; +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/hmi/cmicd/bcmcnet_cmicd_pdma_rxtx.c b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/hmi/cmicd/bcmcnet_cmicd_pdma_rxtx.c new file mode 100644 index 000000000000..c4a10e160db9 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/hmi/cmicd/bcmcnet_cmicd_pdma_rxtx.c @@ -0,0 +1,1062 @@ +/*! \file bcmcnet_cmicd_pdma_rxtx.c + * + * Utility routines for BCMCNET hardware (CMICd) specific Rx/Tx. + * + * Here are the CMIC specific Rx/Tx routines including DCBs resource allocation + * and clean up, DCBs configuration, Rx buffers allocation, Tx buffers release, + * Rx/Tx packets processing, etc. + * They are shared among all the modes (UNET, KNET, VNET, HNET) and in both of + * user space and kernel space. + * + * The driver uses a ring of DCBs per DMA channel based on Continuous DMA mode. + * The beginning is written to register pointing to the physical address of the + * start of the ring. The ring size is maintained by the driver. A HALT DCB + * physical address is written to DMA register timely to indicate how many DCBs + * can be handled by HW. + * + * When a packet is received, an interrupt is triggered. The handler will go + * through the Rx DCB ring to process the current completed DCB and every + * subsequent DCBs until no one is left. The received packet is processed and + * passed up to the high level SW. After that, a new buffer is allocated and + * the DCB is updated for receiving a new packet. A new HALT DCB is selected + * and its physical address is written to DMA register. + * + * When a packet is transmitted, the driver starts where it left off last time + * in the Tx DCB ring, updates the DCB and writes its physical address to DMA + * register so as to start DMA. Once the transmitting is finished, the handler + * is informed to clean up the buffer based on the work mode. In KNET or HNET + * mode, an interrupt will be triggered. Polling mode is used in CNET or VNET + * mode, the buffers will be cleaned up when the number of dirty DCBs reaches + * a pre-defined threshold. + * + * In VNET and HNET modes, DCB updating between virtual ring and real ring and + * a IOCTL based notification mechanism are involved. The hypervisor in kernel + * emulates the DMA HW behaviors to update DCBs in virtual network and inform + * the handler something happened. Likewise, the hypervisor updates itself real + * DCB ring from the virtual ring to start DMA for transmitting a packet once a + * notification is received from the virtual network. + * + */ +/* + * $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 +#include +#include +#include +#include + +/*! + * Configure Rx descriptor + */ +static inline void +cmicd_rx_desc_config(struct cmicd_rx_desc *rd, uint32_t addr, uint32_t len) +{ + rd->addr = addr; + rd->md.status = 0; + rd->ctrl = CMICD_DESC_CTRL_CNTLD_INTR | CMICD_DESC_CTRL_CHAIN | + CMICD_DESC_CTRL_LEN(len); +} + +/*! + * Configure Tx descriptor + */ +static inline void +cmicd_tx_desc_config(struct cmicd_tx_desc *td, uint32_t addr, uint32_t len, uint32_t flags) +{ + td->addr = addr; + td->md.status = 0; + td->ctrl = CMICD_DESC_CTRL_CNTLD_INTR | CMICD_DESC_CTRL_CHAIN | + CMICD_DESC_CTRL_FLAGS(flags) | CMICD_DESC_CTRL_LEN(len); +} + +/*! + * Configure Rx reload descriptor + */ +static inline void +cmicd_rx_rldesc_config(struct cmicd_rx_desc *rd, uint32_t addr) +{ + rd->addr = addr; + rd->md.status = 0; + rd->ctrl = CMICD_DESC_CTRL_CNTLD_INTR | CMICD_DESC_CTRL_CHAIN | + CMICD_DESC_CTRL_RELOAD; +} + +/*! + * Configure Tx reload descriptor + */ +static inline void +cmicd_tx_rldesc_config(struct cmicd_tx_desc *td, uint32_t addr) +{ + td->addr = addr; + td->md.status = 0; + td->ctrl = CMICD_DESC_CTRL_CNTLD_INTR | CMICD_DESC_CTRL_CHAIN | + CMICD_DESC_CTRL_RELOAD; +} + +/*! + * Chain Rx descriptor + */ +static inline void +cmicd_rx_desc_chain(struct cmicd_rx_desc *rd, int chain) +{ + if (chain) { + rd->ctrl |= CMICD_DESC_CTRL_CHAIN; + } else { + rd->ctrl &= ~CMICD_DESC_CTRL_CHAIN; + } +} + +/*! + * Chain Tx descriptor + */ +static inline void +cmicd_tx_desc_chain(struct cmicd_tx_desc *td, int chain) +{ + if (chain) { + td->ctrl |= CMICD_DESC_CTRL_CHAIN; + } else { + td->ctrl &= ~CMICD_DESC_CTRL_CHAIN; + } +} + +/*! + * Get unused descriptors in a Rx ring + */ +static inline int +cmicd_pdma_rx_ring_unused(struct pdma_rx_queue *rxq) +{ + /* Leave one descriptor unused so as not to halt */ + return rxq->curr > rxq->halt ? + rxq->curr - rxq->halt - 1 : + rxq->nb_desc + rxq->curr - rxq->halt - 1; +} + +/*! + * Get unused descriptors in a Tx ring + */ +static inline int +cmicd_pdma_tx_ring_unused(struct pdma_tx_queue *txq) +{ + /* Leave one descriptor unused so as not to halt */ + return txq->dirt > txq->curr ? + txq->dirt - txq->curr - 1 : + txq->nb_desc + txq->dirt - txq->curr - 1; +} + +/*! + * Initialize Rx descriptors + */ +static int +cmicd_pdma_rx_desc_init(struct pdma_hw *hw, struct pdma_rx_queue *rxq) +{ + struct pdma_dev *dev = hw->dev; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)dev->ctrl.buf_mngr; + struct cmicd_rx_desc *ring = (struct cmicd_rx_desc *)rxq->ring; + dma_addr_t addr; + uint32_t di; + int rv; + + for (di = 0; di < rxq->nb_desc; di++) { + if (!rxq->pbuf[di].dma) { + /* Allocate pktbuf for ring entry */ + rxq->pbuf[di].adj = CMICD_RX_META_RESV; + rv = bm->rx_buf_alloc(dev, rxq, &rxq->pbuf[di]); + if (SHR_FAILURE(rv)) { + goto cleanup; + } + } + /* Config receive descriptor ring */ + bm->rx_buf_dma(dev, rxq, &rxq->pbuf[di], &addr); + cmicd_rx_desc_config(&ring[di], addr, rxq->buf_size); + if (hw->dev->flags & PDMA_CHAIN_MODE && di == rxq->nb_desc - 1) { + cmicd_rx_desc_chain(&ring[di], 0); + } + } + /* Config the last descriptor in the ring as reload descriptor */ + cmicd_rx_rldesc_config(&ring[di], rxq->ring_addr); + + rxq->curr = 0; + rxq->halt = rxq->state & PDMA_RX_BATCH_REFILL ? 0 : rxq->nb_desc; + + rxq->halt_addr = rxq->ring_addr + sizeof(struct cmicd_rx_desc) * di; + hw->hdls.chan_goto(hw, rxq->chan_id, rxq->halt_addr); + hw->hdls.chan_setup(hw, rxq->chan_id, rxq->ring_addr); + + return SHR_E_NONE; + +cleanup: + for (di = 0; di < rxq->nb_desc; di++) { + if (rxq->pbuf[di].dma) { + bm->rx_buf_free(dev, rxq, &rxq->pbuf[di]); + } + cmicd_rx_desc_config(&ring[di], 0, 0); + } + + CNET_PR("RX: Failed to allocate mem\n"); + + return SHR_E_MEMORY; +} + +/*! + * Cleanup Rx descriptors + */ +static int +cmicd_pdma_rx_desc_clean(struct pdma_hw *hw, struct pdma_rx_queue *rxq) +{ + struct pdma_dev *dev = hw->dev; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)dev->ctrl.buf_mngr; + struct cmicd_rx_desc *ring = (struct cmicd_rx_desc *)rxq->ring; + uint32_t di; + + /* Go through all the descriptors and free pktbuf */ + for (di = 0; di < rxq->nb_desc; di++) { + if (rxq->pbuf[di].dma) { + bm->rx_buf_free(dev, rxq, &rxq->pbuf[di]); + } + cmicd_rx_desc_config(&ring[di], 0, 0); + } + + rxq->curr = 0; + rxq->halt = 0; + + return SHR_E_NONE; +} + +/*! + * Initialize Tx descriptors + */ +static int +cmicd_pdma_tx_desc_init(struct pdma_hw *hw, struct pdma_tx_queue *txq) +{ + struct pdma_dev *dev = hw->dev; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)dev->ctrl.buf_mngr; + struct cmicd_tx_desc *ring = (struct cmicd_tx_desc *)txq->ring; + uint32_t di; + + for (di = 0; di < txq->nb_desc; di++) { + if (txq->pbuf[di].dma) { + bm->tx_buf_free(dev, txq, &txq->pbuf[di]); + } + /* Config transmit descriptor ring */ + cmicd_tx_desc_config(&ring[di], 0, 0, 0); + if (hw->dev->flags & PDMA_CHAIN_MODE) { + cmicd_tx_desc_chain(&ring[di], 0); + } + } + /* Config the last descriptor in the ring as reload descriptor */ + cmicd_tx_rldesc_config(&ring[di], txq->ring_addr); + + txq->curr = 0; + txq->dirt = 0; + txq->halt = 0; + + txq->halt_addr = txq->ring_addr; + hw->hdls.chan_goto(hw, txq->chan_id, txq->halt_addr); + hw->hdls.chan_setup(hw, txq->chan_id, txq->ring_addr); + + return SHR_E_NONE; +} + +/*! + * Cleanup Tx descriptors + */ +static int +cmicd_pdma_tx_desc_clean(struct pdma_hw *hw, struct pdma_tx_queue *txq) +{ + struct pdma_dev *dev = hw->dev; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)dev->ctrl.buf_mngr; + struct cmicd_tx_desc *ring = (struct cmicd_tx_desc *)txq->ring; + uint32_t di; + + /* Go through all the descriptors and free pktbuf */ + for (di = 0; di < txq->nb_desc; di++) { + if (txq->pbuf[di].dma) { + bm->tx_buf_free(dev, txq, &txq->pbuf[di]); + } + cmicd_tx_desc_config(&ring[di], 0, 0, 0); + } + + txq->curr = 0; + txq->dirt = 0; + txq->halt = 0; + + return SHR_E_NONE; +} + +/*! + * Process Rx vring + */ +static int +cmicd_pdma_rx_vring_process(struct pdma_hw *hw, struct pdma_rx_queue *rxq, + struct pdma_rx_buf *pbuf) +{ + struct pdma_dev *dev = hw->dev; + struct cmicd_rx_desc *ring = (struct cmicd_rx_desc *)rxq->ring; + struct pdma_rx_queue *vrxq = NULL; + struct cmicd_rx_desc *vring = NULL; + struct pkt_hdr *pkh = &pbuf->pkb->pkh; + + vrxq = (struct pdma_rx_queue *)dev->ctrl.vnet_rxq[rxq->queue_id]; + vring = (struct cmicd_rx_desc *)vrxq->ring; + if (!vring) { + rxq->stats.dropped++; + return SHR_E_UNAVAIL; + } + + if (vring[vrxq->curr].md.status & CMICD_DESC_STAT_RTX_DONE) { + dev->xnet_wake(dev); + return SHR_E_BUSY; + } + + /* Copy descriptor and packet to vring */ + sal_memcpy(dev->sys_p2v(dev, (uint64_t)vring[vrxq->curr].addr), + &pbuf->pkb->data + pkh->meta_len, pkh->data_len); + sal_memcpy(&vring[vrxq->curr].md, &ring[rxq->curr].md, + sizeof(((struct rx_metadata *)0)->data)); + vring[vrxq->curr].md.status = ring[rxq->curr].md.status; + + MEMORY_BARRIER; + + /* Notify VNET to process if needed */ + if (!vring[(vrxq->curr + vrxq->nb_desc - 1) % vrxq->nb_desc].md.status) { + dev->xnet_wake(dev); + } + vrxq->curr = (vrxq->curr + 1) % vrxq->nb_desc; + + return SHR_E_NONE; +} + +/*! + * Refill Rx ring + */ +static int +cmicd_pdma_rx_ring_refill(struct pdma_hw *hw, struct pdma_rx_queue *rxq) +{ + struct pdma_dev *dev = hw->dev; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)dev->ctrl.buf_mngr; + struct cmicd_rx_desc *ring = (struct cmicd_rx_desc *)rxq->ring; + struct pdma_rx_buf *pbuf = NULL; + int unused = cmicd_pdma_rx_ring_unused(rxq); + dma_addr_t addr; + uint32_t halt; + int rv; + + for (halt = rxq->halt; halt < rxq->halt + unused; halt++) { + pbuf = &rxq->pbuf[halt % rxq->nb_desc]; + /* Allocate a new pktbuf */ + if (!bm->rx_buf_avail(dev, rxq, pbuf)) { + rv = bm->rx_buf_alloc(dev, rxq, pbuf); + if (SHR_FAILURE(rv)) { + rxq->halt = halt % rxq->nb_desc; + rxq->stats.nomems++; + goto fail; + } + } + /* Setup the new descriptor */ + bm->rx_buf_dma(dev, rxq, pbuf, &addr); + cmicd_rx_desc_config(&ring[halt % rxq->nb_desc], addr, rxq->buf_size); + if (dev->flags & PDMA_CHAIN_MODE && halt % rxq->nb_desc == rxq->nb_desc - 1) { + cmicd_rx_desc_chain(&ring[halt % rxq->nb_desc], 0); + } + } + + sal_spinlock_lock(rxq->lock); + rxq->halt = halt % rxq->nb_desc; + if (!(rxq->state & PDMA_RX_QUEUE_XOFF)) { + /* Descriptor cherry pick */ + rxq->halt_addr = rxq->ring_addr + sizeof(struct cmicd_rx_desc) * rxq->halt; + hw->hdls.chan_goto(hw, rxq->chan_id, rxq->halt_addr); + } + sal_spinlock_unlock(rxq->lock); + + return SHR_E_NONE; + +fail: + CNET_PR("RX: Failed to allocate mem\n"); + + return SHR_E_MEMORY; +} + +/*! + * \brief Clean Rx ring + * + * \param [in] hw HW structure point. + * \param [in] rxq Rx queue structure point. + * \param [in] budget Polling budget. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +cmicd_pdma_rx_ring_clean(struct pdma_hw *hw, struct pdma_rx_queue *rxq, int budget) +{ + struct pdma_dev *dev = hw->dev; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)dev->ctrl.buf_mngr; + struct cmicd_rx_desc *ring = (struct cmicd_rx_desc *)rxq->ring; + struct pdma_rx_buf *pbuf = NULL; + struct pkt_hdr *pkh = NULL; + dma_addr_t addr; + uint32_t stat, curr; + int len, done = 0; + int rv; + + curr = rxq->curr; + while (CMICD_DESC_STAT_DONE(ring[curr].md.status)) { + if (dev->mode == DEV_MODE_VNET && rxq->state & PDMA_RX_QUEUE_XOFF) { + break; + } + if (!(rxq->state & PDMA_RX_BATCH_REFILL) && + !(rxq->state & PDMA_RX_QUEUE_XOFF)) { + /* Descriptor cherry pick */ + rxq->halt_addr = rxq->ring_addr + sizeof(struct cmicd_rx_desc) * curr; + hw->hdls.chan_goto(hw, rxq->chan_id, rxq->halt_addr); + rxq->halt = curr; + } + if (done == budget) { + break; + } + + /* Get the current pktbuf to process */ + pbuf = &rxq->pbuf[curr]; + stat = ring[curr].md.status; + len = CMICD_DESC_STAT_LEN(stat); + pkh = bm->rx_buf_get(dev, rxq, pbuf, len); + if (!pkh) { + rxq->stats.nomems++; + goto fail; + } + + /* Setup packet header */ + pkh->data_len = len; + pkh->meta_len = pbuf->adj; + pkh->queue_id = rxq->queue_id; + pkh->attrs = CMICD_DESC_STAT_FLAGS(stat); + sal_memcpy(&pbuf->pkb->data, &ring[curr].md, sizeof(struct rx_metadata)); + + /* Send up the packet */ + rv = dev->pkt_recv(dev, rxq->queue_id, (void *)pbuf->skb); + if (SHR_FAILURE(rv)) { + if (dev->mode == DEV_MODE_HNET && pkh->attrs & PDMA_RX_TO_VNET) { + rv = cmicd_pdma_rx_vring_process(hw, rxq, pbuf); + if (SHR_FAILURE(rv) && rv == SHR_E_BUSY) { + rxq->state |= PDMA_RX_QUEUE_BUSY; + return done; + } + } else { + rxq->stats.dropped++; + } + bm->rx_buf_put(dev, rxq, pbuf, len); + } + + /* Count the packets/bytes */ + rxq->stats.packets++; + rxq->stats.bytes += len; + + /* Count the errors if any */ + if (stat & CMICD_DESC_STAT_ERR_MASK) { + rxq->stats.errors++; + if (stat & CMICD_DESC_STAT_HEAD_ERR) { + rxq->stats.head_errors++; + } + if (stat & CMICD_DESC_STAT_DATA_ERR) { + rxq->stats.data_errors++; + } + if (stat & CMICD_DESC_STAT_CELL_ERR) { + rxq->stats.cell_errors++; + } + } + + /* Setup the new descriptor */ + if (!(rxq->state & PDMA_RX_BATCH_REFILL)) { + if (!bm->rx_buf_avail(dev, rxq, pbuf)) { + rv = bm->rx_buf_alloc(dev, rxq, pbuf); + if (SHR_FAILURE(rv)) { + rxq->stats.nomems++; + goto fail; + } + } + bm->rx_buf_dma(dev, rxq, pbuf, &addr); + cmicd_rx_desc_config(&ring[curr], addr, rxq->buf_size); + if (dev->flags & PDMA_CHAIN_MODE && curr == rxq->nb_desc - 1) { + cmicd_rx_desc_chain(&ring[curr], 0); + } + } else { + cmicd_rx_desc_config(&ring[curr], 0, 0); + } + + /* Notify HNET to process if needed */ + if (dev->mode == DEV_MODE_VNET) { + MEMORY_BARRIER; + if (ring[(curr + rxq->nb_desc - 1) % rxq->nb_desc].md.status) { + dev->xnet_wake(dev); + } + } + + /* Update the indicators */ + if (!(rxq->state & PDMA_RX_BATCH_REFILL) && rxq->halt != curr) { + sal_spinlock_lock(rxq->lock); + if (!(rxq->state & PDMA_RX_QUEUE_XOFF)) { + /* Descriptor cherry pick */ + rxq->halt_addr = rxq->ring_addr + sizeof(struct cmicd_rx_desc) * curr; + hw->hdls.chan_goto(hw, rxq->chan_id, rxq->halt_addr); + rxq->halt = curr; + } + curr = (curr + 1) % rxq->nb_desc; + sal_spinlock_unlock(rxq->lock); + } else { + curr = (curr + 1) % rxq->nb_desc; + } + rxq->curr = curr; + done++; + + /* Restart DMA if in chain mode */ + if (dev->flags & PDMA_CHAIN_MODE) { + if (curr == 0 && !(rxq->state & PDMA_RX_QUEUE_XOFF)) { + hw->hdls.chan_stop(hw, rxq->chan_id); + hw->hdls.chan_start(hw, rxq->chan_id); + } + } + } + + /* One more poll for chain done in chain mode */ + if (dev->flags & PDMA_CHAIN_MODE) { + if (curr == rxq->nb_desc - 1 && done) { + done = budget; + } + } + + /* In batching mode, replenish all the unused descriptors */ + if (rxq->state & PDMA_RX_BATCH_REFILL && + cmicd_pdma_rx_ring_unused(rxq) >= (int)rxq->free_thresh) { + cmicd_pdma_rx_ring_refill(hw, rxq); + } + + /* Notify the other side to process */ + if (dev->mode == DEV_MODE_VNET || dev->mode == DEV_MODE_HNET) { + if (done) { + dev->xnet_wake(dev); + } + } + + return done; + +fail: + CNET_PR("RX: Failed to allocate mem\n"); + + return done; +} + +/*! + * Process Tx vring + */ +static int +cmicd_pdma_tx_vring_process(struct pdma_hw *hw, struct pdma_tx_queue *txq, + struct pdma_tx_buf *pbuf) +{ + struct pdma_dev *dev = hw->dev; + struct cmicd_tx_desc *ring = (struct cmicd_tx_desc *)txq->ring; + struct pdma_tx_queue *vtxq = NULL; + struct cmicd_tx_desc *vring = NULL; + + vtxq = (struct pdma_tx_queue *)dev->ctrl.vnet_txq[txq->queue_id]; + vring = (struct cmicd_tx_desc *)vtxq->ring; + if (!vring) { + return SHR_E_UNAVAIL; + } + + /* Update vring descriptor */ + vring[vtxq->dirt].md.status = ring[txq->dirt].md.status; + pbuf->dma = 0; + + MEMORY_BARRIER; + + /* Notify VNET to process if needed */ + if (!vring[(vtxq->dirt + vtxq->nb_desc - 1) % vtxq->nb_desc].md.status) { + dev->xnet_wake(dev); + } + vtxq->dirt = (vtxq->dirt + 1) % vtxq->nb_desc; + + return SHR_E_NONE; +} + +/*! + * \brief Clean Tx ring + * + * \param [in] hw HW structure point. + * \param [in] txq Tx queue structure point. + * \param [in] budget Polling budget. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +cmicd_pdma_tx_ring_clean(struct pdma_hw *hw, struct pdma_tx_queue *txq, int budget) +{ + struct pdma_dev *dev = hw->dev; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)dev->ctrl.buf_mngr; + struct cmicd_tx_desc *ring = (struct cmicd_tx_desc *)txq->ring; + uint32_t dirt, curr; + int done = 0; + + dirt = txq->dirt; + while (txq->pbuf[dirt].dma) { + if (!CMICD_DESC_STAT_DONE(ring[dirt].md.status)) { + break; + } + if (done == budget) { + break; + } + + if (dev->mode == DEV_MODE_HNET && !txq->pbuf[dirt].skb) { + cmicd_pdma_tx_vring_process(hw, txq, &txq->pbuf[dirt]); + } else { + /* Free the done pktbuf */ + bm->tx_buf_free(dev, txq, &txq->pbuf[dirt]); + } + + cmicd_tx_desc_config(&ring[dirt], 0, 0, 0); + + /* Update the indicators */ + dirt = (dirt + 1) % txq->nb_desc; + txq->dirt = dirt; + done++; + + /* Restart DMA if in chain mode */ + if (dev->flags & PDMA_CHAIN_MODE) { + sal_spinlock_lock(txq->lock); + curr = txq->curr; + if (dirt == txq->halt && dirt != curr) { + hw->hdls.chan_stop(hw, txq->chan_id); + cmicd_tx_desc_chain(&ring[(curr + txq->nb_desc - 1) % txq->nb_desc], 0); + hw->hdls.chan_setup(hw, txq->chan_id, + txq->ring_addr + sizeof(struct cmicd_tx_desc) * txq->halt); + hw->hdls.chan_start(hw, txq->chan_id); + txq->halt = curr; + } + sal_spinlock_unlock(txq->lock); + } + } + + /* One more poll for chain done in chain mode */ + if (dev->flags & PDMA_CHAIN_MODE) { + sal_spinlock_lock(txq->lock); + if (dirt != txq->halt) { + done = budget; + } + sal_spinlock_unlock(txq->lock); + } + + /* Resume Tx if any */ + sal_spinlock_lock(txq->lock); + if (cmicd_pdma_tx_ring_unused(txq) && txq->state & PDMA_TX_QUEUE_XOFF) { + txq->state &= ~PDMA_TX_QUEUE_XOFF; + sal_spinlock_unlock(txq->lock); + if (dev->tx_resume) { + dev->tx_resume(dev, txq->queue_id); + } else if (!(txq->state & PDMA_TX_QUEUE_POLL)) { + sal_sem_give(txq->sem); + } + return done; + } + sal_spinlock_unlock(txq->lock); + + return done; +} + +/*! + * Dump Rx ring + */ +static int +cmicd_pdma_rx_ring_dump(struct pdma_hw *hw, struct pdma_rx_queue *rxq) +{ + struct cmicd_rx_desc *ring = (struct cmicd_rx_desc *)rxq->ring; + struct cmicd_rx_desc *rd; + uint32_t di; + + CNET_PR("\nRX: queue=%d, chan=%d, curr=%d, halt=%d, halt@%p\n", + rxq->queue_id, rxq->chan_id, rxq->curr, rxq->halt, (void *)&ring[rxq->halt]); + CNET_PR("----------------------------------------------------------------\n"); + for (di = 0; di < rxq->nb_desc + 1; di++) { + rd = &ring[di]; + CNET_PR("DESC[%03d]: (%p)->%08x %08x ... %08x\n", + di, (void *)(unsigned long)(rxq->ring_addr + di * CMICD_PDMA_DCB_SIZE), + rd->addr, rd->ctrl, rd->md.status); + } + + return SHR_E_NONE; +} + +/*! + * Dump Tx ring + */ +static int +cmicd_pdma_tx_ring_dump(struct pdma_hw *hw, struct pdma_tx_queue *txq) +{ + struct cmicd_tx_desc *ring = (struct cmicd_tx_desc *)txq->ring; + struct cmicd_tx_desc *td; + uint32_t di; + + CNET_PR("\nTX: queue=%d, chan=%d, curr=%d, dirt=%d, halt@%p\n", + txq->queue_id, txq->chan_id, txq->curr, txq->dirt, (void *)&ring[txq->curr]); + CNET_PR("----------------------------------------------------------------\n"); + for (di = 0; di < txq->nb_desc + 1; di++) { + td = &ring[di]; + CNET_PR("DESC[%03d]: (%p)->%08x %08x ... %08x\n", + di, (void *)(unsigned long)(txq->ring_addr + di * CMICD_PDMA_DCB_SIZE), + td->addr, td->ctrl, td->md.status); + } + + return SHR_E_NONE; +} + +/*! + * Fetch Tx vring + */ +static int +cmicd_pdma_tx_vring_fetch(struct pdma_hw *hw, struct pdma_tx_queue *txq, + struct pdma_tx_buf *pbuf) +{ + struct pdma_dev *dev = hw->dev; + struct cmicd_tx_desc *ring = (struct cmicd_tx_desc *)txq->ring; + struct pdma_tx_queue *vtxq = NULL; + struct cmicd_tx_desc *vring = NULL; + + vtxq = (struct pdma_tx_queue *)dev->ctrl.vnet_txq[txq->queue_id]; + vring = (struct cmicd_tx_desc *)vtxq->ring; + if (!vring || !CMICD_DESC_CTRL_LEN(vring[vtxq->curr].ctrl)) { + return SHR_E_UNAVAIL; + } + + /* Fetch vring descriptor */ + sal_memcpy(&ring[txq->curr], &vring[vtxq->curr], sizeof(struct cmicd_tx_desc)); + vring[vtxq->curr].ctrl &= ~CMICD_DESC_CTRL_LEN(-1); + + MEMORY_BARRIER; + + pbuf->dma = vring[vtxq->curr].addr; + pbuf->len = CMICD_DESC_CTRL_LEN(ring[txq->curr].ctrl); + vtxq->curr = (vtxq->curr + 1) % vtxq->nb_desc; + + return SHR_E_NONE; +} + +/*! + * Check Tx ring + */ +static inline int +cmicd_pdma_tx_ring_check(struct pdma_hw *hw, struct pdma_tx_queue *txq) +{ + if (cmicd_pdma_tx_ring_unused(txq)) { + return SHR_E_NONE; + } + + sal_spinlock_lock(txq->lock); + if (!cmicd_pdma_tx_ring_unused(txq)) { + txq->state |= PDMA_TX_QUEUE_XOFF; + txq->stats.xoffs++; + sal_spinlock_unlock(txq->lock); + if (hw->dev->tx_suspend) { + hw->dev->tx_suspend(hw->dev, txq->queue_id); + } + return SHR_E_BUSY; + } + sal_spinlock_unlock(txq->lock); + + return SHR_E_NONE; +} + +/*! + * \brief Start packet transmission + * + * \param [in] hw HW structure point. + * \param [in] txq Tx queue structure point. + * \param [in] buf Tx packet buffer. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +cmicd_pdma_pkt_xmit(struct pdma_hw *hw, struct pdma_tx_queue *txq, void *buf) +{ + struct pdma_dev *dev = hw->dev; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)dev->ctrl.buf_mngr; + struct cmicd_tx_desc *ring = (struct cmicd_tx_desc *)txq->ring; + struct pdma_tx_buf *pbuf = NULL; + struct pkt_hdr *pkh = NULL; + dma_addr_t addr; + uint32_t curr, flags = 0; + int retry = 5000000; + int rv; + + if (!(txq->state & PDMA_TX_QUEUE_ACTIVE)) { + return SHR_E_UNAVAIL; + } + + if (dev->tx_suspend) { + sal_spinlock_lock(txq->mutex); + } else { + sal_sem_take(txq->sem, SAL_SEM_FOREVER); + } + + /* Check Tx resource */ + if (dev->tx_suspend) { + /* Suspend Tx if no resource */ + rv = cmicd_pdma_tx_ring_check(hw, txq); + if (SHR_FAILURE(rv)) { + sal_spinlock_unlock(txq->mutex); + return rv; + } + } else { + /* Abort Tx if a fatal error happened */ + if (txq->state & PDMA_TX_QUEUE_XOFF) { + sal_sem_give(txq->sem); + return SHR_E_RESOURCE; + } + } + + /* Setup the new descriptor */ + curr = txq->curr; + pbuf = &txq->pbuf[curr]; + if (dev->mode == DEV_MODE_HNET && !buf) { + rv = cmicd_pdma_tx_vring_fetch(hw, txq, pbuf); + if (SHR_FAILURE(rv)) { + sal_spinlock_unlock(txq->mutex); + return SHR_E_EMPTY; + } + } else { + pbuf->adj = 0; + pkh = bm->tx_buf_get(dev, txq, pbuf, buf); + if (!pkh) { + txq->stats.dropped++; + if (dev->tx_suspend) { + sal_spinlock_unlock(txq->mutex); + } else { + sal_sem_give(txq->sem); + } + return SHR_E_NONE; + } + bm->tx_buf_dma(dev, txq, pbuf, &addr); + flags |= pkh->attrs & PDMA_TX_HIGIG_PKT ? CMICD_DESC_TX_HIGIG_PKT : 0; + flags |= pkh->attrs & PDMA_TX_PAUSE_PKT ? CMICD_DESC_TX_PAUSE_PKT : 0; + flags |= pkh->attrs & PDMA_TX_PURGE_PKT ? CMICD_DESC_TX_PURGE_PKT : 0; + cmicd_tx_desc_config(&ring[curr], addr, pbuf->len, flags); + if (pkh->meta_len) { + sal_memcpy(&ring[curr].md, &pbuf->pkb->data, sizeof(ring->md.data)); + } + } + + /* Notify HNET to process if needed */ + if (dev->mode == DEV_MODE_VNET) { + MEMORY_BARRIER; + if (!CMICD_DESC_CTRL_LEN(ring[(curr + txq->nb_desc - 1) % txq->nb_desc].ctrl)) { + dev->xnet_wake(dev); + } + } + + /* Update the indicators */ + curr = (curr + 1) % txq->nb_desc; + txq->curr = curr; + + /* Start DMA if in chain mode */ + if (dev->flags & PDMA_CHAIN_MODE) { + if (txq->state & PDMA_TX_QUEUE_POLL) { + do { + rv = cmicd_pdma_tx_ring_clean(hw, txq, txq->nb_desc - 1); + if (rv != (int)txq->nb_desc - 1) { + break; + } + sal_usleep(1); + } while (retry--); + if (retry <= 0) { + CNET_PR("Last Tx could not be done in given time\n"); + } + } + sal_spinlock_lock(txq->lock); + if (txq->dirt == txq->halt && txq->dirt != curr) { + hw->hdls.chan_stop(hw, txq->chan_id); + cmicd_tx_desc_chain(&ring[(curr + txq->nb_desc - 1) % txq->nb_desc], 0); + hw->hdls.chan_setup(hw, txq->chan_id, + txq->ring_addr + sizeof(struct cmicd_tx_desc) * txq->halt); + hw->hdls.chan_start(hw, txq->chan_id); + txq->halt = curr; + } + sal_spinlock_unlock(txq->lock); + } + + /* Kick off DMA */ + txq->halt_addr = txq->ring_addr + sizeof(struct cmicd_tx_desc) * curr; + hw->hdls.chan_goto(hw, txq->chan_id, txq->halt_addr); + + /* Count the packets/bytes */ + txq->stats.packets++; + txq->stats.bytes += pbuf->len; + + /* Clean up ring if in polling mode */ + if (txq->state & PDMA_TX_QUEUE_POLL && + cmicd_pdma_tx_ring_unused(txq) <= (int)txq->free_thresh) { + cmicd_pdma_tx_ring_clean(hw, txq, txq->nb_desc - txq->free_thresh); + } + + /* Suspend Tx if no resource */ + rv = cmicd_pdma_tx_ring_check(hw, txq); + if (SHR_FAILURE(rv)) { + if (dev->mode == DEV_MODE_VNET) { + dev->xnet_wake(dev); + } + + if (txq->state & PDMA_TX_QUEUE_POLL) { + /* In polling mode, must wait till the ring is available */ + do { + cmicd_pdma_tx_ring_clean(hw, txq, txq->free_thresh); + if (!(txq->state & PDMA_TX_QUEUE_XOFF)) { + break; + } + sal_usleep(1); + } while (retry--); + if (retry <= 0) { + CNET_PR("Fatal error: Tx ring is full, packets have not been transmitted for 5 seconds\n"); + if (!dev->tx_suspend) { + sal_sem_give(txq->sem); + return SHR_E_RESOURCE; + } + } + } else { + /* In interrupt mode, the handle thread will wake up Tx */ + if (!dev->tx_suspend) { + return SHR_E_NONE; + } + } + } + + if (dev->tx_suspend) { + sal_spinlock_unlock(txq->mutex); + } else { + sal_sem_give(txq->sem); + } + + return SHR_E_NONE; +} + +/*! + * Suspend Rx queue + */ +static int +cmicd_pdma_rx_suspend(struct pdma_hw *hw, struct pdma_rx_queue *rxq) +{ + sal_spinlock_lock(rxq->lock); + rxq->state |= PDMA_RX_QUEUE_XOFF; + if (hw->dev->flags & PDMA_CHAIN_MODE) { + hw->hdls.chan_stop(hw, rxq->chan_id); + } + sal_spinlock_unlock(rxq->lock); + + return SHR_E_NONE; +} + +/*! + * Resume Rx queue + */ +static int +cmicd_pdma_rx_resume(struct pdma_hw *hw, struct pdma_rx_queue *rxq) +{ + sal_spinlock_lock(rxq->lock); + if (!(rxq->state & PDMA_RX_QUEUE_XOFF)) { + sal_spinlock_unlock(rxq->lock); + return SHR_E_NONE; + } + if (rxq->state & PDMA_RX_BATCH_REFILL) { + rxq->halt_addr = rxq->ring_addr + sizeof(struct cmicd_rx_desc) * rxq->halt; + hw->hdls.chan_goto(hw, rxq->chan_id, rxq->halt_addr); + } else if (rxq->halt == rxq->curr || (rxq->halt == rxq->nb_desc && rxq->curr == 0)) { + rxq->halt = (rxq->curr + 1) % rxq->nb_desc; + rxq->halt_addr = rxq->ring_addr + sizeof(struct cmicd_rx_desc) * rxq->halt; + hw->hdls.chan_goto(hw, rxq->chan_id, rxq->halt_addr); + } + if (hw->dev->flags & PDMA_CHAIN_MODE) { + rxq->curr = 0; + hw->hdls.chan_start(hw, rxq->chan_id); + } + rxq->state &= ~PDMA_RX_QUEUE_XOFF; + sal_spinlock_unlock(rxq->lock); + + return SHR_E_NONE; +} + +/*! + * Initialize function pointers + */ +int +bcmcnet_cmicd_pdma_desc_ops_init(struct pdma_hw *hw) +{ + if (!hw) { + return SHR_E_PARAM; + } + + hw->dops.rx_desc_init = cmicd_pdma_rx_desc_init; + hw->dops.rx_desc_clean = cmicd_pdma_rx_desc_clean; + hw->dops.rx_ring_clean = cmicd_pdma_rx_ring_clean; + hw->dops.rx_ring_dump = cmicd_pdma_rx_ring_dump; + hw->dops.rx_suspend = cmicd_pdma_rx_suspend; + hw->dops.rx_resume = cmicd_pdma_rx_resume; + hw->dops.tx_desc_init = cmicd_pdma_tx_desc_init; + hw->dops.tx_desc_clean = cmicd_pdma_tx_desc_clean; + hw->dops.tx_ring_clean = cmicd_pdma_tx_ring_clean; + hw->dops.tx_ring_dump = cmicd_pdma_tx_ring_dump; + hw->dops.pkt_xmit = cmicd_pdma_pkt_xmit; + + return SHR_E_NONE; +} + +/*! + * Attach device driver + */ +int +bcmcnet_cmicd_pdma_driver_attach(struct pdma_dev *dev) +{ + struct pdma_hw *hw = NULL; + + /* Allocate memory for HW data */ + hw = sal_alloc(sizeof(*hw), "bcmcnetPdmaHw"); + if (!hw) { + return SHR_E_MEMORY; + } + sal_memset(hw, 0, sizeof(*hw)); + hw->unit = dev->unit; + hw->dev = dev; + dev->ctrl.hw = hw; + + bcmcnet_cmicd_pdma_hw_hdls_init(hw); + bcmcnet_cmicd_pdma_desc_ops_init(hw); + + return SHR_E_NONE; +} + +/*! + * Detach device driver + */ +int +bcmcnet_cmicd_pdma_driver_detach(struct pdma_dev *dev) +{ + if (dev->ctrl.hw) { + sal_free(dev->ctrl.hw); + } + dev->ctrl.hw = NULL; + + return SHR_E_NONE; +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/hmi/cmicx/bcmcnet_cmicx_pdma_hw.c b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/hmi/cmicx/bcmcnet_cmicx_pdma_hw.c new file mode 100644 index 000000000000..6dc77c4b7c04 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/hmi/cmicx/bcmcnet_cmicx_pdma_hw.c @@ -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 +#include +#include +#include + +/*! + * 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; +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/hmi/cmicx/bcmcnet_cmicx_pdma_rxtx.c b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/hmi/cmicx/bcmcnet_cmicx_pdma_rxtx.c new file mode 100644 index 000000000000..651728465d56 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/hmi/cmicx/bcmcnet_cmicx_pdma_rxtx.c @@ -0,0 +1,1094 @@ +/*! \file bcmcnet_cmicx_pdma_rxtx.c + * + * Utility routines for BCMCNET hardware (CMICx) specific Rx/Tx. + * + * Here are the CMIC specific Rx/Tx routines including DCBs resource allocation + * and clean up, DCBs configuration, Rx buffers allocation, Tx buffers release, + * Rx/Tx packets processing, etc. + * They are shared among all the modes (UNET, KNET, VNET, HNET) and in both of + * user space and kernel space. + * + * The driver uses a ring of DCBs per DMA channel based on Continuous DMA mode. + * The beginning is written to register pointing to the physical address of the + * start of the ring. The ring size is maintained by the driver. A HALT DCB + * physical address is written to DMA register timely to indicate how many DCBs + * can be handled by HW. + * + * When a packet is received, an interrupt is triggered. The handler will go + * through the Rx DCB ring to process the current completed DCB and every + * subsequent DCBs until no one is left. The received packet is processed and + * passed up to the high level SW. After that, a new buffer is allocated and + * the DCB is updated for receiving a new packet. A new HALT DCB is selected + * and its physical address is written to DMA register. + * + * When a packet is transmitted, the driver starts where it left off last time + * in the Tx DCB ring, updates the DCB and writes its physical address to DMA + * register so as to start DMA. Once the transmitting is finished, the handler + * is informed to clean up the buffer based on the work mode. In KNET or HNET + * mode, an interrupt will be triggered. Polling mode is used in CNET or VNET + * mode, the buffers will be cleaned up when the number of dirty DCBs reaches + * a pre-defined threshold. + * + * In VNET and HNET modes, DCB updating between virtual ring and real ring and + * a IOCTL based notification mechanism are involved. The hypervisor in kernel + * emulates the DMA HW behaviors to update DCBs in virtual network and inform + * the handler something happened. Likewise, the hypervisor updates itself real + * DCB ring from the virtual ring to start DMA for transmitting a packet once a + * notification is received from the virtual network. + * + */ +/* + * $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 +#include +#include +#include +#include + +/*! + * Configure Rx descriptor + */ +static inline void +cmicx_rx_desc_config(struct cmicx_rx_desc *rd, uint64_t addr, uint32_t len) +{ + uint32_t ctrl; + + rd->addr_lo = addr; + rd->addr_hi = DMA_TO_BUS_HI(addr >> 32); + rd->status = 0; + ctrl = rd->ctrl; + ctrl &= CMICX_DESC_CTRL_REMAIN(0xf); + ctrl |= CMICX_DESC_CTRL_CNTLD_INTR | CMICX_DESC_CTRL_CHAIN | + CMICX_DESC_CTRL_LEN(len); + rd->ctrl = ctrl; +} + +/*! + * Configure Tx descriptor + */ +static inline void +cmicx_tx_desc_config(struct cmicx_tx_desc *td, uint64_t addr, uint32_t len, uint32_t flags) +{ + uint32_t ctrl; + + td->addr_lo = addr; + td->addr_hi = DMA_TO_BUS_HI(addr >> 32); + td->status = 0; + ctrl = td->ctrl; + ctrl &= CMICX_DESC_CTRL_REMAIN(0xf); + ctrl |= CMICX_DESC_CTRL_CNTLD_INTR | CMICX_DESC_CTRL_CHAIN | + CMICX_DESC_CTRL_FLAGS(flags) | CMICX_DESC_CTRL_LEN(len); + td->ctrl = ctrl; +} + +/*! + * Configure Rx reload descriptor + */ +static inline void +cmicx_rx_rldesc_config(struct cmicx_rx_desc *rd, uint64_t addr) +{ + rd->addr_lo = addr; + rd->addr_hi = DMA_TO_BUS_HI(addr >> 32); + rd->status = 0; + rd->ctrl = CMICX_DESC_CTRL_CNTLD_INTR | CMICX_DESC_CTRL_CHAIN | + CMICX_DESC_CTRL_RELOAD; +} + +/*! + * Configure Tx reload descriptor + */ +static inline void +cmicx_tx_rldesc_config(struct cmicx_tx_desc *td, uint64_t addr) +{ + td->addr_lo = addr; + td->addr_hi = DMA_TO_BUS_HI(addr >> 32); + td->status = 0; + td->ctrl = CMICX_DESC_CTRL_CNTLD_INTR | CMICX_DESC_CTRL_CHAIN | + CMICX_DESC_CTRL_RELOAD; +} + +/*! + * Chain Rx descriptor + */ +static inline void +cmicx_rx_desc_chain(struct cmicx_rx_desc *rd, int chain) +{ + if (chain) { + rd->ctrl |= CMICX_DESC_CTRL_CHAIN; + } else { + rd->ctrl &= ~CMICX_DESC_CTRL_CHAIN; + } +} + +/*! + * Chain Tx descriptor + */ +static inline void +cmicx_tx_desc_chain(struct cmicx_tx_desc *td, int chain) +{ + if (chain) { + td->ctrl |= CMICX_DESC_CTRL_CHAIN; + } else { + td->ctrl &= ~CMICX_DESC_CTRL_CHAIN; + } +} + +/*! + * Set Rx descriptor remain + */ +static inline void +cmicx_rx_desc_remain(struct cmicx_rx_desc *rd, uint32_t rm) +{ + rd->ctrl &= ~CMICX_DESC_CTRL_REMAIN(0xf); + rd->ctrl |= CMICX_DESC_CTRL_REMAIN(rm); +} + +/*! + * Set Tx descriptor remain + */ +static inline void +cmicx_tx_desc_remain(struct cmicx_tx_desc *td, uint32_t rm) +{ + td->ctrl &= ~CMICX_DESC_CTRL_REMAIN(0xf); + td->ctrl |= CMICX_DESC_CTRL_REMAIN(rm); +} + +/*! + * Get unused descriptors in a Rx ring + */ +static inline int +cmicx_pdma_rx_ring_unused(struct pdma_rx_queue *rxq) +{ + /* Leave one descriptor unused so as not to halt */ + return rxq->curr > rxq->halt ? + rxq->curr - rxq->halt - 1 : + rxq->nb_desc + rxq->curr - rxq->halt - 1; +} + +/*! + * Get unused descriptors in a Tx ring + */ +static inline int +cmicx_pdma_tx_ring_unused(struct pdma_tx_queue *txq) +{ + /* Leave one descriptor unused so as not to halt */ + return txq->dirt > txq->curr ? + txq->dirt - txq->curr - 1 : + txq->nb_desc + txq->dirt - txq->curr - 1; +} + +/*! + * Initialize Rx descriptors + */ +static int +cmicx_pdma_rx_desc_init(struct pdma_hw *hw, struct pdma_rx_queue *rxq) +{ + struct pdma_dev *dev = hw->dev; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)dev->ctrl.buf_mngr; + struct cmicx_rx_desc *ring = (struct cmicx_rx_desc *)rxq->ring; + dma_addr_t addr; + uint32_t di, rm; + int rv; + + for (di = 0; di < rxq->nb_desc; di++) { + if (!rxq->pbuf[di].dma) { + /* Allocate pktbuf for ring entry */ + rv = bm->rx_buf_alloc(dev, rxq, &rxq->pbuf[di]); + if (SHR_FAILURE(rv)) { + goto cleanup; + } + } + /* Config receive descriptor ring */ + bm->rx_buf_dma(dev, rxq, &rxq->pbuf[di], &addr); + cmicx_rx_desc_config(&ring[di], addr, rxq->buf_size); + rm = (rxq->nb_desc - di) >= CMICX_DESC_REMAIN_MAX ? + CMICX_DESC_REMAIN_MAX : rxq->nb_desc - di; + cmicx_rx_desc_remain(&ring[di], rm); + if (hw->dev->flags & PDMA_CHAIN_MODE && di == rxq->nb_desc - 1) { + cmicx_rx_desc_chain(&ring[di], 0); + } + } + /* Config the last descriptor in the ring as reload descriptor */ + cmicx_rx_rldesc_config(&ring[di], rxq->ring_addr); + + rxq->curr = 0; + rxq->halt = rxq->state & PDMA_RX_BATCH_REFILL ? 0 : rxq->nb_desc; + + rxq->halt_addr = rxq->ring_addr + sizeof(struct cmicx_rx_desc) * di; + hw->hdls.chan_goto(hw, rxq->chan_id, rxq->halt_addr); + hw->hdls.chan_setup(hw, rxq->chan_id, rxq->ring_addr); + + return SHR_E_NONE; + +cleanup: + for (di = 0; di < rxq->nb_desc; di++) { + if (rxq->pbuf[di].dma) { + bm->rx_buf_free(dev, rxq, &rxq->pbuf[di]); + } + cmicx_rx_desc_config(&ring[di], 0, 0); + } + + CNET_PR("RX: Failed to allocate mem\n"); + + return SHR_E_MEMORY; +} + +/*! + * Cleanup Rx descriptors + */ +static int +cmicx_pdma_rx_desc_clean(struct pdma_hw *hw, struct pdma_rx_queue *rxq) +{ + struct pdma_dev *dev = hw->dev; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)dev->ctrl.buf_mngr; + struct cmicx_rx_desc *ring = (struct cmicx_rx_desc *)rxq->ring; + uint32_t di; + + /* Go through all the descriptors and free pktbuf */ + for (di = 0; di < rxq->nb_desc; di++) { + if (rxq->pbuf[di].dma) { + bm->rx_buf_free(dev, rxq, &rxq->pbuf[di]); + } + cmicx_rx_desc_config(&ring[di], 0, 0); + } + + rxq->curr = 0; + rxq->halt = 0; + + return SHR_E_NONE; +} + +/*! + * Initialize Tx descriptors + */ +static int +cmicx_pdma_tx_desc_init(struct pdma_hw *hw, struct pdma_tx_queue *txq) +{ + struct pdma_dev *dev = hw->dev; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)dev->ctrl.buf_mngr; + struct cmicx_tx_desc *ring = (struct cmicx_tx_desc *)txq->ring; + uint32_t di, rm; + + for (di = 0; di < txq->nb_desc; di++) { + if (txq->pbuf[di].dma) { + bm->tx_buf_free(dev, txq, &txq->pbuf[di]); + } + /* Config transmit descriptor ring */ + cmicx_tx_desc_config(&ring[di], 0, 0, 0); + rm = (txq->nb_desc - di) >= CMICX_DESC_REMAIN_MAX ? + CMICX_DESC_REMAIN_MAX : txq->nb_desc - di; + cmicx_tx_desc_remain(&ring[di], rm); + if (hw->dev->flags & PDMA_CHAIN_MODE) { + cmicx_tx_desc_chain(&ring[di], 0); + } + } + /* Config the last descriptor in the ring as reload descriptor */ + cmicx_tx_rldesc_config(&ring[di], txq->ring_addr); + + txq->curr = 0; + txq->dirt = 0; + txq->halt = 0; + + txq->halt_addr = txq->ring_addr; + hw->hdls.chan_goto(hw, txq->chan_id, txq->halt_addr); + hw->hdls.chan_setup(hw, txq->chan_id, txq->ring_addr); + + return SHR_E_NONE; +} + +/*! + * Cleanup Tx descriptors + */ +static int +cmicx_pdma_tx_desc_clean(struct pdma_hw *hw, struct pdma_tx_queue *txq) +{ + struct pdma_dev *dev = hw->dev; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)dev->ctrl.buf_mngr; + struct cmicx_tx_desc *ring = (struct cmicx_tx_desc *)txq->ring; + uint32_t di; + + /* Go through all the descriptors and free pktbuf */ + for (di = 0; di < txq->nb_desc; di++) { + if (txq->pbuf[di].dma) { + bm->tx_buf_free(dev, txq, &txq->pbuf[di]); + } + cmicx_tx_desc_config(&ring[di], 0, 0, 0); + } + + txq->curr = 0; + txq->dirt = 0; + txq->halt = 0; + + return SHR_E_NONE; +} + +/*! + * Process Rx vring + */ +static int +cmicx_pdma_rx_vring_process(struct pdma_hw *hw, struct pdma_rx_queue *rxq, + struct pdma_rx_buf *pbuf) +{ + struct pdma_dev *dev = hw->dev; + struct cmicx_rx_desc *ring = (struct cmicx_rx_desc *)rxq->ring; + struct pdma_rx_queue *vrxq = NULL; + struct cmicx_rx_desc *vring = NULL; + struct pkt_hdr *pkh = &pbuf->pkb->pkh; + uint64_t buf_addr; + + vrxq = (struct pdma_rx_queue *)dev->ctrl.vnet_rxq[rxq->queue_id]; + vring = (struct cmicx_rx_desc *)vrxq->ring; + if (!vring) { + rxq->stats.dropped++; + return SHR_E_UNAVAIL; + } + + if (vring[vrxq->curr].status & CMICX_DESC_STAT_RTX_DONE) { + dev->xnet_wake(dev); + return SHR_E_BUSY; + } + + /* Copy descriptor and packet to vring */ + buf_addr = BUS_TO_DMA_HI(vring[vrxq->curr].addr_hi); + buf_addr = buf_addr << 32 | vring[vrxq->curr].addr_lo; + sal_memcpy(dev->sys_p2v(dev, buf_addr), &pbuf->pkb->data, + pkh->meta_len + pkh->data_len); + vring[vrxq->curr].status = ring[rxq->curr].status; + + MEMORY_BARRIER; + + /* Notify VNET to process if needed */ + if (!vring[(vrxq->curr + vrxq->nb_desc - 1) % vrxq->nb_desc].status) { + dev->xnet_wake(dev); + } + vrxq->curr = (vrxq->curr + 1) % vrxq->nb_desc; + + return SHR_E_NONE; +} + +/*! + * Refill Rx ring + */ +static int +cmicx_pdma_rx_ring_refill(struct pdma_hw *hw, struct pdma_rx_queue *rxq) +{ + struct pdma_dev *dev = hw->dev; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)dev->ctrl.buf_mngr; + struct cmicx_rx_desc *ring = (struct cmicx_rx_desc *)rxq->ring; + struct pdma_rx_buf *pbuf = NULL; + int unused = cmicx_pdma_rx_ring_unused(rxq); + dma_addr_t addr; + uint32_t halt; + int rv; + + for (halt = rxq->halt; halt < rxq->halt + unused; halt++) { + pbuf = &rxq->pbuf[halt % rxq->nb_desc]; + /* Allocate a new pktbuf */ + if (!bm->rx_buf_avail(dev, rxq, pbuf)) { + rv = bm->rx_buf_alloc(dev, rxq, pbuf); + if (SHR_FAILURE(rv)) { + rxq->halt = halt % rxq->nb_desc; + rxq->stats.nomems++; + goto fail; + } + } + /* Setup the new descriptor */ + bm->rx_buf_dma(dev, rxq, pbuf, &addr); + cmicx_rx_desc_config(&ring[halt % rxq->nb_desc], addr, rxq->buf_size); + if (dev->flags & PDMA_CHAIN_MODE && halt % rxq->nb_desc == rxq->nb_desc - 1) { + cmicx_rx_desc_chain(&ring[halt % rxq->nb_desc], 0); + } + } + + sal_spinlock_lock(rxq->lock); + rxq->halt = halt % rxq->nb_desc; + if (!(rxq->state & PDMA_RX_QUEUE_XOFF)) { + /* Descriptor cherry pick */ + rxq->halt_addr = rxq->ring_addr + sizeof(struct cmicx_rx_desc) * rxq->halt; + hw->hdls.chan_goto(hw, rxq->chan_id, rxq->halt_addr); + } + sal_spinlock_unlock(rxq->lock); + + return SHR_E_NONE; + +fail: + CNET_PR("RX: Failed to allocate mem\n"); + + return SHR_E_MEMORY; +} + +/*! + * \brief Clean Rx ring + * + * \param [in] hw HW structure point. + * \param [in] rxq Rx queue structure point. + * \param [in] budget Polling budget. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +cmicx_pdma_rx_ring_clean(struct pdma_hw *hw, struct pdma_rx_queue *rxq, int budget) +{ + struct pdma_dev *dev = hw->dev; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)dev->ctrl.buf_mngr; + struct cmicx_rx_desc *ring = (struct cmicx_rx_desc *)rxq->ring; + struct pdma_rx_buf *pbuf = NULL; + struct pkt_hdr *pkh = NULL; + dma_addr_t addr; + uint32_t stat, curr; + int len, done = 0; + int rv; + + curr = rxq->curr; + while (CMICX_DESC_STAT_DONE(ring[curr].status)) { + if (dev->mode == DEV_MODE_VNET && rxq->state & PDMA_RX_QUEUE_XOFF) { + break; + } + if (!(rxq->state & PDMA_RX_BATCH_REFILL) && + !(rxq->state & PDMA_RX_QUEUE_XOFF)) { + /* Descriptor cherry pick */ + rxq->halt_addr = rxq->ring_addr + sizeof(struct cmicx_rx_desc) * curr; + hw->hdls.chan_goto(hw, rxq->chan_id, rxq->halt_addr); + rxq->halt = curr; + } + if (done == budget) { + break; + } + + /* Get the current pktbuf to process */ + pbuf = &rxq->pbuf[curr]; + stat = ring[curr].status; + len = CMICX_DESC_STAT_LEN(stat); + pkh = bm->rx_buf_get(dev, rxq, pbuf, len); + if (!pkh) { + rxq->stats.nomems++; + goto fail; + } + + /* Setup packet header */ + pkh->data_len = len - hw->info.rx_ph_size; + pkh->meta_len = hw->info.rx_ph_size; + pkh->queue_id = rxq->queue_id; + pkh->attrs = CMICX_DESC_STAT_FLAGS(stat); + + /* Send up the packet */ + rv = dev->pkt_recv(dev, rxq->queue_id, (void *)pbuf->skb); + if (SHR_FAILURE(rv)) { + if (dev->mode == DEV_MODE_HNET && pkh->attrs & PDMA_RX_TO_VNET) { + rv = cmicx_pdma_rx_vring_process(hw, rxq, pbuf); + if (SHR_FAILURE(rv) && rv == SHR_E_BUSY) { + rxq->state |= PDMA_RX_QUEUE_BUSY; + return done; + } + } else { + rxq->stats.dropped++; + } + bm->rx_buf_put(dev, rxq, pbuf, len); + } + + /* Count the packets/bytes */ + rxq->stats.packets++; + rxq->stats.bytes += len; + + /* Count the errors if any */ + if (stat & CMICX_DESC_STAT_ERR_MASK) { + rxq->stats.errors++; + if (stat & CMICX_DESC_STAT_DATA_ERR) { + rxq->stats.data_errors++; + } + if (stat & CMICX_DESC_STAT_CELL_ERR) { + rxq->stats.cell_errors++; + } + } + + /* Setup the new descriptor */ + if (!(rxq->state & PDMA_RX_BATCH_REFILL)) { + if (!bm->rx_buf_avail(dev, rxq, pbuf)) { + rv = bm->rx_buf_alloc(dev, rxq, pbuf); + if (SHR_FAILURE(rv)) { + rxq->stats.nomems++; + goto fail; + } + } + bm->rx_buf_dma(dev, rxq, pbuf, &addr); + cmicx_rx_desc_config(&ring[curr], addr, rxq->buf_size); + if (dev->flags & PDMA_CHAIN_MODE && curr == rxq->nb_desc - 1) { + cmicx_rx_desc_chain(&ring[curr], 0); + } + } else { + cmicx_rx_desc_config(&ring[curr], 0, 0); + } + + /* Notify HNET to process if needed */ + if (dev->mode == DEV_MODE_VNET) { + MEMORY_BARRIER; + if (ring[(curr + rxq->nb_desc - 1) % rxq->nb_desc].status) { + dev->xnet_wake(dev); + } + } + + /* Update the indicators */ + if (!(rxq->state & PDMA_RX_BATCH_REFILL) && rxq->halt != curr) { + sal_spinlock_lock(rxq->lock); + if (!(rxq->state & PDMA_RX_QUEUE_XOFF)) { + /* Descriptor cherry pick */ + rxq->halt_addr = rxq->ring_addr + sizeof(struct cmicx_rx_desc) * curr; + hw->hdls.chan_goto(hw, rxq->chan_id, rxq->halt_addr); + rxq->halt = curr; + } + curr = (curr + 1) % rxq->nb_desc; + sal_spinlock_unlock(rxq->lock); + } else { + curr = (curr + 1) % rxq->nb_desc; + } + rxq->curr = curr; + done++; + + /* Restart DMA if in chain mode */ + if (dev->flags & PDMA_CHAIN_MODE) { + if (curr == 0 && !(rxq->state & PDMA_RX_QUEUE_XOFF)) { + hw->hdls.chan_stop(hw, rxq->chan_id); + hw->hdls.chan_start(hw, rxq->chan_id); + } + } + } + + /* One more poll for chain done in chain mode */ + if (dev->flags & PDMA_CHAIN_MODE) { + if (curr == rxq->nb_desc - 1 && done) { + done = budget; + } + } + + /* In batching mode, replenish all the unused descriptors */ + if (rxq->state & PDMA_RX_BATCH_REFILL && + cmicx_pdma_rx_ring_unused(rxq) >= (int)rxq->free_thresh) { + cmicx_pdma_rx_ring_refill(hw, rxq); + } + + /* Notify the other side to process */ + if (dev->mode == DEV_MODE_VNET || dev->mode == DEV_MODE_HNET) { + if (done) { + dev->xnet_wake(dev); + } + } + + return done; + +fail: + CNET_PR("RX: Failed to allocate mem\n"); + + return done; +} + +/*! + * Process Tx vring + */ +static int +cmicx_pdma_tx_vring_process(struct pdma_hw *hw, struct pdma_tx_queue *txq, + struct pdma_tx_buf *pbuf) +{ + struct pdma_dev *dev = hw->dev; + struct cmicx_tx_desc *ring = (struct cmicx_tx_desc *)txq->ring; + struct pdma_tx_queue *vtxq = NULL; + struct cmicx_tx_desc *vring = NULL; + + vtxq = (struct pdma_tx_queue *)dev->ctrl.vnet_txq[txq->queue_id]; + vring = (struct cmicx_tx_desc *)vtxq->ring; + if (!vring) { + return SHR_E_UNAVAIL; + } + + /* Update vring descriptor */ + vring[vtxq->dirt].status = ring[txq->dirt].status; + pbuf->dma = 0; + + MEMORY_BARRIER; + + /* Notify VNET to process if needed */ + if (!vring[(vtxq->dirt + vtxq->nb_desc - 1) % vtxq->nb_desc].status) { + dev->xnet_wake(dev); + } + vtxq->dirt = (vtxq->dirt + 1) % vtxq->nb_desc; + + return SHR_E_NONE; +} + +/*! + * \brief Clean Tx ring + * + * \param [in] hw HW structure point. + * \param [in] txq Tx queue structure point. + * \param [in] budget Polling budget. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +cmicx_pdma_tx_ring_clean(struct pdma_hw *hw, struct pdma_tx_queue *txq, int budget) +{ + struct pdma_dev *dev = hw->dev; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)dev->ctrl.buf_mngr; + struct cmicx_tx_desc *ring = (struct cmicx_tx_desc *)txq->ring; + uint32_t dirt, curr; + int done = 0; + + dirt = txq->dirt; + while (txq->pbuf[dirt].dma) { + if (!CMICX_DESC_STAT_DONE(ring[dirt].status)) { + break; + } + if (done == budget) { + break; + } + + if (dev->mode == DEV_MODE_HNET && !txq->pbuf[dirt].skb) { + cmicx_pdma_tx_vring_process(hw, txq, &txq->pbuf[dirt]); + } else { + /* Free the done pktbuf */ + bm->tx_buf_free(dev, txq, &txq->pbuf[dirt]); + } + + cmicx_tx_desc_config(&ring[dirt], 0, 0, 0); + + /* Update the indicators */ + dirt = (dirt + 1) % txq->nb_desc; + txq->dirt = dirt; + done++; + + /* Restart DMA if in chain mode */ + if (dev->flags & PDMA_CHAIN_MODE) { + sal_spinlock_lock(txq->lock); + curr = txq->curr; + if (dirt == txq->halt && dirt != curr) { + hw->hdls.chan_stop(hw, txq->chan_id); + cmicx_tx_desc_chain(&ring[(curr + txq->nb_desc - 1) % txq->nb_desc], 0); + hw->hdls.chan_setup(hw, txq->chan_id, + txq->ring_addr + sizeof(struct cmicx_tx_desc) * txq->halt); + hw->hdls.chan_start(hw, txq->chan_id); + txq->halt = curr; + } + sal_spinlock_unlock(txq->lock); + } + } + + /* One more poll for chain done in chain mode */ + if (dev->flags & PDMA_CHAIN_MODE) { + sal_spinlock_lock(txq->lock); + if (dirt != txq->halt) { + done = budget; + } + sal_spinlock_unlock(txq->lock); + } + + /* Resume Tx if any */ + sal_spinlock_lock(txq->lock); + if (cmicx_pdma_tx_ring_unused(txq) && txq->state & PDMA_TX_QUEUE_XOFF) { + txq->state &= ~PDMA_TX_QUEUE_XOFF; + sal_spinlock_unlock(txq->lock); + if (dev->tx_resume) { + dev->tx_resume(dev, txq->queue_id); + } else if (!(txq->state & PDMA_TX_QUEUE_POLL)) { + sal_sem_give(txq->sem); + } + return done; + } + sal_spinlock_unlock(txq->lock); + + return done; +} + +/*! + * Dump Rx ring + */ +static int +cmicx_pdma_rx_ring_dump(struct pdma_hw *hw, struct pdma_rx_queue *rxq) +{ + struct cmicx_rx_desc *ring = (struct cmicx_rx_desc *)rxq->ring; + struct cmicx_rx_desc *rd; + uint32_t di; + + CNET_PR("\nRX: queue=%d, chan=%d, curr=%d, halt=%d, halt@%p\n", + rxq->queue_id, rxq->chan_id, rxq->curr, rxq->halt, (void *)&ring[rxq->halt]); + CNET_PR("----------------------------------------------------------------\n"); + for (di = 0; di < rxq->nb_desc + 1; di++) { + rd = &ring[di]; + CNET_PR("DESC[%03d]: (%p)->%08x %08x %08x %08x\n", + di, (void *)(unsigned long)(rxq->ring_addr + di * CMICX_PDMA_DCB_SIZE), + rd->addr_lo, rd->addr_hi, rd->ctrl, rd->status); + } + + return SHR_E_NONE; +} + +/*! + * Dump Tx ring + */ +static int +cmicx_pdma_tx_ring_dump(struct pdma_hw *hw, struct pdma_tx_queue *txq) +{ + struct cmicx_tx_desc *ring = (struct cmicx_tx_desc *)txq->ring; + struct cmicx_tx_desc *td; + uint32_t di; + + CNET_PR("\nTX: queue=%d, chan=%d, curr=%d, dirt=%d, halt@%p\n", + txq->queue_id, txq->chan_id, txq->curr, txq->dirt, (void *)&ring[txq->curr]); + CNET_PR("----------------------------------------------------------------\n"); + for (di = 0; di < txq->nb_desc + 1; di++) { + td = &ring[di]; + CNET_PR("DESC[%03d]: (%p)->%08x %08x %08x %08x\n", + di, (void *)(unsigned long)(txq->ring_addr + di * CMICX_PDMA_DCB_SIZE), + td->addr_lo, td->addr_hi, td->ctrl, td->status); + } + + return SHR_E_NONE; +} + +/*! + * Fetch Tx vring + */ +static int +cmicx_pdma_tx_vring_fetch(struct pdma_hw *hw, struct pdma_tx_queue *txq, + struct pdma_tx_buf *pbuf) +{ + struct pdma_dev *dev = hw->dev; + struct cmicx_tx_desc *ring = (struct cmicx_tx_desc *)txq->ring; + struct pdma_tx_queue *vtxq = NULL; + struct cmicx_tx_desc *vring = NULL; + + vtxq = (struct pdma_tx_queue *)dev->ctrl.vnet_txq[txq->queue_id]; + vring = (struct cmicx_tx_desc *)vtxq->ring; + if (!vring || !CMICX_DESC_CTRL_LEN(vring[vtxq->curr].ctrl)) { + return SHR_E_UNAVAIL; + } + + /* Fetch vring descriptor */ + sal_memcpy(&ring[txq->curr], &vring[vtxq->curr], sizeof(struct cmicx_tx_desc)); + vring[vtxq->curr].ctrl &= ~CMICX_DESC_CTRL_LEN(-1); + + MEMORY_BARRIER; + + pbuf->dma = vring[vtxq->curr].addr_lo; + pbuf->len = CMICX_DESC_CTRL_LEN(ring[txq->curr].ctrl); + vtxq->curr = (vtxq->curr + 1) % vtxq->nb_desc; + + return SHR_E_NONE; +} + +/*! + * Check Tx ring + */ +static inline int +cmicx_pdma_tx_ring_check(struct pdma_hw *hw, struct pdma_tx_queue *txq) +{ + if (cmicx_pdma_tx_ring_unused(txq)) { + return SHR_E_NONE; + } + + sal_spinlock_lock(txq->lock); + if (!cmicx_pdma_tx_ring_unused(txq)) { + txq->state |= PDMA_TX_QUEUE_XOFF; + txq->stats.xoffs++; + sal_spinlock_unlock(txq->lock); + if (hw->dev->tx_suspend) { + hw->dev->tx_suspend(hw->dev, txq->queue_id); + } + return SHR_E_BUSY; + } + sal_spinlock_unlock(txq->lock); + + return SHR_E_NONE; +} + +/*! + * \brief Start packet transmission + * + * \param [in] hw HW structure point. + * \param [in] txq Tx queue structure point. + * \param [in] buf Tx packet buffer. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +cmicx_pdma_pkt_xmit(struct pdma_hw *hw, struct pdma_tx_queue *txq, void *buf) +{ + struct pdma_dev *dev = hw->dev; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)dev->ctrl.buf_mngr; + struct cmicx_tx_desc *ring = (struct cmicx_tx_desc *)txq->ring; + struct pdma_tx_buf *pbuf = NULL; + struct pkt_hdr *pkh = NULL; + dma_addr_t addr; + uint32_t curr, flags = 0; + int retry = 5000000; + int rv; + + if (!(txq->state & PDMA_TX_QUEUE_ACTIVE)) { + return SHR_E_UNAVAIL; + } + + if (dev->tx_suspend) { + sal_spinlock_lock(txq->mutex); + } else { + sal_sem_take(txq->sem, SAL_SEM_FOREVER); + } + + /* Check Tx resource */ + if (dev->tx_suspend) { + /* Suspend Tx if no resource */ + rv = cmicx_pdma_tx_ring_check(hw, txq); + if (SHR_FAILURE(rv)) { + sal_spinlock_unlock(txq->mutex); + return rv; + } + } else { + /* Abort Tx if a fatal error happened */ + if (txq->state & PDMA_TX_QUEUE_XOFF) { + sal_sem_give(txq->sem); + return SHR_E_RESOURCE; + } + } + + /* Setup the new descriptor */ + curr = txq->curr; + pbuf = &txq->pbuf[curr]; + if (dev->mode == DEV_MODE_HNET && !buf) { + rv = cmicx_pdma_tx_vring_fetch(hw, txq, pbuf); + if (SHR_FAILURE(rv)) { + sal_spinlock_unlock(txq->mutex); + return SHR_E_EMPTY; + } + } else { + pbuf->adj = 1; + pkh = bm->tx_buf_get(dev, txq, pbuf, buf); + if (!pkh) { + txq->stats.dropped++; + if (dev->tx_suspend) { + sal_spinlock_unlock(txq->mutex); + } else { + sal_sem_give(txq->sem); + } + return SHR_E_NONE; + } + bm->tx_buf_dma(dev, txq, pbuf, &addr); + flags |= pkh->attrs & PDMA_TX_HIGIG_PKT ? CMICX_DESC_TX_HIGIG_PKT : 0; + flags |= pkh->attrs & PDMA_TX_PURGE_PKT ? CMICX_DESC_TX_PURGE_PKT : 0; + cmicx_tx_desc_config(&ring[curr], addr, pbuf->len, flags); + } + + /* Notify HNET to process if needed */ + if (dev->mode == DEV_MODE_VNET) { + MEMORY_BARRIER; + if (!CMICX_DESC_CTRL_LEN(ring[(curr + txq->nb_desc - 1) % txq->nb_desc].ctrl)) { + dev->xnet_wake(dev); + } + } + + /* Update the indicators */ + curr = (curr + 1) % txq->nb_desc; + txq->curr = curr; + + /* Start DMA if in chain mode */ + if (dev->flags & PDMA_CHAIN_MODE) { + if (txq->state & PDMA_TX_QUEUE_POLL) { + do { + rv = cmicx_pdma_tx_ring_clean(hw, txq, txq->nb_desc - 1); + if (rv != (int)txq->nb_desc - 1) { + break; + } + sal_usleep(1); + } while (retry--); + if (retry <= 0) { + CNET_PR("Last Tx could not be done in given time\n"); + } + } + sal_spinlock_lock(txq->lock); + if (txq->dirt == txq->halt && txq->dirt != curr) { + hw->hdls.chan_stop(hw, txq->chan_id); + cmicx_tx_desc_chain(&ring[(curr + txq->nb_desc - 1) % txq->nb_desc], 0); + hw->hdls.chan_setup(hw, txq->chan_id, + txq->ring_addr + sizeof(struct cmicx_tx_desc) * txq->halt); + hw->hdls.chan_start(hw, txq->chan_id); + txq->halt = curr; + } + sal_spinlock_unlock(txq->lock); + } + + /* Kick off DMA */ + txq->halt_addr = txq->ring_addr + sizeof(struct cmicx_tx_desc) * curr; + hw->hdls.chan_goto(hw, txq->chan_id, txq->halt_addr); + + /* Count the packets/bytes */ + txq->stats.packets++; + txq->stats.bytes += pbuf->len; + + /* Clean up ring if in polling mode */ + if (txq->state & PDMA_TX_QUEUE_POLL && + cmicx_pdma_tx_ring_unused(txq) <= (int)txq->free_thresh) { + cmicx_pdma_tx_ring_clean(hw, txq, txq->nb_desc - txq->free_thresh); + } + + /* Suspend Tx if no resource */ + rv = cmicx_pdma_tx_ring_check(hw, txq); + if (SHR_FAILURE(rv)) { + if (dev->mode == DEV_MODE_VNET) { + dev->xnet_wake(dev); + } + + if (txq->state & PDMA_TX_QUEUE_POLL) { + /* In polling mode, must wait till the ring is available */ + do { + cmicx_pdma_tx_ring_clean(hw, txq, txq->free_thresh); + if (!(txq->state & PDMA_TX_QUEUE_XOFF)) { + break; + } + sal_usleep(1); + } while (retry--); + if (retry <= 0) { + CNET_PR("Fatal error: Tx ring is full, packets have not been transmitted for 5 seconds\n"); + if (!dev->tx_suspend) { + sal_sem_give(txq->sem); + return SHR_E_RESOURCE; + } + } + } else { + /* In interrupt mode, the handle thread will wake up Tx */ + if (!dev->tx_suspend) { + return SHR_E_NONE; + } + } + } + + if (dev->tx_suspend) { + sal_spinlock_unlock(txq->mutex); + } else { + sal_sem_give(txq->sem); + } + + return SHR_E_NONE; +} + +/*! + * Suspend Rx queue + */ +static int +cmicx_pdma_rx_suspend(struct pdma_hw *hw, struct pdma_rx_queue *rxq) +{ + sal_spinlock_lock(rxq->lock); + rxq->state |= PDMA_RX_QUEUE_XOFF; + if (hw->dev->flags & PDMA_CHAIN_MODE) { + hw->hdls.chan_stop(hw, rxq->chan_id); + } + sal_spinlock_unlock(rxq->lock); + + return SHR_E_NONE; +} + +/*! + * Resume Rx queue + */ +static int +cmicx_pdma_rx_resume(struct pdma_hw *hw, struct pdma_rx_queue *rxq) +{ + sal_spinlock_lock(rxq->lock); + if (!(rxq->state & PDMA_RX_QUEUE_XOFF)) { + sal_spinlock_unlock(rxq->lock); + return SHR_E_NONE; + } + if (rxq->state & PDMA_RX_BATCH_REFILL) { + rxq->halt_addr = rxq->ring_addr + sizeof(struct cmicx_rx_desc) * rxq->halt; + hw->hdls.chan_goto(hw, rxq->chan_id, rxq->halt_addr); + } else if (rxq->halt == rxq->curr || (rxq->halt == rxq->nb_desc && rxq->curr == 0)) { + rxq->halt = (rxq->curr + 1) % rxq->nb_desc; + rxq->halt_addr = rxq->ring_addr + sizeof(struct cmicx_rx_desc) * rxq->halt; + hw->hdls.chan_goto(hw, rxq->chan_id, rxq->halt_addr); + } + if (hw->dev->flags & PDMA_CHAIN_MODE) { + rxq->curr = 0; + hw->hdls.chan_start(hw, rxq->chan_id); + } + rxq->state &= ~PDMA_RX_QUEUE_XOFF; + sal_spinlock_unlock(rxq->lock); + + return SHR_E_NONE; +} + +/*! + * Initialize function pointers + */ +int +bcmcnet_cmicx_pdma_desc_ops_init(struct pdma_hw *hw) +{ + if (!hw) { + return SHR_E_PARAM; + } + + hw->dops.rx_desc_init = cmicx_pdma_rx_desc_init; + hw->dops.rx_desc_clean = cmicx_pdma_rx_desc_clean; + hw->dops.rx_ring_clean = cmicx_pdma_rx_ring_clean; + hw->dops.rx_ring_dump = cmicx_pdma_rx_ring_dump; + hw->dops.rx_suspend = cmicx_pdma_rx_suspend; + hw->dops.rx_resume = cmicx_pdma_rx_resume; + hw->dops.tx_desc_init = cmicx_pdma_tx_desc_init; + hw->dops.tx_desc_clean = cmicx_pdma_tx_desc_clean; + hw->dops.tx_ring_clean = cmicx_pdma_tx_ring_clean; + hw->dops.tx_ring_dump = cmicx_pdma_tx_ring_dump; + hw->dops.pkt_xmit = cmicx_pdma_pkt_xmit; + + return SHR_E_NONE; +} + +/*! + * Attach device driver + */ +int +bcmcnet_cmicx_pdma_driver_attach(struct pdma_dev *dev) +{ + struct pdma_hw *hw = NULL; + + /* Allocate memory for HW data */ + hw = sal_alloc(sizeof(*hw), "bcmcnetPdmaHw"); + if (!hw) { + return SHR_E_MEMORY; + } + sal_memset(hw, 0, sizeof(*hw)); + hw->unit = dev->unit; + hw->dev = dev; + dev->ctrl.hw = hw; + + bcmcnet_cmicx_pdma_hw_hdls_init(hw); + bcmcnet_cmicx_pdma_desc_ops_init(hw); + + return SHR_E_NONE; +} + +/*! + * Detach device driver + */ +int +bcmcnet_cmicx_pdma_driver_detach(struct pdma_dev *dev) +{ + if (dev->ctrl.hw) { + sal_free(dev->ctrl.hw); + } + dev->ctrl.hw = NULL; + + return SHR_E_NONE; +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_cmicd.h b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_cmicd.h new file mode 100644 index 000000000000..ef9717923e70 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_cmicd.h @@ -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 */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_cmicx.h b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_cmicx.h new file mode 100644 index 000000000000..a8657c8b46a9 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_cmicx.h @@ -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 */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_core.h b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_core.h new file mode 100644 index 000000000000..13db809dda36 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_core.h @@ -0,0 +1,1323 @@ +/*! \file bcmcnet_core.h + * + * Generic data structure definitions and APIs 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.$ + */ + +#ifndef BCMCNET_CORE_H +#define BCMCNET_CORE_H + +#include +#include + +/*! + * \brief Packet header structure. + */ +struct pkt_hdr { + /*! Meta data or outer header */ + uint8_t meta_data[16]; + + /*! Reserved */ + uint16_t rsvd0; + + /*! Packet signature */ + uint16_t pkt_sig; + + /*! Reserved */ + uint32_t rsvd1; + + /*! Data length */ + uint16_t data_len; + + /*! Reserved */ + uint16_t rsvd2; + + /*! Meta length */ + uint8_t meta_len; + + /*! Queue index */ + uint8_t queue_id; + + /*! Attributes */ + uint16_t attrs; + /*! Tx higig packet */ +#define PDMA_TX_HIGIG_PKT (1 << 0) + /*! Tx pause packet */ +#define PDMA_TX_PAUSE_PKT (1 << 1) + /*! Tx purge packet */ +#define PDMA_TX_PURGE_PKT (1 << 2) + /*! Tx queue number */ +#define PDMA_TX_BIND_QUE (1 << 3) + /*! Tx cookded header */ +#define PDMA_TX_HDR_COOKED (1 << 4) + /*! Tx to HNET */ +#define PDMA_TX_TO_HNET (1 << 5) + /*! Rx to VNET */ +#define PDMA_RX_TO_VNET (1 << 10) + /*! Rx strip vlan tag */ +#define PDMA_RX_STRIP_TAG (1 << 11) + /*! Rx set protocol type */ +#define PDMA_RX_SET_PROTO (1 << 12) + /*! Rx IP checksum */ +#define PDMA_RX_IP_CSUM (1 << 13) + /*! Rx TCPUDP checksum */ +#define PDMA_RX_TU_CSUM (1 << 14) +}; + +/*! Packet header size */ +#define PKT_HDR_SIZE sizeof(struct pkt_hdr) + +/*! + * \brief Packet buffer structure. + */ +struct pkt_buf { + /*! Packet header */ + struct pkt_hdr pkh; + + /*! Packet data */ + uint8_t data; +}; + +/*! + * \brief Interrupt handle. + */ +struct intr_handle { + /*! Device number */ + int unit; + + /*! Group number */ + int group; + + /*! Channel number */ + int chan; + + /*! Queue number */ + int queue; + + /*! Direction */ + int dir; + + /*! Polling budget */ + int budget; + + /*! Device point */ + void *dev; + + /*! Private point */ + void *priv; + + /*! Interrupt number */ + int intr_num; + + /*! Interrupt flags */ + uint32_t intr_flags; +}; + +/*! + * \brief Queue group structure. + */ +struct queue_group { + /*! Pointer to the device control structure */ + struct dev_ctrl *ctrl; + + /*! Interrupt handles */ + struct intr_handle intr_hdl[NUM_Q_PER_GRP]; + + /*! Rx queue pointers */ + void *rx_queue[NUM_Q_PER_GRP]; + + /*! Tx queue pointers */ + void *tx_queue[NUM_Q_PER_GRP]; + + /*! Virtual Rx queue pointers */ + void *vnet_rxq[NUM_Q_PER_GRP]; + + /*! Virtual Tx queue pointers */ + void *vnet_txq[NUM_Q_PER_GRP]; + + /*! Bitmap for Rx queues at work */ + uint32_t bm_rxq; + + /*! Bitmap for Tx queues at work */ + uint32_t bm_txq; + + /*! Number of Rx queues at work */ + uint32_t nb_rxq; + + /*! Number of Tx queues at work */ + uint32_t nb_txq; + + /*! Number of descriptors */ + uint32_t nb_desc[NUM_Q_PER_GRP]; + + /*! Rx buffer size */ + uint32_t rx_size[NUM_Q_PER_GRP]; + + /*! Queue mode */ + uint32_t que_ctrl[NUM_Q_PER_GRP]; + /*! Packet_byte_swap */ +#define PDMA_PKT_BYTE_SWAP (1 << 0) + /*! Non packet_byte_swap */ +#define PDMA_OTH_BYTE_SWAP (1 << 1) + /*! Header_byte_swap */ +#define PDMA_HDR_BYTE_SWAP (1 << 2) + + /*! Group ID */ + int id; + + /*! Queues need to poll */ + uint32_t poll_queues; + + /*! Active IRQs for DMA control */ + uint32_t irq_mask; + + /*! Indicating the group is attached */ + int attached; +}; + +/*! + * \brief Device control structure. + */ +struct dev_ctrl { + /*! Pointer to the device structure */ + struct pdma_dev *dev; + + /*! Pointer to hardware-specific data */ + void *hw; + + /*! HW base address */ + volatile void *hw_addr; + + /*! Queue groups */ + struct queue_group grp[NUM_GRP_MAX]; + + /*! Pointers to Rx queues */ + void *rx_queue[NUM_QUE_MAX]; + + /*! Pointers to Tx queues */ + void *tx_queue[NUM_QUE_MAX]; + + /*! Pointers to virtual Rx queues */ + void *vnet_rxq[NUM_QUE_MAX]; + + /*! Pointers to virtual Tx queues */ + void *vnet_txq[NUM_QUE_MAX]; + + /*! Pointer to buffer manager */ + void *buf_mngr; + + /*! VNET sync data */ + vnet_sync_t vsync; + + /*! Bitmap of groups at work */ + uint32_t bm_grp; + + /*! Bitmap of Rx queues at work */ + uint32_t bm_rxq; + + /*! Bitmap of Tx queues at work */ + uint32_t bm_txq; + + /*! Number of groups at work */ + uint32_t nb_grp; + + /*! Number of Rx queues at work */ + uint32_t nb_rxq; + + /*! Number of Tx queues at work */ + uint32_t nb_txq; + + /*! Number of descriptors for a queue */ + uint32_t nb_desc; + + /*! Budget for once queue processing */ + uint32_t budget; + + /*! Common Rx buffer size for all queues */ + uint32_t rx_buf_size; + + /*! Rx descriptor size */ + uint32_t rx_desc_size; + + /*! Tx descriptor size */ + uint32_t tx_desc_size; +}; + +/*! + * Configure device. + * + * \param [in] dev Pointer to device structure. + * \param [in] bm_rxq Rx queue bitmap. + * \param [in] bm_txq Tx queue bitmap. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_dev_config_f)(struct pdma_dev *dev, uint32_t bm_rxq, uint32_t bm_txq); + +/*! + * Start device. + * + * \param [in] dev Pointer to device structure. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_dev_start_f)(struct pdma_dev *dev); + +/*! + * Stop device. + * + * \param [in] dev Pointer to device structure. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_dev_stop_f)(struct pdma_dev *dev); + +/*! + * Close device. + * + * \param [in] dev Pointer to device structure. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_dev_close_f)(struct pdma_dev *dev); + +/*! + * Suspend device. + * + * \param [in] dev Pointer to device structure. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_dev_suspend_f)(struct pdma_dev *dev); + +/*! + * Resume device. + * + * \param [in] dev Pointer to device structure. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_dev_resume_f)(struct pdma_dev *dev); + +/*! + * Get device information. + * + * \param [in] dev Pointer to device structure. + */ +typedef void (*pdma_dev_info_get_f)(struct pdma_dev *dev); + +/*! + * Get device statistics. + * + * \param [in] dev Pointer to device structure. + */ +typedef void (*pdma_dev_stats_get_f)(struct pdma_dev *dev); + +/*! + * Reset device statistics. + * + * \param [in] dev Pointer to device structure. + */ +typedef void (*pdma_dev_stats_reset_f)(struct pdma_dev *dev); + +/*! + * Convert logic queue to physical queue. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Logic queue number. + * \param [in] dir Transmit direction. + * \param [in] chan Channel number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_dev_lq2pq_f)(struct pdma_dev *dev, int queue, int dir, int *chan); + +/*! + * Convert physical queue to logic queue. + * + * \param [in] dev Pointer to device structure. + * \param [in] chan Channel number. + * \param [in] queue Logic queue number. + * \param [in] dir Transmit direction. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_dev_pq2lq_f)(struct pdma_dev *dev, int chan, int *queue, int *dir); + +/*! + * Start queue. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Queue number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_queue_start_f)(struct pdma_dev *dev, int queue); + +/*! + * Stop queue. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Queue number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_queue_stop_f)(struct pdma_dev *dev, int queue); + +/*! + * Set up queue. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Queue number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_queue_setup_f)(struct pdma_dev *dev, int queue); + +/*! + * Release queue. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Queue number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_queue_release_f)(struct pdma_dev *dev, int queue); + +/*! + * Restore queue. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Queue number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_queue_restore_f)(struct pdma_dev *dev, int queue); + +/*! + * Enable queue interrupt. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Queue number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_intr_enable_f)(struct pdma_dev *dev, int queue); + +/*! + * Disable queue interrupt. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Queue number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_intr_disable_f)(struct pdma_dev *dev, int queue); + +/*! + * Acknowledge queue interrupt. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Queue number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_intr_ack_f)(struct pdma_dev *dev, int queue); + +/*! + * Query queue interrupt. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Queue number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_intr_query_f)(struct pdma_dev *dev, int queue); + +/*! + * Check queue interrupt. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Queue number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_intr_check_f)(struct pdma_dev *dev, int queue); + +/*! + * Suspend Rx queue. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Queue number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_rx_queue_suspend_f)(struct pdma_dev *dev, int queue); + +/*! + * Resume Rx queue. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Queue number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_rx_queue_resume_f)(struct pdma_dev *dev, int queue); + +/*! + * Wake up Tx queue. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Queue number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_tx_queue_wakeup_f)(struct pdma_dev *dev, int queue); + +/*! + * Poll Rx queue. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Queue number. + * \param [in] budget Max number of descriptor to poll. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_rx_queue_poll_f)(struct pdma_dev *dev, int queue, int budget); + +/*! + * Poll Tx queue. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Queue number. + * \param [in] budget Max number of descriptor to poll. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_tx_queue_poll_f)(struct pdma_dev *dev, int queue, int budget); + +/*! + * Poll queue group. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Queue number. + * \param [in] budget Max number of descriptor to poll. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +typedef int (*pdma_group_poll_f)(struct pdma_dev *dev, int group, int budget); + +/*! + * \brief Exported functions structure. + */ +struct dev_ops { + /*! Configure device */ + pdma_dev_config_f dev_config; + + /*! Start device */ + pdma_dev_start_f dev_start; + + /*! Stop device */ + pdma_dev_stop_f dev_stop; + + /*! Close device */ + pdma_dev_close_f dev_close; + + /*! Suspend device */ + pdma_dev_suspend_f dev_suspend; + + /*! Resume device */ + pdma_dev_resume_f dev_resume; + + /*! Get device information */ + pdma_dev_info_get_f dev_info_get; + + /*! Get device statistics */ + pdma_dev_stats_get_f dev_stats_get; + + /*! Reset device statistics */ + pdma_dev_stats_reset_f dev_stats_reset; + + /*! Logic queue to physical queue */ + pdma_dev_lq2pq_f dev_lq_to_pq; + + /*! Physical queue to logic queue */ + pdma_dev_pq2lq_f dev_pq_to_lq; + + /*! Start Rx for a queue */ + pdma_queue_start_f rx_queue_start; + + /*! Stop Rx for a queue */ + pdma_queue_stop_f rx_queue_stop; + + /*! Start Tx for a queue */ + pdma_queue_start_f tx_queue_start; + + /*! Stop Tx for a queue */ + pdma_queue_stop_f tx_queue_stop; + + /*! Set up Rx queue */ + pdma_queue_setup_f rx_queue_setup; + + /*! Release Rx queue */ + pdma_queue_release_f rx_queue_release; + + /*! Restore stopped Rx queue */ + pdma_queue_restore_f rx_queue_restore; + + /*! Set up virtual Rx queue */ + pdma_queue_setup_f rx_vqueue_setup; + + /*! Release virtual Rx queue */ + pdma_queue_release_f rx_vqueue_release; + + /*! Set up Tx queue */ + pdma_queue_setup_f tx_queue_setup; + + /*! Release Tx queue */ + pdma_queue_release_f tx_queue_release; + + /*! Restore stopped Tx queue */ + pdma_queue_restore_f tx_queue_restore; + + /*! Set up virtual Tx queue */ + pdma_queue_setup_f tx_vqueue_setup; + + /*! Release virtual Tx queue */ + pdma_queue_release_f tx_vqueue_release; + + /*! Enable Rx queue interrupt */ + pdma_intr_enable_f rx_queue_intr_enable; + + /*! Disable Rx queue interrupt */ + pdma_intr_disable_f rx_queue_intr_disable; + + /*! Acknowledge interrupt for Rx queue */ + pdma_intr_ack_f rx_queue_intr_ack; + + /*! Query interrupt status for Rx queue */ + pdma_intr_query_f rx_queue_intr_query; + + /*! Check interrupt validity for Rx queue */ + pdma_intr_check_f rx_queue_intr_check; + + /*! Enable Tx queue interrupt */ + pdma_intr_enable_f tx_queue_intr_enable; + + /*! Disable Tx queue interrupt */ + pdma_intr_disable_f tx_queue_intr_disable; + + /*! Acknowledge interrupt for Tx queue */ + pdma_intr_ack_f tx_queue_intr_ack; + + /*! Query interrupt status for Tx queue */ + pdma_intr_query_f tx_queue_intr_query; + + /*! Check interrupt validity for Tx queue */ + pdma_intr_check_f tx_queue_intr_check; + + /*! Suspend a Rx queue */ + pdma_rx_queue_suspend_f rx_queue_suspend; + + /*! Resume a Rx queue */ + pdma_rx_queue_resume_f rx_queue_resume; + + /*! Wake up a Tx queue to transmit */ + pdma_tx_queue_wakeup_f tx_queue_wakeup; + + /*! Poll for a Rx queue */ + pdma_rx_queue_poll_f rx_queue_poll; + + /*! Poll for a Tx queue */ + pdma_tx_queue_poll_f tx_queue_poll; + + /*! Poll for a group */ + pdma_group_poll_f group_poll; +}; + +/*! + * Read 32-bit device register. + * + * \param [in] dev Pointer to device structure. + * \param [in] addr Register address. + * \param [in] data Pointer to read data. + * + * \retval SHR_E_NONE No errors. + */ +typedef int (*reg32_read_f)(struct pdma_dev *dev, uint32_t addr, uint32_t *data); + +/*! + * Write 32-bit device register. + * + * \param [in] dev Pointer to device structure. + * \param [in] addr Register address. + * \param [in] data Data to write. + * + * \retval SHR_E_NONE No errors. + */ +typedef int (*reg32_write_f)(struct pdma_dev *dev, uint32_t addr, uint32_t data); + +/*! + * Receive packet. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Rx queue number. + * \param [in] buf Pointer to packet buffer. + * + * \retval SHR_E_NONE No errors. + */ +typedef int (*pdma_rx_f)(struct pdma_dev *dev, int queue, void *buf); + +/*! + * Transmit packet. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Tx queue number. + * \param [in] buf Pointer to packet buffer. + * + * \retval SHR_E_NONE No errors. + */ +typedef int (*pdma_tx_f)(struct pdma_dev *dev, int queue, void *buf); + +/*! + * Suspend Tx queue. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Tx queue number. + */ +typedef void (*sys_tx_suspend_f)(struct pdma_dev *dev, int queue); + +/*! + * Resume Tx queue. + * + * \param [in] dev Pointer to device structure. + * \param [in] queue Tx queue number. + */ +typedef void (*sys_tx_resume_f)(struct pdma_dev *dev, int queue); + +/*! + * Enable interrupts. + * + * \param [in] dev Pointer to device structure. + * \param [in] group Channel group number. + * \param [in] chan Channel number. + * \param [in] reg Interrupt enable register. + * \param [in] mask Interrupt mask. + */ +typedef void (*sys_intr_unmask_f)(struct pdma_dev *dev, int group, int chan, + uint32_t reg, uint32_t mask); + +/*! + * Disable interrupts. + * + * \param [in] dev Pointer to device structure. + * \param [in] group Channel group number. + * \param [in] chan Channel number. + * \param [in] reg Interrupt enable register. + * \param [in] mask Interrupt mask. + */ +typedef void (*sys_intr_mask_f)(struct pdma_dev *dev, int group, int chan, + uint32_t reg, uint32_t mask); + +/*! + * Wait for notification from the other side. + * + * \param [in] dev Pointer to device structure. + * + * \retval SHR_E_NONE No errors. + */ +typedef int (*xnet_wait_f)(struct pdma_dev *dev); + +/*! + * Wake up the other side. + * + * \param [in] dev Pointer to device structure. + * + * \retval SHR_E_NONE No errors. + */ +typedef int (*xnet_wake_f)(struct pdma_dev *dev); + +/*! + * Convert physical address to virtual address. + * + * \param [in] dev Pointer to device structure. + * \param [in] paddr Physical address. + * + * \retval Virtual address. + */ +typedef void *(*sys_p2v_f)(struct pdma_dev *dev, uint64_t paddr); + +/*! + * Convert virtual address to physical address. + * + * \param [in] dev Pointer to device structure. + * \param [in] vaddr Virtual address. + * + * \retval Physical address. + */ +typedef uint64_t (*sys_v2p_f)(struct pdma_dev *dev, void *vaddr); + +/*! + * \brief Device structure. + */ +struct pdma_dev { + /*! Device name */ + char name[DEV_NAME_LEN_MAX]; + + /*! Device ID */ + uint32_t dev_id; + + /*! Device type */ + uint32_t dev_type; + + /*! Device Number */ + int unit; + + /*! Device control structure */ + struct dev_ctrl ctrl; + + /*! Pointer to the exported funtions structure */ + struct dev_ops *ops; + + /*! Device information */ + struct bcmcnet_dev_info info; + + /*! Device statistics data */ + struct bcmcnet_dev_stats stats; + + /*! Private data */ + void *priv; + + /*! Read 32-bit device register */ + reg32_read_f dev_read32; + + /*! Write 32-bit device register */ + reg32_write_f dev_write32; + + /*! Packet reception */ + pdma_rx_f pkt_recv; + + /*! Packet transmission */ + pdma_tx_f pkt_xmit; + + /*! Tx suspend */ + sys_tx_suspend_f tx_suspend; + + /*! Tx resume */ + sys_tx_resume_f tx_resume; + + /*! Enable a set of interrupts */ + sys_intr_unmask_f intr_unmask; + + /*! Disable a set of interrupts */ + sys_intr_mask_f intr_mask; + + /*! Virtual network wait for */ + xnet_wait_f xnet_wait; + + /*! Virtual network wake up */ + xnet_wake_f xnet_wake; + + /*! Physical address to virtual address */ + sys_p2v_f sys_p2v; + + /*! Virtual address to physical address */ + sys_v2p_f sys_v2p; + + /*! Maximum number of groups */ + int num_groups; + + /*! Maximum number of group queues */ + int grp_queues; + + /*! Maximum number of queues */ + int num_queues; + + /*! Rx packet header size */ + uint32_t rx_ph_size; + + /*! Tx packet header size */ + uint32_t tx_ph_size; + + /*! Flags */ + uint32_t flags; + /*! Interrupt processing per group */ +#define PDMA_GROUP_INTR (1 << 0) + /*! Tx polling mode */ +#define PDMA_TX_POLLING (1 << 1) + /*! Rx batch refilling */ +#define PDMA_RX_BATCHING (1 << 2) + /*! DMA chain mode */ +#define PDMA_CHAIN_MODE (1 << 3) + /*! Descriptor prefetch mode */ +#define PDMA_DESC_PREFETCH (1 << 4) + /*! VNET is docked */ +#define PDMA_VNET_DOCKED (1 << 5) + + /*! Device mode */ + dev_mode_t mode; + + /*! Device is started */ + int started; + + /*! Device is initialized and HMI driver is attached */ + int attached; +}; + +/*! + * \brief Initialize device. + * + * \param [in] dev Device structure point. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_pdma_dev_init(struct pdma_dev *dev); + +/*! + * \brief Clean up device. + * + * \param [in] dev Device structure point. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_pdma_dev_cleanup(struct pdma_dev *dev); + +/*! + * \brief Start device. + * + * \param [in] dev Device structure point. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_pdma_dev_start(struct pdma_dev *dev); + +/*! + * \brief Stop device. + * + * \param [in] dev Device structure point. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_pdma_dev_stop(struct pdma_dev *dev); + +/*! + * \brief Suspend device. + * + * \param [in] dev Device structure point. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_pdma_dev_suspend(struct pdma_dev *dev); + +/*! + * \brief Resume device. + * + * \param [in] dev Device structure point. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_pdma_dev_resume(struct pdma_dev *dev); + +/*! + * \brief Suspend device Rx. + * + * \param [in] dev Device structure point. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_pdma_dev_rx_suspend(struct pdma_dev *dev); + +/*! + * \brief Resume device Rx. + * + * \param [in] dev Device structure point. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_pdma_dev_rx_resume(struct pdma_dev *dev); + +/*! + * \brief Dock device. + * + * \param [in] dev Device structure point. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_pdma_dev_dock(struct pdma_dev *dev); + +/*! + * \brief Undock device. + * + * \param [in] dev Device structure point. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_pdma_dev_undock(struct pdma_dev *dev); + +/*! + * \brief Get device information. + * + * \param [in] dev Device structure point. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_pdma_dev_info_get(struct pdma_dev *dev); + +/*! + * \brief Get device statistics. + * + * \param [in] dev Device structure point. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_pdma_dev_stats_get(struct pdma_dev *dev); + +/*! + * \brief Reset device statistics. + * + * \param [in] dev Device structure point. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_pdma_dev_stats_reset(struct pdma_dev *dev); + +/*! + * \brief Change queue number to channel number. + * + * \param [in] dev Device structure point. + * \param [in] queue Queue number. + * \param [in] dir Transmit direction. + * \param [out] chan Channel number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_pdma_dev_queue_to_chan(struct pdma_dev *dev, int queue, int dir, int *chan); + +/*! + * \brief Change channel number to queue number. + * + * \param [in] dev Device structure point. + * \param [in] chan Channel number. + * \param [out] queue Queue number. + * \param [out] dir Transmit direction. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_pdma_dev_chan_to_queue(struct pdma_dev *dev, int chan, int *queue, int *dir); + +/*! + * \brief Enable Rx queue interrupt. + * + * \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_rx_queue_intr_enable(struct pdma_dev *dev, int queue); + +/*! + * \brief Disable Rx queue interrupt. + * + * \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_rx_queue_intr_disable(struct pdma_dev *dev, int queue); + +/*! + * \brief Acknowledge Rx queue interrupt. + * + * \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_rx_queue_intr_ack(struct pdma_dev *dev, int queue); + +/*! + * \brief Check Rx queue interrupt. + * + * \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_rx_queue_intr_check(struct pdma_dev *dev, int queue); + +/*! + * \brief Enable Tx queue interrupt. + * + * \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_tx_queue_intr_enable(struct pdma_dev *dev, int queue); + +/*! + * \brief Disable Tx queue interrupt. + * + * \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_tx_queue_intr_disable(struct pdma_dev *dev, int queue); + +/*! + * \brief Acknowledge Tx queue interrupt. + * + * \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_tx_queue_intr_ack(struct pdma_dev *dev, int queue); + +/*! + * \brief Check Tx queue interrupt. + * + * \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_tx_queue_intr_check(struct pdma_dev *dev, int queue); + +/*! + * \brief Enable queue interrupt. + * + * \param [in] dev Device structure point. + * \param [in] hdl Queue interrupt handle. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_queue_intr_enable(struct pdma_dev *dev, struct intr_handle *hdl); + +/*! + * \brief Disable queue interrupt. + * + * \param [in] dev Device structure point. + * \param [in] hdl Queue interrupt handle. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_queue_intr_disable(struct pdma_dev *dev, struct intr_handle *hdl); + +/*! + * \brief Acknowledge queue interrupt. + * + * \param [in] dev Device structure point. + * \param [in] hdl Queue interrupt handle. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_queue_intr_ack(struct pdma_dev *dev, struct intr_handle *hdl); + +/*! + * \brief Check queue interrupt. + * + * \param [in] dev Device structure point. + * \param [in] hdl Queue interrupt handle. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_queue_intr_check(struct pdma_dev *dev, struct intr_handle *hdl); + +/*! + * \brief Enable group interrupt. + * + * \param [in] dev Device structure point. + * \param [in] group Group number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_group_intr_enable(struct pdma_dev *dev, int group); + +/*! + * \brief Disable group interrupt. + * + * \param [in] dev Device structure point. + * \param [in] group Group number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_group_intr_disable(struct pdma_dev *dev, int group); + +/*! + * \brief Acknowledge group interrupt. + * + * \param [in] dev Device structure point. + * \param [in] group Group number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_group_intr_ack(struct pdma_dev *dev, int group); + +/*! + * \brief Check group interrupt. + * + * \param [in] dev Device structure point. + * \param [in] group Group number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_group_intr_check(struct pdma_dev *dev, int group); + +/*! + * \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_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_tx_queue_poll(struct pdma_dev *dev, int queue, int budget); + +/*! + * \brief Poll queue. + * + * \param [in] dev Device structure point. + * \param [in] hdl Queue interrupt handle. + * \param [in] budget Poll budget. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +extern int +bcmcnet_queue_poll(struct pdma_dev *dev, struct intr_handle *hdl, int budget); + +/*! + * \brief Poll 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_group_poll(struct pdma_dev *dev, int group, int budget); + +#endif /* BCMCNET_CORE_H */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_dev.h b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_dev.h new file mode 100644 index 000000000000..bc3367b34fae --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_dev.h @@ -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 + +/*! + * \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 */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_internal.h b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_internal.h new file mode 100644 index 000000000000..e4b2051a34bc --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_internal.h @@ -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 + +/*! 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 */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_rxtx.h b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_rxtx.h new file mode 100644 index 000000000000..eb5834d895b0 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_rxtx.h @@ -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 */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_types.h b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_types.h new file mode 100644 index 000000000000..42bd9240828b --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/include/bcmcnet/bcmcnet_types.h @@ -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 + +/*! 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 */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/main/bcmcnet_core.c b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/main/bcmcnet_core.c new file mode 100644 index 000000000000..ef4aca7da49e --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/main/bcmcnet_core.c @@ -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 +#include + +/*! + * 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); +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/main/bcmcnet_dev.c b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/main/bcmcnet_dev.c new file mode 100644 index 000000000000..1f39515a7a62 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/main/bcmcnet_dev.c @@ -0,0 +1,1059 @@ +/*! \file bcmcnet_dev.c + * + * Utility routines 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.$ + */ + +#include +#include +#include +#include + +/*! + * Free resource for a Rx queue + */ +static void +bcn_rx_queues_free(struct pdma_dev *dev) +{ + struct dev_ctrl *ctrl = &dev->ctrl; + struct pdma_rx_queue *rxq = NULL; + int gi, qi; + + for (gi = 0; gi < dev->num_groups; gi++) { + for (qi = 0; qi < dev->grp_queues; qi++) { + rxq = (struct pdma_rx_queue *)ctrl->grp[gi].rx_queue[qi]; + if (!rxq) { + continue; + } + sal_free(rxq); + ctrl->grp[gi].rx_queue[qi] = NULL; + if (dev->mode == DEV_MODE_HNET && ctrl->grp[gi].vnet_rxq[qi]) { + sal_free(ctrl->grp[gi].vnet_rxq[qi]); + ctrl->grp[gi].vnet_rxq[qi] = NULL; + } + } + } +} + +/*! + * Allocate resource for a Rx queue + */ +static int +bcn_rx_queues_alloc(struct pdma_dev *dev) +{ + struct dev_ctrl *ctrl = &dev->ctrl; + struct pdma_rx_queue *rxq = NULL, *vrxq = NULL; + int gi, qi; + + for (gi = 0; gi < dev->num_groups; gi++) { + for (qi = 0; qi < dev->grp_queues; qi++) { + rxq = sal_alloc(sizeof(*rxq), "bcmcnetRxQueue"); + if (!rxq) { + goto error; + } + sal_memset(rxq, 0, sizeof(*rxq)); + rxq->group_id = gi; + rxq->chan_id = qi + gi * dev->grp_queues; + rxq->ctrl = ctrl; + ctrl->grp[gi].rx_queue[qi] = rxq; + if (dev->mode == DEV_MODE_HNET) { + vrxq = sal_alloc(sizeof(*vrxq), "bcmcnetVnetRxQueue"); + if (!vrxq) { + goto error; + } + sal_memset(vrxq, 0, sizeof(*vrxq)); + vrxq->group_id = gi; + vrxq->chan_id = qi + gi * dev->grp_queues; + vrxq->ctrl = ctrl; + ctrl->grp[gi].vnet_rxq[qi] = vrxq; + } + } + } + + return SHR_E_NONE; + +error: + bcn_rx_queues_free(dev); + + return SHR_E_MEMORY; +} + +/*! + * Free resource for a Tx queue + */ +static void +bcn_tx_queues_free(struct pdma_dev *dev) +{ + struct dev_ctrl *ctrl = &dev->ctrl; + struct pdma_tx_queue *txq = NULL; + int gi, qi; + + for (gi = 0; gi < dev->num_groups; gi++) { + for (qi = 0; qi < dev->grp_queues; qi++) { + txq = (struct pdma_tx_queue *)ctrl->grp[gi].tx_queue[qi]; + if (!txq) { + continue; + } + sal_free(txq); + ctrl->grp[gi].tx_queue[qi] = NULL; + if (dev->mode == DEV_MODE_HNET && ctrl->grp[gi].vnet_txq[qi]) { + sal_free(ctrl->grp[gi].vnet_txq[qi]); + ctrl->grp[gi].vnet_txq[qi] = NULL; + } + } + } +} + +/*! + * Allocate resource for a Tx queue + */ +static int +bcn_tx_queues_alloc(struct pdma_dev *dev) +{ + struct dev_ctrl *ctrl = &dev->ctrl; + struct pdma_tx_queue *txq = NULL, *vtxq = NULL; + int gi, qi; + + for (gi = 0; gi < dev->num_groups; gi++) { + for (qi = 0; qi < dev->grp_queues; qi++) { + txq = sal_alloc(sizeof(*txq), "bcmcnetTxQueue"); + if (!txq) { + goto error; + } + sal_memset(txq, 0, sizeof(*txq)); + txq->group_id = gi; + txq->chan_id = qi + gi * dev->grp_queues; + txq->ctrl = ctrl; + ctrl->grp[gi].tx_queue[qi] = txq; + if (dev->mode == DEV_MODE_HNET) { + vtxq = sal_alloc(sizeof(*vtxq), "bcmcnetVnetTxQueue"); + if (!vtxq) { + goto error; + } + sal_memset(vtxq, 0, sizeof(*vtxq)); + vtxq->group_id = gi; + vtxq->chan_id = qi + gi * dev->grp_queues; + vtxq->ctrl = ctrl; + ctrl->grp[gi].vnet_txq[qi] = vtxq; + } + } + } + + return SHR_E_NONE; + +error: + bcn_tx_queues_free(dev); + + return SHR_E_MEMORY; +} + +/*! + * \brief Parse Rx groups + * + * \param [in] dev Device structure point. + * \param [in] qbm Rx queue bitmap. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +bcn_rx_queue_group_parse(struct pdma_dev *dev, uint32_t qbm) +{ + struct dev_ctrl *ctrl = &dev->ctrl; + struct pdma_buf_mngr *bm = (struct pdma_buf_mngr *)ctrl->buf_mngr; + struct pdma_rx_queue *rxq = NULL; + struct intr_handle *hdl = NULL; + uint32_t mask; + int gi, qi, qn; + + ctrl->nb_rxq = 0; + sal_memset(ctrl->rx_queue, 0, sizeof(ctrl->rx_queue)); + + /* Figure out available groups and Rx queues */ + for (gi = 0; gi < dev->num_groups; gi++) { + if (!ctrl->grp[gi].attached) { + continue; + } + qn = 0; + mask = 0; + for (qi = 0; qi < dev->grp_queues; qi++) { + rxq = (struct pdma_rx_queue *)ctrl->grp[gi].rx_queue[qi]; + hdl = &ctrl->grp[gi].intr_hdl[qi]; + if (1 << (qi + gi * dev->grp_queues) & qbm) { + /* Set the number of descriptors */ + rxq->nb_desc = ctrl->grp[gi].nb_desc[qi]; + if (!rxq->nb_desc) { + rxq->nb_desc = ctrl->nb_desc; + ctrl->grp[gi].nb_desc[qi] = rxq->nb_desc; + } + /* Set Rx buffer size */ + rxq->buf_size = ctrl->grp[gi].rx_size[qi]; + if (rxq->buf_size < RX_BUF_SIZE_MIN) { + rxq->buf_size = RX_BUF_SIZE_MIN; + ctrl->grp[gi].rx_size[qi] = rxq->buf_size; + } else if (rxq->buf_size > RX_BUF_SIZE_MAX) { + rxq->buf_size = ctrl->rx_buf_size; + ctrl->grp[gi].rx_size[qi] = rxq->buf_size; + } + rxq->buf_size += dev->rx_ph_size; + /* Set mode and state for the queue */ + rxq->mode = bm->rx_buf_mode(dev, rxq); + rxq->state = PDMA_RX_QUEUE_USED; + if (dev->flags & PDMA_RX_BATCHING) { + rxq->free_thresh = rxq->nb_desc / 4; + rxq->state |= PDMA_RX_BATCH_REFILL; + } + /* Update queue index */ + rxq->queue_id = ctrl->nb_rxq; + ctrl->rx_queue[rxq->queue_id] = rxq; + ctrl->nb_rxq++; + qn++; + mask |= 1 << qi; + /* Set up handler for the queue */ + hdl->queue = rxq->queue_id; + hdl->dir = PDMA_Q_RX; + hdl->budget = ctrl->budget < rxq->nb_desc ? + ctrl->budget : rxq->nb_desc; + if (dev->mode == DEV_MODE_HNET) { + ctrl->vnet_rxq[rxq->queue_id] = ctrl->grp[gi].vnet_rxq[qi]; + } + } else { + rxq->state = 0; + } + } + + /* Set group metadata */ + if (qn) { + ctrl->grp[gi].bm_rxq = mask; + ctrl->grp[gi].nb_rxq = qn; + } else { + ctrl->grp[gi].bm_rxq = 0; + ctrl->grp[gi].nb_rxq = 0; + } + } + + return SHR_E_NONE; +} + +/*! + * \brief Parse Tx groups + * + * \param [in] dev Device structure point. + * \param [in] qbm Tx queue bitmap. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +bcn_tx_queue_group_parse(struct pdma_dev *dev, uint32_t qbm) +{ + struct dev_ctrl *ctrl = &dev->ctrl; + struct pdma_tx_queue *txq = NULL; + struct intr_handle *hdl = NULL; + uint32_t mask; + int gi, qi, qn; + + ctrl->nb_txq = 0; + sal_memset(ctrl->tx_queue, 0, sizeof(ctrl->tx_queue)); + + /* Figure out available groups and Tx queues */ + for (gi = 0; gi < dev->num_groups; gi++) { + if (!ctrl->grp[gi].attached) { + continue; + } + qn = 0; + mask = 0; + for (qi = 0; qi < dev->grp_queues; qi++) { + txq = (struct pdma_tx_queue *)ctrl->grp[gi].tx_queue[qi]; + hdl = &ctrl->grp[gi].intr_hdl[qi]; + if (1 << (qi + gi * dev->grp_queues) & qbm) { + /* Set the number of descriptors */ + txq->nb_desc = ctrl->grp[gi].nb_desc[qi]; + if (!txq->nb_desc) { + txq->nb_desc = ctrl->nb_desc; + ctrl->grp[gi].nb_desc[qi] = txq->nb_desc; + } + /* Set mode and state for the queue */ + txq->state = PDMA_TX_QUEUE_USED; + if (dev->flags & PDMA_TX_POLLING) { + txq->free_thresh = txq->nb_desc / 4; + txq->state |= PDMA_TX_QUEUE_POLL; + } + /* Update queue index */ + txq->queue_id = ctrl->nb_txq; + ctrl->tx_queue[txq->queue_id] = txq; + ctrl->nb_txq++; + qn++; + mask |= 1 << qi; + /* Set up handler for the queue */ + hdl->queue = txq->queue_id; + hdl->dir = PDMA_Q_TX; + hdl->budget = ctrl->budget < txq->nb_desc ? + ctrl->budget : txq->nb_desc; + if (dev->mode == DEV_MODE_HNET) { + ctrl->vnet_txq[txq->queue_id] = ctrl->grp[gi].vnet_txq[qi]; + } + } else { + txq->state = 0; + } + } + + /* Set group metadata */ + if (qn) { + ctrl->grp[gi].bm_txq = mask; + ctrl->grp[gi].nb_txq = qn; + } else { + ctrl->grp[gi].bm_txq = 0; + ctrl->grp[gi].nb_txq = 0; + } + } + + return SHR_E_NONE; +} + +/*! + * \brief Configure device + * + * \param [in] dev Device structure point. + * \param [in] bm_rxq Rx queue bitmap. + * \param [in] bm_txq Tx queue bitmap. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +bcmcnet_pdma_config(struct pdma_dev *dev, uint32_t bm_rxq, uint32_t bm_txq) +{ + struct dev_ctrl *ctrl = &dev->ctrl; + struct pdma_hw *hw = (struct pdma_hw *)ctrl->hw; + int gi; + + if (!bm_rxq || !bm_txq || (bm_rxq & bm_txq)) { + return SHR_E_PARAM; + } + + bcn_rx_queue_group_parse(dev, bm_rxq); + bcn_tx_queue_group_parse(dev, bm_txq); + + for (gi = 0; gi < dev->num_groups; gi++) { + if (!ctrl->grp[gi].attached) { + continue; + } + /* Update group metadata */ + if (!ctrl->grp[gi].bm_rxq && !ctrl->grp[gi].bm_txq) { + ctrl->grp[gi].attached = 0; + ctrl->bm_grp &= ~(1 << gi); + ctrl->nb_grp--; + continue; + } + ctrl->grp[gi].ctrl = ctrl; + ctrl->grp[gi].id = gi; + ctrl->grp[gi].irq_mask = 0; + } + + return hw->hdls.hw_config(hw); +} + +/*! + * Close device + */ +static int +bcmcnet_pdma_close(struct pdma_dev *dev) +{ + struct dev_ctrl *ctrl = &dev->ctrl; + struct pdma_hw *hw = (struct pdma_hw *)dev->ctrl.hw; + int gi; + + hw->hdls.hw_reset(hw); + + for (gi = 0; gi < dev->num_groups; gi++) { + if (!ctrl->grp[gi].attached) { + continue; + } + /* Reset group metadata */ + ctrl->bm_grp &= ~(1 << gi); + ctrl->nb_grp--; + ctrl->grp[gi].irq_mask = 0; + ctrl->grp[gi].poll_queues = 0; + ctrl->grp[gi].attached = 0; + } + + bcn_rx_queues_free(dev); + bcn_tx_queues_free(dev); + + return SHR_E_NONE; +} + +/*! + * Suspend device + */ +static int +bcmcnet_pdma_suspend(struct pdma_dev *dev) +{ + struct dev_ctrl *ctrl = &dev->ctrl; + uint32_t qi; + + for (qi = 0; qi < ctrl->nb_rxq; qi++) { + bcmcnet_pdma_rx_queue_suspend(dev, qi); + } + + for (qi = 0; qi < ctrl->nb_txq; qi++) { + bcmcnet_pdma_tx_queue_suspend(dev, qi); + } + + return SHR_E_NONE; +} + +/*! + * Resume device + */ +static int +bcmcnet_pdma_resume(struct pdma_dev *dev) +{ + struct dev_ctrl *ctrl = &dev->ctrl; + uint32_t qi; + + for (qi = 0; qi < ctrl->nb_rxq; qi++) { + bcmcnet_pdma_rx_queue_resume(dev, qi); + } + + for (qi = 0; qi < ctrl->nb_txq; qi++) { + bcmcnet_pdma_tx_queue_resume(dev, qi); + } + + return SHR_E_NONE; +} + +/*! + * Get device information + */ +static void +bcmcnet_pdma_info_get(struct pdma_dev *dev) +{ + 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; + uint32_t qi; + + sal_strncpy(dev->info.dev_name, dev->name, sizeof(dev->info.dev_name) - 1); + dev->info.dev_name[sizeof(dev->info.dev_name) - 1] = 0; + dev->info.dev_id = dev->dev_id; + dev->info.dev_type = dev->dev_type; + dev->info.max_groups = hw->info.num_cmcs; + dev->info.max_queues = hw->info.num_chans; + dev->info.bm_groups = ctrl->bm_grp; + dev->info.bm_rx_queues = ctrl->bm_rxq; + dev->info.bm_tx_queues = ctrl->bm_txq; + dev->info.nb_groups = ctrl->nb_grp; + dev->info.nb_rx_queues = ctrl->nb_rxq; + dev->info.nb_tx_queues = ctrl->nb_txq; + dev->info.rx_desc_size = hw->info.rx_dcb_size; + dev->info.tx_desc_size = hw->info.tx_dcb_size; + dev->info.rx_ph_size = hw->info.rx_ph_size; + dev->info.tx_ph_size = hw->info.tx_ph_size; + dev->info.rx_buf_dflt = ctrl->rx_buf_size; + dev->info.nb_desc_dflt = ctrl->nb_desc; + + for (qi = 0; qi < ctrl->nb_rxq; qi++) { + rxq = (struct pdma_rx_queue *)ctrl->rx_queue[qi]; + if (!rxq) { + continue; + } + dev->info.rx_buf_size[qi] = rxq->buf_size; + dev->info.nb_rx_desc[qi] = rxq->nb_desc; + } + + for (qi = 0; qi < ctrl->nb_txq; qi++) { + txq = (struct pdma_tx_queue *)ctrl->tx_queue[qi]; + if (!txq) { + continue; + } + dev->info.nb_tx_desc[qi] = txq->nb_desc; + } +} + +/*! + * Get device statistics + */ +static void +bcmcnet_pdma_stats_get(struct pdma_dev *dev) +{ + struct dev_ctrl *ctrl = &dev->ctrl; + struct pdma_rx_queue *rxq = NULL; + struct pdma_tx_queue *txq = NULL; + uint32_t packets = 0, bytes = 0, dropped = 0, errors = 0, nomems = 0, xoffs = 0; + uint32_t head_errors = 0, data_errors = 0, cell_errors = 0; + uint32_t qi; + + for (qi = 0; qi < ctrl->nb_rxq; qi++) { + rxq = (struct pdma_rx_queue *)ctrl->rx_queue[qi]; + if (!rxq) { + continue; + } + packets += rxq->stats.packets; + bytes += rxq->stats.bytes; + dropped += rxq->stats.dropped; + errors += rxq->stats.errors; + head_errors += rxq->stats.head_errors; + data_errors += rxq->stats.data_errors; + cell_errors += rxq->stats.cell_errors; + nomems += rxq->stats.nomems; + dev->stats.rxq_packets[qi] = rxq->stats.packets; + dev->stats.rxq_bytes[qi] = rxq->stats.bytes; + dev->stats.rxq_dropped[qi] = rxq->stats.dropped; + dev->stats.rxq_errors[qi] = rxq->stats.errors; + dev->stats.rxq_head_errors[qi] = rxq->stats.head_errors; + dev->stats.rxq_data_errors[qi] = rxq->stats.data_errors; + dev->stats.rxq_cell_errors[qi] = rxq->stats.cell_errors; + dev->stats.rxq_nomems[qi] = rxq->stats.nomems; + } + + dev->stats.rx_packets = packets; + dev->stats.rx_bytes = bytes; + dev->stats.rx_dropped = dropped; + dev->stats.rx_errors = errors; + dev->stats.rx_head_errors = head_errors; + dev->stats.rx_data_errors = data_errors; + dev->stats.rx_cell_errors = cell_errors; + dev->stats.rx_nomems = nomems; + + packets = bytes = dropped = errors = 0; + for (qi = 0; qi < ctrl->nb_txq; qi++) { + txq = (struct pdma_tx_queue *)ctrl->tx_queue[qi]; + if (!txq) { + continue; + } + packets += txq->stats.packets; + bytes += txq->stats.bytes; + dropped += txq->stats.dropped; + errors += txq->stats.errors; + xoffs += txq->stats.xoffs; + dev->stats.txq_packets[qi] = txq->stats.packets; + dev->stats.txq_bytes[qi] = txq->stats.bytes; + dev->stats.txq_dropped[qi] = txq->stats.dropped; + dev->stats.txq_errors[qi] = txq->stats.errors; + dev->stats.txq_xoffs[qi] = txq->stats.xoffs; + } + + dev->stats.tx_packets = packets; + dev->stats.tx_bytes = bytes; + dev->stats.tx_dropped = dropped; + dev->stats.tx_errors = errors; + dev->stats.tx_xoffs = xoffs; +} + +/*! + * Reset device statistics + */ +static void +bcmcnet_pdma_stats_reset(struct pdma_dev *dev) +{ + struct dev_ctrl *ctrl = &dev->ctrl; + struct pdma_rx_queue *rxq = NULL; + struct pdma_tx_queue *txq = NULL; + uint32_t qi; + + sal_memset(&dev->stats, 0, sizeof(struct bcmcnet_dev_stats)); + + for (qi = 0; qi < ctrl->nb_rxq; qi++) { + rxq = (struct pdma_rx_queue *)ctrl->rx_queue[qi]; + if (!rxq) { + continue; + } + rxq->stats.packets = 0; + rxq->stats.bytes = 0; + rxq->stats.dropped = 0; + rxq->stats.errors = 0; + rxq->stats.head_errors = 0; + rxq->stats.data_errors = 0; + rxq->stats.cell_errors = 0; + rxq->stats.nomems = 0; + } + + for (qi = 0; qi < ctrl->nb_txq; qi++) { + txq = (struct pdma_tx_queue *)ctrl->tx_queue[qi]; + if (!txq) { + continue; + } + txq->stats.packets = 0; + txq->stats.bytes = 0; + txq->stats.dropped = 0; + txq->stats.errors = 0; + txq->stats.xoffs = 0; + } +} + +/*! + * Convert logic queue to physical queue + */ +static int +bcmcnet_pdma_lq_to_pq(struct pdma_dev *dev, int queue, int dir, int *chan) +{ + struct dev_ctrl *ctrl = &dev->ctrl; + struct pdma_rx_queue *rxq = NULL; + struct pdma_tx_queue *txq = NULL; + + if (dir == PDMA_Q_RX) { + rxq = (struct pdma_rx_queue *)ctrl->rx_queue[queue]; + if (rxq->state & PDMA_RX_QUEUE_USED) { + *chan = rxq->chan_id; + return SHR_E_NONE; + } + } else { + txq = (struct pdma_tx_queue *)ctrl->tx_queue[queue]; + if (txq->state & PDMA_TX_QUEUE_USED) { + *chan = txq->chan_id; + return SHR_E_NONE; + } + } + + return SHR_E_UNAVAIL; +} + +/*! + * Convert physical queue to logic queue + */ +static int +bcmcnet_pdma_pq_to_lq(struct pdma_dev *dev, int chan, int *queue, int *dir) +{ + struct dev_ctrl *ctrl = &dev->ctrl; + struct pdma_rx_queue *rxq = NULL; + struct pdma_tx_queue *txq = NULL; + + rxq = ctrl->grp[chan / dev->grp_queues].rx_queue[chan % dev->grp_queues]; + if (rxq->state & PDMA_RX_QUEUE_USED) { + *queue = rxq->queue_id; + *dir = PDMA_Q_RX; + return SHR_E_NONE; + } + + txq = ctrl->grp[chan / dev->grp_queues].tx_queue[chan % dev->grp_queues]; + if (txq->state & PDMA_TX_QUEUE_USED) { + *queue = txq->queue_id; + *dir = PDMA_Q_TX; + return SHR_E_NONE; + } + + return SHR_E_UNAVAIL; +} + +/*! + * Start Rx queue + */ +static int +bcmcnet_pdma_rx_queue_start(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]; + rxq->state |= PDMA_RX_QUEUE_ACTIVE; + + return hw->hdls.chan_start(hw, rxq->chan_id); +} + +/*! + * Stop Rx queue + */ +static int +bcmcnet_pdma_rx_queue_stop(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]; + rxq->state &= ~PDMA_RX_QUEUE_ACTIVE; + + return hw->hdls.chan_stop(hw, rxq->chan_id); +} + +/*! + * Start Tx queue + */ +static int +bcmcnet_pdma_tx_queue_start(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]; + txq->state |= PDMA_TX_QUEUE_ACTIVE; + + return dev->flags & PDMA_CHAIN_MODE ? SHR_E_NONE : + hw->hdls.chan_start(hw, txq->chan_id); +} + +/*! + * Stop Tx queue + */ +static int +bcmcnet_pdma_tx_queue_stop(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]; + txq->state &= ~PDMA_TX_QUEUE_ACTIVE; + + return hw->hdls.chan_stop(hw, txq->chan_id); +} + +/*! + * Enable Rx queue interrupt + */ +static int +bcmcnet_pdma_rx_queue_intr_enable(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]; + + return hw->hdls.chan_intr_enable(hw, rxq->chan_id); +} + +/*! + * Disable Rx queue interrupt + */ +static int +bcmcnet_pdma_rx_queue_intr_disable(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]; + + return hw->hdls.chan_intr_disable(hw, rxq->chan_id); +} + +/*! + * Acknowledge Rx queue interrupt + */ +static int +bcmcnet_pdma_rx_queue_intr_ack(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]; + + return hw->hdls.chan_clear(hw, rxq->chan_id); +} + +/*! + * Query Rx queue interrupt + */ +static int +bcmcnet_pdma_rx_queue_intr_query(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]; + + return hw->hdls.chan_intr_query(hw, rxq->chan_id); +} + +/*! + * Check Rx queue interrupt + */ +static int +bcmcnet_pdma_rx_queue_intr_check(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]; + + return hw->hdls.chan_intr_check(hw, rxq->chan_id); +} + +/*! + * Enable Tx queue interrupt + */ +static int +bcmcnet_pdma_tx_queue_intr_enable(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_POLL) { + return SHR_E_NONE; + } else { + return hw->hdls.chan_intr_enable(hw, txq->chan_id); + } +} + +/*! + * Disable Tx queue interrupt + */ +static int +bcmcnet_pdma_tx_queue_intr_disable(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]; + + return hw->hdls.chan_intr_disable(hw, txq->chan_id); +} + +/*! + * Acknowledge Tx queue interrupt + */ +static int +bcmcnet_pdma_tx_queue_intr_ack(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]; + + return hw->hdls.chan_clear(hw, txq->chan_id); +} + +/*! + * Query Tx queue interrupt + */ +static int +bcmcnet_pdma_tx_queue_intr_query(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]; + + return hw->hdls.chan_intr_query(hw, txq->chan_id); +} + +/*! + * Check Tx queue interrupt + */ +static int +bcmcnet_pdma_tx_queue_intr_check(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]; + + return hw->hdls.chan_intr_check(hw, txq->chan_id); +} + +/*! + * \brief Device operation functions. + */ +static const struct dev_ops pdma_dev_ops = { + .dev_config = bcmcnet_pdma_config, + .dev_close = bcmcnet_pdma_close, + .dev_suspend = bcmcnet_pdma_suspend, + .dev_resume = bcmcnet_pdma_resume, + .dev_info_get = bcmcnet_pdma_info_get, + .dev_stats_get = bcmcnet_pdma_stats_get, + .dev_stats_reset = bcmcnet_pdma_stats_reset, + .dev_lq_to_pq = bcmcnet_pdma_lq_to_pq, + .dev_pq_to_lq = bcmcnet_pdma_pq_to_lq, + .rx_queue_start = bcmcnet_pdma_rx_queue_start, + .rx_queue_stop = bcmcnet_pdma_rx_queue_stop, + .tx_queue_start = bcmcnet_pdma_tx_queue_start, + .tx_queue_stop = bcmcnet_pdma_tx_queue_stop, + .rx_queue_setup = bcmcnet_pdma_rx_queue_setup, + .rx_queue_release = bcmcnet_pdma_rx_queue_release, + .rx_queue_restore = bcmcnet_pdma_rx_queue_restore, + .rx_vqueue_setup = bcmcnet_pdma_rx_vqueue_setup, + .rx_vqueue_release = bcmcnet_pdma_rx_vqueue_release, + .tx_queue_setup = bcmcnet_pdma_tx_queue_setup, + .tx_queue_release = bcmcnet_pdma_tx_queue_release, + .tx_queue_restore = bcmcnet_pdma_tx_queue_restore, + .tx_vqueue_setup = bcmcnet_pdma_tx_vqueue_setup, + .tx_vqueue_release = bcmcnet_pdma_tx_vqueue_release, + .rx_queue_intr_enable = bcmcnet_pdma_rx_queue_intr_enable, + .rx_queue_intr_disable = bcmcnet_pdma_rx_queue_intr_disable, + .rx_queue_intr_ack = bcmcnet_pdma_rx_queue_intr_ack, + .rx_queue_intr_query = bcmcnet_pdma_rx_queue_intr_query, + .rx_queue_intr_check = bcmcnet_pdma_rx_queue_intr_check, + .tx_queue_intr_enable = bcmcnet_pdma_tx_queue_intr_enable, + .tx_queue_intr_disable = bcmcnet_pdma_tx_queue_intr_disable, + .tx_queue_intr_ack = bcmcnet_pdma_tx_queue_intr_ack, + .tx_queue_intr_query = bcmcnet_pdma_tx_queue_intr_query, + .tx_queue_intr_check = bcmcnet_pdma_tx_queue_intr_check, + .rx_queue_suspend = bcmcnet_pdma_rx_queue_suspend, + .rx_queue_resume = bcmcnet_pdma_rx_queue_resume, + .tx_queue_wakeup = bcmcnet_pdma_tx_queue_wakeup, + .rx_queue_poll = bcmcnet_pdma_rx_queue_poll, + .tx_queue_poll = bcmcnet_pdma_tx_queue_poll, + .group_poll = bcmcnet_pdma_group_poll, +}; + +/*! + * Open a device + */ +int +bcmcnet_pdma_open(struct pdma_dev *dev) +{ + struct pdma_hw *hw = (struct pdma_hw *)dev->ctrl.hw; + struct intr_handle *hdl = NULL; + int chan, gi, qi; + + if (!hw) { + return SHR_E_INIT; + } + + /* Initialize the hardware */ + hw->hdls.hw_reset(hw); + hw->hdls.hw_init(hw); + + if ((uint32_t)dev->num_groups > hw->info.num_cmcs) { + return SHR_E_PARAM; + } + dev->grp_queues = hw->info.cmc_chans; + dev->num_queues = hw->info.num_chans; + dev->rx_ph_size = hw->info.rx_ph_size; + dev->tx_ph_size = hw->info.tx_ph_size; + dev->ctrl.nb_desc = NUM_RING_DESC; + dev->ctrl.budget = NUM_RXTX_BUDGET; + dev->ctrl.rx_desc_size = hw->info.rx_dcb_size; + dev->ctrl.tx_desc_size = hw->info.tx_dcb_size; + + /* Initialize interrupt handler */ + for (chan = 0; chan < dev->num_queues; chan++) { + gi = chan / dev->grp_queues; + qi = chan % dev->grp_queues; + hdl = &dev->ctrl.grp[gi].intr_hdl[qi]; + hdl->unit = dev->unit; + hdl->group = gi; + hdl->chan = chan; + hdl->dev = dev; + hdl->intr_num = hw->hdls.chan_intr_num_get(hw, chan); + if (hdl->intr_num < 0) { + return SHR_E_INTERNAL; + } + } + + /* Initialize buffer manager */ + bcmcnet_buf_mngr_init(dev); + + /* Allocate all the queues */ + bcn_rx_queues_alloc(dev); + bcn_tx_queues_alloc(dev); + + dev->pkt_xmit = bcmcnet_pdma_tx_queue_xmit; + + dev->ops = (struct dev_ops *)&pdma_dev_ops; + + return SHR_E_NONE; +} + +/*! + * Coalesce Rx interrupt + */ +int +bcmcnet_pdma_rx_queue_int_coalesce(struct pdma_dev *dev, int queue, int count, int timer) +{ + struct dev_ctrl *ctrl = &dev->ctrl; + struct pdma_hw *hw = (struct pdma_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]; + rxq->intr_coalescing = 1; + rxq->ic_val = (count & 0x7fff) << 16 | (timer & 0xffff); + + return hw->hdls.chan_intr_coalesce(hw, rxq->chan_id, count, timer); +} + +/*! + * Coalesce Tx interrupt + */ +int +bcmcnet_pdma_tx_queue_int_coalesce(struct pdma_dev *dev, int queue, int count, int timer) +{ + struct dev_ctrl *ctrl = &dev->ctrl; + struct pdma_hw *hw = (struct pdma_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]; + txq->intr_coalescing = 1; + txq->ic_val = (count & 0x7fff) << 16 | (timer & 0xffff); + + return hw->hdls.chan_intr_coalesce(hw, txq->chan_id, count, timer); +} + +/*! + * Dump Rx queue registers + */ +int +bcmcnet_pdma_rx_queue_reg_dump(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; + + if ((uint32_t)queue >= ctrl->nb_rxq) { + return SHR_E_PARAM; + } + + rxq = (struct pdma_rx_queue *)ctrl->rx_queue[queue]; + + return hw->hdls.chan_reg_dump(hw, rxq->chan_id); +} + +/*! + * Dump Tx queue registers + */ +int +bcmcnet_pdma_tx_queue_reg_dump(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; + + if ((uint32_t)queue >= ctrl->nb_txq) { + return SHR_E_PARAM; + } + + txq = (struct pdma_tx_queue *)ctrl->tx_queue[queue]; + + return hw->hdls.chan_reg_dump(hw, txq->chan_id); +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmcnet/main/bcmcnet_rxtx.c b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/main/bcmcnet_rxtx.c new file mode 100644 index 000000000000..cfabe9d95d56 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmcnet/main/bcmcnet_rxtx.c @@ -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 +#include +#include +#include + +/*! + * 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; +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmdrd/include/bcmdrd/bcmdrd_devlist.h b/platform/broadcom/saibcm-modules/sdklt/bcmdrd/include/bcmdrd/bcmdrd_devlist.h new file mode 100644 index 000000000000..675b9426ea01 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmdrd/include/bcmdrd/bcmdrd_devlist.h @@ -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 + +/* + * 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 */ diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmdrd/include/bcmdrd_config.h b/platform/broadcom/saibcm-modules/sdklt/bcmdrd/include/bcmdrd_config.h new file mode 100644 index 000000000000..68e5a0891098 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmdrd/include/bcmdrd_config.h @@ -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 +#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_ + * + */ +#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_) 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" diff --git a/platform/broadcom/saibcm-modules/sdklt/bcmdrd/include/bcmdrd_config_chips.h b/platform/broadcom/saibcm-modules/sdklt/bcmdrd/include/bcmdrd_config_chips.h new file mode 100644 index 000000000000..5b45879c90e9 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/bcmdrd/include/bcmdrd_config_chips.h @@ -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_ [1|0] + * -- Include or exclude all revisions of the given device + * Example: #define BCMDRD_CONFIG_INCLUDE_BCM56780 1 + * + * (2) #define BCMDRD_CONFIG_INCLUDE__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_ [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 */ diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/bde/Kbuild b/platform/broadcom/saibcm-modules/sdklt/linux/bde/Kbuild new file mode 100644 index 000000000000..76581c02eed2 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/bde/Kbuild @@ -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 diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/bde/Makefile b/platform/broadcom/saibcm-modules/sdklt/linux/bde/Makefile new file mode 100644 index 000000000000..590f4132306f --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/bde/Makefile @@ -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: diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde.h b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde.h new file mode 100644 index 000000000000..56e925f7098d --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde.h @@ -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 +#include + +/*! 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 */ diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_dma.c b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_dma.c new file mode 100644 index 000000000000..9cc2b191f48c --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_dma.c @@ -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 + +/*! \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; +} diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_iio.c b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_iio.c new file mode 100644 index 000000000000..e97f1fcea730 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_iio.c @@ -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 + +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); + } +} diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_intr.c b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_intr.c new file mode 100644 index 000000000000..acec7da100f7 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_intr.c @@ -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 + +/*! \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; +} diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_ioctl.c b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_ioctl.c new file mode 100644 index 000000000000..ccd0b7ee01d0 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_ioctl.c @@ -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 + +#include + +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; +} diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_iproc_probe.c b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_iproc_probe.c new file mode 100644 index 000000000000..63b02a4075a3 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_iproc_probe.c @@ -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 +#include +#include + +/*! \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; +} diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_kapi.c b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_kapi.c new file mode 100644 index 000000000000..340e7b057d44 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_kapi.c @@ -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 + +#include + +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 */ diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_main.c b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_main.c new file mode 100644 index 000000000000..5ce48ebc5134 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_main.c @@ -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 + +/*! \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; +} diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_pci_probe.c b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_pci_probe.c new file mode 100644 index 000000000000..37da39cd38a7 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_pci_probe.c @@ -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 + +/*! \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 + { 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; +} diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_pgmem.c b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_pgmem.c new file mode 100644 index 000000000000..e473f0c545cb --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_pgmem.c @@ -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 + + +/******************************************************************************* + * 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); + } +} diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_pio.c b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_pio.c new file mode 100644 index 000000000000..cab094a2feca --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_pio.c @@ -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 + +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; +} diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_procfs.c b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_procfs.c new file mode 100644 index 000000000000..f99339a5b0dc --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_procfs.c @@ -0,0 +1,120 @@ +/*! \file ngbde_procfs.c + * + * + * + */ +/* + * $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 + +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; +} diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_swdev.c b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_swdev.c new file mode 100644 index 000000000000..60d328ad2526 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_swdev.c @@ -0,0 +1,79 @@ +/*! \file ngbde_swdev.c + * + * + * + */ +/* + * $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 + +/* 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; +} diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/lkm.h b/platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/lkm.h new file mode 100644 index 000000000000..c0ba0a319767 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/lkm.h @@ -0,0 +1,126 @@ +/*! \file lkm.h + * + * + * + */ +/* + * $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 +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +#error Kernel too old +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) +#include +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) +#include +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_DEVFS_FS +#include +#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 */ diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/ngbde_ioctl.h b/platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/ngbde_ioctl.h new file mode 100644 index 000000000000..b90486ce06f2 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/ngbde_ioctl.h @@ -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 +#include + +/*! 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 */ diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/ngbde_kapi.h b/platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/ngbde_kapi.h new file mode 100644 index 000000000000..142aa63b572c --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/ngbde_kapi.h @@ -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 + +/*! 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 */ diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/ngknet_dev.h b/platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/ngknet_dev.h new file mode 100644 index 000000000000..74d3d5b350b0 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/ngknet_dev.h @@ -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 + +/*! 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 . + * + * 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 */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/ngknet_ioctl.h b/platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/ngknet_ioctl.h new file mode 100644 index 000000000000..6da52c778191 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/include/lkm/ngknet_ioctl.h @@ -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 */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/include/net/psample.h b/platform/broadcom/saibcm-modules/sdklt/linux/include/net/psample.h new file mode 100644 index 000000000000..64188c95daeb --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/include/net/psample.h @@ -0,0 +1,24 @@ +#ifndef __NET_PSAMPLE_H +#define __NET_PSAMPLE_H + +#include +#include +#include +#include + +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 */ diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/include/uapi/linux/psample.h b/platform/broadcom/saibcm-modules/sdklt/linux/include/uapi/linux/psample.h new file mode 100644 index 000000000000..ed48996ec0e8 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/include/uapi/linux/psample.h @@ -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 diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/Kbuild b/platform/broadcom/saibcm-modules/sdklt/linux/knet/Kbuild new file mode 100644 index 000000000000..fe5d5c5bfefc --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/Kbuild @@ -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 diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/Makefile b/platform/broadcom/saibcm-modules/sdklt/linux/knet/Makefile new file mode 100644 index 000000000000..785b81fadb17 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/Makefile @@ -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 diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_buff.c b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_buff.c new file mode 100644 index 000000000000..750fff69caf3 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_buff.c @@ -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 +#include +#include +#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; +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_buff.h b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_buff.h new file mode 100644 index 000000000000..54768e826917 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_buff.h @@ -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 */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_callback.c b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_callback.c new file mode 100644 index 000000000000..21512a51fbd2 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_callback.c @@ -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); diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_callback.h b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_callback.h new file mode 100644 index 000000000000..54583adffa36 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_callback.h @@ -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 +#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 */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_dep.h b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_dep.h new file mode 100644 index 000000000000..919dd6450340 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_dep.h @@ -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 +#include + +#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 + +/*! 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 + NGKNET_DEV_T_COUNT +} ngknet_dev_type_t; + +#endif /* NGKNET_DEP_H */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_extra.c b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_extra.c new file mode 100644 index 000000000000..00fdb3da8849 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_extra.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#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; + } +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_extra.h b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_extra.h new file mode 100644 index 000000000000..27dea9e368e7 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_extra.h @@ -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 */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_linux.c b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_linux.c new file mode 100644 index 000000000000..0162ae5b96c1 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_linux.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_linux.h b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_linux.h new file mode 100644 index 000000000000..686aac8f5571 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_linux.h @@ -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 +#include +#include +#include + +/*! + * 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 */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_main.c b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_main.c new file mode 100644 index 000000000000..b8af31d85ff2 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_main.c @@ -0,0 +1,2689 @@ +/*! \file ngknet_main.c + * + * NGKNET 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.$ + */ + +/* + * This module implements a Linux network driver for Broadcom + * XGS switch devices. The driver simultaneously serves a + * number of virtual Linux network devices. + * + * Packets received from the switch device are sent to a virtual + * Linux network device based on a set of packet filters. + * + * Packets from the virtual Linux network devices are multiplexed + * with fifo mode if only one Tx queue enabled. + * + * A command-based IOCTL interface is used for managing the devices, + * packet filters and virtual Linux network interfaces. + * + * A virtual network interface can be configured to work in RCPU + * mode, which means that packets from the switch device will + * be encapsulated with a RCPU header and a block of meta data + * that basically contains the core DCB information. Likewise, + * packets received from the Linux network stack are assumed to + * be RCPU encapsulated when going out on an interface in RCPU + * mode. If a virtual network interface does not work in RCPU + * mode and transmits to this interface will unmodified go to + * specified physical switch port, DCB information should be + * provided when the interface is created. + * + * The module implements basic Rx DMA rate control. The rate is + * specified in packets per second, and different Rx DMA channels + * can be configured to use different maximum packet rates. + * The packet rate can be configure as a module parameter, and + * it can also be changed dynamically through the proc file + * system (syntax is described in function header comment). + * + * For a list of supported module parameters, please see below. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "ngknet_main.h" +#include "ngknet_extra.h" +#include "ngknet_procfs.h" +#include "ngknet_callback.h" +#include "ngknet_ptp.h" + +/*! \cond */ +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_DESCRIPTION("Network Device Driver Module"); +MODULE_LICENSE("GPL"); +/*! \endcond */ + +/*! \cond */ +static int debug = 0; +MODULE_PARAM(debug, int, 0); +MODULE_PARM_DESC(debug, +"Debug level (default 0)"); +/*! \endcond */ + +/*! \cond */ +static char *base_dev_name = "bcm"; +MODULE_PARAM(base_dev_name, charp, 0); +MODULE_PARM_DESC(base_dev_name, +"Base device name (default bcm0, bcm1, etc.)"); +/*! \endcond */ + +/*! \cond */ +static char *mac_addr = NULL; +MODULE_PARAM(mac_addr, charp, 0); +MODULE_PARM_DESC(mac_addr, +"Ethernet MAC address (default 02:10:18:xx:xx:xx)"); +/*! \endcond */ + +/*! \cond */ +static int default_mtu = 1500; +MODULE_PARAM(default_mtu, int, 0); +MODULE_PARM_DESC(default_mtu, +"Default MTU for NGKNET network interfaces (default 1500)"); +/*! \endcond */ + +/*! \cond */ +static int rx_buffer_size = RX_BUF_SIZE_DFLT; +MODULE_PARAM(rx_buffer_size, int, 0); +MODULE_PARM_DESC(rx_buffer_size, +"Default size of RX packet buffers (default 9216)"); +/*! \endcond */ + +/*! \cond */ +static int rx_rate_limit = -1; +MODULE_PARAM(rx_rate_limit, int, 0); +MODULE_PARM_DESC(rx_rate_limit, +"Rx rate limit (pps, default -1 no limit)"); +/*! \endcond */ + +/*! \cond */ +static int tx_polling = 0; +MODULE_PARAM(tx_polling, int, 0); +MODULE_PARM_DESC(tx_polling, +"Tx polling mode (default 0 in interrupt mode)"); +/*! \endcond */ + +/*! \cond */ +static int rx_batching = 0; +MODULE_PARAM(rx_batching, int, 0); +MODULE_PARM_DESC(rx_batching, +"Rx batching mode (default 0 in single fill mode)"); +/*! \endcond */ + +typedef int (*drv_ops_attach)(struct pdma_dev *dev); + +struct bcmcnet_drv_ops { + const char *drv_desc; + drv_ops_attach drv_attach; + drv_ops_attach drv_detach; +}; + +#define BCMDRD_DEVLIST_ENTRY(_nm,_vn,_dv,_rv,_md,_pi,_bd,_bc,_fn,_cn,_pf,_pd,_r0,_r1) \ + static struct bcmcnet_drv_ops _bd##_cnet_drv_ops = { \ + #_bd, \ + _bd##_cnet_pdma_attach, \ + _bd##_cnet_pdma_detach, \ + }; +#include + +#define BCMDRD_DEVLIST_ENTRY(_nm,_vn,_dv,_rv,_md,_pi,_bd,_bc,_fn,_cn,_pf,_pd,_r0,_r1) \ + &_bd##_cnet_drv_ops, +static struct bcmcnet_drv_ops *drv_ops[] = { + NULL, +#include + NULL +}; +static int drv_num = sizeof(drv_ops) / sizeof(drv_ops[0]); + +struct ngknet_dev ngknet_devices[NUM_PDMA_DEV_MAX]; + +/* Default random MAC address has Broadcom OUI with local admin bit set */ +static uint8_t ngknet_dev_mac[6] = {0x02, 0x10, 0x18, 0x00, 0x00, 0x00}; + +/* Interrupt handles */ +struct ngknet_intr_handle { + struct napi_struct napi; + struct intr_handle *hdl; + int napi_resched; + int napi_pending; +}; + +static struct ngknet_intr_handle priv_hdl[NUM_PDMA_DEV_MAX][NUM_QUE_MAX]; + +/*! + * Dump packet content for debug + */ +static void +ngknet_pkt_dump(uint8_t *data, int len) +{ + char str[128]; + int i; + + len = len > 256 ? 256 : len; + + for (i = 0; i < len; i++) { + if ((i & 0x1f) == 0) { + sprintf(str, "%04x: ", i); + } + sprintf(&str[strlen(str)], "%02x", data[i]); + if ((i & 0x1f) == 0x1f) { + sprintf(&str[strlen(str)], "\n"); + printk(str); + continue; + } + if ((i & 0x3) == 0x3) { + sprintf(&str[strlen(str)], " "); + } + } + if ((i & 0x1f) != 0) { + sprintf(&str[strlen(str)], "\n"); + printk(str); + } + printk("\n"); +} + +/*! + * Rx packets rate test for debug + */ +static void +ngknet_pkt_stats(struct pdma_dev *pdev, int dir) +{ + static struct timeval tv0[2], tv1[2]; + static uint32_t pkts[2] = {0}, prts[2] = {0}; + static uint64_t intrs = 0; + + if (pkts[dir] == 0) { + kal_time_val_get(&tv0[dir]); + intrs = pdev->stats.intrs; + } + if (++pkts[dir] >= 100000) { + uint32_t iv_time; + uint32_t pps; + kal_time_val_get(&tv1[dir]); + iv_time = (tv1[dir].tv_sec - tv0[dir].tv_sec) * 1000000 + + (tv1[dir].tv_usec - tv0[dir].tv_usec); + pps = 100000 * 1000 / (iv_time / 1000); + prts[dir]++; + if (pps <= 100000 || prts[dir] * 100000 >= pps) { + printk(KERN_CRIT "%s -- limit: %d pps, 100K pkts time: %d usec, rate: %d pps, intrs: %llu\n", + dir == PDMA_Q_RX ? "Rx" : "Tx", + dir == PDMA_Q_RX ? rx_rate_limit : -1, + iv_time, pps, pdev->stats.intrs - intrs); + prts[dir] = 0; + } + pkts[dir] = 0; + } +} + +/*! + * Read 32-bit register callback + */ +static int +ngknet_dev_read32(struct pdma_dev *dev, uint32_t addr, uint32_t *data) +{ + *data = ngbde_kapi_pio_read32(dev->unit, addr); + + return 0; +} + +/*! + * Write 32-bit register callback + */ +static int +ngknet_dev_write32(struct pdma_dev *dev, uint32_t addr, uint32_t data) +{ + ngbde_kapi_pio_write32(dev->unit, addr, data); + + return 0; +} + +/*! + * Set Rx HW timestamping. + */ +static int +ngknet_ptp_rx_hwts_set(struct net_device *ndev, struct sk_buff *skb) +{ + struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); + uint64_t ts = 0; + int rv; + + rv = ngknet_ptp_rx_hwts_get(ndev, skb, &ts); + if (SHR_FAILURE(rv) || !ts) { + return SHR_E_FAIL; + } + + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); + shhwtstamps->hwtstamp = ns_to_ktime(ts); + + return SHR_E_NONE; +} + +/*! + * \brief Process Rx packet. + * + * Add RCPU encapsulation or strip matadata if needed + * + * \param [in] ndev Network device structure point. + * \param [in] oskb Rx packet SKB. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +ngknet_rx_frame_process(struct net_device *ndev, struct sk_buff **oskb) +{ + struct ngknet_private *priv = netdev_priv(ndev); + struct ngknet_dev *dev = priv->bkn_dev; + struct sk_buff *skb = *oskb; + struct ngknet_rcpu_hdr *rch = (struct ngknet_rcpu_hdr *)skb->data; + struct pkt_hdr *pkh = (struct pkt_hdr *)skb->data; + uint8_t meta_len = pkh->meta_len; + + /* Do Rx timestamping */ + if (priv->hwts_rx_filter) { + ngknet_ptp_rx_hwts_set(ndev, skb); + } + + /* Remove FCS from packet length */ + skb_trim(skb, skb->len - ETH_FCS_LEN); + pkh->data_len -= ETH_FCS_LEN; + + if (priv->flags & NGKNET_NETIF_F_RCPU_ENCAP) { + /* Set up RCPU header */ + memcpy(skb->data, skb->data + PKT_HDR_SIZE + meta_len, 2 * ETH_ALEN); + if (*(uint32_t *)&dev->rcpu_ctrl.dst_mac[0] != 0 || + *(uint16_t *)&dev->rcpu_ctrl.dst_mac[4] != 0) { + memcpy(rch->dst_mac, dev->rcpu_ctrl.dst_mac, ETH_ALEN); + } + if (*(uint32_t *)&dev->rcpu_ctrl.src_mac[0] != 0 || + *(uint16_t *)&dev->rcpu_ctrl.src_mac[4] != 0) { + memcpy(rch->src_mac, dev->rcpu_ctrl.src_mac, ETH_ALEN); + } + rch->vlan_tpid = htons(dev->rcpu_ctrl.vlan_tpid); + rch->vlan_tci = htons(dev->rcpu_ctrl.vlan_tci); + rch->eth_type = htons(dev->rcpu_ctrl.eth_type); + rch->pkt_sig = htons(dev->rcpu_ctrl.pkt_sig); + rch->op_code = RCPU_OPCODE_RX; + rch->flags = RCPU_FLAG_MODHDR; + rch->trans_id = htons(dev->rcpu_ctrl.trans_id); + rch->data_len = htons(pkh->data_len); + } else { + /* Remove packet header and meta data */ + skb_pull(skb, PKT_HDR_SIZE + meta_len); + } + + /* Optional callback handle */ + if (dev->cbc->rx_cb) { + struct ngknet_callback_desc *cbd = NGKNET_SKB_CB(skb); + cbd->dev_no = dev->dev_no; + cbd->dev_id = dev->pdma_dev.dev_id; + cbd->type_str = drv_ops[dev->pdma_dev.dev_type]->drv_desc; + cbd->priv = priv; + if (priv->flags & NGKNET_NETIF_F_RCPU_ENCAP) { + cbd->pmd = skb->data + PKT_HDR_SIZE; + cbd->pkt_len = ntohs(rch->data_len); + } else { + cbd->pmd = skb->data - meta_len; + cbd->pkt_len = pkh->data_len; + } + cbd->pmd_len = meta_len; + skb = dev->cbc->rx_cb(skb); + if (!skb) { + *oskb = NULL; + return SHR_E_UNAVAIL; + } + if (priv->flags & NGKNET_NETIF_F_RCPU_ENCAP) { + rch = (struct ngknet_rcpu_hdr *)skb->data; + rch->data_len = htons(skb->len - PKT_HDR_SIZE - meta_len); + } + } + + /* Update SKB pointer */ + *oskb = skb; + + return SHR_E_NONE; +} + +/*! + * \brief Network interface Rx function. + * + * After processing the packet, send it up to network stack. + * + * \param [in] ndev Network device structure point. + * \param [in] skb Rx packet SKB. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +ngknet_netif_recv(struct net_device *ndev, struct sk_buff *skb) +{ + struct ngknet_private *priv = netdev_priv(ndev); + struct ngknet_dev *dev = priv->bkn_dev; + struct pdma_dev *pdev = &dev->pdma_dev; + struct pkt_hdr *pkh = (struct pkt_hdr *)skb->data; + struct napi_struct *napi = NULL; + uint16_t proto; + int chan, gi, qi; + int rv; + + /* Handle one incoming packet */ + rv = ngknet_rx_frame_process(ndev, &skb); + if (SHR_FAILURE(rv)) { + if (!skb) { + return SHR_E_NONE; + } + } + + DBG_VERB(("Rx packet sent up to ndev%d (%d bytes).\n", priv->id, skb->len)); + if (debug & DBG_LVL_PDMP) { + ngknet_pkt_dump(skb->data, skb->len); + } + + if (ndev->features & NETIF_F_RXCSUM) { + if ((pkh->attrs & (PDMA_RX_TU_CSUM | PDMA_RX_IP_CSUM)) == + (PDMA_RX_TU_CSUM | PDMA_RX_IP_CSUM)) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + skb_checksum_none_assert(skb); + } + } + + if (!(priv->flags & NGKNET_NETIF_F_RCPU_ENCAP) && + ndev->features & NETIF_F_HW_VLAN_CTAG_RX && + pkh->attrs & PDMA_RX_STRIP_TAG) { + kal_vlan_hwaccel_put_tag(skb, ETH_P_8021Q, priv->vlan); + } + + proto = eth_type_trans(skb, ndev); + if (priv->flags & NGKNET_NETIF_F_RCPU_ENCAP) { + skb->protocol = htons(dev->rcpu_ctrl.eth_type); + } else if (!(pkh->attrs & PDMA_RX_SET_PROTO) || !skb->protocol) { + skb->protocol = proto; + } + + skb_record_rx_queue(skb, pkh->queue_id); + + bcmcnet_pdma_dev_queue_to_chan(pdev, pkh->queue_id, PDMA_Q_RX, &chan); + gi = chan / pdev->grp_queues; + if (pdev->flags & PDMA_GROUP_INTR) { + napi = (struct napi_struct *)pdev->ctrl.grp[gi].intr_hdl[0].priv; + } else { + qi = pkh->queue_id; + napi = (struct napi_struct *)pdev->ctrl.grp[gi].intr_hdl[qi].priv; + } + napi_gro_receive(napi, skb); + + /* Update accounting */ + priv->stats.rx_packets++; + priv->stats.rx_bytes += skb->len; + + /* Rate limit */ + if (rx_rate_limit >= 0) { + if (!ngknet_rx_rate_limit_started()) { + ngknet_rx_rate_limit_start(dev); + } + ngknet_rx_rate_limit(dev, rx_rate_limit); + } + + return SHR_E_NONE; +} + +/*! + * \brief Driver Rx callback. + * + * After processing the packet, send it up to network stack. + * + * \param [in] pdev Packet DMA device structure point. + * \param [in] buf Raw Rx buffer. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +ngknet_frame_recv(struct pdma_dev *pdev, int queue, void *buf) +{ + struct ngknet_dev *dev = (struct ngknet_dev *)pdev->priv; + struct sk_buff *skb = (struct sk_buff *)buf, *mskb = NULL; + struct net_device *ndev = NULL, *mndev = NULL; + struct ngknet_private *priv = NULL; + unsigned long flags; + int rv; + + DBG_VERB(("Rx packet (%d bytes).\n", skb->len)); + if (debug & DBG_LVL_PDMP) { + ngknet_pkt_dump(skb->data, skb->len); + } + + /* Go through the filters */ + rv = ngknet_rx_pkt_filter(dev, skb, &ndev, &mndev, &mskb); + if (SHR_FAILURE(rv) || !ndev) { + return SHR_E_FAIL; + } + + /* Populate header, checksum status, VLAN, and protocol */ + priv = netdev_priv(ndev); + if (netif_carrier_ok(ndev)) { + ngknet_netif_recv(ndev, skb); + } else { + priv->stats.rx_dropped++; + rv = SHR_E_UNAVAIL; + } + + spin_lock_irqsave(&dev->lock, flags); + priv->users--; + if (!priv->users && priv->wait) { + wake_up(&dev->wq); + } + spin_unlock_irqrestore(&dev->lock, flags); + + /* Handle mirrored packet */ + if (mndev && mskb) { + priv = netdev_priv(mndev); + if (netif_carrier_ok(mndev)) { + ngknet_netif_recv(mndev, mskb); + } else { + priv->stats.rx_dropped++; + dev_kfree_skb_any(mskb); + } + spin_lock_irqsave(&dev->lock, flags); + priv->users--; + if (!priv->users && priv->wait) { + wake_up(&dev->wq); + } + spin_unlock_irqrestore(&dev->lock, flags); + } + + /* Measure speed */ + if (debug & DBG_LVL_RATE) { + ngknet_pkt_stats(pdev, PDMA_Q_RX); + } + + return rv; +} + +/*! + * Set Tx HW timestamping. + */ +static int +ngknet_ptp_tx_hwts_set(struct net_device *ndev, struct sk_buff *skb) +{ + struct skb_shared_hwtstamps shhwtstamps; + uint64_t ts = 0; + int rv; + + rv = ngknet_ptp_tx_hwts_get(ndev, skb, &ts); + if (SHR_FAILURE(rv) || !ts) { + return SHR_E_FAIL; + } + + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); + shhwtstamps.hwtstamp = ns_to_ktime(ts); + skb_tstamp_tx(skb, &shhwtstamps); + + return SHR_E_NONE; +} + +/*! + * PTP Tx worker. + */ +static void +ngknet_ptp_tx_work(struct work_struct *work) +{ + struct ngknet_dev *dev = container_of(work, struct ngknet_dev, ptp_tx_work); + struct sk_buff *skb; + int rv; + + while (skb_queue_len(&dev->ptp_tx_queue)) { + skb = skb_dequeue(&dev->ptp_tx_queue); + rv = ngknet_ptp_tx_hwts_set(dev->net_dev, skb); + if (SHR_FAILURE(rv)) { + printk("Timestamp value has not been set for current skb.\n"); + } + dev_kfree_skb_any(skb); + } +} + +/*! + * Config Tx metadata for HW timestamping. + */ +static int +ngknet_ptp_tx_config(struct net_device *ndev, struct sk_buff *skb) +{ + struct ngknet_private *priv = netdev_priv(ndev); + struct ngknet_dev *dev = priv->bkn_dev; + int rv; + + if (priv->type == NGKNET_NETIF_T_PORT) { + rv = ngknet_ptp_tx_meta_set(ndev, skb); + if (SHR_FAILURE(rv)) { + return rv; + } + } else if (priv->hwts_tx_type != HWTSTAMP_TX_ONESTEP_SYNC) { + return SHR_E_UNAVAIL; + } + + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + + if (priv->hwts_tx_type == HWTSTAMP_TX_ONESTEP_SYNC) { + skb_queue_tail(&dev->ptp_tx_queue, skb_get(skb)); + schedule_work(&dev->ptp_tx_work); + } + + return SHR_E_NONE; +} + +/*! + * \brief Process Tx packet. + * + * Strip RCPU encapsulation, setup CNET packet buffer, add vlan tag + * or pad the packet. + * + * \param [in] ndev Network device structure point. + * \param [in] oskb Tx packet SKB. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +ngknet_tx_frame_process(struct net_device *ndev, struct sk_buff **oskb) +{ + struct ngknet_private *priv = netdev_priv(ndev); + struct ngknet_dev *dev = priv->bkn_dev; + struct sk_buff *skb = *oskb; + struct ngknet_rcpu_hdr *rch = (struct ngknet_rcpu_hdr *)skb->data; + struct pkt_hdr *pkh = (struct pkt_hdr *)skb->data; + struct sk_buff *nskb = NULL; + char *data = NULL; + uint32_t copy_len, meta_len, data_len, pkt_len, tag_len; + uint16_t tpid; + + /* Set up packet header */ + if (priv->flags & NGKNET_NETIF_F_RCPU_ENCAP) { + /* RCPU encapsulation packet */ + data_len = pkh->attrs & PDMA_TX_HDR_COOKED ? + pkh->data_len - ETH_FCS_LEN : ntohs(rch->data_len); + pkt_len = PKT_HDR_SIZE + rch->meta_len + data_len; + if (skb->len != pkt_len || skb->len < (PKT_HDR_SIZE + 14)) { + DBG_WARN(("Tx drop: Invalid RCPU encapsulation\n")); + return SHR_E_FAIL; + } + if (dev->rcpu_ctrl.pkt_sig && dev->rcpu_ctrl.pkt_sig != ntohs(rch->pkt_sig)) { + DBG_WARN(("Tx drop: Invalid RCPU signature\n")); + return SHR_E_FAIL; + } + if (pkh->attrs & PDMA_TX_HDR_COOKED) { + /* Resumed packet */ + return SHR_E_NONE; + } + pkh->data_len = data_len + ETH_FCS_LEN; + pkh->meta_len = rch->meta_len; + pkh->attrs = 0; + if (rch->flags & RCPU_FLAG_MODHDR) { + pkh->attrs |= PDMA_TX_HIGIG_PKT; + } + if (rch->flags & RCPU_FLAG_PAUSE) { + pkh->attrs |= PDMA_TX_PAUSE_PKT; + } + if (rch->flags & RCPU_FLAG_PURGE) { + pkh->attrs |= PDMA_TX_PURGE_PKT; + } + if (rch->flags & RCPU_FLAG_BIND_QUE) { + pkh->attrs |= PDMA_TX_BIND_QUE; + } + } else { + /* Non-RCPU encapsulation packet */ + data_len = pkh->data_len - ETH_FCS_LEN; + pkt_len = PKT_HDR_SIZE + pkh->meta_len + data_len; + if (skb->len == pkt_len && pkh->attrs & PDMA_TX_HDR_COOKED && + pkh->pkt_sig == dev->rcpu_ctrl.pkt_sig) { + /* Resumed packet */ + return SHR_E_NONE; + } + meta_len = 0; + if (priv->type == NGKNET_NETIF_T_PORT) { + meta_len = priv->meta_len; + if (!meta_len) { + printk("Tx abort: no metadata\n"); + return SHR_E_UNAVAIL; + } + } + if (skb_header_cloned(skb) || + skb_headroom(skb) < (PKT_HDR_SIZE + meta_len + VLAN_HLEN) || + skb_tailroom(skb) < ETH_FCS_LEN) { + nskb = skb_copy_expand(skb, PKT_HDR_SIZE + meta_len + VLAN_HLEN, + ETH_FCS_LEN, GFP_ATOMIC); + if (!nskb) { + return SHR_E_MEMORY; + } + skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags; + skb = nskb; + } + skb_push(skb, PKT_HDR_SIZE + meta_len); + memset(skb->data, 0, PKT_HDR_SIZE + meta_len); + pkh = (struct pkt_hdr *)skb->data; + pkh->data_len = skb->len - PKT_HDR_SIZE - meta_len + ETH_FCS_LEN; + pkh->meta_len = meta_len; + pkh->attrs = 0; + if (priv->type == NGKNET_NETIF_T_PORT) { + /* Send to physical port using netif metadata */ + if (priv->meta_off) { + memmove(skb->data + PKT_HDR_SIZE, skb->data + PKT_HDR_SIZE + meta_len, priv->meta_off); + } + memcpy(skb->data + PKT_HDR_SIZE + priv->meta_off, priv->meta_data, priv->meta_len); + pkh->attrs |= PDMA_TX_HIGIG_PKT; + } + pkh->pkt_sig = dev->rcpu_ctrl.pkt_sig; + } + + /* Packet header done here */ + pkh->attrs |= PDMA_TX_HDR_COOKED; + + data = skb->data + PKT_HDR_SIZE + pkh->meta_len; + tpid = data[12] << 8 | data[13]; + tag_len = (tpid == ETH_P_8021Q || tpid == ETH_P_8021AD) ? VLAN_HLEN : 0; + + /* Need to add VLAN tag if packet is untagged */ + if (!tag_len && (!(pkh->attrs & PDMA_TX_HIGIG_PKT) || priv->flags & NGKNET_NETIF_F_ADD_TAG)) { + copy_len = PKT_HDR_SIZE + pkh->meta_len + 2 * ETH_ALEN; + if (skb_header_cloned(skb) || skb_headroom(skb) < VLAN_HLEN) { + nskb = skb_copy_expand(skb, VLAN_HLEN, 0, GFP_ATOMIC); + if (!nskb) { + return SHR_E_MEMORY; + } + skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags; + skb = nskb; + } + skb_push(skb, VLAN_HLEN); + memmove(skb->data, skb->data + VLAN_HLEN, copy_len); + pkh = (struct pkt_hdr *)skb->data; + data = skb->data + PKT_HDR_SIZE + pkh->meta_len; + data[12] = 0x81; + data[13] = 0x00; + data[14] = priv->vlan >> 8 & 0xf; + data[15] = priv->vlan & 0xff; + pkh->data_len += VLAN_HLEN; + tag_len = VLAN_HLEN; + } + + /* Optional callback handle */ + if (dev->cbc->tx_cb) { + struct ngknet_callback_desc *cbd = NGKNET_SKB_CB(skb); + cbd->dev_no = dev->dev_no; + cbd->dev_id = dev->pdma_dev.dev_id; + cbd->type_str = drv_ops[dev->pdma_dev.dev_type]->drv_desc; + cbd->priv = priv; + cbd->pmd = skb->data + PKT_HDR_SIZE; + cbd->pmd_len = pkh->meta_len; + cbd->pkt_len = skb->len - PKT_HDR_SIZE - pkh->meta_len; + skb = dev->cbc->tx_cb(skb); + if (!skb) { + if (!nskb) { + *oskb = NULL; + } + return SHR_E_UNAVAIL; + } + pkh = (struct pkt_hdr *)skb->data; + pkh->data_len = skb->len - PKT_HDR_SIZE - pkh->meta_len + ETH_FCS_LEN; + } + + /* Pad packet if needed */ + if (pkh->data_len < (64 + tag_len)) { + pkh->data_len = 64 + tag_len; + if (skb_padto(skb, PKT_HDR_SIZE + pkh->meta_len + pkh->data_len - ETH_FCS_LEN)) { + if (!nskb) { + *oskb = NULL; + } + return SHR_E_MEMORY; + } + } + + /* Update SKB pointer */ + *oskb = skb; + + return SHR_E_NONE; +} + +/*! + * Suspend Tx queue callback + */ +static void +ngknet_tx_suspend(struct pdma_dev *pdev, int queue) +{ + struct ngknet_dev *dev = (struct ngknet_dev *)pdev->priv; + unsigned long flags; + int vdi; + + netif_stop_subqueue(dev->net_dev, queue); + + spin_lock_irqsave(&dev->lock, flags); + for (vdi = 1; vdi <= NUM_VDEV_MAX; vdi++) { + if (!dev->vdev[vdi]) { + continue; + } + netif_stop_subqueue(dev->vdev[vdi], queue); + } + spin_unlock_irqrestore(&dev->lock, flags); +} + +/*! + * Resume Tx queue callback + */ +static void +ngknet_tx_resume(struct pdma_dev *pdev, int queue) +{ + struct ngknet_dev *dev = (struct ngknet_dev *)pdev->priv; + unsigned long flags; + int vdi; + + if (__netif_subqueue_stopped(dev->net_dev, queue)) { + netif_wake_subqueue(dev->net_dev, queue); + } + + spin_lock_irqsave(&dev->lock, flags); + for (vdi = 1; vdi <= NUM_VDEV_MAX; vdi++) { + if (!dev->vdev[vdi]) { + continue; + } + if (__netif_subqueue_stopped(dev->vdev[vdi], queue)) { + netif_wake_subqueue(dev->vdev[vdi], queue); + } + } + spin_unlock_irqrestore(&dev->lock, flags); + + if (pdev->mode == DEV_MODE_HNET) { + atomic_set(&dev->hnet_active, 1); + wake_up_interruptible(&dev->hnet_wq); + } +} + +/*! + * Enable interrupt callback + */ +static void +ngknet_intr_enable(struct pdma_dev *pdev, int cmc, int chan, + uint32_t reg, uint32_t mask) +{ + pdev->ctrl.grp[cmc].irq_mask |= mask; + ngbde_kapi_intr_mask_write(pdev->unit, 0, reg, pdev->ctrl.grp[cmc].irq_mask); +} + +/*! + * Disable interrupt callback + */ +static void +ngknet_intr_disable(struct pdma_dev *pdev, int cmc, int chan, + uint32_t reg, uint32_t mask) +{ + pdev->ctrl.grp[cmc].irq_mask &= ~mask; + ngbde_kapi_intr_mask_write(pdev->unit, 0, reg, pdev->ctrl.grp[cmc].irq_mask); +} + +/*! + * NAPI polling function + */ +static int +ngknet_poll(struct napi_struct *napi, int budget) +{ + struct ngknet_intr_handle *kih = (struct ngknet_intr_handle *)napi; + struct intr_handle *hdl = kih->hdl; + struct pdma_dev *pdev = (struct pdma_dev *)hdl->dev; + struct ngknet_dev *dev = (struct ngknet_dev *)pdev->priv; + unsigned long flags; + int work_done; + + DBG_NAPI(("Scheduled NAPI on queue %d.\n", hdl->queue)); + + kih->napi_resched = 0; + kih->napi_pending = 0; + + if (pdev->flags & PDMA_GROUP_INTR) { + work_done = bcmcnet_group_poll(pdev, hdl->group, budget); + } else { + work_done = bcmcnet_queue_poll(pdev, hdl, budget); + } + + if (work_done < budget) { + napi_complete(napi); + if (kih->napi_pending && napi_schedule_prep(napi)) { + __napi_schedule(napi); + return work_done; + } + spin_lock_irqsave(&dev->lock, flags); + if (!kih->napi_resched) { + if (pdev->flags & PDMA_GROUP_INTR) { + bcmcnet_group_intr_enable(pdev, hdl->group); + } else { + bcmcnet_queue_intr_enable(pdev, hdl); + } + } + spin_unlock_irqrestore(&dev->lock, flags); + } + + return work_done; +} + +/*! + * NGKNET ISR + */ +static int +ngknet_isr(void *isr_data) +{ + struct ngknet_dev *dev = isr_data; + struct pdma_dev *pdev = &dev->pdma_dev; + struct intr_handle *hdl = NULL; + struct napi_struct *napi = NULL; + unsigned long flags; + int gi, qi; + int iv = 0; + + for (gi = 0; gi < pdev->num_groups; gi++) { + if (!pdev->ctrl.grp[gi].attached) { + continue; + } + for (qi = 0; qi < pdev->grp_queues; qi++) { + hdl = &pdev->ctrl.grp[gi].intr_hdl[qi]; + if (pdev->flags & PDMA_GROUP_INTR) { + if (!bcmcnet_group_intr_check(pdev, gi)) { + break; + } + } else { + if (!bcmcnet_queue_intr_check(pdev, hdl)) { + continue; + } + } + spin_lock_irqsave(&dev->lock, flags); + if (pdev->flags & PDMA_GROUP_INTR) { + bcmcnet_group_intr_disable(pdev, gi); + } else { + bcmcnet_queue_intr_disable(pdev, hdl); + } + spin_unlock_irqrestore(&dev->lock, flags); + napi = (struct napi_struct *)hdl->priv; + if (likely(napi_schedule_prep(napi))) { + __napi_schedule(napi); + } + iv++; + if (pdev->flags & PDMA_GROUP_INTR) { + break; + } + } + } + + if (iv) { + DBG_IRQ(("Got interrupt on device %d.\n", dev->dev_no)); + pdev->stats.intrs++; + return IRQ_HANDLED; + } else { + return IRQ_NONE; + } +} + +/*! + * Hypervisor network work handler + */ +static void +ngknet_dev_hnet_work(struct pdma_dev *pdev) +{ + struct ngknet_dev *dev = (struct ngknet_dev *)pdev->priv; + struct intr_handle *hdl = NULL; + struct napi_struct *napi = NULL; + struct ngknet_intr_handle *kih = NULL; + unsigned long flags; + int gi, qi; + + for (gi = 0; gi < pdev->num_groups; gi++) { + if (!pdev->ctrl.grp[gi].attached) { + continue; + } + for (qi = 0; qi < pdev->grp_queues; qi++) { + hdl = &pdev->ctrl.grp[gi].intr_hdl[qi]; + napi = (struct napi_struct *)hdl->priv; + kih = (struct ngknet_intr_handle *)napi; + kih->napi_pending = 1; + if (napi_schedule_prep(napi)) { + spin_lock_irqsave(&dev->lock, flags); + kih->napi_resched = 1; + spin_unlock_irqrestore(&dev->lock, flags); + local_bh_disable(); + __napi_schedule(napi); + local_bh_enable(); + } + if (pdev->flags & PDMA_GROUP_INTR) { + break; + } + } + } +} + +/*! + * Hypervisor network wait handler + */ +static int +ngknet_dev_hnet_wait(struct pdma_dev *pdev) +{ + struct ngknet_dev *dev = (struct ngknet_dev *)pdev->priv; + int qi; + int rv; + + while (!kthread_should_stop()) { + wait_event_interruptible(dev->hnet_wq, + atomic_read(&dev->hnet_active) != 0); + if (!(dev->flags & NGKNET_DEV_ACTIVE)) { + schedule_timeout(HZ); + continue; + } + atomic_set(&dev->hnet_active, 0); + for (qi = 0; qi < pdev->ctrl.nb_txq; qi++) { + do { + rv = pdev->pkt_xmit(pdev, qi, 0); + } while (rv == SHR_E_NONE); + } + schedule_work(&dev->hnet_work); + } + + return 0; +} + +/*! + * Hypervisor network wake handler + */ +static int +ngknet_dev_vnet_wake(struct pdma_dev *pdev) +{ + struct ngknet_dev *dev = (struct ngknet_dev *)pdev->priv; + + atomic_set(&dev->vnet_active, 1); + wake_up_interruptible(&dev->vnet_wq); + + return SHR_E_NONE; +} + +/*! + * Hypervisor network process + */ +static int +ngknet_dev_hnet_process(void *data) +{ + return ngknet_dev_hnet_wait((struct pdma_dev *)data); +} + +/*! + * Hypervisor network schedule + */ +static void +ngknet_dev_hnet_schedule(struct work_struct *work) +{ + struct ngknet_dev *dev = container_of(work, struct ngknet_dev, hnet_work); + + ngknet_dev_hnet_work(&dev->pdma_dev); +} + +/*! + * Convert physical address to virtual address + */ +static void * +ngknet_sys_p2v(struct pdma_dev *pdev, uint64_t paddr) +{ + return ngbde_kapi_dma_bus_to_virt(pdev->unit, (dma_addr_t)paddr); +} + +/*! + * Convert virtual address to physical address + */ +static uint64_t +ngknet_sys_v2p(struct pdma_dev *pdev, void *vaddr) +{ + return (uint64_t)ngbde_kapi_dma_virt_to_bus(pdev->unit, vaddr); +} + +/*! + * Open network device + */ +static int +ngknet_enet_open(struct net_device *ndev) +{ + struct ngknet_private *priv = netdev_priv(ndev); + struct ngknet_dev *dev = priv->bkn_dev; + struct pdma_dev *pdev = &dev->pdma_dev; + struct napi_struct *napi = NULL; + unsigned long bm_queue; + int gi, qi; + int rv; + + if (!pdev->ctrl.bm_rxq || !pdev->ctrl.bm_txq) { + printk("Not config Rx or Tx queue yet!\n"); + return -EPERM; + } + + if (priv->id <= 0) { + /* Register interrupt handler */ + ngbde_kapi_intr_connect(dev->dev_no, 0, ngknet_isr, dev); + + /* Start PDMA device */ + rv = bcmcnet_pdma_dev_start(pdev); + if (SHR_FAILURE(rv)) { + ngbde_kapi_intr_disconnect(dev->dev_no, 0); + return -EPERM; + } + + /* Start rate limit */ + if (rx_rate_limit >= 0) { + ngknet_rx_rate_limit_start(dev); + } + + /* Notify the stack of the actual queue counts. */ + rv = netif_set_real_num_rx_queues(dev->net_dev, pdev->ctrl.nb_rxq); + if (rv < 0) { + ngbde_kapi_intr_disconnect(dev->dev_no, 0); + return rv; + } + rv = netif_set_real_num_tx_queues(dev->net_dev, pdev->ctrl.nb_txq); + if (rv < 0) { + ngbde_kapi_intr_disconnect(dev->dev_no, 0); + return rv; + } + + for (gi = 0; gi < pdev->num_groups; gi++) { + if (!pdev->ctrl.grp[gi].attached) { + continue; + } + bm_queue = pdev->ctrl.grp[gi].bm_rxq | pdev->ctrl.grp[gi].bm_txq; + for (qi = 0; qi < pdev->grp_queues; qi++) { + napi = (struct napi_struct *)pdev->ctrl.grp[gi].intr_hdl[qi].priv; + if (pdev->flags & PDMA_GROUP_INTR) { + napi_enable(napi); + break; + } + if (1 << qi & bm_queue) { + napi_enable(napi); + } + } + } + } else { + /* Notify the stack of the actual queue counts. */ + rv = netif_set_real_num_rx_queues(ndev, pdev->ctrl.nb_rxq); + if (rv < 0) { + return rv; + } + rv = netif_set_real_num_tx_queues(ndev, pdev->ctrl.nb_txq); + if (rv < 0) { + return rv; + } + } + + /* Prevent tx timeout */ + kal_netif_trans_update(ndev); + + netif_tx_wake_all_queues(ndev); + + return 0; +} + +/*! + * Stop network device + */ +static int +ngknet_enet_stop(struct net_device *ndev) +{ + struct ngknet_private *priv = netdev_priv(ndev); + struct ngknet_dev *dev = priv->bkn_dev; + struct pdma_dev *pdev = &dev->pdma_dev; + struct napi_struct *napi = NULL; + unsigned long bm_queue; + int gi, qi; + + netif_tx_stop_all_queues(ndev); + + if (priv->id <= 0) { + /* Stop rate limit */ + if (rx_rate_limit >= 0) { + ngknet_rx_rate_limit_stop(dev); + } + + /* Suspend PDMA device */ + bcmcnet_pdma_dev_suspend(pdev); + + for (gi = 0; gi < pdev->num_groups; gi++) { + if (!pdev->ctrl.grp[gi].attached) { + continue; + } + bm_queue = pdev->ctrl.grp[gi].bm_rxq | pdev->ctrl.grp[gi].bm_txq; + for (qi = 0; qi < pdev->grp_queues; qi++) { + napi = (struct napi_struct *)pdev->ctrl.grp[gi].intr_hdl[qi].priv; + if (pdev->flags & PDMA_GROUP_INTR) { + napi_disable(napi); + break; + } + if (1 << qi & bm_queue) { + napi_disable(napi); + } + } + } + + /* Stop PDMA device */ + bcmcnet_pdma_dev_stop(pdev); + + /* Unregister interrupt handler */ + ngbde_kapi_intr_disconnect(dev->dev_no, 0); + } + + return 0; +} + +/*! + * Start transmission + */ +static int +ngknet_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct ngknet_private *priv = netdev_priv(ndev); + struct ngknet_dev *dev = priv->bkn_dev; + struct pdma_dev *pdev = &dev->pdma_dev; + struct sk_buff *bskb = skb; + uint32_t len = skb->len; + int queue; + int rv; + + DBG_VERB(("Tx packet from ndev%d (%d bytes).\n", priv->id, skb->len)); + if (debug & DBG_LVL_PDMP) { + ngknet_pkt_dump(skb->data, skb->len); + } + + /* Do not transmit on base device */ + if (priv->id <= 0) { + priv->stats.tx_dropped++; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + /* Measure speed */ + if (debug & DBG_LVL_RATE) { + ngknet_pkt_stats(pdev, PDMA_Q_TX); + } + + queue = skb->queue_mapping; + + /* Handle one outgoing packet */ + rv = ngknet_tx_frame_process(ndev, &skb); + if (SHR_FAILURE(rv)) { + priv->stats.tx_dropped++; + if (skb) { + dev_kfree_skb_any(skb); + } + return NETDEV_TX_OK; + } + + /* Schedule Tx queue */ + ngknet_tx_queue_schedule(dev, skb, &queue); + skb->queue_mapping = queue; + + DBG_VERB(("Tx packet (%d bytes).\n", skb->len)); + if (debug & DBG_LVL_PDMP) { + ngknet_pkt_dump(skb->data, skb->len); + } + + /* Do Tx timestamping */ + if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { + ngknet_ptp_tx_config(ndev, skb); + } + + skb_tx_timestamp(skb); + + rv = pdev->pkt_xmit(pdev, queue, skb); + + if (rv == SHR_E_UNAVAIL) { + DBG_WARN(("Tx drop: DMA device not ready\n")); + priv->stats.tx_dropped++; + if (skb != bskb) { + dev_kfree_skb_any(skb); + } + dev_kfree_skb_any(bskb); + return NETDEV_TX_OK; + } + + if (rv == SHR_E_BUSY) { + DBG_WARN(("Tx suspend: No DMA resources\n")); + priv->stats.tx_fifo_errors++; + if (skb != bskb) { + dev_kfree_skb_any(skb); + } + return NETDEV_TX_BUSY; + } else { + if (skb != bskb) { + dev_kfree_skb_any(bskb); + } + } + + /* Update accounting */ + priv->stats.tx_packets++; + priv->stats.tx_bytes += len; + + return NETDEV_TX_OK; +} + +/*! + * Get network device stats + */ +static struct net_device_stats * +ngknet_get_stats(struct net_device *ndev) +{ + struct ngknet_private *priv = netdev_priv(ndev); + + return &priv->stats; +} + +/*! + * Set network device MC list + */ +static void +ngknet_set_multicast_list(struct net_device *ndev) +{ + return; +} + +/*! + * Set network device MAC address + */ +static int +ngknet_set_mac_address(struct net_device *ndev, void *addr) +{ + if (!is_valid_ether_addr(((struct sockaddr *)addr)->sa_data)) { + return -EINVAL; + } + + netdev_info(ndev, "Setting new MAC address\n"); + memcpy(ndev->dev_addr, ((struct sockaddr *)addr)->sa_data, ndev->addr_len); + + return 0; +} + +/*! + * Change network device MTU + */ +static int +ngknet_change_mtu(struct net_device *ndev, int new_mtu) +{ + int frame_size = new_mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN; + + if (frame_size < 68 || frame_size > rx_buffer_size) { + return -EINVAL; + } + + netdev_info(ndev, "Changing MTU from %d to %d\n", ndev->mtu, new_mtu); + ndev->mtu = new_mtu; + + return 0; +} + +/*! + * Do I/O control + */ +static int +ngknet_do_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) +{ + struct ngknet_private *priv = netdev_priv(ndev); + struct hwtstamp_config config; + int rv; + + if (cmd == SIOCSHWTSTAMP) { + if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) { + return -EFAULT; + } + + if (priv->type != NGKNET_NETIF_T_PORT) { + return -ENOSYS; + } + + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + priv->hwts_tx_type = HWTSTAMP_TX_OFF; + rv = ngknet_ptp_tx_config_set(ndev, priv->hwts_tx_type); + if (SHR_FAILURE(rv)) { + return -ENOSYS; + } + break; + case HWTSTAMP_TX_ON: + priv->hwts_tx_type = HWTSTAMP_TX_ON; + rv = ngknet_ptp_tx_config_set(ndev, priv->hwts_tx_type); + if (SHR_FAILURE(rv)) { + return -ENOSYS; + } + break; + case HWTSTAMP_TX_ONESTEP_SYNC: + priv->hwts_tx_type = HWTSTAMP_TX_ONESTEP_SYNC; + rv = ngknet_ptp_tx_config_set(ndev, priv->hwts_tx_type); + if (SHR_FAILURE(rv)) { + return -ENOSYS; + } + break; + default: + return -ERANGE; + } + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + rv = ngknet_ptp_rx_config_set(ndev, &config.rx_filter); + if (SHR_FAILURE(rv)) { + return -ENOSYS; + } + priv->hwts_rx_filter = HWTSTAMP_FILTER_NONE; + break; + default: + rv = ngknet_ptp_rx_config_set(ndev, &config.rx_filter); + if (SHR_FAILURE(rv)) { + return -ENOSYS; + } + priv->hwts_rx_filter = config.rx_filter; + break; + } + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) + if (cmd == SIOCGHWTSTAMP) { + config.flags = 0; + config.tx_type = priv->hwts_tx_type; + config.rx_filter = priv->hwts_rx_filter; + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; + } +#endif + + return -EINVAL; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +/*! + * Poll network device + */ +static void +ngknet_poll_controller(struct net_device *ndev) +{ + struct ngknet_private *priv = netdev_priv(ndev); + + disable_irq(ndev->irq); + ngknet_isr(priv->bkn_dev); + enable_irq(ndev->irq); +} +#endif + +static const struct net_device_ops ngknet_netdev_ops = { + .ndo_open = ngknet_enet_open, + .ndo_stop = ngknet_enet_stop, + .ndo_start_xmit = ngknet_start_xmit, + .ndo_get_stats = ngknet_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_rx_mode = ngknet_set_multicast_list, + .ndo_set_mac_address = ngknet_set_mac_address, + .ndo_change_mtu = ngknet_change_mtu, + .ndo_set_features = NULL, + .ndo_do_ioctl = ngknet_do_ioctl, + .ndo_tx_timeout = NULL, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ngknet_poll_controller, +#endif +}; + +static void +ngknet_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) +{ + strlcpy(drvinfo->driver, "linux_ngknet", sizeof(drvinfo->driver)); + snprintf(drvinfo->version, sizeof(drvinfo->version), "%d", NGKNET_IOC_VERSION); + strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); + strlcpy(drvinfo->bus_info, "N/A", sizeof(drvinfo->bus_info)); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)) +static int +ngknet_get_ts_info(struct net_device *ndev, struct ethtool_ts_info *info) +{ + int rv; + + info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + info->tx_types = 1 << HWTSTAMP_TX_OFF | 1 << HWTSTAMP_TX_ON | 1 << HWTSTAMP_TX_ONESTEP_SYNC; + info->rx_filters = 1 << HWTSTAMP_FILTER_NONE | 1 << HWTSTAMP_FILTER_ALL; + rv = ngknet_ptp_phc_index_get(ndev, &info->phc_index); + if (SHR_FAILURE(rv)) { + info->phc_index = -1; + } + + return 0; +} +#endif + +static const struct ethtool_ops ngknet_ethtool_ops = { + .get_drvinfo = ngknet_get_drvinfo, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)) + .get_ts_info = ngknet_get_ts_info, +#endif +}; + +/*! + * \brief Initialize network device. + * + * \param [in] name Network device name. + * \param [in] mac Network device MAC address. + * \param [out] nd New registered network device. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +ngknet_ndev_init(ngknet_netif_t *netif, struct net_device **nd) +{ + struct net_device *ndev = NULL; + uint8_t *ma; + int rv; + + if (!netif) { + DBG_WARN(("Network interface is NULL.\n")); + return SHR_E_PARAM; + } + if (!nd) { + DBG_WARN(("Network device is NULL.\n")); + return SHR_E_PARAM; + } + + ndev = alloc_etherdev_mq(sizeof(struct ngknet_private), NUM_QUE_MAX); + if (!ndev) { + DBG_WARN(("Error allocating network device.\n")); + return SHR_E_MEMORY; + } + if (!ndev->dev_addr) { + DBG_WARN(("ndev->dev_addr is NULL\n")); + free_netdev(ndev); + return SHR_E_INTERNAL; + } + + /* Device information -- not available right now */ + ndev->irq = 0; + ndev->base_addr = 0; + + /* Fill in the dev structure */ + ndev->watchdog_timeo = 5 * HZ; + + /* Default MTU should not exceed MTU of switch front-panel ports */ + ndev->mtu = netif->mtu; + if (!ndev->mtu) { + ndev->mtu = default_mtu ? default_mtu : rx_buffer_size; + } + + ndev->netdev_ops = &ngknet_netdev_ops; + ndev->ethtool_ops = &ngknet_ethtool_ops; + + /* Network device name */ + if (netif->name && *netif->name) { + strncpy(ndev->name, netif->name, IFNAMSIZ - 1); + } + + /* Set the device MAC address */ + ma = netif->macaddr; + if ((ma[0] | ma[1] | ma[2] | ma[3] | ma[4] | ma[5]) == 0) { + ngknet_dev_mac[5]++; + ma = ngknet_dev_mac; + } + memcpy(ndev->dev_addr, ma, ETH_ALEN); + + /* Initialize the device features */ + ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | + NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX; + ndev->features |= NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_CTAG_RX; + + /* Register the kernel network device */ + rv = register_netdev(ndev); + if (rv < 0) { + DBG_WARN(("Error registering network device %s.\n", ndev->name)); + free_netdev(ndev); + return SHR_E_FAIL; + } + + *nd = ndev; + + DBG_VERB(("Created network device %s.\n", ndev->name)); + + return SHR_E_NONE; +} + +/*! + * \brief Initialize Packet DMA device. + * + * \param [in] dev NGKNET device structure point. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +ngknet_pdev_init(struct ngknet_dev *dev) +{ + struct pdma_dev *pdev = &dev->pdma_dev; + int rv; + + /* Initialize PDMA control structure */ + pdev->unit = dev->dev_no; + pdev->priv = dev; + pdev->ctrl.dev = pdev; + pdev->ctrl.hw_addr = dev->base_addr; + pdev->ctrl.rx_buf_size = rx_buffer_size; + + /* Hook callbacks */ + pdev->dev_read32 = ngknet_dev_read32; + pdev->dev_write32 = ngknet_dev_write32; + pdev->pkt_recv = ngknet_frame_recv; + pdev->tx_suspend = ngknet_tx_suspend; + pdev->tx_resume = ngknet_tx_resume; + pdev->intr_unmask = ngknet_intr_enable; + pdev->intr_mask = ngknet_intr_disable; + pdev->xnet_wait = ngknet_dev_hnet_wait; + pdev->xnet_wake = ngknet_dev_vnet_wake; + pdev->sys_p2v = ngknet_sys_p2v; + pdev->sys_v2p = ngknet_sys_v2p; + + pdev->flags |= PDMA_GROUP_INTR; + if (tx_polling) { + pdev->flags |= PDMA_TX_POLLING; + } + if (rx_batching || pdev->mode == DEV_MODE_HNET) { + pdev->flags |= PDMA_RX_BATCHING; + } + + /* Attach PDMA driver */ + rv = drv_ops[pdev->dev_type]->drv_attach(pdev); + if (SHR_FAILURE(rv)) { + DBG_WARN(("Attach DMA driver failed.\n")); + return rv; + } + + /* Initialize PDMA device */ + rv = bcmcnet_pdma_dev_init(pdev); + if (SHR_FAILURE(rv)) { + DBG_WARN(("Init DMA device.failed.\n")); + return rv; + } + + DBG_VERB(("Attached DMA device %s.\n", pdev->name)); + + return SHR_E_NONE; +} + +/*! + * \brief Get device information from BDE. + * + * \param [in] dn Device number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +ngknet_dev_info_get(int dn) +{ + struct ngknet_dev *dev = &ngknet_devices[dn]; + + dev->base_addr = ngbde_kapi_pio_membase(dn); + dev->dev = ngbde_kapi_dma_dev_get(dn); + + if (!dev->base_addr || !dev->dev) { + return SHR_E_ACCESS; + } + + dev->dev_no = dn; + + return SHR_E_NONE; +} + +/*! + * \brief Probe device. + * + * Get the information from BDE, initialize Packet DMA device, + * initialize base network device and allocate other resources. + * + * \param [in] dn Device number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +ngknet_dev_probe(int dn, ngknet_netif_t *netif) +{ + struct ngknet_dev *dev = &ngknet_devices[dn]; + struct pdma_dev *pdev = &dev->pdma_dev; + struct net_device *ndev = NULL; + struct ngknet_private *priv = NULL; + struct intr_handle *hdl = NULL; + struct cpumask mask; + int gi, qi; + int rv; + + DBG_VERB(("%s: dev %d\n",__FUNCTION__, dn)); + + /* Get device information */ + rv = ngknet_dev_info_get(dn); + if (SHR_FAILURE(rv)) { + return rv; + } + + /* Initialize PDMA device */ + rv = ngknet_pdev_init(dev); + if (SHR_FAILURE(rv)) { + return rv; + } + + /* Get base network device name */ + if (netif->name[0] == '\0') { + /* Reserve 6 vacancies for base&vitual device number, i.e. nameAB_XYZ */ + if (strlen(base_dev_name) < IFNAMSIZ - 6) { + snprintf(netif->name, IFNAMSIZ, "%s%d", base_dev_name, dn); + } else { + DBG_WARN(("Too long network device name: %s.\n", base_dev_name)); + return SHR_E_PARAM; + } + } + + rv = ngknet_ndev_init(netif, &ndev); + if (SHR_FAILURE(rv)) { + bcmcnet_pdma_dev_cleanup(pdev); + return rv; + } + dev->net_dev = ndev; + + /* Initialize private information for base network device */ + priv = netdev_priv(ndev); + priv->net_dev = ndev; + priv->bkn_dev = dev; + priv->id = 0; + priv->type = netif->type; + if (priv->type == NGKNET_NETIF_T_PORT) { + priv->meta_off = netif->meta_off; + priv->meta_len = netif->meta_len; + memcpy(priv->meta_data, netif->meta_data, priv->meta_len); + } + priv->flags = netif->flags; + priv->vlan = netif->vlan; + priv->chan = netif->chan; + memcpy(priv->user_data, netif->user_data, sizeof(priv->user_data)); + + netif->id = priv->id; + memcpy(netif->macaddr, ndev->dev_addr, ETH_ALEN); + netif->mtu = ndev->mtu; + memcpy(netif->name, ndev->name, sizeof(netif->name) - 1); + + if (priv->flags & NGKNET_NETIF_F_BIND_CHAN) { + dev->bdev[priv->chan] = ndev; + } + + /* Register for napi */ + for (gi = 0; gi < pdev->num_groups; gi++) { + if (!pdev->ctrl.grp[gi].attached) { + continue; + } + for (qi = 0; qi < pdev->grp_queues; qi++) { + hdl = &pdev->ctrl.grp[gi].intr_hdl[qi]; + priv_hdl[hdl->unit][hdl->chan].hdl = hdl; + hdl->priv = &priv_hdl[hdl->unit][hdl->chan]; + netif_napi_add(ndev, (struct napi_struct *)hdl->priv, + ngknet_poll, pdev->ctrl.budget); + if (pdev->flags & PDMA_GROUP_INTR) { + break; + } + } + } + + /* Get callback control */ + ngknet_callback_control_get(&dev->cbc); + + INIT_LIST_HEAD(&dev->filt_list); + spin_lock_init(&dev->lock); + init_waitqueue_head(&dev->wq); + if (pdev->mode == DEV_MODE_HNET) { + init_waitqueue_head(&dev->vnet_wq); + atomic_set(&dev->vnet_active, 0); + init_waitqueue_head(&dev->hnet_wq); + atomic_set(&dev->hnet_active, 0); + dev->hnet_task = kthread_run(ngknet_dev_hnet_process, pdev, pdev->name); + if (IS_ERR(dev->hnet_task)) { + dev->hnet_task = NULL; + return SHR_E_INTERNAL; + } + cpumask_clear(&mask); + cpumask_set_cpu(1, &mask); + set_cpus_allowed_ptr(dev->hnet_task, &mask); + INIT_WORK(&dev->hnet_work, ngknet_dev_hnet_schedule); + } + + skb_queue_head_init(&dev->ptp_tx_queue); + INIT_WORK(&dev->ptp_tx_work, ngknet_ptp_tx_work); + + dev->flags |= NGKNET_DEV_ACTIVE; + + DBG_NDEV(("Broadcom NGKNET Attached\n")); + DBG_NDEV(("MAC: %pM\n", ndev->dev_addr)); + DBG_NDEV(("Running with NAPI enabled\n")); + + return SHR_E_NONE; +} + +/*! + * \brief Remove device. + * + * Suspend device firstly, destroy all virtual network devices + * and filters, clean up Packet DMA device. + * + * \param [in] dn Device number. + * + * \retval SHR_E_NONE No errors. + * \retval SHR_E_XXXX Operation failed. + */ +static int +ngknet_dev_remove(int dn) +{ + struct ngknet_dev *dev = &ngknet_devices[dn]; + struct pdma_dev *pdev = &dev->pdma_dev; + struct net_device *ndev = NULL; + struct intr_handle *hdl = NULL; + int di, gi, qi; + int rv; + + if (!(dev->flags & NGKNET_DEV_ACTIVE)) { + return SHR_E_NONE; + } + + DBG_VERB(("%s: dev %d\n",__FUNCTION__, dn)); + + dev->flags &= ~NGKNET_DEV_ACTIVE; + + skb_queue_purge(&dev->ptp_tx_queue); + + if (pdev->mode == DEV_MODE_HNET && dev->hnet_task) { + atomic_set(&dev->hnet_active, 1); + wake_up_interruptible(&dev->hnet_wq); + kthread_stop(dev->hnet_task); + dev->hnet_task = NULL; + } + + /* Destroy all the filters */ + ngknet_filter_destroy_all(dev); + + /* Destroy all the virtual devices */ + for (di = 1; di <= NUM_VDEV_MAX; di++) { + ndev = dev->vdev[di]; + if (ndev) { + netif_carrier_off(ndev); + unregister_netdev(ndev); + free_netdev(ndev); + dev->vdev[di] = NULL; + } + } + dev->vdev[0] = NULL; + + DBG_VERB(("Removing base network device %s.\n", dev->net_dev->name)); + + /* Destroy the base network device */ + ndev = dev->net_dev; + unregister_netdev(ndev); + free_netdev(ndev); + + for (qi = 0; qi < NUM_QUE_MAX; qi++) { + dev->bdev[qi] = NULL; + } + + for (gi = 0; gi < pdev->num_groups; gi++) { + if (!pdev->ctrl.grp[gi].attached) { + continue; + } + for (qi = 0; qi < pdev->grp_queues; qi++) { + hdl = &pdev->ctrl.grp[gi].intr_hdl[qi]; + netif_napi_del((struct napi_struct *)hdl->priv); + priv_hdl[hdl->unit][hdl->chan].hdl = NULL; + if (pdev->flags & PDMA_GROUP_INTR) { + break; + } + } + } + + /* Clean up PDMA device */ + bcmcnet_pdma_dev_cleanup(pdev); + + /* Detach PDMA driver */ + rv = drv_ops[pdev->dev_type]->drv_detach(pdev); + if (SHR_FAILURE(rv)) { + DBG_WARN(("Detach DMA driver failed.\n")); + } + + return rv; +} + +/*! + * Network interface functions + */ + +int +ngknet_netif_create(struct ngknet_dev *dev, ngknet_netif_t *netif) +{ + struct net_device *ndev = NULL; + struct ngknet_private *priv = NULL; + unsigned long flags; + int num, id; + int rv; + + switch (netif->type) { + case NGKNET_NETIF_T_VLAN: + case NGKNET_NETIF_T_PORT: + case NGKNET_NETIF_T_META: + break; + default: + return SHR_E_UNAVAIL; + } + + /* Get vitual network device name */ + if (netif->name[0] == '\0') { + /* Reserve 6 vacancies for base&vitual device number, i.e. nameAB_XYZ */ + if (strlen(base_dev_name) < IFNAMSIZ - 6) { + snprintf(netif->name, IFNAMSIZ, "%s%d%s", base_dev_name, dev->dev_no, "_"); + strncat(netif->name, "%d", 3); + } else { + DBG_WARN(("Too long network device name: %s.\n", base_dev_name)); + return SHR_E_PARAM; + } + } + + rv = ngknet_ndev_init(netif, &ndev); + if (SHR_FAILURE(rv)) { + return rv; + } + + spin_lock_irqsave(&dev->lock, flags); + + num = (long)dev->vdev[0]; + for (id = 1; id < num + 1; id++) { + if (!dev->vdev[id]) { + break; + } + } + if (id > NUM_VDEV_MAX) { + spin_unlock_irqrestore(&dev->lock, flags); + unregister_netdev(ndev); + free_netdev(ndev); + return SHR_E_RESOURCE; + } + + dev->vdev[id] = ndev; + num += id == (num + 1) ? 1 : 0; + dev->vdev[0] = (struct net_device *)(long)num; + + spin_unlock_irqrestore(&dev->lock, flags); + + priv = netdev_priv(ndev); + priv->net_dev = ndev; + priv->bkn_dev = dev; + priv->id = id; + priv->type = netif->type; + if (priv->type == NGKNET_NETIF_T_PORT) { + priv->meta_off = netif->meta_off; + priv->meta_len = netif->meta_len; + memcpy(priv->meta_data, netif->meta_data, priv->meta_len); + } + priv->flags = netif->flags; + priv->vlan = netif->vlan; + priv->chan = netif->chan; + memcpy(priv->user_data, netif->user_data, sizeof(priv->user_data)); + + netif->id = priv->id; + memcpy(netif->macaddr, ndev->dev_addr, ETH_ALEN); + netif->mtu = ndev->mtu; + memcpy(netif->name, ndev->name, sizeof(netif->name) - 1); + + if (priv->flags & NGKNET_NETIF_F_BIND_CHAN) { + dev->bdev[priv->chan] = ndev; + } + + /* Optional netif create callback handle */ + if (dev->cbc->netif_create_cb) { + rv = dev->cbc->netif_create_cb(ndev); + if (rv) { + DBG_WARN(("Netif create callback failed with rv %d for '%s'\n", rv, ndev->name)); + } + } + + DBG_VERB(("Created virtual network device %s (%d).\n", ndev->name, priv->id)); + + return SHR_E_NONE; +} + +int +ngknet_netif_destroy(struct ngknet_dev *dev, int id) +{ + struct net_device *ndev = NULL; + struct ngknet_private *priv = NULL; + unsigned long flags; + int num; + DECLARE_WAITQUEUE(wait, current); + + if (id <= 0 || id > NUM_VDEV_MAX) { + return SHR_E_PARAM; + } + + spin_lock_irqsave(&dev->lock, flags); + + ndev = dev->vdev[id]; + if (!ndev) { + spin_unlock_irqrestore(&dev->lock, flags); + return SHR_E_NOT_FOUND; + } + priv = netdev_priv(ndev); + + add_wait_queue(&dev->wq, &wait); + + while (priv->users) { + priv->wait = 1; + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&dev->lock, flags); + schedule(); + spin_lock_irqsave(&dev->lock, flags); + priv->wait = 0; + set_current_state(TASK_RUNNING); + } + + if (priv->flags & NGKNET_NETIF_F_BIND_CHAN) { + dev->bdev[priv->chan] = NULL; + } + + dev->vdev[id] = NULL; + num = (long)dev->vdev[0]; + while (num-- == id--) { + if (dev->vdev[id]) { + dev->vdev[0] = (struct net_device *)(long)num; + break; + } + } + + spin_unlock_irqrestore(&dev->lock, flags); + + remove_wait_queue(&dev->wq, &wait); + + /* Optional netif destroy callback handle */ + if (dev->cbc->netif_destroy_cb) { + int rv = dev->cbc->netif_destroy_cb(ndev); + if (rv) { + DBG_WARN(("Netif destroy callback failed with rv %d for '%s'\n", rv, ndev->name)); + } + } + DBG_VERB(("Removing virtual network device %s (%d).\n", ndev->name, priv->id)); + + netif_carrier_off(ndev); + unregister_netdev(ndev); + free_netdev(ndev); + + return SHR_E_NONE; +} + +int +ngknet_netif_get(struct ngknet_dev *dev, int id, ngknet_netif_t *netif) +{ + struct net_device *ndev = NULL; + struct ngknet_private *priv = NULL; + unsigned long flags; + int num; + + if (id < 0 || id > NUM_VDEV_MAX) { + return SHR_E_PARAM; + } + + spin_lock_irqsave(&dev->lock, flags); + + ndev = id == 0 ? dev->net_dev : dev->vdev[id]; + if (!ndev) { + spin_unlock_irqrestore(&dev->lock, flags); + return SHR_E_NOT_FOUND; + } + + priv = netdev_priv(ndev); + netif->id = priv->id; + netif->type = priv->type; + netif->flags = priv->flags; + netif->vlan = priv->vlan; + memcpy(netif->macaddr, priv->net_dev->dev_addr, ETH_ALEN); + netif->mtu = priv->net_dev->mtu; + netif->chan = priv->chan; + memcpy(netif->name, priv->net_dev->name, sizeof(netif->name) - 1); + netif->meta_off = priv->meta_off; + netif->meta_len = priv->meta_len; + memcpy(netif->meta_data, priv->meta_data, netif->meta_len); + memcpy(netif->user_data, priv->user_data, sizeof(netif->user_data)); + + num = (long)dev->vdev[0]; + for (id++; id < num + 1; id++) { + if (dev->vdev[id]) { + break; + } + } + netif->next = id == (num + 1) ? 0 : id; + + spin_unlock_irqrestore(&dev->lock, flags); + + DBG_VERB(("Got virtual network device %s (%d).\n", ndev->name, priv->id)); + + return SHR_E_NONE; +} + +int +ngknet_netif_get_next(struct ngknet_dev *dev, ngknet_netif_t *netif) +{ + return ngknet_netif_get(dev, netif->next, netif); +} + +/*! + * System control interfaces + */ + +int +ngknet_debug_level_get(void) +{ + return debug; +} + +void +ngknet_debug_level_set(int debug_level) +{ + debug = debug_level; +} + +int +ngknet_rx_rate_limit_get(void) +{ + return rx_rate_limit; +} + +void +ngknet_rx_rate_limit_set(int rate_limit) +{ + rx_rate_limit = rate_limit; +} + +/*! + * Generic module functions + */ + +static int +ngknet_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +static int +ngknet_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +static long +ngknet_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct ngknet_ioctl ioc; + struct ngknet_dev *dev = NULL; + struct net_device *ndev = NULL; + struct pdma_dev *pdev = NULL; + union { + ngknet_dev_cfg_t dev_cfg; + ngknet_chan_cfg_t chan_cfg; + ngknet_netif_t netif; + ngknet_filter_t filter; + } iod; + ngknet_dev_cfg_t *dev_cfg = &iod.dev_cfg; + ngknet_chan_cfg_t *chan_cfg = &iod.chan_cfg; + ngknet_netif_t *netif = &iod.netif; + ngknet_filter_t *filter = &iod.filter; + char *data = NULL; + int dt, gi, qi; + + if (_IOC_TYPE(cmd) != NGKNET_IOC_MAGIC) { + DBG_WARN(("Unsupported command (cmd=%d)\n", cmd)); + return -EINVAL; + } + + if (copy_from_user(&ioc, (void *)arg, sizeof(ioc))) { + return -EFAULT; + } + + ioc.rc = SHR_E_NONE; + + dev = &ngknet_devices[ioc.unit]; + pdev = &dev->pdma_dev; + + if (cmd != NGKNET_VERSION_GET && + cmd != NGKNET_RX_RATE_LIMIT && + cmd != NGKNET_DEV_INIT && + !(dev->flags & NGKNET_DEV_ACTIVE)) { + ioc.rc = SHR_E_UNAVAIL; + if (copy_to_user((void *)arg, &ioc, sizeof(ioc))) { + return -EFAULT; + } + return 0; + } + + switch (cmd) { + case NGKNET_VERSION_GET: + DBG_CMD(("NGKNET_VERSION_GET\n")); + ioc.op.info.version = NGKNET_IOC_VERSION; + break; + case NGKNET_RX_RATE_LIMIT: + DBG_CMD(("NGKNET_RX_RATE_LIMIT\n")); + if (ioc.iarg[0]) { + ngknet_rx_rate_limit_set(ioc.iarg[1]); + } else { + ioc.iarg[1] = ngknet_rx_rate_limit_get(); + } + break; + case NGKNET_DEV_INIT: + DBG_CMD(("NGKNET_DEV_INIT\n")); + if (dev->flags & NGKNET_DEV_ACTIVE) { + DBG_CMD(("NGKNET_DEV_INIT, retrieve device configurations.\n")); + strlcpy(dev_cfg->name, pdev->name, sizeof(dev_cfg->name)); + dev_cfg->dev_id = pdev->dev_id; + dev_cfg->nb_grp = pdev->ctrl.nb_grp; + dev_cfg->bm_grp = pdev->ctrl.bm_grp; + ioc.rc = ngknet_netif_get(dev, 0, &dev_cfg->base_netif); + if (SHR_FAILURE((int)ioc.rc)) { + break; + } + if (kal_copy_to_user((void *)(unsigned long)ioc.op.data.buf, dev_cfg, + ioc.op.data.len, sizeof(*dev_cfg))) { + return -EFAULT; + } + break; + } + if (kal_copy_from_user(dev_cfg, (void *)(unsigned long)ioc.op.data.buf, + sizeof(*dev_cfg), ioc.op.data.len)) { + return -EFAULT; + } + if (!dev_cfg->name[0] || !dev_cfg->bm_grp || + dev_cfg->bm_grp >= (1 << NUM_GRP_MAX)) { + DBG_WARN(("Invalid parameter: name=%s, bm_grp=0x%x\n", + dev_cfg->name, dev_cfg->bm_grp)); + ioc.rc = SHR_E_PARAM; + break; + } + memset(pdev, 0, sizeof(*pdev)); + strlcpy(pdev->name, dev_cfg->name, sizeof(pdev->name)); + pdev->dev_id = dev_cfg->dev_id; + for (dt = 0; dt < drv_num; dt++) { + if (!drv_ops[dt]) { + continue; + } + if (!strcasecmp(dev_cfg->type_str, drv_ops[dt]->drv_desc)) { + pdev->dev_type = dt; + break; + } + } + if (pdev->dev_type <= NGKNET_DEV_T_NONE || + pdev->dev_type >= NGKNET_DEV_T_COUNT) { + ioc.rc = SHR_E_PARAM; + break; + } + pdev->ctrl.bm_grp = dev_cfg->bm_grp; + for (gi = 0; gi < NUM_GRP_MAX; gi++) { + if (1 << gi & dev_cfg->bm_grp) { + pdev->ctrl.nb_grp++; + pdev->ctrl.grp[gi].attached = 1; + pdev->num_groups = gi + 1; + } + } + pdev->rx_ph_size = dev_cfg->rx_ph_size; + pdev->tx_ph_size = dev_cfg->tx_ph_size; + pdev->mode = dev_cfg->mode; + if (pdev->mode != DEV_MODE_KNET && pdev->mode != DEV_MODE_HNET) { + pdev->mode = DEV_MODE_KNET; + } + ioc.rc = ngknet_dev_probe(ioc.unit, &dev_cfg->base_netif); + if (SHR_FAILURE((int)ioc.rc)) { + break; + } + if (kal_copy_to_user((void *)(unsigned long)ioc.op.data.buf, dev_cfg, + ioc.op.data.len, sizeof(*dev_cfg))) { + return -EFAULT; + } + break; + case NGKNET_DEV_DEINIT: + DBG_CMD(("NGKNET_DEV_DEINIT\n")); + if (dev->flags & NGKNET_DEV_ACTIVE) { + ioc.rc = ngknet_dev_remove(ioc.unit); + } + break; + case NGKNET_QUEUE_CONFIG: + DBG_CMD(("NGKNET_QUEUE_CONFIG\n")); + if (kal_copy_from_user(chan_cfg, (void *)(unsigned long)ioc.op.data.buf, + sizeof(*chan_cfg), ioc.op.data.len)) { + return -EFAULT; + } + gi = chan_cfg->chan / pdev->grp_queues; + if (!(1 << gi & pdev->ctrl.bm_grp)) { + DBG_WARN(("Invalid parameter: chan=%d (bm_grp=0x%x)\n", + chan_cfg->chan, pdev->ctrl.bm_grp)); + ioc.rc = SHR_E_PARAM; + break; + } + if (chan_cfg->dir == PDMA_Q_RX) { + if (1 << chan_cfg->chan & pdev->ctrl.bm_txq) { + pdev->ctrl.bm_txq &= ~(1 << chan_cfg->chan); + pdev->ctrl.nb_txq--; + } + if (!(1 << chan_cfg->chan & pdev->ctrl.bm_rxq)) { + pdev->ctrl.bm_rxq |= 1 << chan_cfg->chan; + pdev->ctrl.nb_rxq++; + } + } else { + if (1 << chan_cfg->chan & pdev->ctrl.bm_rxq) { + pdev->ctrl.bm_rxq &= ~(1 << chan_cfg->chan); + pdev->ctrl.nb_rxq--; + } + if (!(1 << chan_cfg->chan & pdev->ctrl.bm_txq)) { + pdev->ctrl.bm_txq |= 1 << chan_cfg->chan; + pdev->ctrl.nb_txq++; + } + } + qi = chan_cfg->chan % pdev->grp_queues; + pdev->ctrl.grp[gi].nb_desc[qi] = chan_cfg->nb_desc; + pdev->ctrl.grp[gi].rx_size[qi] = chan_cfg->rx_buf_size; + pdev->ctrl.grp[gi].que_ctrl[qi] &= ~(PDMA_PKT_BYTE_SWAP | + PDMA_OTH_BYTE_SWAP | + PDMA_HDR_BYTE_SWAP); + if (chan_cfg->chan_ctrl & NGKNET_PKT_BYTE_SWAP) { + pdev->ctrl.grp[gi].que_ctrl[qi] |= PDMA_PKT_BYTE_SWAP; + } + if (chan_cfg->chan_ctrl & NGKNET_OTH_BYTE_SWAP) { + pdev->ctrl.grp[gi].que_ctrl[qi] |= PDMA_OTH_BYTE_SWAP; + } + if (chan_cfg->chan_ctrl & NGKNET_HDR_BYTE_SWAP) { + pdev->ctrl.grp[gi].que_ctrl[qi] |= PDMA_HDR_BYTE_SWAP; + } + break; + case NGKNET_QUEUE_QUERY: + DBG_CMD(("NGKNET_QUEUE_QUERY\n")); + if (kal_copy_from_user(chan_cfg, (void *)(unsigned long)ioc.op.data.buf, + sizeof(*chan_cfg), ioc.op.data.len)) { + return -EFAULT; + } + if (1 << chan_cfg->chan & pdev->ctrl.bm_rxq) { + chan_cfg->dir = PDMA_Q_RX; + } else if (1 << chan_cfg->chan & pdev->ctrl.bm_txq) { + chan_cfg->dir = PDMA_Q_TX; + } else { + ioc.rc = SHR_E_UNAVAIL; + break; + } + gi = chan_cfg->chan / pdev->grp_queues; + qi = chan_cfg->chan % pdev->grp_queues; + chan_cfg->nb_desc = pdev->ctrl.grp[gi].nb_desc[qi]; + chan_cfg->chan_ctrl = pdev->ctrl.grp[gi].que_ctrl[qi]; + if (chan_cfg->dir == PDMA_Q_RX) { + chan_cfg->rx_buf_size = pdev->ctrl.grp[gi].rx_size[qi]; + } else { + chan_cfg->rx_buf_size = 0; + } + if (kal_copy_to_user((void *)(unsigned long)ioc.op.data.buf, chan_cfg, + ioc.op.data.len, sizeof(*chan_cfg))) { + return -EFAULT; + } + break; + case NGKNET_DEV_SUSPEND: + DBG_CMD(("NGKNET_DEV_SUSPEND\n")); + if (rx_rate_limit >= 0) { + ngknet_rx_rate_limit_stop(dev); + } + ioc.rc = bcmcnet_pdma_dev_suspend(pdev); + break; + case NGKNET_DEV_RESUME: + DBG_CMD(("NGKNET_DEV_RESUME\n")); + ioc.rc = bcmcnet_pdma_dev_resume(pdev); + if (rx_rate_limit >= 0) { + ngknet_rx_rate_limit_start(dev); + } + break; + case NGKNET_DEV_VNET_WAIT: + DBG_CMD(("NGKNET_DEV_VNET_WAIT\n")); + if (pdev->mode != DEV_MODE_HNET) { + ioc.rc = SHR_E_UNAVAIL; + break; + } + wait_event_interruptible(dev->vnet_wq, + atomic_read(&dev->vnet_active) != 0); + atomic_set(&dev->vnet_active, 0); + break; + case NGKNET_DEV_HNET_WAKE: + DBG_CMD(("NGKNET_DEV_HNET_WAKE\n")); + if (pdev->mode != DEV_MODE_HNET) { + ioc.rc = SHR_E_UNAVAIL; + break; + } + atomic_set(&dev->hnet_active, 1); + wake_up_interruptible(&dev->hnet_wq); + break; + case NGKNET_DEV_VNET_DOCK: + DBG_CMD(("NGKNET_DEV_VNET_DOCK\n")); + if (pdev->mode != DEV_MODE_HNET) { + ioc.rc = SHR_E_UNAVAIL; + break; + } + if (kal_copy_from_user(&pdev->ctrl.vsync, (void *)(unsigned long)ioc.op.data.buf, + sizeof(pdev->ctrl.vsync), ioc.op.data.len)) { + return -EFAULT; + } + ioc.rc = bcmcnet_pdma_dev_dock(pdev); + break; + case NGKNET_DEV_VNET_UNDOCK: + DBG_CMD(("NGKNET_DEV_VNET_UNDOCK\n")); + if (pdev->mode != DEV_MODE_HNET) { + ioc.rc = SHR_E_UNAVAIL; + break; + } + ngknet_dev_vnet_wake(pdev); + ioc.rc = bcmcnet_pdma_dev_undock(pdev); + break; + case NGKNET_RCPU_CONFIG: + DBG_CMD(("NGKNET_RCPU_CONFIG\n")); + if (kal_copy_from_user(&dev->rcpu_ctrl, (void *)(unsigned long)ioc.op.data.buf, + sizeof(dev->rcpu_ctrl), ioc.op.data.len)) { + return -EFAULT; + } + break; + case NGKNET_RCPU_GET: + DBG_CMD(("NGKNET_RCPU_GET\n")); + if (kal_copy_to_user((void *)(unsigned long)ioc.op.data.buf, &dev->rcpu_ctrl, + ioc.op.data.len, sizeof(dev->rcpu_ctrl))) { + return -EFAULT; + } + break; + case NGKNET_INFO_GET: + DBG_CMD(("NGKNET_INFO_GET\n")); + bcmcnet_pdma_dev_info_get(pdev); + if (kal_copy_to_user((void *)(unsigned long)ioc.op.data.buf, &pdev->info, + ioc.op.data.len, sizeof(pdev->info))) { + return -EFAULT; + } + break; + case NGKNET_STATS_GET: + DBG_CMD(("NGKNET_STATS_GET\n")); + bcmcnet_pdma_dev_stats_get(pdev); + if (kal_copy_to_user((void *)(unsigned long)ioc.op.data.buf, &pdev->stats, + ioc.op.data.len, sizeof(pdev->stats))) { + return -EFAULT; + } + break; + case NGKNET_STATS_RESET: + DBG_CMD(("NGKNET_STATS_RESET\n")); + bcmcnet_pdma_dev_stats_reset(pdev); + break; + case NGKNET_NETIF_CREATE: + DBG_CMD(("NGKNET_NETIF_CREATE\n")); + if (kal_copy_from_user(netif, (void *)(unsigned long)ioc.op.data.buf, + sizeof(*netif), ioc.op.data.len)) { + return -EFAULT; + } + ioc.rc = ngknet_netif_create(dev, netif); + if (SHR_FAILURE((int)ioc.rc)) { + break; + } + if (kal_copy_to_user((void *)(unsigned long)ioc.op.data.buf, netif, + ioc.op.data.len, sizeof(*netif))) { + return -EFAULT; + } + break; + case NGKNET_NETIF_DESTROY: + DBG_CMD(("NGKNET_NETIF_DESTROY\n")); + ioc.rc = ngknet_netif_destroy(dev, ioc.iarg[0]); + break; + case NGKNET_NETIF_GET: + DBG_CMD(("NGKNET_NETIF_GET\n")); + ioc.rc = ngknet_netif_get(dev, ioc.iarg[0], netif); + if (SHR_FAILURE((int)ioc.rc)) { + break; + } + if (kal_copy_to_user((void *)(unsigned long)ioc.op.data.buf, netif, + ioc.op.data.len, sizeof(*netif))) { + return -EFAULT; + } + break; + case NGKNET_NETIF_NEXT: + DBG_CMD(("NGKNET_NETIF_NEXT\n")); + if (kal_copy_from_user(netif, (void *)(unsigned long)ioc.op.data.buf, + sizeof(*netif), ioc.op.data.len)) { + return -EFAULT; + } + ioc.rc = ngknet_netif_get_next(dev, netif); + if (SHR_FAILURE((int)ioc.rc)) { + break; + } + if (kal_copy_to_user((void *)(unsigned long)ioc.op.data.buf, netif, + ioc.op.data.len, sizeof(*netif))) { + return -EFAULT; + } + break; + case NGKNET_NETIF_LINK_SET: + DBG_CMD(("NGKNET_NETIF_LINK_SET\n")); + ioc.rc = ngknet_netif_get(dev, ioc.iarg[0], netif); + if (SHR_FAILURE((int)ioc.rc)) { + break; + } + ndev = dev->vdev[netif->id]; + if (ioc.iarg[1]) { + if (!netif_carrier_ok(ndev)) { + netif_carrier_on(ndev); + netif_tx_wake_all_queues(ndev); + DBG_LINK(("%s: link up\n", netif->name)); + } + } else { + if (netif_carrier_ok(ndev)) { + netif_carrier_off(ndev); + netif_tx_stop_all_queues(ndev); + DBG_LINK(("%s: link down\n", netif->name)); + } + } + break; + case NGKNET_FILT_CREATE: + DBG_CMD(("NGKNET_FILT_CREATE\n")); + if (kal_copy_from_user(filter, (void *)(unsigned long)ioc.op.data.buf, + sizeof(*filter), ioc.op.data.len)) { + return -EFAULT; + } + ioc.rc = ngknet_filter_create(dev, filter); + if (SHR_FAILURE((int)ioc.rc)) { + break; + } + if (kal_copy_to_user((void *)(unsigned long)ioc.op.data.buf, filter, + ioc.op.data.len, sizeof(*filter))) { + return -EFAULT; + } + break; + case NGKNET_FILT_DESTROY: + DBG_CMD(("NGKNET_FILT_DESTROY\n")); + ioc.rc = ngknet_filter_destroy(dev, ioc.iarg[0]); + break; + case NGKNET_FILT_GET: + DBG_CMD(("NGKNET_FILT_GET\n")); + ioc.rc = ngknet_filter_get(dev, ioc.iarg[0], filter); + if (SHR_FAILURE((int)ioc.rc)) { + break; + } + if (kal_copy_to_user((void *)(unsigned long)ioc.op.data.buf, filter, + ioc.op.data.len, sizeof(*filter))) { + return -EFAULT; + } + break; + case NGKNET_FILT_NEXT: + DBG_CMD(("NGKNET_FILT_NEXT\n")); + if (kal_copy_from_user(filter, (void *)(unsigned long)ioc.op.data.buf, + sizeof(*filter), ioc.op.data.len)) { + return -EFAULT; + } + ioc.rc = ngknet_filter_get_next(dev, filter); + if (SHR_FAILURE((int)ioc.rc)) { + break; + } + if (kal_copy_to_user((void *)(unsigned long)ioc.op.data.buf, filter, + ioc.op.data.len, sizeof(*filter))) { + return -EFAULT; + } + break; + case NGKNET_PTP_DEV_CTRL: + DBG_CMD(("NGKNET_PTP_DEV_CTRL\n")); + if (ioc.op.data.len) { + data = kmalloc(ioc.op.data.len, GFP_ATOMIC); + if (data == NULL) { + printk("Fatal error: no memory for PTP device ioctl\n"); + return -EFAULT; + } + if (copy_from_user(data, (void *)(unsigned long)ioc.op.data.buf, + ioc.op.data.len)) { + kfree(data); + return -EFAULT; + } + } + ioc.rc = ngknet_ptp_dev_ctrl(dev, ioc.iarg[0], data, ioc.op.data.len); + if (SHR_FAILURE((int)ioc.rc)) { + if (data) { + kfree(data); + } + break; + } + if (ioc.op.data.len) { + if (copy_to_user((void *)(unsigned long)ioc.op.data.buf, data, + ioc.op.data.len)) { + kfree(data); + return -EFAULT; + } + kfree(data); + } + break; + default: + ioc.rc = SHR_E_UNAVAIL; + printk("Invalid IOCTL"); + break; + } + + if (copy_to_user((void *)arg, &ioc, sizeof(ioc))) { + return -EFAULT; + } + + return 0; +} + +static int +ngknet_mmap(struct file *filp, struct vm_area_struct *vma) +{ + return 0; +} + +static struct file_operations ngknet_fops = { + .open = ngknet_open, + .release = ngknet_release, + .unlocked_ioctl = ngknet_ioctl, + .compat_ioctl = ngknet_ioctl, + .mmap = ngknet_mmap, +}; + +static int __init +ngknet_init_module(void) +{ + int idx; + int rv; + + rv = register_chrdev(NGKNET_MODULE_MAJOR, NGKNET_MODULE_NAME, &ngknet_fops); + if (rv < 0) { + printk(KERN_WARNING "%s: can't get major %d\n", + NGKNET_MODULE_NAME, NGKNET_MODULE_MAJOR); + return rv; + } + + /* Randomize lower 3 bytes of the MAC address (TESTING ONLY) */ + get_random_bytes(&ngknet_dev_mac[3], 3); + + /* Check for user-supplied MAC address (recommended) */ + if (mac_addr != NULL && strlen(mac_addr) == 17) { + for (idx = 0; idx < 6; idx++) { + ngknet_dev_mac[idx] = simple_strtoul(&mac_addr[idx * 3], NULL, 16); + } + /* Do not allow multicast address */ + ngknet_dev_mac[0] &= ~0x01; + } + + /* Initialize procfs */ + ngknet_procfs_init(); + + /* Initialize Rx rate limit */ + ngknet_rx_rate_limit_init(ngknet_devices); + + return 0; +} + +static void __exit +ngknet_exit_module(void) +{ + int idx; + + /* Cleanup Rx rate limit */ + ngknet_rx_rate_limit_cleanup(); + + /* Cleanup procfs */ + ngknet_procfs_cleanup(); + + /* Remove all the devices */ + for (idx = 0; idx < NUM_PDMA_DEV_MAX; idx++) { + ngknet_dev_remove(idx); + } + + unregister_chrdev(NGKNET_MODULE_MAJOR, NGKNET_MODULE_NAME); +} + +module_init(ngknet_init_module); +module_exit(ngknet_exit_module); + diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_main.h b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_main.h new file mode 100644 index 000000000000..fb38f1b9abc3 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_main.h @@ -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 +#include +#include +#include + +/*! 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 */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_procfs.c b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_procfs.c new file mode 100644 index 000000000000..85edaa26abb9 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_procfs.c @@ -0,0 +1,655 @@ +/*! \file ngknet_procfs.c + * + * + * + */ +/* + * $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 +#include +#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; +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_procfs.h b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_procfs.h new file mode 100644 index 000000000000..3c1938121ebb --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_procfs.h @@ -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 */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_ptp.c b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_ptp.c new file mode 100644 index 000000000000..13579208eab0 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_ptp.c @@ -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 . + * 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 . + * 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 . + * 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 . + * 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 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 . + * 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 is the command defined by the user. The parameter + * and 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); +} + diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_ptp.h b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_ptp.h new file mode 100644 index 000000000000..86dcb6c4904a --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knet/ngknet_ptp.h @@ -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 +#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 */ + diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knetcb/Kbuild b/platform/broadcom/saibcm-modules/sdklt/linux/knetcb/Kbuild new file mode 100644 index 000000000000..2ce66edb3c63 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knetcb/Kbuild @@ -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) diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knetcb/Makefile b/platform/broadcom/saibcm-modules/sdklt/linux/knetcb/Makefile new file mode 100644 index 000000000000..e2acfed49d6c --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knetcb/Makefile @@ -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: diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knetcb/ngknetcb_main.c b/platform/broadcom/saibcm-modules/sdklt/linux/knetcb/ngknetcb_main.c new file mode 100644 index 000000000000..aa248dafce52 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knetcb/ngknetcb_main.c @@ -0,0 +1,444 @@ +/*! \file ngknetcb_main.c + * + * NGKNET Callback module entry. + */ +/* + * $Copyright: (c) 2019 Broadcom. + * Broadcom Proprietary and Confidential. All rights reserved.$ + */ + +#include +#include +#include "psample-cb.h" + +/*! \cond */ +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_DESCRIPTION("NGKNET Callback Module"); +MODULE_LICENSE("GPL"); +/*! \endcond */ + +/*! \cond */ +int debug = 0; +MODULE_PARAM(debug, int, 0); +MODULE_PARM_DESC(debug, +"Debug level (default 0)"); +/*! \endcond */ + +/*! Module information */ +#define NGKNETCB_MODULE_NAME "linux_ngknetcb" +#define NGKNETCB_MODULE_MAJOR 122 + +/* set KNET_CB_DEBUG for debug info */ +#define KNET_CB_DEBUG + +/* These below need to match incoming enum values */ +#define FILTER_TAG_STRIP 0 +#define FILTER_TAG_KEEP 1 +#define FILTER_TAG_ORIGINAL 2 + +/* Maintain tag strip statistics */ +struct strip_stats_s { + unsigned long stripped; /* Number of packets that have been stripped */ + unsigned long checked; + unsigned long skipped; +}; + +static struct strip_stats_s strip_stats; +static unsigned int rx_count = 0; + +/* Local function prototypes */ +static void strip_vlan_tag(struct sk_buff *skb); + +/* Remove VLAN tag for select TPIDs */ +static void +strip_vlan_tag(struct sk_buff *skb) +{ + uint16_t vlan_proto; + uint8_t *pkt = skb->data; + + vlan_proto = (uint16_t) ((pkt[12] << 8) | pkt[13]); + if ((vlan_proto == 0x8100) || (vlan_proto == 0x88a8) || (vlan_proto == 0x9100)) { + /* Move first 12 bytes of packet back by 4 */ + memmove(&skb->data[4], skb->data, 12); + skb_pull(skb, 4); /* Remove 4 bytes from start of buffer */ + } +} + +/* + * The function get_tag_status() returns the tag status. + * 0 = Untagged + * 1 = Single inner-tag + * 2 = Single outer-tag + * 3 = Double tagged. + * -1 = Unsupported type + */ +static int +get_tag_status(uint32_t dev_type, void *meta) +{ + uint32_t *valptr; + uint32_t fd_index; + uint32_t outer_l2_hdr; + int tag_status = -1; + + if ((dev_type == 0xb880) || (dev_type == 0xb780)) + { + /* Field BCM_PKTIO_RXPMD_MATCH_ID_LO has tag status in RX PMD */ + fd_index = 2; + valptr = (uint32_t *)meta; + outer_l2_hdr = (valptr[fd_index] >> ((dev_type == 0xb780) ? 2 : 1) & 0xFF); + + if (outer_l2_hdr & 0x1) { +#ifdef KNET_CB_DEBUG + if (debug & 0x1) { + printk(" L2 Header Present\n"); + } +#endif + tag_status = 0; + if (outer_l2_hdr & 0x4) { +#ifdef KNET_CB_DEBUG + if (debug & 0x1) { + printk(" SNAP/LLC\n"); + } +#endif + tag_status = 0; + } + if (outer_l2_hdr & 0x10) { +#ifdef KNET_CB_DEBUG + if (debug & 0x1) { + printk(" Outer Tagged\n"); + } +#endif + tag_status = 2; + if (outer_l2_hdr & 0x20) { +#ifdef KNET_CB_DEBUG + if (debug & 0x1) { + printk(" Double Tagged\n"); + } +#endif + tag_status = 3; + } + } + else if (outer_l2_hdr & 0x20) { +#ifdef KNET_CB_DEBUG + if (debug & 0x1) { + printk(" Inner Tagged\n"); + } +#endif + tag_status = 1; + } + } + } + else if ((dev_type == 0xb990)|| (dev_type == 0xb996)) + { + fd_index = 9; + valptr = (uint32_t *)meta; + /* On TH4, outer_l2_header means INCOMING_TAG_STATUS. + * TH4 only supports single tagging, so if TAG_STATUS + * says there's a tag, then we don't want to strip. + * Otherwise, we do. + */ + outer_l2_hdr = (valptr[fd_index] >> 13) & 3; + + if (outer_l2_hdr) + { + tag_status = 2; +#ifdef KNET_CB_DEBUG + if (debug & 0x1) + { + printk(" Incoming frame tagged\n"); + } +#endif + } + else + { + tag_status = 0; +#ifdef KNET_CB_DEBUG + if (debug & 0x1) + { + printk(" Incoming frame untagged\n"); + } +#endif + } + } +#ifdef KNET_CB_DEBUG + if (debug & 0x1) { + printk("%s; Device Type: %d; tag status: %d\n", __func__, dev_type, tag_status); + } +#endif + return tag_status; +} + +#ifdef KNET_CB_DEBUG +static void +dump_buffer(uint8_t * data, int size) +{ + const char *const to_hex = "0123456789ABCDEF"; + int i; + char buffer[128]; + char *buffer_ptr; + int addr = 0; + + buffer_ptr = buffer; + for (i = 0; i < size; i++) { + *buffer_ptr++ = ' '; + *buffer_ptr++ = to_hex[(data[i] >> 4) & 0xF]; + *buffer_ptr++ = to_hex[data[i] & 0xF]; + if (((i % 16) == 15) || (i == size - 1)) { + *buffer_ptr = '\0'; + buffer_ptr = buffer; + printk(KERN_INFO "%04X %s\n", addr, buffer); + addr = i + 1; + } + } +} + +static void +show_pmd(uint8_t *pmd, int len) +{ + if (debug & 0x1) { + printk("PMD (%d bytes):\n", len); + dump_buffer(pmd, len); + } +} + +static void +show_mac(uint8_t *pkt) +{ + if (debug & 0x1) { + printk("DMAC=%02X:%02X:%02X:%02X:%02X:%02X\n", + pkt[0], pkt[1], pkt[2], pkt[3], pkt[4], pkt[5]); + } +} +#endif + +static struct sk_buff * +strip_tag_rx_cb(struct sk_buff *skb) +{ + const struct ngknet_callback_desc *cbd = NGKNET_SKB_CB(skb); + const struct ngknet_private *priv = cbd->priv; + int rcpu_mode = 0; + int tag_status; + + rcpu_mode = (priv->flags & NGKNET_NETIF_F_RCPU_ENCAP)? 1 : 0; +#ifdef KNET_CB_DEBUG + if (debug & 0x1) + { + printk(KERN_INFO + "\n%4u --------------------------------------------------------------------------------\n", + rx_count); + printk(KERN_INFO + "RX KNET callback: dev_no=%1d; dev_id=0x%04X; type_str=%4s; RCPU: %3s \n", + cbd->dev_no, cbd->dev_id, cbd->type_str, rcpu_mode ? "yes" : "no"); + printk(KERN_INFO " pkt_len=%4d; pmd_len=%2d; SKB len: %4d\n", + cbd->pkt_len, cbd->pmd_len, skb->len); + if (cbd->filt) { + printk(KERN_INFO "Filter user data: 0x%08x\n", + *(uint32_t *) cbd->filt->user_data); + } + printk(KERN_INFO "Before SKB (%d bytes):\n", skb->len); + dump_buffer(skb->data, skb->len); + printk("rx_cb for dev %d: id 0x%x, %s\n", cbd->dev_no, cbd->dev_id, cbd->type_str); + printk("netif user data: 0x%08x\n", *(uint32_t *)cbd->priv->user_data); + show_pmd(cbd->pmd, cbd->pmd_len); + if (rcpu_mode) { + const int RCPU_header_len = PKT_HDR_SIZE + cbd->pmd_len; + const int payload_len = skb->len - RCPU_header_len; + unsigned char *payload_start = skb->data + payload_len; + + printk(KERN_INFO "Packet Payload (%d bytes):\n", payload_len); + dump_buffer(payload_start, payload_len); + } else { + printk(KERN_INFO "Packet (%d bytes):\n", cbd->pkt_len); + dump_buffer(skb->data, cbd->pkt_len); + } + } +#endif + + if ((!rcpu_mode) && (cbd->filt)) { + if (FILTER_TAG_ORIGINAL == cbd->filt->user_data[0]) { + tag_status = get_tag_status(cbd->dev_id, (void *)cbd->pmd); + if (tag_status < 0) { + strip_stats.skipped++; + goto _strip_tag_rx_cb_exit; + } + strip_stats.checked++; + if (tag_status < 2) { + strip_stats.stripped++; + strip_vlan_tag(skb); + } + } + } +_strip_tag_rx_cb_exit: +#ifdef KNET_CB_DEBUG + if (debug & 0x1) { + printk(KERN_INFO "After SKB (%d bytes):\n", skb->len); + dump_buffer(skb->data, skb->len); + printk(KERN_INFO + "\n%4u --------------------------------------------------------------------------------\n", + rx_count++); + } +#endif + return skb; +} + +static struct sk_buff * +strip_tag_tx_cb(struct sk_buff *skb) +{ +#ifdef KNET_CB_DEBUG + struct ngknet_callback_desc *cbd = NGKNET_SKB_CB(skb); + + if (debug & 0x1) { + printk("tx_cb for dev %d: %s\n", cbd->dev_no, cbd->type_str); + } + show_pmd(cbd->pmd, cbd->pmd_len); + show_mac(cbd->pmd + cbd->pmd_len); +#endif + return skb; +} + +static struct sk_buff * +ngknet_rx_cb(struct sk_buff *skb) +{ + skb = strip_tag_rx_cb(skb); +#ifdef PSAMPLE_SUPPORT + skb = psample_rx_cb(skb); +#endif + return skb; +} + +static struct sk_buff * +ngknet_tx_cb(struct sk_buff *skb) +{ + skb = strip_tag_tx_cb(skb); + return skb; +} + +static int +ngknet_netif_create_cb(struct net_device *dev) +{ + int retv = 0; +#ifdef PSAMPLE_SUPPORT + retv = psample_netif_create_cb(dev); +#endif + return retv; +} + +static int +ngknet_netif_destroy_cb(struct net_device *dev) +{ + int retv = 0; +#ifdef PSAMPLE_SUPPORT + retv = psample_netif_destroy_cb(dev); +#endif + return retv; +} + +/*! + * Generic module functions + */ +static int +ngknetcb_show(struct seq_file *m, void *v) +{ + seq_printf(m, "Broadcom Linux NGKNET Callback: Untagged VLAN Stripper\n"); + seq_printf(m, " %lu stripped packets\n", strip_stats.stripped); + seq_printf(m, " %lu packets checked\n", strip_stats.checked); + seq_printf(m, " %lu packets skipped\n", strip_stats.skipped); + return 0; +} + +static int +ngknetcb_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, ngknetcb_show, NULL); +} + +static int +ngknetcb_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +static ssize_t +ngknetcb_write(struct file *file, const char *buf, + size_t count, loff_t *loff) +{ + memset(&strip_stats, 0, sizeof(strip_stats)); + printk("Cleared NGKNET callback stats\n"); + return count; +} + +static long +ngknetcb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static int +ngknetcb_mmap(struct file *filp, struct vm_area_struct *vma) +{ + return 0; +} + +static struct file_operations ngknetcb_fops = { + .owner = THIS_MODULE, + .open = ngknetcb_open, + .read = seq_read, + .write = ngknetcb_write, + .llseek = seq_lseek, + .release = ngknetcb_release, + .unlocked_ioctl = ngknetcb_ioctl, + .compat_ioctl = ngknetcb_ioctl, + .mmap = ngknetcb_mmap, +}; + +static int __init +ngknetcb_init_module(void) +{ + int rv; + struct proc_dir_entry *entry = NULL; + + rv = register_chrdev(NGKNETCB_MODULE_MAJOR, NGKNETCB_MODULE_NAME, &ngknetcb_fops); + if (rv < 0) { + printk(KERN_WARNING "%s: can't get major %d\n", + NGKNETCB_MODULE_NAME, NGKNETCB_MODULE_MAJOR); + return rv; + } + + PROC_CREATE(entry, NGKNETCB_MODULE_NAME, 0666, NULL, &ngknetcb_fops); + if (entry == NULL) { + printk(KERN_ERR "%s: proc_mkdir failed\n", + NGKNETCB_MODULE_NAME); + } + + ngknet_rx_cb_register(ngknet_rx_cb); + ngknet_tx_cb_register(ngknet_tx_cb); + +#ifdef PSAMPLE_SUPPORT + psample_init(); +#endif + + ngknet_netif_create_cb_register(ngknet_netif_create_cb); + ngknet_netif_destroy_cb_register(ngknet_netif_destroy_cb); + return 0; +} + +static void __exit +ngknetcb_exit_module(void) +{ + ngknet_netif_create_cb_unregister(ngknet_netif_create_cb); + ngknet_netif_destroy_cb_unregister(ngknet_netif_destroy_cb); + +#ifdef PSAMPLE_SUPPORT + psample_cleanup(); +#endif + + ngknet_rx_cb_unregister(ngknet_rx_cb); + ngknet_tx_cb_unregister(ngknet_tx_cb); + + remove_proc_entry(NGKNETCB_MODULE_NAME, NULL); + + unregister_chrdev(NGKNETCB_MODULE_MAJOR, NGKNETCB_MODULE_NAME); +} + +module_init(ngknetcb_init_module); +module_exit(ngknetcb_exit_module); diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knetcb/psample-cb.c b/platform/broadcom/saibcm-modules/sdklt/linux/knetcb/psample-cb.c new file mode 100644 index 000000000000..be34430218d3 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knetcb/psample-cb.c @@ -0,0 +1,995 @@ +/* + * Copyright 2017-2019 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: psample_cb.c $ + * $Copyright: (c) 2019 Broadcom Corp. + * All Rights Reserved.$ + */ + +/* + * Driver for call-back functions for Linux KNET driver. + * + * This code is used to integrate packet sampling KNET callback to + * the psample infra for sending sampled pkts to userspace sflow + * applications such as Host Sflow (https://github.com/sflow/host-sflow) + * using genetlink interfaces. + * + * The module can be built from the standard Linux user mode target + * directories using the following command (assuming bash), e.g. + * + * cd $SDK/systems/linux/user/ + * make BUILD_KNET_CB=1 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "psample-cb.h" + +#define PSAMPLE_CB_DBG +#ifdef PSAMPLE_CB_DBG +extern int debug; +#define PSAMPLE_CB_DBG_LVL_VERB (0x1) +#define PSAMPLE_CB_DBG_LVL_PMD (0x2) +#define PSAMPLE_CB_DBG_PRINT(...) if (debug & PSAMPLE_CB_DBG_LVL_VERB) { printk(__VA_ARGS__); } +#define PSAMPLE_CB_PMD_PRINT(...) if (debug & PSAMPLE_CB_DBG_LVL_PMD) { printk(__VA_ARGS__); } +#else +#define PSAMPLE_CB_DBG_PRINT(...) +#define PSAMPLE_CB_PMD_PRINT(...) +#endif + +#define FCS_SZ 4 +#define PSAMPLE_NLA_PADDING 4 +#define PSAMPLE_PKT_HANDLED (1) + +#define PSAMPLE_RATE_DFLT 1 +#define PSAMPLE_SIZE_DFLT 128 +static int psample_size = PSAMPLE_SIZE_DFLT; +MODULE_PARAM(psample_size, int, 0); +MODULE_PARM_DESC(psample_size, +"psample pkt size (default 128 bytes)"); + +#define PSAMPLE_QLEN_DFLT 1024 +static int psample_qlen = PSAMPLE_QLEN_DFLT; +MODULE_PARAM(psample_qlen, int, 0); +MODULE_PARM_DESC(psample_qlen, +"psample queue length (default 1024 buffers)"); + +/* driver proc entry root */ +static struct proc_dir_entry *psample_proc_root = NULL; +static struct proc_dir_entry *knet_cb_proc_root = NULL; + +/* psample general info */ +typedef struct { + struct list_head netif_list; + int netif_count; + struct net *netns; + spinlock_t lock; + int dcb_type; +} psample_info_t; +static psample_info_t g_psample_info = {0}; + +/* Maintain sampled pkt statistics */ +typedef struct psample_stats_s { + unsigned long pkts_f_psample_cb; + unsigned long pkts_f_psample_mod; + unsigned long pkts_f_handled; + unsigned long pkts_f_pass_through; + unsigned long pkts_f_dst_mc; + unsigned long pkts_c_qlen_cur; + unsigned long pkts_c_qlen_hi; + unsigned long pkts_d_qlen_max; + unsigned long pkts_d_no_mem; + unsigned long pkts_d_no_group; + unsigned long pkts_d_sampling_disabled; + unsigned long pkts_d_not_ready; + unsigned long pkts_d_metadata; + unsigned long pkts_d_skb; + unsigned long pkts_d_skb_cbd; + unsigned long pkts_d_meta_srcport; + unsigned long pkts_d_meta_dstport; + unsigned long pkts_d_invalid_size; +} psample_stats_t; +static psample_stats_t g_psample_stats = {0}; + +typedef struct psample_meta_s { + int trunc_size; + int src_ifindex; + int dst_ifindex; + int sample_rate; +} psample_meta_t; + +typedef struct psample_pkt_s { + struct list_head list; + struct psample_group *group; + psample_meta_t meta; + struct sk_buff *skb; +} psample_pkt_t; + +typedef struct psample_work_s { + struct list_head pkt_list; + struct work_struct wq; + spinlock_t lock; +} psample_work_t; +static psample_work_t g_psample_work = {0}; + +static psample_netif_t* +psample_netif_lookup_by_ifindex(int ifindex) +{ + struct list_head *list; + psample_netif_t *psample_netif = NULL; + unsigned long flags; + + /* look for port from list of available net_devices */ + spin_lock_irqsave(&g_psample_info.lock, flags); + list_for_each(list, &g_psample_info.netif_list) { + psample_netif = (psample_netif_t*)list; + if (psample_netif->dev->ifindex == ifindex) { + spin_unlock_irqrestore(&g_psample_info.lock, flags); + return psample_netif; + } + } + spin_unlock_irqrestore(&g_psample_info.lock, flags); + return (NULL); +} + +static psample_netif_t* +psample_netif_lookup_by_port(int port) +{ + struct list_head *list; + psample_netif_t *psample_netif = NULL; + unsigned long flags; + + /* look for port from list of available net_devices */ + spin_lock_irqsave(&g_psample_info.lock, flags); + list_for_each(list, &g_psample_info.netif_list) { + psample_netif = (psample_netif_t*)list; + if (psample_netif->port == port) { + spin_unlock_irqrestore(&g_psample_info.lock, flags); + return psample_netif; + } + } + spin_unlock_irqrestore(&g_psample_info.lock, flags); + return (NULL); +} + +static int +psample_meta_sample_reason(uint8_t *pkt, void *pkt_meta) +{ + uint32_t *metadata = (uint32_t*)pkt_meta; + uint32_t reason = 0; + uint32_t reason_hi = 0; + uint32_t sample_rx_reason_mask = 0; + + if (metadata) { + /* Sample Pkt reason code (bcmRxReasonSampleSource) */ + switch(g_psample_info.dcb_type) { + case 36: /* TD3 */ + case 38: /* TH3 */ + reason_hi = *(metadata + 4); + reason = *(metadata + 5); + sample_rx_reason_mask = (1 << 3); + break; + case 32: /* TH1/TH2 */ + case 26: /* TD2 */ + case 23: /* HX4 */ + reason_hi = *(metadata + 2); + reason = *(metadata + 3); + sample_rx_reason_mask = (1 << 5); + break; + default: + break; + } + } + PSAMPLE_CB_DBG_PRINT("%s: DCB%d sample_rx_reason_mask: 0x%08x, reason: 0x%08x, reason_hi: 0x%08x\n", + __func__, g_psample_info.dcb_type, sample_rx_reason_mask, reason, reason_hi); + + /* Check if only sample reason code is set. + * If only sample reason code, then consume pkt. + * If other reason codes exist, then pkt should be + * passed through to Linux network stack. + */ + if ((reason & ~sample_rx_reason_mask) || reason_hi) { + return 0; /* multiple reasons set, pass through */ + } + + /* only sample rx reason set, consume pkt */ + return (PSAMPLE_PKT_HANDLED); +} + +static int +psample_meta_get(struct sk_buff *skb, psample_meta_t *sflow_meta) +{ + int src_ifindex = 0; + int sample_rate = 1; + int sample_size = PSAMPLE_SIZE_DFLT; + psample_netif_t *psample_netif = NULL; + const struct ngknet_callback_desc *cbd = NGKNET_SKB_CB(skb); + const struct ngknet_private *netif = cbd->priv; + memset(sflow_meta, 0, sizeof(psample_meta_t)); + + /* find src port */ + if ((psample_netif = psample_netif_lookup_by_ifindex(netif->net_dev->ifindex))) { + src_ifindex = psample_netif->dev->ifindex; + sample_rate = psample_netif->sample_rate; + sample_size = psample_netif->sample_size; + } else { + g_psample_stats.pkts_d_meta_srcport++; + PSAMPLE_CB_DBG_PRINT("%s: could not find psample netif for src dev %s (ifidx %d)\n", + __func__, netif->net_dev->name, netif->net_dev->ifindex); + } + + sflow_meta->src_ifindex = src_ifindex; + sflow_meta->trunc_size = sample_size; + sflow_meta->sample_rate = sample_rate; + return (0); +} + +static void +psample_task(struct work_struct *work) +{ + psample_work_t *psample_work = container_of(work, psample_work_t, wq); + unsigned long flags; + struct list_head *list_ptr, *list_next; + psample_pkt_t *pkt; + + spin_lock_irqsave(&psample_work->lock, flags); + list_for_each_safe(list_ptr, list_next, &psample_work->pkt_list) { + /* dequeue pkt from list */ + pkt = list_entry(list_ptr, psample_pkt_t, list); + list_del(list_ptr); + g_psample_stats.pkts_c_qlen_cur--; + spin_unlock_irqrestore(&psample_work->lock, flags); + + /* send to psample */ + if (pkt) { + PSAMPLE_CB_DBG_PRINT("%s: group 0x%x, trunc_size %d, src_ifdx 0x%x, dst_ifdx 0x%x, sample_rate %d\n", + __func__, pkt->group->group_num, + pkt->meta.trunc_size, pkt->meta.src_ifindex, + pkt->meta.dst_ifindex, pkt->meta.sample_rate); + + psample_sample_packet(pkt->group, + pkt->skb, + pkt->meta.trunc_size, + pkt->meta.src_ifindex, + pkt->meta.dst_ifindex, + pkt->meta.sample_rate); + g_psample_stats.pkts_f_psample_mod++; + + dev_kfree_skb_any(pkt->skb); + kfree(pkt); + } + spin_lock_irqsave(&psample_work->lock, flags); + } + spin_unlock_irqrestore(&psample_work->lock, flags); +} + +struct sk_buff* +psample_rx_cb(struct sk_buff *skb) +{ + struct psample_group *group; + psample_meta_t meta; + int rv = 0, size; + const struct ngknet_callback_desc *cbd = NULL; + const struct ngknet_private *netif = NULL; + const struct ngknet_filter_s *filt = NULL; + const struct ngknet_filter_s *filt_src = NULL; + + if (!skb) { + printk("%s: skb is NULL\n", __func__); + g_psample_stats.pkts_d_skb++; + return (NULL); + } + cbd = NGKNET_SKB_CB(skb); + netif = cbd->priv; + filt_src = cbd->filt; + filt = cbd->filt_cb; + + if (!cbd || !netif || !filt_src) { + printk("%s: cbd(0x%p) or priv(0x%p) or filter src(0x%p) is NULL\n", + __func__, cbd, netif, filt_src); + g_psample_stats.pkts_d_skb_cbd++; + return (skb); + } + + /* Enable PMD output in dmesg: "echo "debug=0x2" > /proc/bcm/knet-cb/psample/debug" + * Use bshell cmd "pmddecode rxpmd ..." to decode pkt metadata + */ + if (debug & PSAMPLE_CB_DBG_LVL_PMD) { + char str[128]; + int i, len = cbd->pmd_len > 128? 128 : cbd->pmd_len; + PSAMPLE_CB_PMD_PRINT("PMD (%d bytes): %s\n", + cbd->pmd_len, skb->dev->name); + for (i=0; ipmd+i))); + if ((i & 0x1c) == 0x1c) { + sprintf(&str[strlen(str)], "\n"); + printk(str); + continue; + } + } + if ((i & 0x1f) != 0) { + sprintf(&str[strlen(str)], "\n"); + PSAMPLE_CB_PMD_PRINT(str); + } + } + + /* check if this packet is sampled packet (from sample filter) */ + if (!filt || + (NGKNET_FILTER_DEST_T_CB != filt->dest_type) || + (strncmp(filt->desc, PSAMPLE_CB_NAME, NGKNET_FILTER_DESC_MAX) != 0)) { + return (skb); + } + + PSAMPLE_CB_DBG_PRINT("%s: src dev %s, pkt size %d, filt->dest_id %d\n", + __func__, skb->dev->name, cbd->pkt_len, filt->dest_id); + g_psample_stats.pkts_f_psample_cb++; + + /* get psample group info. psample genetlink group ID passed in filt->dest_id */ + group = psample_group_get(g_psample_info.netns, filt->dest_id); + if (!group) { + printk("%s: Could not find psample genetlink group %d\n", __func__, filt->dest_id); + g_psample_stats.pkts_d_no_group++; + goto PSAMPLE_FILTER_CB_PKT_HANDLED; + } + + /* get psample metadata */ + rv = psample_meta_get(skb, &meta); + if (rv < 0) { + printk("%s: Could not parse pkt metadata\n", __func__); + g_psample_stats.pkts_d_metadata++; + goto PSAMPLE_FILTER_CB_PKT_HANDLED; + } + + /* Adjust original pkt size to remove 4B FCS */ + size = cbd->pkt_len; + if (size < FCS_SZ) { + g_psample_stats.pkts_d_invalid_size++; + goto PSAMPLE_FILTER_CB_PKT_HANDLED; + } else { + size -= FCS_SZ; + } + + /* Account for padding in libnl used by psample */ + if (meta.trunc_size >= size) { + meta.trunc_size = size - PSAMPLE_NLA_PADDING; + } + + PSAMPLE_CB_DBG_PRINT("%s: group 0x%x, trunc_size %d, src_ifdx 0x%x, dst_ifdx 0x%x, sample_rate %d\n", + __func__, group->group_num, meta.trunc_size, meta.src_ifindex, meta.dst_ifindex, meta.sample_rate); + + /* drop if configured sample rate is 0 */ + if (meta.sample_rate > 0) { + unsigned long flags; + psample_pkt_t *psample_pkt; + struct sk_buff *skb_psample; + + if (g_psample_stats.pkts_c_qlen_cur >= psample_qlen) { + printk("%s: tail drop due to max qlen %d reached\n", __func__, psample_qlen); + g_psample_stats.pkts_d_qlen_max++; + goto PSAMPLE_FILTER_CB_PKT_HANDLED; + } + + if ((psample_pkt = kmalloc(sizeof(psample_pkt_t), GFP_ATOMIC)) == NULL) { + printk("%s: failed to alloc psample mem for pkt\n", __func__); + g_psample_stats.pkts_d_no_mem++; + goto PSAMPLE_FILTER_CB_PKT_HANDLED; + } + memcpy(&psample_pkt->meta, &meta, sizeof(psample_meta_t)); + psample_pkt->group = group; + + if ((skb_psample = dev_alloc_skb(meta.trunc_size)) == NULL) { + printk("%s: failed to alloc psample mem for pkt skb\n", __func__); + g_psample_stats.pkts_d_no_mem++; + goto PSAMPLE_FILTER_CB_PKT_HANDLED; + } + + /* setup skb to point to pkt */ + memcpy(skb_psample->data, skb->data, meta.trunc_size); + skb_put(skb_psample, meta.trunc_size); + skb_psample->len = meta.trunc_size; + psample_pkt->skb = skb_psample; + + spin_lock_irqsave(&g_psample_work.lock, flags); + list_add_tail(&psample_pkt->list, &g_psample_work.pkt_list); + + g_psample_stats.pkts_c_qlen_cur++; + if (g_psample_stats.pkts_c_qlen_cur > g_psample_stats.pkts_c_qlen_hi) { + g_psample_stats.pkts_c_qlen_hi = g_psample_stats.pkts_c_qlen_cur; + } + + schedule_work(&g_psample_work.wq); + spin_unlock_irqrestore(&g_psample_work.lock, flags); + } else { + g_psample_stats.pkts_d_sampling_disabled++; + } + +PSAMPLE_FILTER_CB_PKT_HANDLED: + /* if sample reason only, consume pkt. else pass through */ + rv = psample_meta_sample_reason(skb->data, cbd->pmd); + if (rv) { + g_psample_stats.pkts_f_handled++; + return NULL; + } + g_psample_stats.pkts_f_pass_through++; + return skb; +} + +int +psample_netif_create_cb(struct net_device *dev) +{ + int found; + struct list_head *list; + psample_netif_t *psample_netif, *lpsample_netif; + unsigned long flags; + struct ngknet_private *netif = NULL; + + if (!dev) { + printk("%s: net_device is NULL\n", __func__); + return (-1); + } + netif = netdev_priv(dev); + + if ((psample_netif = kmalloc(sizeof(psample_netif_t), GFP_ATOMIC)) == NULL) { + printk("%s: failed to alloc psample mem for netif '%s'\n", + __func__, dev->name); + return (-1); + } + + spin_lock_irqsave(&g_psample_info.lock, flags); + + psample_netif->dev = dev; + psample_netif->id = netif->id; + /* FIXME: port is not saved in ngknet_private, need to get from metadata?? */ + //psample_netif->port = netif->port; + psample_netif->vlan = netif->vlan; + psample_netif->sample_rate = PSAMPLE_RATE_DFLT; + psample_netif->sample_size = PSAMPLE_SIZE_DFLT; + + /* insert netif sorted by ID similar to bkn_knet_netif_create() */ + found = 0; + list_for_each(list, &g_psample_info.netif_list) { + lpsample_netif = (psample_netif_t*)list; + if (netif->id < lpsample_netif->id) { + found = 1; + g_psample_info.netif_count++; + break; + } + } + + if (found) { + /* Replace previously removed interface */ + list_add_tail(&psample_netif->list, &lpsample_netif->list); + } else { + /* No holes - add to end of list */ + list_add_tail(&psample_netif->list, &g_psample_info.netif_list); + } + + spin_unlock_irqrestore(&g_psample_info.lock, flags); + + PSAMPLE_CB_DBG_PRINT("%s: added psample netif '%s'\n", __func__, dev->name); + return (0); +} + +int +psample_netif_destroy_cb(struct net_device *dev) +{ + int found; + struct list_head *list; + psample_netif_t *psample_netif; + unsigned long flags; + struct ngknet_private *netif = NULL; + + if (!dev) { + printk("%s: net_device is NULL\n", __func__); + return (-1); + } + netif = netdev_priv(dev); + + spin_lock_irqsave(&g_psample_info.lock, flags); + + list_for_each(list, &g_psample_info.netif_list) { + psample_netif = (psample_netif_t*)list; + if (netif->id == psample_netif->id) { + found = 1; + list_del(&psample_netif->list); + PSAMPLE_CB_DBG_PRINT("%s: removing psample netif '%s'\n", __func__, dev->name); + kfree(psample_netif); + g_psample_info.netif_count--; + break; + } + } + + spin_unlock_irqrestore(&g_psample_info.lock, flags); + + if (!found) { + printk("%s: netif ID %d not found!\n", __func__, netif->id); + return (-1); + } + return (0); +} + +/* + * psample rate Proc Read Entry + */ +static int +psample_proc_rate_show(struct seq_file *m, void *v) +{ + struct list_head *list; + psample_netif_t *psample_netif; + unsigned long flags; + + spin_lock_irqsave(&g_psample_info.lock, flags); + + list_for_each(list, &g_psample_info.netif_list) { + psample_netif = (psample_netif_t*)list; + seq_printf(m, " %-14s %d\n", psample_netif->dev->name, psample_netif->sample_rate); + } + + spin_unlock_irqrestore(&g_psample_info.lock, flags); + + return 0; +} + +static int +psample_proc_rate_open(struct inode * inode, struct file * file) +{ + return single_open(file, psample_proc_rate_show, NULL); +} + +/* + * psample rate Proc Write Entry + * + * Syntax: + * = + * + * Where is a virtual network interface name. + * + * Examples: + * eth4=1000 + */ +static ssize_t +psample_proc_rate_write(struct file *file, const char *buf, + size_t count, loff_t *loff) +{ + int found; + struct list_head *list; + psample_netif_t *psample_netif; + char sample_str[40], *ptr, *newline; + unsigned long flags; + + + if (count > sizeof(sample_str)) { + count = sizeof(sample_str) - 1; + sample_str[count] = '\0'; + } + if (copy_from_user(sample_str, buf, count)) { + return -EFAULT; + } + sample_str[count] = 0; + newline = strchr(sample_str, '\n'); + if (newline) { + /* Chop off the trailing newline */ + *newline = '\0'; + } + + if ((ptr = strchr(sample_str, '=')) == NULL && + (ptr = strchr(sample_str, ':')) == NULL) { + printk("Error: Pkt sample rate syntax not recognized: '%s'\n", sample_str); + return count; + } + *ptr++ = 0; + + spin_lock_irqsave(&g_psample_info.lock, flags); + + found = 0; + list_for_each(list, &g_psample_info.netif_list) { + psample_netif = (psample_netif_t*)list; + if (strcmp(psample_netif->dev->name, sample_str) == 0) { + psample_netif->sample_rate = simple_strtol(ptr, NULL, 10); + // TODO MLI@BRCM - check valid sample rate + found = 1; + break; + } + } + + spin_unlock_irqrestore(&g_psample_info.lock, flags); + + if (!found) { + printk("Warning: Failed setting psample rate on unknown network interface: '%s'\n", sample_str); + } + return count; +} + +struct file_operations psample_proc_rate_file_ops = { + owner: THIS_MODULE, + open: psample_proc_rate_open, + read: seq_read, + llseek: seq_lseek, + write: psample_proc_rate_write, + release: single_release, +}; + +/* + * psample size Proc Read Entry + */ +static int +psample_proc_size_show(struct seq_file *m, void *v) +{ + struct list_head *list; + psample_netif_t *psample_netif; + unsigned long flags; + + spin_lock_irqsave(&g_psample_info.lock, flags); + + list_for_each(list, &g_psample_info.netif_list) { + psample_netif = (psample_netif_t*)list; + seq_printf(m, " %-14s %d\n", psample_netif->dev->name, psample_netif->sample_size); + } + + spin_unlock_irqrestore(&g_psample_info.lock, flags); + return 0; +} + +static int +psample_proc_size_open(struct inode * inode, struct file * file) +{ + return single_open(file, psample_proc_size_show, NULL); +} + +/* + * psample size Proc Write Entry + * + * Syntax: + * = + * + * Where is a virtual network interface name. + * + * Examples: + * eth4=128 + */ +static ssize_t +psample_proc_size_write(struct file *file, const char *buf, + size_t count, loff_t *loff) +{ + int found; + struct list_head *list; + psample_netif_t *psample_netif; + char sample_str[40], *ptr, *newline; + unsigned long flags; + + if (count > sizeof(sample_str)) { + count = sizeof(sample_str) - 1; + sample_str[count] = '\0'; + } + if (copy_from_user(sample_str, buf, count)) { + return -EFAULT; + } + sample_str[count] = 0; + newline = strchr(sample_str, '\n'); + if (newline) { + /* Chop off the trailing newline */ + *newline = '\0'; + } + + if ((ptr = strchr(sample_str, '=')) == NULL && + (ptr = strchr(sample_str, ':')) == NULL) { + printk("Error: Pkt sample size syntax not recognized: '%s'\n", sample_str); + return count; + } + *ptr++ = 0; + + spin_lock_irqsave(&g_psample_info.lock, flags); + + found = 0; + list_for_each(list, &g_psample_info.netif_list) { + psample_netif = (psample_netif_t*)list; + if (strcmp(psample_netif->dev->name, sample_str) == 0) { + psample_netif->sample_size = simple_strtol(ptr, NULL, 10); + // TODO MLI@BRCM - check valid sample size + found = 1; + break; + } + } + + spin_unlock_irqrestore(&g_psample_info.lock, flags); + + if (!found) { + printk("Warning: Failed setting psample size on unknown network interface: '%s'\n", sample_str); + } + return count; +} + +struct file_operations psample_proc_size_file_ops = { + owner: THIS_MODULE, + open: psample_proc_size_open, + read: seq_read, + llseek: seq_lseek, + write: psample_proc_size_write, + release: single_release, +}; + +/* + * psample map Proc Read Entry + */ +static int +psample_proc_map_show(struct seq_file *m, void *v) +{ + struct list_head *list; + psample_netif_t *psample_netif; + unsigned long flags; + + seq_printf(m, " Interface logical port ifindex\n"); + seq_printf(m, "------------- ------------ -------\n"); + spin_lock_irqsave(&g_psample_info.lock, flags); + + list_for_each(list, &g_psample_info.netif_list) { + psample_netif = (psample_netif_t*)list; + seq_printf(m, " %-14s %-14d %d\n", + psample_netif->dev->name, + psample_netif->port, + psample_netif->dev->ifindex); + } + + spin_unlock_irqrestore(&g_psample_info.lock, flags); + return 0; +} + +static int +psample_proc_map_open(struct inode * inode, struct file * file) +{ + return single_open(file, psample_proc_map_show, NULL); +} + +struct file_operations psample_proc_map_file_ops = { + owner: THIS_MODULE, + open: psample_proc_map_open, + read: seq_read, + llseek: seq_lseek, + write: NULL, + release: single_release, +}; + +/* + * psample debug Proc Read Entry + */ +static int +psample_proc_debug_show(struct seq_file *m, void *v) +{ + seq_printf(m, "BCM KNET %s Callback Config\n", PSAMPLE_CB_NAME); + seq_printf(m, " debug: 0x%x\n", debug); + seq_printf(m, " dcb_type: %d\n", g_psample_info.dcb_type); + seq_printf(m, " netif_count: %d\n", g_psample_info.netif_count); + seq_printf(m, " queue length: %d\n", psample_qlen); + + return 0; +} + +static int +psample_proc_debug_open(struct inode * inode, struct file * file) +{ + return single_open(file, psample_proc_debug_show, NULL); +} + +/* + * psample debug Proc Write Entry + * + * Syntax: + * debug= + * + * Where corresponds to the debug module parameter. + * + * Examples: + * debug=0x1 + */ +static ssize_t +psample_proc_debug_write(struct file *file, const char *buf, + size_t count, loff_t *loff) +{ + char debug_str[40]; + char *ptr; + + if (count > sizeof(debug_str)) { + count = sizeof(debug_str) - 1; + debug_str[count] = '\0'; + } + if (copy_from_user(debug_str, buf, count)) { + return -EFAULT; + } + + if ((ptr = strstr(debug_str, "debug=")) != NULL) { + ptr += 6; + debug = simple_strtol(ptr, NULL, 0); + } else { + printk("Warning: unknown configuration setting\n"); + } + + return count; +} + +struct file_operations psample_proc_debug_file_ops = { + owner: THIS_MODULE, + open: psample_proc_debug_open, + read: seq_read, + llseek: seq_lseek, + write: psample_proc_debug_write, + release: single_release, +}; + +static int +psample_proc_stats_show(struct seq_file *m, void *v) +{ + seq_printf(m, "BCM KNET %s Callback Stats\n", PSAMPLE_CB_NAME); + seq_printf(m, " DCB type %d\n", g_psample_info.dcb_type); + seq_printf(m, " pkts filter psample cb %10lu\n", g_psample_stats.pkts_f_psample_cb); + seq_printf(m, " pkts sent to psample module %10lu\n", g_psample_stats.pkts_f_psample_mod); + seq_printf(m, " pkts handled by psample %10lu\n", g_psample_stats.pkts_f_handled); + seq_printf(m, " pkts pass through %10lu\n", g_psample_stats.pkts_f_pass_through); + seq_printf(m, " pkts with mc destination %10lu\n", g_psample_stats.pkts_f_dst_mc); + seq_printf(m, " pkts current queue length %10lu\n", g_psample_stats.pkts_c_qlen_cur); + seq_printf(m, " pkts high queue length %10lu\n", g_psample_stats.pkts_c_qlen_hi); + seq_printf(m, " pkts drop max queue length %10lu\n", g_psample_stats.pkts_d_qlen_max); + seq_printf(m, " pkts drop no memory %10lu\n", g_psample_stats.pkts_d_no_mem); + seq_printf(m, " pkts drop no psample group %10lu\n", g_psample_stats.pkts_d_no_group); + seq_printf(m, " pkts drop sampling disabled %10lu\n", g_psample_stats.pkts_d_sampling_disabled); + seq_printf(m, " pkts drop psample not ready %10lu\n", g_psample_stats.pkts_d_not_ready); + seq_printf(m, " pkts drop metadata parse error %10lu\n", g_psample_stats.pkts_d_metadata); + seq_printf(m, " pkts drop skb error %10lu\n", g_psample_stats.pkts_d_skb); + seq_printf(m, " pkts drop skb cbd error %10lu\n", g_psample_stats.pkts_d_skb_cbd); + seq_printf(m, " pkts with invalid src port %10lu\n", g_psample_stats.pkts_d_meta_srcport); + seq_printf(m, " pkts with invalid dst port %10lu\n", g_psample_stats.pkts_d_meta_dstport); + seq_printf(m, " pkts with invalid orig pkt sz %10lu\n", g_psample_stats.pkts_d_invalid_size); + return 0; +} + +static int +psample_proc_stats_open(struct inode * inode, struct file * file) +{ + return single_open(file, psample_proc_stats_show, NULL); +} + +/* + * psample stats Proc Write Entry + * + * Syntax: + * write any value to clear stats + */ +static ssize_t +psample_proc_stats_write(struct file *file, const char *buf, + size_t count, loff_t *loff) +{ + int qlen_cur = 0; + unsigned long flags; + + spin_lock_irqsave(&g_psample_work.lock, flags); + qlen_cur = g_psample_stats.pkts_c_qlen_cur; + memset(&g_psample_stats, 0, sizeof(psample_stats_t)); + g_psample_stats.pkts_c_qlen_cur = qlen_cur; + spin_unlock_irqrestore(&g_psample_work.lock, flags); + + return count; +} +struct file_operations psample_proc_stats_file_ops = { + owner: THIS_MODULE, + open: psample_proc_stats_open, + read: seq_read, + llseek: seq_lseek, + write: psample_proc_stats_write, + release: single_release, +}; + +int psample_cleanup(void) +{ + cancel_work_sync(&g_psample_work.wq); + remove_proc_entry("stats", psample_proc_root); + remove_proc_entry("rate", psample_proc_root); + remove_proc_entry("size", psample_proc_root); + remove_proc_entry("debug", psample_proc_root); + remove_proc_entry("map" , psample_proc_root); + remove_proc_entry("psample", knet_cb_proc_root); + remove_proc_entry("bcm/knet-cb", NULL); + remove_proc_entry("bcm", NULL); + return 0; +} + +int psample_init(void) +{ + #define PROCFS_MAX_PATH 1024 + char psample_procfs_path[PROCFS_MAX_PATH]; + struct proc_dir_entry *entry; + + /* initialize proc files (for ngknet) */ + proc_mkdir("bcm", NULL); + + /* create procfs for psample */ + snprintf(psample_procfs_path, PROCFS_MAX_PATH, "bcm/knet-cb"); + knet_cb_proc_root = proc_mkdir(psample_procfs_path, NULL); + snprintf(psample_procfs_path, PROCFS_MAX_PATH, "%s/%s", psample_procfs_path, PSAMPLE_CB_NAME); + psample_proc_root = proc_mkdir(psample_procfs_path, NULL); + + /* create procfs for psample stats */ + PROC_CREATE(entry, "stats", 0666, psample_proc_root, &psample_proc_stats_file_ops); + if (entry == NULL) { + printk("%s: Unable to create procfs entry '/procfs/%s/stats'\n", __func__, psample_procfs_path); + return -1; + } + + /* create procfs for setting sample rates */ + PROC_CREATE(entry, "rate", 0666, psample_proc_root, &psample_proc_rate_file_ops); + if (entry == NULL) { + printk("%s: Unable to create procfs entry '/procfs/%s/rate'\n", __func__, psample_procfs_path); + return -1; + } + + /* create procfs for setting sample size */ + PROC_CREATE(entry, "size", 0666, psample_proc_root, &psample_proc_size_file_ops); + if (entry == NULL) { + printk("%s: Unable to create procfs entry '/procfs/%s/size'\n", __func__, psample_procfs_path); + return -1; + } + + /* create procfs for getting netdev mapping */ + PROC_CREATE(entry, "map", 0666, psample_proc_root, &psample_proc_map_file_ops); + if (entry == NULL) { + printk("%s: Unable to create procfs entry '/procfs/%s/map'\n", __func__, psample_procfs_path); + return -1; + } + + /* create procfs for debug log */ + PROC_CREATE(entry, "debug", 0666, psample_proc_root, &psample_proc_debug_file_ops); + if (entry == NULL) { + printk("%s: Unable to create procfs entry '/procfs/%s/debug'\n", __func__, psample_procfs_path); + return -1; + } + + /* clear data structs */ + memset(&g_psample_stats, 0, sizeof(psample_stats_t)); + memset(&g_psample_info, 0, sizeof(psample_info_t)); + memset(&g_psample_work, 0, sizeof(psample_work_t)); + + /* FIXME: How to get DCB type from NGKNET? */ + //g_psample_info.dcb_type + + /* setup psample_info struct */ + INIT_LIST_HEAD(&g_psample_info.netif_list); + spin_lock_init(&g_psample_info.lock); + + /* setup psample work queue */ + spin_lock_init(&g_psample_work.lock); + INIT_LIST_HEAD(&g_psample_work.pkt_list); + INIT_WORK(&g_psample_work.wq, psample_task); + + /* get net namespace */ + g_psample_info.netns = get_net_ns_by_pid(current->pid); + if (!g_psample_info.netns) { + printk("%s: Could not get network namespace for pid %d\n", __func__, current->pid); + return (-1); + } + PSAMPLE_CB_DBG_PRINT("%s: current->pid %d, netns 0x%p, sample_size %d\n", __func__, + current->pid, g_psample_info.netns, psample_size); + + + return 0; +} diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/knetcb/psample-cb.h b/platform/broadcom/saibcm-modules/sdklt/linux/knetcb/psample-cb.h new file mode 100644 index 000000000000..2e3342ead5c3 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/knetcb/psample-cb.h @@ -0,0 +1,57 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +/* + * $Id: psample_cb.h $ + * $Copyright: (c) 2019 Broadcom Corp. + * All Rights Reserved.$ + */ +#ifndef __PSAMPLE_CB_H__ +#define __PSAMPLE_CB_H__ + +#include +#include + +//#define PSAMPLE_SUPPORT 1 // TODO: MLI@BRCM - Add this as part of conditional in Makefile +#define PSAMPLE_CB_NAME "psample" + +extern int +psample_init(void); + +extern int +psample_cleanup(void); + +extern struct sk_buff* +psample_rx_cb(struct sk_buff *skb); + +/* psample data per interface */ +typedef struct { + struct list_head list; + struct net_device *dev; + uint16_t id; + uint8_t port; + uint16_t vlan; + uint16_t qnum; + uint32_t sample_rate; + uint32_t sample_size; +} psample_netif_t; + +extern int +psample_netif_create_cb(struct net_device *dev); + +extern int +psample_netif_destroy_cb(struct net_device *dev); + +#endif /* __PSAMPLE_CB_H__ */ diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/psample/Kbuild b/platform/broadcom/saibcm-modules/sdklt/linux/psample/Kbuild new file mode 100644 index 000000000000..0049e399076b --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/psample/Kbuild @@ -0,0 +1,18 @@ +# -*- Kbuild -*- +# +# Linux psample module. +# +# $Copyright: (c) 2020 Broadcom. +# Broadcom Proprietary and Confidential. All rights reserved.$ +# + +obj-m := linux_psample.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 + +linux_psample-y := psample.o diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/psample/Makefile b/platform/broadcom/saibcm-modules/sdklt/linux/psample/Makefile new file mode 100644 index 000000000000..b37b8ebb1c29 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/psample/Makefile @@ -0,0 +1,21 @@ +# -*- Makefile -*- +# +# Linux psample module. +# +# $Copyright: (c) 2020 Broadcom. +# Broadcom Proprietary and Confidential. All rights reserved.$ +# + +include Kbuild + +ifeq ($(KERNELRELEASE),) + +MOD_NAME = linux_psample + +include $(SDK)/make/lkm.mk + +endif + +.PHONY: distclean + +distclean: diff --git a/platform/broadcom/saibcm-modules/sdklt/linux/psample/psample.c b/platform/broadcom/saibcm-modules/sdklt/linux/psample/psample.c new file mode 100644 index 000000000000..f0c9beab5784 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/linux/psample/psample.c @@ -0,0 +1,302 @@ +/* + * net/psample/psample.c - Netlink channel for packet sampling + * Copyright (c) 2017 Yotam Gigi + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PSAMPLE_MAX_PACKET_SIZE 0xffff + +static LIST_HEAD(psample_groups_list); +static DEFINE_SPINLOCK(psample_groups_lock); + +/* multicast groups */ +enum psample_nl_multicast_groups { + PSAMPLE_NL_MCGRP_CONFIG, + PSAMPLE_NL_MCGRP_SAMPLE, +}; + +static const struct genl_multicast_group psample_nl_mcgrps[] = { + [PSAMPLE_NL_MCGRP_CONFIG] = { .name = PSAMPLE_NL_MCGRP_CONFIG_NAME }, + [PSAMPLE_NL_MCGRP_SAMPLE] = { .name = PSAMPLE_NL_MCGRP_SAMPLE_NAME }, +}; + +static struct genl_family psample_nl_family; + +static int psample_group_nl_fill(struct sk_buff *msg, + struct psample_group *group, + enum psample_command cmd, u32 portid, u32 seq, + int flags) +{ + void *hdr; + int ret; + + hdr = genlmsg_put(msg, portid, seq, &psample_nl_family, flags, cmd); + if (!hdr) + return -EMSGSIZE; + + ret = nla_put_u32(msg, PSAMPLE_ATTR_SAMPLE_GROUP, group->group_num); + if (ret < 0) + goto error; + + ret = nla_put_u32(msg, PSAMPLE_ATTR_GROUP_REFCOUNT, group->refcount); + if (ret < 0) + goto error; + + ret = nla_put_u32(msg, PSAMPLE_ATTR_GROUP_SEQ, group->seq); + if (ret < 0) + goto error; + + genlmsg_end(msg, hdr); + return 0; + +error: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int psample_nl_cmd_get_group_dumpit(struct sk_buff *msg, + struct netlink_callback *cb) +{ + struct psample_group *group; + int start = cb->args[0]; + int idx = 0; + int err; + + spin_lock(&psample_groups_lock); + list_for_each_entry(group, &psample_groups_list, list) { + if (!net_eq(group->net, sock_net(msg->sk))) + continue; + if (idx < start) { + idx++; + continue; + } + err = psample_group_nl_fill(msg, group, PSAMPLE_CMD_NEW_GROUP, + NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, NLM_F_MULTI); + if (err) + break; + idx++; + } + + spin_unlock(&psample_groups_lock); + cb->args[0] = idx; + return msg->len; +} + +static const struct genl_ops psample_nl_ops[] = { + { + .cmd = PSAMPLE_CMD_GET_GROUP, + .dumpit = psample_nl_cmd_get_group_dumpit, + /* can be retrieved by unprivileged users */ + } +}; + +static struct genl_family psample_nl_family = { + .name = PSAMPLE_GENL_NAME, + .version = PSAMPLE_GENL_VERSION, + .maxattr = PSAMPLE_ATTR_MAX, + .netnsok = true, + .module = THIS_MODULE, + .mcgrps = psample_nl_mcgrps, + .ops = psample_nl_ops, + .n_ops = ARRAY_SIZE(psample_nl_ops), + .n_mcgrps = ARRAY_SIZE(psample_nl_mcgrps), +}; + +static void psample_group_notify(struct psample_group *group, + enum psample_command cmd) +{ + struct sk_buff *msg; + int err; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!msg) + return; + + err = psample_group_nl_fill(msg, group, cmd, 0, 0, NLM_F_MULTI); + if (!err) + genlmsg_multicast_netns(&psample_nl_family, group->net, msg, 0, + PSAMPLE_NL_MCGRP_CONFIG, GFP_ATOMIC); + else + nlmsg_free(msg); +} + +static struct psample_group *psample_group_create(struct net *net, + u32 group_num) +{ + struct psample_group *group; + + group = kzalloc(sizeof(*group), GFP_ATOMIC); + if (!group) + return NULL; + + group->net = net; + group->group_num = group_num; + list_add_tail(&group->list, &psample_groups_list); + + psample_group_notify(group, PSAMPLE_CMD_NEW_GROUP); + return group; +} + +static void psample_group_destroy(struct psample_group *group) +{ + psample_group_notify(group, PSAMPLE_CMD_DEL_GROUP); + list_del(&group->list); + kfree(group); +} + +static struct psample_group * +psample_group_lookup(struct net *net, u32 group_num) +{ + struct psample_group *group; + + list_for_each_entry(group, &psample_groups_list, list) + if ((group->group_num == group_num) && (group->net == net)) + return group; + return NULL; +} + +struct psample_group *psample_group_get(struct net *net, u32 group_num) +{ + struct psample_group *group; + + spin_lock(&psample_groups_lock); + + group = psample_group_lookup(net, group_num); + if (!group) { + group = psample_group_create(net, group_num); + if (!group) + goto out; + } + group->refcount++; + +out: + spin_unlock(&psample_groups_lock); + return group; +} +EXPORT_SYMBOL_GPL(psample_group_get); + +void psample_group_put(struct psample_group *group) +{ + spin_lock(&psample_groups_lock); + + if (--group->refcount == 0) + psample_group_destroy(group); + + spin_unlock(&psample_groups_lock); +} +EXPORT_SYMBOL_GPL(psample_group_put); + +void psample_sample_packet(struct psample_group *group, struct sk_buff *skb, + u32 trunc_size, int in_ifindex, int out_ifindex, + u32 sample_rate) +{ + struct sk_buff *nl_skb; + int data_len; + int meta_len; + void *data; + int ret; + + meta_len = (in_ifindex ? nla_total_size(sizeof(u16)) : 0) + + (out_ifindex ? nla_total_size(sizeof(u16)) : 0) + + nla_total_size(sizeof(u32)) + /* sample_rate */ + nla_total_size(sizeof(u32)) + /* orig_size */ + nla_total_size(sizeof(u32)) + /* group_num */ + nla_total_size(sizeof(u32)); /* seq */ + + data_len = min(skb->len, trunc_size); + if (meta_len + nla_total_size(data_len) > PSAMPLE_MAX_PACKET_SIZE) + data_len = PSAMPLE_MAX_PACKET_SIZE - meta_len - NLA_HDRLEN + - NLA_ALIGNTO; + + nl_skb = genlmsg_new(meta_len + nla_total_size(data_len), GFP_ATOMIC); + if (unlikely(!nl_skb)) + return; + + data = genlmsg_put(nl_skb, 0, 0, &psample_nl_family, 0, + PSAMPLE_CMD_SAMPLE); + if (unlikely(!data)) + goto error; + + if (in_ifindex) { + ret = nla_put_u16(nl_skb, PSAMPLE_ATTR_IIFINDEX, in_ifindex); + if (unlikely(ret < 0)) + goto error; + } + + if (out_ifindex) { + ret = nla_put_u16(nl_skb, PSAMPLE_ATTR_OIFINDEX, out_ifindex); + if (unlikely(ret < 0)) + goto error; + } + + ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_SAMPLE_RATE, sample_rate); + if (unlikely(ret < 0)) + goto error; + + ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_ORIGSIZE, skb->len); + if (unlikely(ret < 0)) + goto error; + + ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_SAMPLE_GROUP, group->group_num); + if (unlikely(ret < 0)) + goto error; + + ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_GROUP_SEQ, group->seq++); + if (unlikely(ret < 0)) + goto error; + + if (data_len) { + int nla_len = nla_total_size(data_len); + struct nlattr *nla; + + nla = (struct nlattr *)skb_put(nl_skb, nla_len); + nla->nla_type = PSAMPLE_ATTR_DATA; + nla->nla_len = nla_attr_size(data_len); + + if (skb_copy_bits(skb, 0, nla_data(nla), data_len)) + goto error; + } + + genlmsg_end(nl_skb, data); + genlmsg_multicast_netns(&psample_nl_family, group->net, nl_skb, 0, + PSAMPLE_NL_MCGRP_SAMPLE, GFP_ATOMIC); + + return; +error: + pr_err_ratelimited("Could not create psample log message\n"); + nlmsg_free(nl_skb); +} +EXPORT_SYMBOL_GPL(psample_sample_packet); + +static int __init psample_module_init(void) +{ + return genl_register_family(&psample_nl_family); +} + +static void __exit psample_module_exit(void) +{ + genl_unregister_family(&psample_nl_family); +} + +module_init(psample_module_init); +module_exit(psample_module_exit); + +MODULE_AUTHOR("Yotam Gigi "); +MODULE_DESCRIPTION("netlink channel for packet sampling"); +MODULE_LICENSE("GPL v2"); diff --git a/platform/broadcom/saibcm-modules/sdklt/make/lkm.mk b/platform/broadcom/saibcm-modules/sdklt/make/lkm.mk new file mode 100644 index 000000000000..c3d2a4d40b50 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/make/lkm.mk @@ -0,0 +1,76 @@ +# +# $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.$ +# +# Shared makefile include for building Linux kernel modules. +# + +# KDIR must point to the Linux kernel sources +ifndef KDIR +nokdir:; @echo 'The $$KDIR variable is not set'; exit 1 +endif + +# Required for older kernels +export EXTRA_CFLAGS = $(ccflags-y) + +PWD := $(shell pwd) + +ifneq ($(LKM_BLDDIR),) +# +# If a build directory has been specified, then we symlink all sources +# to this directory and redirect the module build path. +# +# Note that the KBUILD_OUTPUT variable cannot be used to redirect the +# output as we want it. +# +MDIR = $(LKM_BLDDIR) +MSRCS = $(patsubst %.o,%.c,$($(MOD_NAME)-y)) +MSRCS += Makefile Kbuild +BSRCS = $(addprefix $(PWD)/,$(MSRCS)) +else +# +# Build in current directory by default. +# +MDIR = $(PWD) +endif + +all: + $(Q)echo Building kernel module $(MOD_NAME) +ifneq ($(LKM_BLDDIR),) +ifneq ($(LKM_BLDDIR),$(PWD)) + $(Q)mkdir -p $(MDIR) + (cd $(MDIR); \ + rm -rf *.c Makefile Kbuild; \ + for f in $(BSRCS); do \ + ln -s $$f; \ + done) +endif +endif + $(MAKE) -C $(KDIR) M=$(MDIR) + +clean:: + $(Q)echo Cleaning kernel module $(MOD_NAME) + $(MAKE) -C $(KDIR) M=$(MDIR) clean +ifneq ($(LKM_BLDDIR),) +ifneq ($(LKM_BLDDIR),$(PWD)) +# Remove all files except for Makefile (needed by 'make clean') + rm -f $(LKM_BLDDIR)/*[cdors] +endif +endif + +.PHONY: all clean + +# Standard documentation targets +-include $(SDK)/make/doc.mk diff --git a/platform/broadcom/saibcm-modules/sdklt/shr/include/shr/shr_error.h b/platform/broadcom/saibcm-modules/sdklt/shr/include/shr/shr_error.h new file mode 100644 index 000000000000..1924d600de53 --- /dev/null +++ b/platform/broadcom/saibcm-modules/sdklt/shr/include/shr/shr_error.h @@ -0,0 +1,195 @@ +/*! \file shr_error.h + * + * Shared error codes. + * + */ +/* + * $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 SHR_ERROR_H +#define SHR_ERROR_H + +/*! + * \brief Standard SDK error codes. + * + * IMPORTANT: These error codes must match the corresponding text + * messages in shr_error.c. + */ +typedef enum { + + /*! + * The operation completed successfully. + */ + SHR_E_NONE = 0, + + /*! + * This usually indicates that software encountered an internal + * data inconsistency or an unanticipated hardware state. + */ + SHR_E_INTERNAL = -1, + + /*! + * An operation failed due to insufficient dynamically allocated + * memory. + */ + SHR_E_MEMORY = -2, + + /*! + * The first argument of many API routines is a unit number. This + * error occurs if that number refers to a non-existent unit. + */ + SHR_E_UNIT = -3, + + /*! + * A parameter to an API routine was invalid. A null pointer value + * may have been passed to the routine, or an integer parameter + * may be outside of its allowed range. + */ + SHR_E_PARAM = -4, + + /*! + * The operation encountered a pooled resource (e.g. a table or a + * list) with no valid elements. + */ + SHR_E_EMPTY = -5, + + /*! + * The operation encountered a pooled resource (e.g. a table or a + * list) with no room for new elements. + */ + SHR_E_FULL = -6, + + /*! + * The specified entry in a pooled resource (e.g. a table or a + * list) could not be found. + */ + SHR_E_NOT_FOUND = -7, + + /*! + * The specified entry of a pooled resource (e.g. a table or a + * list) already exists. + */ + SHR_E_EXISTS = -8, + + /*! + * The operation did not complete within the maximum allowed time frame. + */ + SHR_E_TIMEOUT = -9, + + /*! + * An operation was attempted before the previous operation had + * completed. + */ + SHR_E_BUSY = -10, + + /*! + * An operation could not be completed. This may be due to a + * hardware or configuration problem. + */ + SHR_E_FAIL = -11, + + /*! + * The operation could not be completed because a required feature + * was disabled. + */ + SHR_E_DISABLED = -12, + + /*! + * The specified identifier was not valid. Note that this error + * code will normally take precedence over \ref SHR_E_PARAM. + */ + SHR_E_BADID = -13, + + /*! + * The operation could not be completed due to lack of hardware + * resources. + */ + SHR_E_RESOURCE = -14, + + /*! + * The operation could not be completed due to incomplete or + * incorrect configuration. + */ + SHR_E_CONFIG = -15, + + /*! + * The hardware does not support the requested operation. + */ + SHR_E_UNAVAIL = -16, + + /*! + * An operation was attempted before initialization was complete. + */ + SHR_E_INIT = -17, + + /*! + * The specified port value was not valid. Note that this error + * code will normally take precedence over \ref SHR_E_PARAM. + */ + SHR_E_PORT = -18, + + /*! + * A low-level register or memory access failed. + */ + SHR_E_IO = -19, + + /*! + * Access method not permitted. Typically returned if attempting + * to write to a read-only object. + */ + SHR_E_ACCESS = -20, + + /*! + * No handler exists to perform the hardware access associated + * with a an operation on a software object. + */ + SHR_E_NO_HANDLER = -21, + + /*! + * The operation was only partially completed, and this could + * potentially leave the system in an unexpected state. + */ + SHR_E_PARTIAL = -22, + + /*! + * The operation failed because of a hash collision. + */ + SHR_E_COLL = -23, + + SHR_E_LIMIT = -24 /* Must come last */ + +} shr_error_t; + +/*! Check for successful return value. */ +#define SHR_SUCCESS(_expr) ((_expr) >= 0) + +/*! Check for error return value. */ +#define SHR_FAILURE(_expr) ((_expr) < 0) + +/*! + * \brief Get standard error message + * + * Returns a text message corresponding to the error code passed in. + * + * \param [in] rv Error code + * + * \return Pointer to error message + */ +extern const char * +shr_errmsg(int rv); + +#endif /* SHR_ERROR_H */