From c9562c4db286483a7a3a55ddc5423795d99050ec Mon Sep 17 00:00:00 2001 From: Guohan Lu Date: Mon, 18 Feb 2019 01:28:34 +0000 Subject: [PATCH 1/2] Revert "[knet driver] fix PCI device init race condition" This reverts commit 560d35bf423ee684ebd1424c0beb73a048fe54af. --- .../systems/bde/linux/include/linux_dma.h | 2 +- .../bde/linux/kernel/linux-kernel-bde.c | 87 ++++++++----------- .../systems/bde/linux/kernel/linux_dma.c | 39 ++++----- 3 files changed, 55 insertions(+), 73 deletions(-) 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 bfbbceb2d8e7..e4ec58db9fd2 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 @@ -58,7 +58,7 @@ #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) #endif -extern void _dma_init(int robo_switch, int dev_index); +extern void _dma_init(int robo_switch); extern int _dma_cleanup(void); extern void _dma_pprint(void); extern uint32_t *_salloc(int d, int size, const char *name); 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 e26d35332cc8..ab5d48639954 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 @@ -540,40 +540,6 @@ _parse_eb_args(char *str, char * format, ...) return 0; } -static void -_bde_add_device(void) -{ - /* - * In order to be backward compatible with the user mode BDE - * (specifically the interrupt IOCTLs) and the CM, switch devices - * *must* come first. If this is not the case (due to the probing - * order), we let the non-switch device(s) drop down to the end of - * the device array. - */ - if (_switch_ndevices > 0) { - bde_ctrl_t tmp_dev; - int i, s = 0; - - while (s < _switch_ndevices) { - if (_devices[s].dev_type & BDE_SWITCH_DEV_TYPE) { - s++; - continue; - } - tmp_dev = _devices[s]; - for (i = s; i < _ndevices - 1; i++) { - _devices[i] = _devices[i+1]; - } - _devices[i] = tmp_dev; - } - } - - /* Initialize device locks and dma */ - if (_ndevices > 0) { - spin_lock_init(&_devices[_ndevices-1].lock); - _dma_init(robo_switch, _ndevices-1); - } -} - static int _eb_device_create(resource_size_t paddr, int irq, int rd_hw, int wr_hw) { @@ -609,8 +575,6 @@ _eb_device_create(resource_size_t paddr, int irq, int rd_hw, int wr_hw) ctrl->isr = NULL; ctrl->isr_data = NULL; - _bde_add_device(); - gprintk("Created EB device at BA=%x IRQ=%d RD16=%d WR16=%d device=0x%x\n", (unsigned int)paddr, irq, rd_hw, wr_hw, ctrl->bde_dev.device); @@ -663,10 +627,6 @@ sand_device_create(void) ctrl->dev_type |= BDE_PCI_DEV_TYPE | BDE_SWITCH_DEV_TYPE; } -#ifndef __DUNE_LINUX_BCM_CPU_PCIE__ - _bde_add_device(); -#endif - return 0; } #endif @@ -774,7 +734,6 @@ iproc_cmicd_probe(struct platform_device *pldev) #endif /* Let's boogie */ - _bde_add_device(); return 0; } @@ -1032,7 +991,6 @@ _ics_bde_create(void) ctrl->isr = NULL; ctrl->isr_data = NULL; - _bde_add_device(); printk("Created ICS device ..%x\n", ctrl->bde_dev.base_address); } @@ -2671,10 +2629,6 @@ _pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) ctrl->dma_dev = &dev->dev; #endif - if (!rescan) { - _bde_add_device(); - } - if (debug >= 2) { gprintk("_pci_probe: configured dev:0x%x rev:0x%x with base_addresses: 0x%lx 0x%lx\n", (unsigned)ctrl->bde_dev.device, (unsigned)ctrl->bde_dev.rev, @@ -3014,7 +2968,6 @@ probe_robo_switch_iproc_spi(void) ctrl->isr = NULL; ctrl->isr_data = NULL; robo_switch++; - _bde_add_device(); } @@ -3228,7 +3181,6 @@ probe_robo_switch(void) #if defined(KEYSTONE) spi_freq = _spi_id_table[match_idx].spifreq; #endif - _bde_add_device(); } #if defined(KEYSTONE) @@ -3274,8 +3226,6 @@ map_local_bus(uint64_t addr, uint32_t size) ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(addr, size); ctrl->phys_address = addr; - _bde_add_device(); - return(ctrl); } @@ -3427,8 +3377,6 @@ map_local_bus2(bde_ctrl_t *plx_ctrl, uint32_t dev_base, uint32_t size) ctrl->bde_dev.device = dev_rev_id >> 16; ctrl->bde_dev.rev = (dev_rev_id & 0xFF); - _bde_add_device(); - switch (ctrl->bde_dev.device) { case BCM88130_DEVICE_ID: case BME3200_DEVICE_ID: @@ -3749,6 +3697,41 @@ _init(void) tok = strtok(NULL,","); } } + + _dma_init(robo_switch); + + /* + * In order to be backward compatible with the user mode BDE + * (specifically the interrupt IOCTLs) and the CM, switch devices + * *must* come first. If this is not the case (due to the probing + * order), we let the non-switch device(s) drop down to the end of + * the device array. + */ + if (_switch_ndevices > 0) { + bde_ctrl_t tmp_dev; + int i, s = 0; + + while (s < _switch_ndevices) { + if (_devices[s].dev_type & BDE_SWITCH_DEV_TYPE) { + s++; + continue; + } + tmp_dev = _devices[s]; + for (i = s; i < _ndevices - 1; i++) { + _devices[i] = _devices[i+1]; + } + _devices[i] = tmp_dev; + } + } + + /* Initialize device locks */ + if (_ndevices > 0) { + int i; + + for (i = 0; i < _ndevices; i++) { + spin_lock_init(&_devices[i].lock); + } + } return 0; } 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 32b769784c2e..196b4e6326b9 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 @@ -590,7 +590,9 @@ _pgcleanup(void) static void _alloc_mpool(size_t size) { + int i, ndevices; unsigned long pbase = 0; + unsigned long orig_pbase = 0; #if defined(__arm__) && !defined(CONFIG_HIGHMEM) if (_use_himem) { @@ -647,18 +649,27 @@ _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. */ - if (DMA_DEV(0)) { - pbase = dma_map_single(DMA_DEV(0), _dma_vbase, size, DMA_BIDIRECTIONAL); - if (dma_mapping_error(DMA_DEV(0), pbase)) { - gprintk("Failed to map memory at %p\n", _dma_vbase); + ndevices = BDE_NUM_DEVICES(BDE_ALL_DEVICES); + for (i = 0; i < ndevices && DMA_DEV(i); i ++) { + /* Use dma_map_single to obtain DMA bus address or IOVA if iommu is present. */ + pbase = dma_map_single(DMA_DEV(i), _dma_vbase, size, DMA_BIDIRECTIONAL); + if (_use_dma_mapping && (orig_pbase != pbase)) { + /* Bus address/IOVA must be identical for all devices. */ + gprintk("deivce %d has different pbase: %lx (should be %lx)\n", + i, pbase, orig_pbase); + dma_unmap_single(DMA_DEV(i), (dma_addr_t)pbase, size, DMA_BIDIRECTIONAL); + while (--i >= 0 && DMA_DEV(i)) { + dma_unmap_single(DMA_DEV(i), (dma_addr_t)orig_pbase, size, DMA_BIDIRECTIONAL); + } + _use_dma_mapping = 0; _pgcleanup(); _dma_vbase = NULL; - _cpu_pbase = 0; return; } + orig_pbase = pbase; _use_dma_mapping = 1; - } else { + } + if (!_use_dma_mapping) { /* Device has not been probed. */ pbase = _cpu_pbase; } @@ -719,20 +730,8 @@ _dma_cleanup(void) return 0; } -void _dma_init(int robo_switch, int dev_index) +void _dma_init(int robo_switch) { - unsigned long pbase; - - if (dev_index > 0) { - if ((_use_dma_mapping == 1) && DMA_DEV(dev_index) && _dma_vbase) { - pbase = dma_map_single(DMA_DEV(dev_index), _dma_vbase, _dma_mem_size, DMA_BIDIRECTIONAL); - if (dma_mapping_error(DMA_DEV(dev_index), pbase)) { - gprintk("Failed to map memory for device %d at %p\n", dev_index, _dma_vbase); - } - } - return; - } - /* DMA Setup */ if (dmasize) { if ((dmasize[strlen(dmasize)-1] & ~0x20) == 'M') { From fc5a375a9b7e96f7b2ab76b31d066057ee2100b2 Mon Sep 17 00:00:00 2001 From: Guohan Lu Date: Mon, 18 Feb 2019 01:37:11 +0000 Subject: [PATCH 2/2] [saibcm-modules]: import bcm modules from sdk 6.5.14 Signed-off-by: Guohan Lu --- .../broadcom/saibcm-modules/include/ibde.h | 22 ++ .../broadcom/saibcm-modules/include/kcom.h | 14 +- .../saibcm-modules/include/soc/devids.h | 63 ++++ .../saibcm-modules/make/Makefile.linux-gto | 8 +- .../bde/linux/kernel/linux-kernel-bde.c | 278 +++++++++++++----- .../bde/linux/user/kernel/linux-user-bde.c | 190 +++++++++++- .../bde/linux/user/kernel/linux-user-bde.h | 6 +- .../systems/bde/shared/shbde_iproc.c | 37 ++- .../linux/kernel/modules/bcm-knet/bcm-knet.c | 232 +++++++++------ .../linux/kernel/modules/include/lkm.h | 3 + .../linux/kernel/modules/knet-cb/knet-cb.c | 249 +++------------- 11 files changed, 700 insertions(+), 402 deletions(-) diff --git a/platform/broadcom/saibcm-modules/include/ibde.h b/platform/broadcom/saibcm-modules/include/ibde.h index bfc05e330e03..9c8956f5e3e0 100644 --- a/platform/broadcom/saibcm-modules/include/ibde.h +++ b/platform/broadcom/saibcm-modules/include/ibde.h @@ -148,6 +148,28 @@ typedef struct ibde_s { */ int (*get_cmic_ver)(int d, uint32 *ver); + /* + * Probe available devices. + * Return value : + * 0: success to probe available devices + * -1: error happens during probe + */ + int (*probe)(void); + + /* + * I2C operations on the Device, assuming it is connected by I2C to the CPU. + */ + /* Read from the internal device Address space using I2C */ + int (*i2c_device_read)( + int dev, /* The device ID to access */ + uint32 addr, /* The address to access in the internal device address space */ + uint32 *value);/* the value to be read. */ + /* Write to the internal device Address space using I2C */ + int (*i2c_device_write)( + int dev, /* The device ID to access */ + uint32 addr, /* The address to access in the internal device address space */ + uint32 value); /* the value to be written. */ + } ibde_t; diff --git a/platform/broadcom/saibcm-modules/include/kcom.h b/platform/broadcom/saibcm-modules/include/kcom.h index f66e382e4d8f..76f3e47a8de5 100644 --- a/platform/broadcom/saibcm-modules/include/kcom.h +++ b/platform/broadcom/saibcm-modules/include/kcom.h @@ -46,6 +46,7 @@ #define KCOM_M_HW_INIT 4 /* H/W initialized */ #define KCOM_M_ETH_HW_CONFIG 5 /* ETH HW config*/ #define KCOM_M_DETACH 6 /* Detach kernel module */ +#define KCOM_M_REPROBE 7 /* Reprobe device */ #define KCOM_M_NETIF_CREATE 11 /* Create network interface */ #define KCOM_M_NETIF_DESTROY 12 /* Destroy network interface */ #define KCOM_M_NETIF_LIST 13 /* Get list of network interface IDs */ @@ -59,7 +60,7 @@ #define KCOM_M_DBGPKT_GET 42 /* Get debug packet function info */ #define KCOM_M_WB_CLEANUP 51 /* Clean up for warmbooting */ -#define KCOM_VERSION 9 /* Protocol version */ +#define KCOM_VERSION 10 /* Protocol version */ /* * Message status codes @@ -305,7 +306,7 @@ typedef struct kcom_eth_hw_config_s { uint8 chan; uint32 flags; uint32 value; - } kcom_eth_hw_config_t; +} kcom_eth_hw_config_t; /* * Message types @@ -379,6 +380,14 @@ typedef struct kcom_msg_detach_s { uint32 flags; } kcom_msg_detach_t; +/* + * Reprobe switch device. + */ +typedef struct kcom_msg_reprobe_s { + kcom_msg_hdr_t hdr; + uint32 flags; +} kcom_msg_reprobe_t; + /* * Enable/Disable debugging packet function. */ @@ -498,6 +507,7 @@ typedef union kcom_msg_s { kcom_msg_hw_init_t hw_init; kcom_msg_eth_hw_config_t eth_hw_config; kcom_msg_detach_t detach; + kcom_msg_reprobe_t reprobe; kcom_msg_netif_create_t netif_create; kcom_msg_netif_destroy_t netif_destroy; kcom_msg_netif_list_t netif_list; diff --git a/platform/broadcom/saibcm-modules/include/soc/devids.h b/platform/broadcom/saibcm-modules/include/soc/devids.h index c1b350f217a5..cb072a78cbd7 100644 --- a/platform/broadcom/saibcm-modules/include/soc/devids.h +++ b/platform/broadcom/saibcm-modules/include/soc/devids.h @@ -1238,6 +1238,15 @@ #define BCM56980_DEVICE_ID 0xb980 #define BCM56980_A0_REV_ID 1 +#define BCM56980_B0_REV_ID 0x11 +#define BCM56981_DEVICE_ID 0xb981 +#define BCM56981_A0_REV_ID 1 +#define BCM56982_DEVICE_ID 0xb982 +#define BCM56982_A0_REV_ID 1 +#define BCM56983_DEVICE_ID 0xb983 +#define BCM56983_A0_REV_ID 1 +#define BCM56984_DEVICE_ID 0xb984 +#define BCM56984_A0_REV_ID 1 #define BCM56968_DEVICE_ID 0xb968 #define BCM56968_A0_REV_ID 1 @@ -1289,15 +1298,20 @@ #define BCM56670_DEVICE_ID 0xb670 #define BCM56670_A0_REV_ID 1 +#define BCM56670_B0_REV_ID 0x11 #define BCM56671_DEVICE_ID 0xb671 #define BCM56671_A0_REV_ID 1 +#define BCM56671_B0_REV_ID 0x11 #define BCM56672_DEVICE_ID 0xb672 #define BCM56672_A0_REV_ID 1 +#define BCM56672_B0_REV_ID 0x11 #define BCM56675_DEVICE_ID 0xb675 #define BCM56675_A0_REV_ID 1 +#define BCM56675_B0_REV_ID 0x11 + #define BCM56565_DEVICE_ID 0xb565 #define BCM56565_A0_REV_ID 1 @@ -1317,12 +1331,19 @@ #define BCM56760_DEVICE_ID 0xb760 #define BCM56760_A0_REV_ID 1 +#define BCM56760_A1_REV_ID 2 #define BCM56760_B0_REV_ID 0x11 #define BCM56761_DEVICE_ID 0xb761 #define BCM56761_A0_REV_ID 1 #define BCM56761_B0_REV_ID 0x11 +#define BCM56761_DEVICE_ID 0xb761 +#define BCM56761_A0_REV_ID 1 +#define BCM56761_A1_REV_ID 2 +#define BCM56761_B0_REV_ID 0x11 +#define BCM56761_B1_REV_ID 0x12 + #define BCM56762_DEVICE_ID 0xb762 #define BCM56762_A0_REV_ID 1 #define BCM56762_B0_REV_ID 0x11 @@ -1347,6 +1368,11 @@ #define BCM56068_A0_REV_ID 1 #define BCM56068_B0_REV_ID 0x11 +#define BCM56068_DEVICE_ID 0xb068 +#define BCM56068_A0_REV_ID 1 +#define BCM56068_B0_REV_ID 0x11 +#define BCM56068_B1_REV_ID 0x12 + #define BCM56069_DEVICE_ID 0xb069 #define BCM56069_A0_REV_ID 1 #define BCM56069_B0_REV_ID 0x11 @@ -1400,6 +1426,42 @@ #define BCM56873_DEVICE_ID 0xb873 #define BCM56873_A0_REV_ID 1 +#define BCM56370_DEVICE_ID 0xb370 +#define BCM56370_A0_REV_ID 1 + +#define BCM56371_DEVICE_ID 0xb371 +#define BCM56371_A0_REV_ID 1 + +#define BCM56372_DEVICE_ID 0xb372 +#define BCM56372_A0_REV_ID 1 + +#define BCM56374_DEVICE_ID 0xb374 +#define BCM56374_A0_REV_ID 1 + +#define BCM56375_DEVICE_ID 0xb375 +#define BCM56375_A0_REV_ID 1 + +#define BCM56376_DEVICE_ID 0xb376 +#define BCM56376_A0_REV_ID 1 + +#define BCM56377_DEVICE_ID 0xb377 +#define BCM56377_A0_REV_ID 1 + +#define BCM56577_DEVICE_ID 0xb577 +#define BCM56577_A0_REV_ID 1 + +#define BCM56578_DEVICE_ID 0xb578 +#define BCM56578_A0_REV_ID 1 + +#define BCM56579_DEVICE_ID 0xb579 +#define BCM56579_A0_REV_ID 1 + +#define BCM56770_DEVICE_ID 0xb770 +#define BCM56770_A0_REV_ID 1 + +#define BCM56771_DEVICE_ID 0xb771 +#define BCM56771_A0_REV_ID 1 + #define BCM53540_DEVICE_ID 0x8540 #define BCM53540_A0_REV_ID 1 #define BCM53547_DEVICE_ID 0x8547 @@ -1718,6 +1780,7 @@ #define DNXC_B0_REV_ID 0x0011 #define BCM88790_DEVICE_ID 0x8790 #define BCM88790_A0_REV_ID DNXC_A0_REV_ID +#define BCM88790_B0_REV_ID DNXC_B0_REV_ID #define BCM88791_DEVICE_ID 0x8791 #define BCM88792_DEVICE_ID 0x8792 #define BCM88793_DEVICE_ID 0x8793 diff --git a/platform/broadcom/saibcm-modules/make/Makefile.linux-gto b/platform/broadcom/saibcm-modules/make/Makefile.linux-gto index cd5e8fbca195..947c20e74f93 100644 --- a/platform/broadcom/saibcm-modules/make/Makefile.linux-gto +++ b/platform/broadcom/saibcm-modules/make/Makefile.linux-gto @@ -86,15 +86,19 @@ endif endif ifdef DPP_CHIPS -CFLAGS += -DDUNE_BCM -D__DUNE_GTO_BCM_CPU__ -D__DUNE_LINUX_BCM_CPU_PCIE__ -D__DUNE_LINUX_BCM_CPU_PCP_DMA__ +CFLAGS += -DDUNE_BCM -D__DUNE_LINUX_BCM_CPU_PCP_DMA__ CFGFLAGS += -DSOC_CM_FUNCTION endif ifdef DFE_CHIPS -CFLAGS += -DDUNE_BCM -D__DUNE_GTO_BCM_CPU__ -D__DUNE_LINUX_BCM_CPU_PCIE__ +CFLAGS += -DDUNE_BCM CFGFLAGS += -DSOC_CM_FUNCTION endif +ifdef SAND_CHIPS +CFLAGS += -D__DUNE_GTO_BCM_CPU__ -D__DUNE_LINUX_BCM_CPU_PCIE__ +endif + ifdef SHADOW_PLX CFLAGS += -DBCM_PLX9656_LOCAL_BUS -DBDE_LINUX_NON_INTERRUPTIBLE -DSHADOW_SVK endif 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 ab5d48639954..1e0ed761e9cc 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 @@ -94,6 +94,8 @@ LKM_MOD_PARAM(nodevices, "i", int, 0); MODULE_PARM_DESC(nodevices, "Ignore all recognized devices (default no)"); +int msixcnt = 1; + /* * This usually is defined at /usr/include/linux/pci_ids.h * But this ID is newer. @@ -366,6 +368,12 @@ static int robo_switch = 0; #define VALID_DEVICE(_n) ((_n >= 0) && (_n < _ndevices)) +#if defined(IPROC_CMICD) && defined(CONFIG_OF) +#define ICFG_CHIP_ID_REG 0x10236000 +#define IHOST_CMICX_MAX_INTRS 128 +static uint32 iproc_cmicx_irqs[IHOST_CMICX_MAX_INTRS]; +#endif + /* CPU MMIO area used with CPU cards provided on demo boards */ #if (defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT)) && (defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__)) static void *cpu_address = NULL; @@ -656,9 +664,9 @@ iproc_cmicd_get_irqres(ibde_dev_t bde_dev, struct resource *res_irq) #include #include -extern void iproc_platform_driver_register(struct platform_driver *drv); +extern int iproc_platform_driver_register(struct platform_driver *drv); extern void iproc_platform_driver_unregister(struct platform_driver *drv); -extern void iproc_platform_device_register(struct platform_device *drv); +extern int iproc_platform_device_register(struct platform_device *drv); extern void iproc_platform_device_unregister(struct platform_device *drv); extern struct resource * @@ -671,13 +679,14 @@ iproc_platform_get_resource(struct platform_device *dev, unsigned int type, #define IPROC_CMICD_INT 194 #define IPROC_CMICD_COMPATIBLE "brcm,iproc-cmicd" +#define IPROC_CMICX_COMPATIBLE "brcm,iproc-cmicx" static int iproc_cmicd_probe(struct platform_device *pldev) { bde_ctrl_t *ctrl; uint32 size, dev_rev_id; - struct resource *memres, *irqres; + struct resource *memres, *irqres; #ifdef CONFIG_OF if (debug >= 1) { gprintk("iproc_cmicd_probe %s\n", pldev->dev.of_node ? "with device node":""); @@ -685,7 +694,7 @@ iproc_cmicd_probe(struct platform_device *pldev) #endif memres = iproc_platform_get_resource(pldev, IORESOURCE_MEM, 0); if (memres == NULL) { - gprintk("Unable to retrieve iProc CMIC resources"); + gprintk("Unable to retrieve iProc CMIC resources"); return -1; } size = memres->end - memres->start + 1; @@ -699,32 +708,62 @@ iproc_cmicd_probe(struct platform_device *pldev) /* Map CMIC block in the AXI memory space into CPU address space */ ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(memres->start, size); if (!ctrl->bde_dev.base_address) { - gprintk("Error mapping iProc CMIC registers"); + gprintk("Error mapping iProc CMIC registers"); return -1; } ctrl->phys_address = memres->start; - /* Read switch device ID from CMIC */ - dev_rev_id = *((uint32_t*)(ctrl->bde_dev.base_address + 0x10224)); +#ifdef CONFIG_OF + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + uint32 *icfg_chip_id; + icfg_chip_id = (uint32 *)IOREMAP(ICFG_CHIP_ID_REG, 2 * sizeof(uint32)); + if (icfg_chip_id == NULL) { + gprintk("Error mapping ICFG_CHIP_ID_REG\n"); + return -1; + } + ctrl->bde_dev.device = readl(icfg_chip_id) & 0xffff; + ctrl->bde_dev.rev = readl(icfg_chip_id+1) & 0xff; + iounmap(icfg_chip_id); + } else +#endif + { + /* Read switch device ID from CMIC */ + dev_rev_id = *((uint32 *)(ctrl->bde_dev.base_address + 0x10224)); #if defined(BCM_CMICM_SUPPORT) && defined(BE_HOST) - ctrl->bde_dev.device = ( (((dev_rev_id >> 16) & 0xff) << 8) | - ((dev_rev_id >> 24) & 0xff)); - ctrl->bde_dev.rev = (dev_rev_id >> 8) & 0xff ; + ctrl->bde_dev.device = ( (((dev_rev_id >> 16) & 0xff) << 8) | + ((dev_rev_id >> 24) & 0xff)); + ctrl->bde_dev.rev = (dev_rev_id >> 8) & 0xff ; #else - ctrl->bde_dev.device = dev_rev_id & 0xffff; - ctrl->bde_dev.rev = (dev_rev_id >> 16) & 0xff; + ctrl->bde_dev.device = dev_rev_id & 0xffff; + ctrl->bde_dev.rev = (dev_rev_id >> 16) & 0xff; #endif + } #ifdef CONFIG_OF if (!pldev->dev.of_node) #endif { /* Assign locally if not available from device node */ - iproc_cmicd_get_irqres(ctrl->bde_dev, &pldev->resource[0]); + iproc_cmicd_get_irqres(ctrl->bde_dev, &pldev->resource[0]); } - irqres = iproc_platform_get_resource(pldev, IORESOURCE_IRQ, 0); - ctrl->iLine = irqres->start; +#ifdef CONFIG_OF + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + int i; + for (i = 0; i < IHOST_CMICX_MAX_INTRS; i++) { + irqres = iproc_platform_get_resource(pldev, IORESOURCE_IRQ, i); + iproc_cmicx_irqs[i] = irqres->start; + if (debug >= 1) { + gprintk("iproc_cmicx_irqs[%d] = %d\n", i, iproc_cmicx_irqs[i]); + } + } + ctrl->iLine = iproc_cmicx_irqs[0]; + } else +#endif + { + irqres = iproc_platform_get_resource(pldev, IORESOURCE_IRQ, 0); + ctrl->iLine = irqres->start; + } ctrl->isr = NULL; ctrl ->isr_data = NULL; @@ -744,14 +783,15 @@ iproc_cmicd_remove(struct platform_device *pldev) } #ifdef CONFIG_OF static const struct of_device_id iproc_cmicd_of_match[] = { - { .compatible = "brcm,iproc-cmicd" }, + { .compatible = IPROC_CMICD_COMPATIBLE }, + { .compatible = IPROC_CMICX_COMPATIBLE }, {}, }; MODULE_DEVICE_TABLE(of, iproc_cmicd_of_match); #endif static char iproc_cmicd_string[] = "bcmiproc-cmicd"; -static struct platform_driver iproc_cmicd_driver = +static struct platform_driver iproc_cmicd_driver = { .probe = iproc_cmicd_probe, .remove = iproc_cmicd_remove, @@ -954,10 +994,10 @@ iproc_cmicd_get_memregion(struct resource *res_mem) iounmap(erom_base); if (debug >= 1) { - gprintk("CMICD info by %s: cmicd_mem.start=%x, cmicd_mem.end=%x\n", + gprintk("CMICD info by %s: cmicd_mem.start=%lx, cmicd_mem.end=%lx\n", found_cmicd_dev ? "EROM" : "Default", - iproc_cmicd_resources[IPROC_CMICD_RES_MEM].start, - iproc_cmicd_resources[IPROC_CMICD_RES_MEM].end); + (unsigned long)iproc_cmicd_resources[IPROC_CMICD_RES_MEM].start, + (unsigned long)iproc_cmicd_resources[IPROC_CMICD_RES_MEM].end); } } #endif /* IPROC_CMICD */ @@ -1340,6 +1380,7 @@ static const struct pci_device_id _id_table[] = { { BROADCOM_VENDOR_ID, BCM56672_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56675_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56568_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56670_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56760_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56761_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56762_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, @@ -1504,8 +1545,24 @@ static const struct pci_device_id _id_table[] = { { BROADCOM_VENDOR_ID, BCM56832_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56836_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56870_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, - { BROADCOM_VENDOR_ID, BCM56980_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56370_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56371_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56372_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56374_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56375_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56376_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56377_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56577_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56578_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56579_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM56873_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56770_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56771_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56980_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56981_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56982_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56983_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + { BROADCOM_VENDOR_ID, BCM56984_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM53540_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM53547_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { BROADCOM_VENDOR_ID, BCM53548_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, @@ -1939,6 +1996,7 @@ _pci_msix_table_size(struct pci_dev *dev) if (nr_entries < 0) { nr_entries = 0; } + pci_disable_msix(dev); kfree(entries); } } @@ -1954,45 +2012,56 @@ _pci_msix_table_size(struct pci_dev *dev) static int _msi_connect(bde_ctrl_t *ctrl) { - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84)) int ret; if (ctrl->use_msi == PCI_USE_INT_MSIX) { int i; - ret = _pci_msix_table_size(ctrl->pci_device); + ret = _pci_msix_table_size(ctrl->pci_device); if (ret == 0) { /* MSI-X failed */ gprintk("MSI-X not supported.\n"); goto er_intx; } - ctrl->entries = kcalloc(ret, sizeof(struct msix_entry)*ret, GFP_KERNEL); + ctrl->entries = kcalloc(ret, sizeof(struct msix_entry), GFP_KERNEL); if (!ctrl->entries) { goto er_intx; } - /* We need only that much interrupt vecotrs */ - ctrl->msix_cnt = ret/4; + /* Only one vector is mapped by default */ + /* May be more in future, can be controlled using module param */ + ctrl->msix_cnt = msixcnt; if (unlikely(debug > 1)) gprintk("MSIX Table size = %d\n", ctrl->msix_cnt); for (i = 0; i < ctrl->msix_cnt; i++) ctrl->entries[i].entry = i; - +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) + ret = pci_enable_msix_range(ctrl->pci_device, + ctrl->entries, ctrl->msix_cnt, ctrl->msix_cnt); +#else ret = pci_enable_msix(ctrl->pci_device, ctrl->entries, ctrl->msix_cnt); +#endif if (ret > 0) { /* Not enough vectors available , Retry MSI-X */ gprintk("Retrying with MSI-X interrupts = %d\n", ret); ctrl->msix_cnt = ret; + msixcnt = ret; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) + ret = pci_enable_msix_range(ctrl->pci_device, + ctrl->entries, ctrl->msix_cnt, ctrl->msix_cnt); +#else ret = pci_enable_msix(ctrl->pci_device, ctrl->entries, ctrl->msix_cnt); +#endif if (ret != 0) goto er_intx_free; } else if (ret < 0) { /* Error */ goto er_intx_free; } else { - gprintk("Enabled MSI-X interrupts = %d\n", ctrl->msix_cnt); + gprintk("Enabled MSI-X interrupts = %d\n", ctrl->msix_cnt); + return 0; } } #endif @@ -2007,7 +2076,7 @@ _msi_connect(bde_ctrl_t *ctrl) } } else { /* failed */ - gprintk("Not MSI/MSIC interrupt.\n"); + gprintk("Not MSI/MSIX interrupt.\n"); goto er_intx; } return 0; @@ -2026,9 +2095,12 @@ _msi_disconnect(bde_ctrl_t *ctrl) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84)) if (ctrl->use_msi == PCI_USE_INT_MSIX) { - pci_disable_msix(ctrl->pci_device); - kfree(ctrl->entries); - ctrl->msix_cnt = 0; + if (ctrl->msix_cnt) { + pci_disable_msix(ctrl->pci_device); + kfree(ctrl->entries); + ctrl->entries = NULL; + ctrl->msix_cnt = 0; + } } #endif if (ctrl->use_msi == PCI_USE_INT_MSI) { @@ -2043,16 +2115,30 @@ _msi_disconnect(bde_ctrl_t *ctrl) static void -config_pci_intr_type(bde_ctrl_t *ctrl) +config_pci_intr_type(struct pci_dev *dev, bde_ctrl_t *ctrl, int iproc) { - #ifdef CONFIG_PCI_MSI int ret; + shbde_iproc_config_t icfg; + /* Each device follows global policy by default */ ctrl->use_msi = use_msi; + if (unlikely(debug > 1)) gprintk("%s: msi = %d\n", __func__, ctrl->use_msi); + /* Check IPROC version for MSIX support */ + if (iproc && ctrl->bde_dev.base_address1 && + (ctrl->use_msi == PCI_USE_INT_MSIX)) { + if (shbde_pci_iproc_version_get(&ctrl->shbde, dev, &icfg.iproc_ver, + &icfg.cmic_ver, &icfg.cmic_rev)) { + if (icfg.iproc_ver < 0xe) { + gprintk("%s: MSI-X not supported, using MSI.\n", __func__); + ctrl->use_msi = PCI_USE_INT_MSI; + } + } + } + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84)) if (ctrl->use_msi == PCI_USE_INT_MSIX) { /* check for support MSIX vector */ @@ -2066,10 +2152,10 @@ config_pci_intr_type(bde_ctrl_t *ctrl) if (ctrl->use_msi == PCI_USE_INT_MSI) { /* check for support MSI vector */ - ret = pci_enable_msi(ctrl->pci_device); + ret = pci_enable_msi(ctrl->pci_device); if (ret < 0) { ctrl->use_msi = PCI_USE_INT_INTX; - gprintk("%s: Failed to enable MSI\n", __func__); + gprintk("%s: Failed to enable MSI, using INTx.\n", __func__); } else { pci_disable_msi(ctrl->pci_device); } @@ -2226,7 +2312,7 @@ _pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) return 0; } if (_switch_ndevices >= LINUX_BDE_MAX_SWITCH_DEVICES) { - return 0;; + return 0; } if (rescan) { @@ -2508,22 +2594,8 @@ _pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) } } - /* Each device follows global policy by default */ - ctrl->use_msi = use_msi; - - /* Check is MSI is properly supported in kernel for this device */ - if (ctrl->use_msi) { - if (pci_enable_msi(ctrl->pci_device) == 0) { - /* Release MSI resources until interrupt_connect is called */ - pci_disable_msi(ctrl->pci_device); - } else { - gprintk("Could not enable MSI interrupts\n"); - ctrl->use_msi = 0; - } - } - /* configure interrupt type */ - config_pci_intr_type(ctrl); + config_pci_intr_type(dev, ctrl, iproc); /* Configure iProc PCI-AXI bridge */ if (iproc && ctrl->bde_dev.base_address1) { @@ -2538,7 +2610,7 @@ _pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) &icfg->cmic_ver, &icfg->cmic_rev); shbde_iproc_config_init(icfg, ctrl->bde_dev.device, ctrl->bde_dev.rev); - if (debug >=2) { + if (debug >= 2) { gprintk("iproc version = %x dma_hi_bits = %x\n", icfg->iproc_ver, icfg->dma_hi_bits); } icfg->use_msi = ctrl->use_msi; @@ -2688,22 +2760,22 @@ _pci_remove(struct pci_dev* dev) if (ctrl->use_msi >= PCI_USE_INT_MSIX) { int i; for (i = 0; i < ctrl->msix_cnt; i++) - free_irq(ctrl->entries[i].vector, ctrl->pci_device); + free_irq(ctrl->entries[i].vector, ctrl); } else #endif { - free_irq(ctrl->iLine, ctrl); + free_irq(ctrl->iLine, ctrl); } } #ifdef CONFIG_PCI_MSI _msi_disconnect(ctrl); #endif - ctrl->isr = NULL; - ctrl->isr_data = NULL; - ctrl->isr2 = NULL; - ctrl->isr2_data = NULL; - } + ctrl->isr = NULL; + ctrl->isr_data = NULL; + ctrl->isr2 = NULL; + ctrl->isr2_data = NULL; +} static struct pci_driver _device_driver = { probe: _pci_probe, @@ -3589,8 +3661,12 @@ _gmac_dev_create(void) static int _init(void) { - #ifdef IPROC_CMICD +#ifdef CONFIG_OF + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + iproc_platform_driver_register(&iproc_cmicd_driver); + } else +#endif if (iproc_has_cmicd()) { iproc_cmicd_get_memregion(&iproc_cmicd_resources[IPROC_CMICD_RES_MEM]); iproc_platform_driver_register(&iproc_cmicd_driver); @@ -3599,8 +3675,8 @@ _init(void) #endif { /* Register platform device if no device node in dtb */ - iproc_platform_device_register(&iproc_cmicd_pdev); - } + iproc_platform_device_register(&iproc_cmicd_pdev); + } } #endif /* IPROC_CMICD */ @@ -3610,7 +3686,7 @@ _init(void) /* Register our goodies */ _device_driver.name = LINUX_KERNEL_BDE_NAME; -#if defined(BCM_ROBO_SUPPORT) +#if defined(BCM_ROBO_SUPPORT) #if defined(IPROC_CMICD) if (_gmac_dev_create()) { return -ENODEV; @@ -3754,6 +3830,11 @@ _cleanup(void) _dma_cleanup(); #ifdef IPROC_CMICD +#ifdef CONFIG_OF + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + iproc_platform_driver_unregister(&iproc_cmicd_driver); + } else +#endif if (iproc_has_cmicd()) { #ifdef CONFIG_OF if (!of_find_compatible_node(NULL, NULL, IPROC_CMICD_COMPATIBLE)) @@ -4234,14 +4315,18 @@ _interrupt_connect(int d, if (ctrl->use_msi == PCI_USE_INT_MSIX) { int i; for (i = 0; i < ctrl->msix_cnt; i++) { - ret = request_irq(ctrl->entries[i].vector, _isr, - irq_flags, LINUX_KERNEL_BDE_NAME, ctrl); + if (unlikely(debug >= 1)) { + gprintk("%s(%d):device# = %d, irq = %d\n", + __func__, __LINE__, d, ctrl->entries[i].vector); + } + ret = request_irq(ctrl->entries[i].vector, _isr, 0, + LINUX_KERNEL_BDE_NAME, ctrl); if (ret < 0) break; } if (ret < 0) { while (i >= 0) - free_irq(ctrl->entries[i--].vector, ctrl->pci_device); + free_irq(ctrl->entries[i--].vector, ctrl); goto err_disable_msi; } @@ -4249,15 +4334,39 @@ _interrupt_connect(int d, else #endif { - ret = request_irq(ctrl->iLine, _isr, irq_flags, +#if defined(IPROC_CMICD) && defined(CONFIG_OF) + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + int i, j; + for (i = 0; i < IHOST_CMICX_MAX_INTRS; i++) { + if (unlikely(debug >= 1)) + gprintk("%s(%d):device# = %d, request_irq(%d)\n", + __func__, __LINE__, d, iproc_cmicx_irqs[i]); + ret = request_irq(iproc_cmicx_irqs[i], _isr, + irq_flags, LINUX_KERNEL_BDE_NAME, ctrl); + if (ret < 0) { + gprintk("request_irq(%d) failed(%d)\n", iproc_cmicx_irqs[i], ret); + break; + } + } + if (ret < 0) { + for (j = 0; j < i; j++) { + free_irq(iproc_cmicx_irqs[j], ctrl); + } + goto err_disable_msi; + } + } else +#endif + { + ret = request_irq(ctrl->iLine, _isr, irq_flags, LINUX_KERNEL_BDE_NAME, ctrl); - if (ret < 0) - goto err_disable_msi; + if (ret < 0) + goto err_disable_msi; - if (unlikely(debug >= 1)) - gprintk("%s(%d):device# = %d, irq_flags = %lu, irq = %d\n", + if (unlikely(debug >= 1)) + gprintk("%s(%d):device# = %d, irq_flags = %lu, irq = %d\n", __func__, __LINE__, d, irq_flags, ctrl->pci_device ? ctrl->pci_device->irq : ctrl->iLine); + } } } return 0; @@ -4275,7 +4384,7 @@ _interrupt_connect(int d, ctrl->isr2_data = NULL; return -1; - } +} static int _interrupt_disconnect(int d) @@ -4336,13 +4445,30 @@ _interrupt_disconnect(int d) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84)) if (ctrl->use_msi >= PCI_USE_INT_MSIX) { int i; - for (i = 0; i < ctrl->msix_cnt; i++) - free_irq(ctrl->entries[i].vector, ctrl->pci_device); + for (i = 0; i < ctrl->msix_cnt; i++) { + if (unlikely(debug > 1)) { + gprintk("%s(%d):device# = %d, irq = %d\n", + __func__, __LINE__, d, ctrl->entries[i].vector); + } + free_irq(ctrl->entries[i].vector, ctrl); + } } else +#endif +#if defined(IPROC_CMICD) && defined(CONFIG_OF) + if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) { + int i; + for (i = 0; i < IHOST_CMICX_MAX_INTRS; i++) { + if (unlikely(debug > 1)) { + gprintk("%s(%d):device# = %d, free_irq(%d)\n", + __func__, __LINE__, d, iproc_cmicx_irqs[i]); + } + free_irq(iproc_cmicx_irqs[i], ctrl); + } + } else #endif { - free_irq(ctrl->iLine, ctrl); + free_irq(ctrl->iLine, ctrl); } #ifdef CONFIG_PCI_MSI if (ctrl->use_msi >= PCI_USE_INT_MSI) { 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 7fc9fd166bbd..6c7c9bb95056 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 @@ -30,6 +30,9 @@ #include "linux-user-bde.h" +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) +#include +#endif #ifdef KEYSTONE #include #endif @@ -75,21 +78,56 @@ MODULE_LICENSE("GPL"); /* CMICX defines */ #define INTC_INTR_REG_NUM (8) -#define INTC_INTR_ENABLE_REG0 (0x180130f0) -#define INTC_INTR_STATUS_REG0 (0x18013190) -#define INTC_INTR_RAW_STATUS_REG0 (0x18013140) +/* +TODO:HX5 +The INTR base address values are changed for HX5, +hence making new #defines so runtime decisions can +be made. +*/ + +#define INTC_INTR_ENABLE_REG0 (0x180130f0) +#define INTC_INTR_STATUS_REG0 (0x18013190) +#define INTC_INTR_RAW_STATUS_REG0 (0x18013140) #define INTC_INTR_ENABLE_BASE (INTC_INTR_ENABLE_REG0) #define INTC_INTR_STATUS_BASE (INTC_INTR_STATUS_REG0) #define INTC_INTR_RAW_STATUS_BASE (INTC_INTR_RAW_STATUS_REG0) -#define INTC_PDMA_INTR_REG_IND 4 +#define HX5_INTC_INTR_ENABLE_REG0 (0x102310f0) +#define HX5_INTC_INTR_STATUS_REG0 (0x10231190) +#define HX5_INTC_INTR_RAW_STATUS_REG0 (0x10231140) + +#define HX5_INTC_INTR_ENABLE_BASE (HX5_INTC_INTR_ENABLE_REG0) +#define HX5_INTC_INTR_STATUS_BASE (HX5_INTC_INTR_STATUS_REG0) +#define HX5_INTC_INTR_RAW_STATUS_BASE (HX5_INTC_INTR_RAW_STATUS_REG0) + +#define IOREMAP(addr, size) ioremap_nocache(addr, size) + +#define HX5_IHOST_GICD_ISENABLERN_0 (0x10781100) +#define HX5_IHOST_GICD_ISENABLERN_1 (0x10781104) +#define HX5_IHOST_GICD_ICENABLERN_1 (0x10781184) +#define HX5_IHOST_GICD_ICENABLERN_8 (0x107811a0) +/* Offset between ISENABLERN_1 and ICENABLERN_1 in 4-bytes */ +#define HX5_IHOST_IRQ_MASK_OFFSET 0x20 +#define HX5_IHOST_INTR_MAP_NUM (HX5_IHOST_GICD_ICENABLERN_8 - HX5_IHOST_GICD_ISENABLERN_0) +#define HX5_IHOST_INTR_STATUS_MAP_NUM (INTC_INTR_REG_NUM * (sizeof(uint32))) +#define IRQ_BIT(intr) (intr % (sizeof(uint32)*8)) +#define IRQ_MASK_INDEX(intr) (intr / (sizeof(uint32)*8)) +#define HX5_CHIP_INTR_LOW_PRIORITY 119 +#define INTR_LOW_PRIORITY_BITPOS (1 << IRQ_BIT(HX5_CHIP_INTR_LOW_PRIORITY)) +#define INTC_LOW_PRIORITY_INTR_REG_IND IRQ_MASK_INDEX(HX5_CHIP_INTR_LOW_PRIORITY) +#define INTC_PDMA_INTR_REG_IND 4 #define READ_INTC_INTR(d, reg, v) \ - (v = user_bde->iproc_read(d, reg)) + (v = user_bde->iproc_read(d, reg)) #define WRITE_INTC_INTR(d, reg, v) \ (user_bde->iproc_write(d, reg, v)) +#define IHOST_READ_INTR(d, reg, v) \ + (v = readl((reg))) +#define IHOST_WRITE_INTR(d, reg, v) \ + (writel((v), (reg))) + /* Allow override of default CMICm CMC */ #ifndef BDE_CMICM_PCIE_CMC #define BDE_CMICM_PCIE_CMC 0 @@ -103,6 +141,9 @@ MODULE_LICENSE("GPL"); /* Defines used to distinguish CMICe from CMICm */ #define CMICE_DEV_REV_ID (0x178 / sizeof(uint32)) +static uint32 *ihost_intr_status_base = NULL; +static uint32 *ihost_intr_enable_base = NULL; + static ibde_t *user_bde = NULL; typedef void (*isr_f)(void *); @@ -225,27 +266,68 @@ _cmicx_interrupt(bde_ctrl_t *ctrl) int d, ind; uint32 stat, iena, mask, fmask; bde_inst_resource_t *res; + uint32 intc_intr_status_base = 0, intc_intr_enable_base = 0; d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t)); res = &_bde_inst_resource[ctrl->inst]; lkbde_irq_mask_get(d, &mask, &fmask); + if ((ctrl->dev_type & BDE_SWITCH_DEV_TYPE) && + ((user_bde->get_dev(d)->device == BCM56370_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56371_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56372_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56374_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56375_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56376_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56377_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56577_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56578_DEVICE_ID) || + (user_bde->get_dev(d)->device == BCM56579_DEVICE_ID))) { + intc_intr_status_base = HX5_INTC_INTR_STATUS_BASE; + intc_intr_enable_base = HX5_INTC_INTR_ENABLE_BASE; + } else { + intc_intr_status_base = INTC_INTR_STATUS_BASE; + intc_intr_enable_base = INTC_INTR_ENABLE_BASE; + } if (fmask) { - READ_INTC_INTR(d, INTC_INTR_STATUS_BASE + 4 * INTC_PDMA_INTR_REG_IND, stat); - READ_INTC_INTR(d, INTC_INTR_ENABLE_BASE + 4 * INTC_PDMA_INTR_REG_IND, iena); + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + IHOST_READ_INTR(d, ihost_intr_status_base + INTC_PDMA_INTR_REG_IND, stat); + IHOST_READ_INTR(d, ihost_intr_enable_base + INTC_PDMA_INTR_REG_IND, iena); + } else { + READ_INTC_INTR(d, intc_intr_status_base + 4 * INTC_PDMA_INTR_REG_IND, stat); + READ_INTC_INTR(d, intc_intr_enable_base + 4 * INTC_PDMA_INTR_REG_IND, iena); + } if (stat & iena) { - WRITE_INTC_INTR(d, INTC_INTR_ENABLE_BASE + 4 * INTC_PDMA_INTR_REG_IND, 0); + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + IHOST_WRITE_INTR(d, ihost_intr_enable_base + INTC_PDMA_INTR_REG_IND + + HX5_IHOST_IRQ_MASK_OFFSET, ~0); + } else { + WRITE_INTC_INTR(d, intc_intr_enable_base + 4 * INTC_PDMA_INTR_REG_IND, 0); + } + for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) { if (ind == INTC_PDMA_INTR_REG_IND) { continue; } - READ_INTC_INTR(d, INTC_INTR_STATUS_BASE + 4 * ind, stat); - READ_INTC_INTR(d, INTC_INTR_ENABLE_BASE + 4 * ind, iena); + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + if (ind < INTC_LOW_PRIORITY_INTR_REG_IND) { + continue; + } + IHOST_READ_INTR(d, ihost_intr_status_base + ind, stat); + IHOST_READ_INTR(d, ihost_intr_enable_base + ind, iena); + if (ind == INTC_LOW_PRIORITY_INTR_REG_IND) { + stat &= INTR_LOW_PRIORITY_BITPOS; + } + } else { + READ_INTC_INTR(d, intc_intr_status_base + 4 * ind, stat); + READ_INTC_INTR(d, intc_intr_enable_base + 4 * ind, iena); + } if (stat & iena) { break; } } + if (ind >= INTC_INTR_REG_NUM) { return; } @@ -260,7 +342,20 @@ _cmicx_interrupt(bde_ctrl_t *ctrl) if (fmask && ind == INTC_PDMA_INTR_REG_IND) { continue; } - WRITE_INTC_INTR(d, INTC_INTR_ENABLE_BASE + 4 * ind, 0); + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + if (ind < INTC_LOW_PRIORITY_INTR_REG_IND) { + continue; + } + if (ind == INTC_LOW_PRIORITY_INTR_REG_IND) { + IHOST_WRITE_INTR(d, ihost_intr_enable_base + INTC_LOW_PRIORITY_INTR_REG_IND + + HX5_IHOST_IRQ_MASK_OFFSET, INTR_LOW_PRIORITY_BITPOS); + } else { + IHOST_WRITE_INTR(d, ihost_intr_enable_base + ind + + HX5_IHOST_IRQ_MASK_OFFSET, ~0); + } + } else { + WRITE_INTC_INTR(d, intc_intr_enable_base + 4*ind, 0); + } } /* Notify */ @@ -750,6 +845,12 @@ _devices_init(int d) uint32 ver; uint16 device_id_mask = 0xFFF0; uint16 device_id; + int state = 0; + + (void)lkbde_dev_state_get(d, &state); + if (state == BDE_DEV_STATE_REMOVED) { + return; + } ctrl = &_devices[d]; /* Initialize our control info */ @@ -849,6 +950,31 @@ _devices_init(int d) case BCM88952_DEVICE_ID: ctrl->isr = (isr_f)_cmicd_cmc0_interrupt; break; + case BCM88790_DEVICE_ID: + ctrl->isr = (isr_f)_cmicx_interrupt; + break; + case BCM56370_DEVICE_ID: + case BCM56371_DEVICE_ID: + case BCM56372_DEVICE_ID: + case BCM56374_DEVICE_ID: + case BCM56375_DEVICE_ID: + case BCM56376_DEVICE_ID: + case BCM56377_DEVICE_ID: + case BCM56577_DEVICE_ID: + case BCM56578_DEVICE_ID: + case BCM56579_DEVICE_ID: + ctrl->isr = (isr_f)_cmicx_interrupt; + if (ctrl->dev_type & BDE_AXI_DEV_TYPE) { + if (!ihost_intr_enable_base) { + ihost_intr_enable_base = (uint32_t *)IOREMAP(HX5_IHOST_GICD_ISENABLERN_1, + HX5_IHOST_INTR_MAP_NUM); + } + if (!ihost_intr_status_base) { + ihost_intr_status_base = (uint32_t *)IOREMAP(HX5_INTC_INTR_RAW_STATUS_REG0, + HX5_IHOST_INTR_STATUS_MAP_NUM); + } + } + break; default: /* Get CMIC version */ if (user_bde->get_cmic_ver(d, &ver) != 0) { @@ -876,7 +1002,7 @@ _devices_init(int d) } break; } - /*All Ramon devices from 0x8790 to 0x879F*/ + /* All Ramon devices from 0x8790 to 0x879F */ if ((user_bde->get_dev(d)->device & BCM88790_DEVICE_ID) == BCM88790_DEVICE_ID) { ctrl->isr = (isr_f)_cmicx_interrupt; } @@ -928,10 +1054,14 @@ _init(void) init_waitqueue_head(&res->intr_wq); atomic_set(&res->intr, 0); + ihost_intr_enable_base = NULL; + ihost_intr_status_base = NULL; + for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) { res->inst_id |= (1 << i); _devices_init(i); } + return 0; } @@ -961,6 +1091,16 @@ _cleanup(void) linux_bde_destroy(user_bde); user_bde = NULL; } + + if (ihost_intr_enable_base) { + iounmap(ihost_intr_enable_base); + ihost_intr_enable_base = NULL; + } + if (ihost_intr_status_base) { + iounmap(ihost_intr_status_base); + ihost_intr_status_base = NULL; + } + return 0; } @@ -1088,6 +1228,7 @@ static int _device_reprobe(void) { int i; + for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) { if (_devices[i].devid == 0) { _devices_init(i); @@ -1167,7 +1308,8 @@ _ioctl(unsigned int cmd, unsigned long arg) ssize_t size; const ibde_dev_t *bde_dev; int inst_id; - bde_inst_resource_t *res; + bde_inst_resource_t *res; + uint32_t *mapaddr; if (copy_from_user(&io, (void *)arg, sizeof(io))) { return -EFAULT; @@ -1396,9 +1538,22 @@ _ioctl(unsigned int cmd, unsigned long arg) } break; case LUBDE_IPROC_READ_REG: - io.d1 = user_bde->iproc_read(io.dev, io.d0); - if (io.d1 == -1) { - io.rc = LUBDE_FAIL; + if (!VALID_DEVICE(io.dev)) { + return -EINVAL; + } + if (_devices[io.dev].dev_type & BDE_AXI_DEV_TYPE) { + mapaddr = IOREMAP(io.d0, sizeof(uint32_t)); + if (mapaddr == NULL) { + io.rc = LUBDE_FAIL; + return -1; + } + io.d1 = readl(mapaddr); + iounmap(mapaddr); + } else { + io.d1 = user_bde->iproc_read(io.dev, io.d0); + if (io.d1 == -1) { + io.rc = LUBDE_FAIL; + } } break; case LUBDE_IPROC_WRITE_REG: @@ -1412,6 +1567,9 @@ _ioctl(unsigned int cmd, unsigned long arg) case LUBDE_GET_DEVICE_STATE: io.rc = lkbde_dev_state_get(io.dev, &io.d0); break; + case LUBDE_REPROBE: + io.rc = _device_reprobe(); + break; default: gprintk("Error: Invalid ioctl (%08x)\n", cmd); io.rc = LUBDE_FAIL; 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 621973b7a7f5..535ccac9fad9 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 @@ -81,6 +81,7 @@ typedef struct { #define LUBDE_IPROC_WRITE_REG _IO(LUBDE_MAGIC, 28) #define LUBDE_ATTACH_INSTANCE _IO(LUBDE_MAGIC, 29) #define LUBDE_GET_DEVICE_STATE _IO(LUBDE_MAGIC, 30) +#define LUBDE_REPROBE _IO(LUBDE_MAGIC, 31) #define LUBDE_SEM_OP_CREATE 1 #define LUBDE_SEM_OP_DESTROY 2 @@ -93,9 +94,10 @@ typedef struct { /* * Version history - * 1:add LUBDE_GET_DEVICE_STATE to support PCI hot plug + * 1: add LUBDE_GET_DEVICE_STATE to support PCI hot plug + * 2: add LUBDE_REPROBE to support reprobe available devices */ -#define KBDE_VERSION 1 +#define KBDE_VERSION 2 /* This is the signal that will be used 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 d1e95725c5f7..e1bdcc4db0da 100644 --- a/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_iproc.c +++ b/platform/broadcom/saibcm-modules/systems/bde/shared/shbde_iproc.c @@ -40,6 +40,8 @@ #define BAR0_PAXB_OARR_2_UPPER 0x2d64 #define BAR0_DMU_PCU_PCIE_SLAVE_RESET_MODE 0x7024 +#define PAXB_0_FUNC0_IMAP1_3 0x2d88 + /* Force byte pointer for offset adjustments */ #define ROFFS(_ptr, _offset) ((unsigned char*)(_ptr) + (_offset)) @@ -47,6 +49,7 @@ #define PAXB_CONFIG_IND_ADDRr_PROTOCOL_LAYERf_MASK 0x3 #define PAXB_CONFIG_IND_ADDRr_ADDRESSf_SHFT 0 #define PAXB_CONFIG_IND_ADDRr_ADDRESSf_MASK 0x7ff +#define PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT 20 /* Register value set/get by field */ #define REG_FIELD_SET(_r, _f, _r_val, _f_val) \ @@ -273,17 +276,25 @@ shbde_iproc_paxb_init(shbde_hal_t *shbde, void *iproc_regs, reg = ROFFS(iproc_regs, BAR0_PAXB_PCIE_EP_AXI_CONFIG); iproc32_write(shbde, reg, 0x0); if(icfg->cmic_ver < 4) { /* Non-CMICX */ - reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_2); - iproc32_write(shbde, reg, 0x1); - reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_2_UPPER); - iproc32_write(shbde, reg, icfg->dma_hi_bits); - - /* Configure MSI interrupt page */ - if (icfg->use_msi) { - reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_FUNC0_MSI_PAGE); - data = iproc32_read(shbde, reg); - iproc32_write(shbde, reg, data | 0x1); + reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_2); + iproc32_write(shbde, reg, 0x1); + reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_2_UPPER); + iproc32_write(shbde, reg, icfg->dma_hi_bits); + /* Configure MSI interrupt page */ + if (icfg->use_msi) { + reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_FUNC0_MSI_PAGE); + data = iproc32_read(shbde, reg); + iproc32_write(shbde, reg, data | 0x1); + } } + /* Configure MSIX interrupt page, only need for iproc ver == 0x10 */ + if ((icfg->use_msi == 2) && (icfg->iproc_ver == 0x10)) { + unsigned int mask = (0x1 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT) - 1; + reg = ROFFS(iproc_regs, PAXB_0_FUNC0_IMAP1_3); + data = iproc32_read(shbde, reg); + data &= mask; + data |= 0x410 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT; + iproc32_write(shbde, reg, data); } return pci_num; } @@ -315,7 +326,8 @@ shbde_iproc_pci_read(shbde_hal_t *shbde, void *iproc_regs, /* Sub-window size is 0x1000 (4K) */ subwin_base = (addr & ~0xfff); - if((icfg->cmic_ver >= 4) && (subwin_base == 0x18013000)) { + if((icfg->cmic_ver >= 4) && + ((subwin_base == 0x10231000) || (subwin_base == 0x18013000))) { /* Route the INTC block access through IMAP0_6 */ reg = ROFFS(iproc_regs, 0x6000 + (addr & 0xfff)); } else { @@ -361,7 +373,8 @@ shbde_iproc_pci_write(shbde_hal_t *shbde, void *iproc_regs, /* Sub-window size is 0x1000 (4K) */ subwin_base = (addr & ~0xfff); - if((icfg->cmic_ver >= 4) && (subwin_base == 0x18013000)) { + if((icfg->cmic_ver >= 4) && + ((subwin_base == 0x10231000) || (subwin_base == 0x18013000))) { /* Route the INTC block access through IMAP0_6 */ reg = ROFFS(iproc_regs, 0x6000 + (addr & 0xfff)); } else { 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 801f5d3e406c..e40a160ef937 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 @@ -301,6 +301,13 @@ static int use_proxy = 0; #endif /* Compatibility */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)) +#define NETDEV_UPDATE_TRANS_START_TIME(dev) dev->trans_start = jiffies +#else +#define NETDEV_UPDATE_TRANS_START_TIME(dev) netif_trans_update(dev) +#endif + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) #define skb_copy_to_linear_data(_skb, _pkt, _len) \ eth_copy_and_sum(_skb, _pkt, _len, 0) @@ -464,6 +471,9 @@ typedef struct bkn_dcb_chain_s { #define NUM_CMICX_RX_CHAN 7 #define NUM_CMICM_RX_CHAN 3 +#define FCS_SZ 4 +#define TAG_SZ 4 + /* Device control info */ typedef struct bkn_switch_info_s { struct list_head list; @@ -505,6 +515,7 @@ typedef struct bkn_switch_info_s { uint32_t rcpu_sig; /* RCPU signature */ uint64_t halt_addr[NUM_DMA_CHAN]; /* DMA halt address */ uint32_t cdma_channels; /* Active channels for Continuous DMA mode */ + uint32_t poll_channels; /* Channels for polling */ uint32_t inst_id; /* Instance id of this device */ int evt_idx; /* Event queue index for this device*/ int basedev_suspended; /* Base device suspended */ @@ -536,7 +547,6 @@ typedef struct bkn_switch_info_s { int dirty; /* Index of next Rx DCB to complete */ int running; /* Rx DMA is active */ int api_active; /* BCM Rx API is active */ - int api_wait; /* Wait BCM Rx API resources */ int chain_complete; /* All DCBs in chain processed */ int sync_err; /* Chain done with incomplete DCBs (debug) */ int sync_retry; /* Total retry times for sync error (debug) */ @@ -684,7 +694,7 @@ typedef struct bkn_pkt_dnx_s { #endif /* defined(CMIC_SOFT_BYTE_SWAP) */ -#define MEMORY_BARRIER mb() +#define MEMORY_BARRIER smp_mb() /* Default random MAC address has Broadcom OUI with local admin bit set */ static u8 bkn_dev_mac[6] = { 0x02, 0x10, 0x18, 0x00, 0x00, 0x00 }; @@ -1753,7 +1763,6 @@ bkn_clean_rx_dcbs(bkn_switch_info_t *sinfo, int chan) } sinfo->rx[chan].running = 0; sinfo->rx[chan].api_active = 0; - sinfo->rx[chan].api_wait = 0; DBG_DCB_RX(("Cleaned Rx%d DCBs (%d %d).\n", chan, sinfo->rx[chan].cur, sinfo->rx[chan].dirty)); } @@ -1959,7 +1968,7 @@ bkn_api_rx_restart(bkn_switch_info_t *sinfo, int chan) sinfo->rx[chan].chain_complete = 0; start_dma = 1; if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) && - sinfo->rx[chan].api_wait) { + sinfo->rx[chan].api_active) { /* HW is running already, so we just move to the next chain */ start_dma = 0; } @@ -1972,7 +1981,6 @@ bkn_api_rx_restart(bkn_switch_info_t *sinfo, int chan) dev_dma_chan_clear(sinfo, XGS_DMA_RX_CHAN + chan); dev_irq_mask_enable(sinfo, XGS_DMA_RX_CHAN + chan, 1); dev_dma_chan_start(sinfo, XGS_DMA_RX_CHAN + chan, dcb_chain->dcb_dma); - sinfo->rx[chan].api_wait = 1; } list_del(&dcb_chain->list); @@ -1992,10 +2000,6 @@ bkn_api_rx_chain_done(bkn_switch_info_t *sinfo, int chan) sinfo->rx[chan].api_dcb_chain = NULL; } bkn_api_rx_restart(sinfo, chan); - if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) && - sinfo->rx[chan].api_dcb_chain == NULL) { - sinfo->rx[chan].api_active = 0; - } } static int @@ -2053,6 +2057,7 @@ bkn_api_rx_copy_from_skb(bkn_switch_info_t *sinfo, } } dcb[sinfo->dcb_wsize-1] = dcb_stat | SOC_DCB_KNET_DONE; + MEMORY_BARRIER; dcb_chain->dcb_cur++; @@ -2062,6 +2067,7 @@ bkn_api_rx_copy_from_skb(bkn_switch_info_t *sinfo, (sinfo->cmic_type != 'x' && dcb[1] & (1 << 18))) { /* Get the next chain if reload done */ dcb[sinfo->dcb_wsize-1] |= 1 << 31 | SOC_DCB_KNET_DONE; + MEMORY_BARRIER; bkn_api_rx_chain_done(sinfo, chan); dcb_chain = sinfo->rx[chan].api_dcb_chain; if (dcb_chain == NULL) { @@ -2090,7 +2096,7 @@ bkn_rx_refill(bkn_switch_info_t *sinfo, int chan) struct sk_buff *skb; bkn_desc_info_t *desc; uint32_t *dcb; - uint32_t encap_size = sinfo->cmic_type == 'x' ? RCPU_HDR_SIZE : RCPU_RX_ENCAP_SIZE; + uint32_t resv_size = sinfo->cmic_type == 'x' ? RCPU_HDR_SIZE : RCPU_RX_ENCAP_SIZE; int prev; if (sinfo->rx[chan].use_rx_skb == 0) { @@ -2107,11 +2113,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 + encap_size); + skb = dev_alloc_skb(rx_buffer_size + RCPU_RX_ENCAP_SIZE); if (skb == NULL) { break; } - skb_reserve(skb, encap_size); + skb_reserve(skb, resv_size); desc->skb = skb; } else { DBG_DCB_RX(("Refill Rx%d SKB in DCB %d recycled.\n", @@ -3198,11 +3204,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++; - if (bkn_api_rx_copy_from_skb(sinfo, chan, desc) < 0) { - /* Suspend SKB Rx due to no API resources */ - sinfo->rx[chan].api_wait = 1; - return dcbs_done; - } + bkn_api_rx_copy_from_skb(sinfo, chan, desc); break; case KCOM_DEST_T_NETIF: priv = bkn_netif_lookup(sinfo, filter->kf.dest_id); @@ -3408,10 +3410,6 @@ bkn_rx_desc_done(bkn_switch_info_t *sinfo, int chan) static void bkn_rx_chain_done(bkn_switch_info_t *sinfo, int chan) { - if (sinfo->rx[chan].use_rx_skb && sinfo->rx[chan].api_wait) { - return; - } - DBG_IRQ(("Rx%d chain done\n", chan)); if (sinfo->rx[chan].chain_complete == 0) { @@ -3809,6 +3807,7 @@ static int xgs_do_dma(bkn_switch_info_t *sinfo, int budget) { int rx_dcbs_done = 0, tx_dcbs_done = 0; + int chan_done, budget_chans = 0; uint32_t dma_stat; int chan; @@ -3817,7 +3816,28 @@ xgs_do_dma(bkn_switch_info_t *sinfo, int budget) for (chan = 0; chan < sinfo->rx_chans; chan++) { if (dma_stat & DS_DESC_DONE_TST(XGS_DMA_RX_CHAN + chan)) { xgs_dma_desc_clear(sinfo, XGS_DMA_RX_CHAN + chan); - rx_dcbs_done += bkn_do_rx(sinfo, chan, budget - rx_dcbs_done); + sinfo->poll_channels |= 1 << chan; + } + } + if (!sinfo->poll_channels) { + sinfo->poll_channels = (uint32_t)(1 << sinfo->rx_chans) - 1; + budget_chans = budget / sinfo->rx_chans; + } else { + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + budget_chans++; + } + } + budget_chans = budget / budget_chans; + } + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + chan_done = bkn_do_rx(sinfo, chan, budget_chans); + rx_dcbs_done += chan_done; + if (chan_done < budget_chans) { + sinfo->poll_channels &= ~(1 << chan); + } bkn_rx_desc_done(sinfo, chan); } @@ -3833,13 +3853,14 @@ xgs_do_dma(bkn_switch_info_t *sinfo, int budget) bkn_tx_chain_done(sinfo, tx_dcbs_done); } - return rx_dcbs_done; + return sinfo->poll_channels ? budget : rx_dcbs_done; } static int xgsm_do_dma(bkn_switch_info_t *sinfo, int budget) { int rx_dcbs_done = 0, tx_dcbs_done = 0; + int chan_done, budget_chans = 0; uint32_t dma_stat, irq_stat = 0; int chan; @@ -3854,7 +3875,28 @@ xgsm_do_dma(bkn_switch_info_t *sinfo, int budget) if (dma_stat & (0x10 << (XGS_DMA_RX_CHAN + chan)) || irq_stat & (0x08000000 << (XGS_DMA_RX_CHAN + chan))) { xgsm_dma_desc_clear(sinfo, XGS_DMA_RX_CHAN + chan); - rx_dcbs_done += bkn_do_rx(sinfo, chan, budget - rx_dcbs_done); + sinfo->poll_channels |= 1 << chan; + } + } + if (!sinfo->poll_channels) { + sinfo->poll_channels = (uint32_t)(1 << sinfo->rx_chans) - 1; + budget_chans = budget / sinfo->rx_chans; + } else { + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + budget_chans++; + } + } + budget_chans = budget / budget_chans; + } + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + chan_done = bkn_do_rx(sinfo, chan, budget_chans); + rx_dcbs_done += chan_done; + if (chan_done < budget_chans) { + sinfo->poll_channels &= ~(1 << chan); + } bkn_rx_desc_done(sinfo, chan); } @@ -3879,22 +3921,45 @@ xgsm_do_dma(bkn_switch_info_t *sinfo, int budget) bkn_tx_chain_done(sinfo, tx_dcbs_done); } - return rx_dcbs_done; + return sinfo->poll_channels ? budget : rx_dcbs_done; } static int xgsx_do_dma(bkn_switch_info_t *sinfo, int budget) { int rx_dcbs_done = 0, tx_dcbs_done = 0; + int chan_done, budget_chans = 0; uint32_t irq_stat; int chan; DEV_READ32(sinfo, CMICX_IRQ_STATr, &irq_stat); + for (chan = 0; chan < sinfo->rx_chans; chan++) { if ((irq_stat & CMICX_DS_CMC_CTRLD_INT(XGS_DMA_RX_CHAN + chan)) || (irq_stat & CMICX_DS_CMC_DESC_DONE(XGS_DMA_RX_CHAN + chan))) { xgsx_dma_desc_clear(sinfo, XGS_DMA_RX_CHAN + chan); - rx_dcbs_done += bkn_do_rx(sinfo, chan, budget - rx_dcbs_done); + sinfo->poll_channels |= 1 << chan; + } + } + if (!sinfo->poll_channels) { + sinfo->poll_channels = (uint32_t)(1 << sinfo->rx_chans) - 1; + budget_chans = budget / sinfo->rx_chans; + } else { + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + budget_chans++; + } + } + budget_chans = budget / budget_chans; + } + + for (chan = 0; chan < sinfo->rx_chans; chan++) { + if (1 << chan & sinfo->poll_channels) { + chan_done = bkn_do_rx(sinfo, chan, budget_chans); + rx_dcbs_done += chan_done; + if (chan_done < budget_chans) { + sinfo->poll_channels &= ~(1 << chan); + } bkn_rx_desc_done(sinfo, chan); } @@ -3919,7 +3984,7 @@ xgsx_do_dma(bkn_switch_info_t *sinfo, int budget) bkn_tx_chain_done(sinfo, tx_dcbs_done); } - return rx_dcbs_done; + return sinfo->poll_channels ? budget : rx_dcbs_done; } static int @@ -4329,7 +4394,7 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) uint32_t *dcb, *meta; pktdata = skb->data; - pktlen = skb->len + 4; + pktlen = skb->len; hdrlen = sinfo->cmic_type == 'x' ? PKT_TX_HDR_SIZE : 0; rcpulen = 0; sop = 0; @@ -4385,7 +4450,7 @@ 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 + 4); + new_skb = dev_alloc_skb(pktlen + TAG_SZ + FCS_SZ); if (new_skb == NULL) { DBG_WARN(("Tx drop: No SKB memory\n")); priv->stats.tx_dropped++; @@ -4396,23 +4461,25 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) } memcpy(new_skb->data, pktdata, 12); memcpy(&new_skb->data[16], &pktdata[12], pktlen - 12); - skb_put(new_skb, pktlen + 4); + skb_put(new_skb, pktlen + TAG_SZ); dev_kfree_skb_any(skb); skb = new_skb; pktdata = skb->data; + rcpulen = 0; } else { /* Add tag to RCPU header space */ DBG_SKB(("Expand into unused RCPU header\n")); - pktdata = &skb->data[rcpulen - 4]; + rcpulen -= TAG_SZ; + pktdata = &skb->data[rcpulen]; for (idx = 0; idx < 12; idx++) { - pktdata[idx] = pktdata[idx + 4]; + pktdata[idx] = pktdata[idx + TAG_SZ]; } } pktdata[12] = 0x81; pktdata[13] = 0x00; pktdata[14] = (priv->vlan >> 8) & 0xf; pktdata[15] = priv->vlan & 0xff; - pktlen += 4; + pktlen += TAG_SZ; } } } else { @@ -4421,7 +4488,7 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) ((unsigned long)skb->data % 4)) { /* Current SKB cannot be modified */ DBG_SKB(("Realloc Tx SKB\n")); - new_skb = dev_alloc_skb(pktlen + hdrlen + 4); + new_skb = dev_alloc_skb(pktlen + hdrlen + 4 + FCS_SZ); if (new_skb == NULL) { DBG_WARN(("Tx drop: No SKB memory\n")); priv->stats.tx_dropped++; @@ -4453,7 +4520,7 @@ 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 + 4); + new_skb = dev_alloc_skb(pktlen + TAG_SZ + FCS_SZ); if (new_skb == NULL) { DBG_WARN(("Tx drop: No SKB memory\n")); priv->stats.tx_dropped++; @@ -4465,15 +4532,15 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) 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 + 4); + skb_put(new_skb, pktlen + TAG_SZ); dev_kfree_skb_any(skb); skb = new_skb; } else { /* Add tag to existing buffer */ DBG_SKB(("Expand Tx SKB\n")); - skb_push(skb, 4); + skb_push(skb, TAG_SZ); for (idx = 0; idx < hdrlen + 12; idx++) { - skb->data[idx] = skb->data[idx + 4]; + skb->data[idx] = skb->data[idx + TAG_SZ]; } } pktdata = skb->data; @@ -4481,7 +4548,7 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) pktdata[hdrlen + 13] = 0x00; pktdata[hdrlen + 14] = (priv->vlan >> 8) & 0xf; pktdata[hdrlen + 15] = priv->vlan & 0xff; - pktlen += 4; + pktlen += TAG_SZ; } } } @@ -4492,8 +4559,8 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) if (tpid == 0x8100) { taglen = 4; } - if (pktlen < (64 + taglen + hdrlen)) { - pktlen = (64 + taglen + hdrlen); + if (pktlen < (60 + taglen + hdrlen)) { + pktlen = (60 + taglen + hdrlen); if (SKB_PADTO(skb, pktlen) != 0) { DBG_WARN(("Tx drop: skb_padto failed\n")); priv->stats.tx_dropped++; @@ -4502,12 +4569,14 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&sinfo->lock, flags); return 0; } + /* skb_padto may update the skb->data pointer */ + pktdata = &skb->data[rcpulen]; DBG_SKB(("Packet padded to %d bytes\n", pktlen)); } - if (pktlen > SOC_DCB_KNET_COUNT_MASK) { + if ((pktlen + FCS_SZ) > SOC_DCB_KNET_COUNT_MASK) { DBG_WARN(("Tx drop: size of pkt (%d) is out of range(%d)\n", - pktlen, SOC_DCB_KNET_COUNT_MASK)); + (pktlen + FCS_SZ), SOC_DCB_KNET_COUNT_MASK)); sinfo->tx.pkts_d_over_limit++; priv->stats.tx_dropped++; dev_kfree_skb_any(skb); @@ -4568,7 +4637,7 @@ 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 for DNX ITMH header\n")); - new_skb = dev_alloc_skb(pktlen + 4 + 2); + new_skb = dev_alloc_skb(pktlen + 4 + 2 + FCS_SZ); if (new_skb == NULL) { DBG_WARN(("Tx drop: No SKB memory for DNX ITMH header\n")); priv->stats.tx_dropped++; @@ -4597,7 +4666,7 @@ 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 for DNX header\n")); - new_skb = dev_alloc_skb(pktlen + 2); + new_skb = dev_alloc_skb(pktlen + 2 + FCS_SZ); if (new_skb == NULL) { DBG_WARN(("Tx drop: No SKB memory for DNX header\n")); priv->stats.tx_dropped++; @@ -4695,11 +4764,10 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) /* Restore (possibly) altered packet variables * bit0 -bit15 of dcb[1] is used to save requested byte count */ - if ((skb->len + 4) <= SOC_DCB_KNET_COUNT_MASK) { - pktdata = skb->data; - pktlen = skb->len + 4; - if (pktlen < (64 + taglen + hdrlen)) { - pktlen = (64 + taglen + hdrlen); + if ((skb->len + FCS_SZ) <= SOC_DCB_KNET_COUNT_MASK) { + pktlen = skb->len; + if (pktlen < (60 + taglen + hdrlen)) { + pktlen = (60 + taglen + hdrlen); if (SKB_PADTO(skb, pktlen) != 0) { DBG_WARN(("Tx drop: skb_padto failed\n")); priv->stats.tx_dropped++; @@ -4710,9 +4778,10 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) } DBG_SKB(("Packet padded to %d bytes after tx callback\n", pktlen)); } + pktdata = skb->data; } else { DBG_WARN(("Tx drop: size of pkt (%d) is out of range(%d)\n", - pktlen, SOC_DCB_KNET_COUNT_MASK)); + (pktlen + FCS_SZ), SOC_DCB_KNET_COUNT_MASK)); sinfo->tx.pkts_d_over_limit++; priv->stats.tx_dropped++; sinfo->tx.pkts_d_callback++; @@ -4724,6 +4793,8 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) /* Prepare for DMA */ desc->skb = skb; + /* Add FCS bytes */ + pktlen = pktlen + FCS_SZ; desc->dma_size = pktlen; desc->skb_dma = DMA_MAP_SINGLE(sinfo->dma_dev, pktdata, desc->dma_size, @@ -4785,11 +4856,8 @@ bkn_tx(struct sk_buff *skb, struct net_device *dev) bkn_suspend_tx(sinfo); } -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,0)) - dev->trans_start = jiffies; -#else - netif_trans_update(dev); -#endif + NETDEV_UPDATE_TRANS_START_TIME(dev); + spin_unlock_irqrestore(&sinfo->lock, flags); return 0; @@ -5491,14 +5559,12 @@ bkn_seq_dma_show(struct seq_file *s, void *v) seq_printf(s, "Rx%d DCB info (unit %d):\n" " api: %d\n" - " wait: %d\n" " dirty: %d\n" " cur: %d\n" " free: %d\n" " run: %d\n", chan, iter->dev_no, sinfo->rx[chan].api_active, - sinfo->rx[chan].api_wait, sinfo->rx[chan].dirty, sinfo->rx[chan].cur, sinfo->rx[chan].free, @@ -6127,6 +6193,7 @@ bkn_knet_dma_info(kcom_msg_dma_info_t *kmsg, int len) if (sinfo->cmic_type == 'x') { dcb_chain_end->dcb_mem[woffset + 1] = DMA_TO_BUS_HI(dcb_chain->dcb_dma >> 32); } + MEMORY_BARRIER; } sinfo->tx.api_dcb_chain_end = dcb_chain; if (sinfo->tx.api_active) { @@ -6181,6 +6248,7 @@ bkn_knet_dma_info(kcom_msg_dma_info_t *kmsg, int len) if (sinfo->cmic_type == 'x') { dcb_chain_end->dcb_mem[woffset + 1] = DMA_TO_BUS_HI(dcb_chain->dcb_dma >> 32); } + MEMORY_BARRIER; } sinfo->rx[chan].api_dcb_chain_end = dcb_chain; if (!sinfo->rx[chan].use_rx_skb) { @@ -6194,18 +6262,6 @@ bkn_knet_dma_info(kcom_msg_dma_info_t *kmsg, int len) if (sinfo->rx[chan].api_active == 0) { bkn_api_rx_restart(sinfo, chan); - /* Resume SKB Rx due to refilled API resources */ - if (sinfo->rx[chan].use_rx_skb && sinfo->rx[chan].api_wait) { - sinfo->rx[chan].api_wait = 0; - if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) { - bkn_do_skb_rx(sinfo, chan, 1); - } else { - bkn_do_skb_rx(sinfo, chan, MAX_RX_DCBS); - if (sinfo->rx[chan].chain_complete) { - bkn_rx_chain_done(sinfo, chan); - } - } - } } spin_unlock_irqrestore(&sinfo->lock, flags); @@ -6272,7 +6328,7 @@ bkn_knet_dev_reprobe(void) for (i = 0; i < kernel_bde->num_devices(BDE_ALL_DEVICES); i++) { sinfo = bkn_sinfo_from_unit(i); - if (sinfo == NULL ) { + if (sinfo == NULL) { /* New device found after re-probe. */ if (bkn_knet_dev_init(i) < 0) { return -1; @@ -6289,7 +6345,7 @@ bkn_knet_dev_reprobe(void) /* Assign the inst_id and evt_idx */ static int -bkn_knet_dev_inst_set(kcom_msg_version_t *kmsg) +bkn_knet_dev_inst_set(kcom_msg_reprobe_t *kmsg) { bkn_switch_info_t *sinfo; int d = kmsg->hdr.unit; @@ -6333,13 +6389,6 @@ bkn_knet_dev_inst_set(kcom_msg_version_t *kmsg) static int bkn_knet_version(kcom_msg_version_t *kmsg, int len) { - /* Support pci hot plug and multiple instance */ - if ((bkn_knet_dev_reprobe() < 0) || - (bkn_knet_dev_inst_set(kmsg) < 0)) { - kmsg->hdr.status = KCOM_E_RESOURCE; - return sizeof(kcom_msg_version_t); - } - kmsg->hdr.type = KCOM_MSG_TYPE_RSP; kmsg->version = KCOM_VERSION; kmsg->netif_max = KCOM_NETIF_MAX; @@ -6496,6 +6545,21 @@ bkn_knet_detach(kcom_msg_detach_t *kmsg, int len) return sizeof(kcom_msg_detach_t); } +static int +bkn_knet_reprobe(kcom_msg_reprobe_t *kmsg, int len) +{ + kmsg->hdr.type = KCOM_MSG_TYPE_RSP; + + /* Support pci hot plug and multiple instance */ + if ((bkn_knet_dev_reprobe() < 0) || + (bkn_knet_dev_inst_set(kmsg) < 0)) { + kmsg->hdr.status = KCOM_E_RESOURCE; + return sizeof(kcom_msg_reprobe_t); + } + + return sizeof(kcom_msg_reprobe_t); +} + static int bkn_knet_netif_create(kcom_msg_netif_create_t *kmsg, int len) { @@ -7007,7 +7071,6 @@ bkn_knet_wb_cleanup(kcom_msg_wb_cleanup_t *kmsg, int len) } sinfo->rx[chan].api_dcb_chain_end = NULL; sinfo->rx[chan].api_active = 0; - sinfo->rx[chan].api_wait = 0; } spin_unlock_irqrestore(&sinfo->lock, flags); @@ -7055,6 +7118,11 @@ bkn_handle_cmd_req(kcom_msg_t *kmsg, int len) /* Detach kernel module */ len = bkn_knet_detach(&kmsg->detach, len); break; + case KCOM_M_REPROBE: + DBG_CMD(("KCOM_M_REPROBE\n")); + /* Reprobe device */ + len = bkn_knet_reprobe(&kmsg->reprobe, len); + break; case KCOM_M_NETIF_CREATE: DBG_CMD(("KCOM_M_NETIF_CREATE\n")); /* Create network interface */ @@ -7174,8 +7242,7 @@ bkn_get_next_dma_event(kcom_msg_dma_info_t *kmsg) } DBG_INST(("%s dev %d evt_idx %d\n",__FUNCTION__, dev_evt, sinfo->evt_idx)); - evt = &_bkn_evt[sinfo->evt_idx]; - dev_no = last_dev_no = dev_evt; + dev_no = last_dev_no; while (1) { dev_no++; sinfo = bkn_sinfo_from_unit(dev_no); @@ -7204,6 +7271,7 @@ bkn_get_next_dma_event(kcom_msg_dma_info_t *kmsg) } if (dev_no == last_dev_no) { + evt = &_bkn_evt[sinfo->evt_idx]; DBG_INST(("wait queue index %d\n",sinfo->evt_idx)); wait_event_interruptible(evt->evt_wq, evt->evt_wq_get != evt->evt_wq_put); 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 d1977076850b..a48cb540adaf 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 @@ -62,6 +62,9 @@ #include #include #include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0) +#include +#endif #include #include 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 da221f9f453a..ab4fc1cab69f 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 @@ -15,258 +15,87 @@ */ /* * $Id: $ - * $Copyright: (c) 2017 Broadcom Corp. + * $Copyright: (c) 2014 Broadcom Corp. * All Rights Reserved.$ */ /* - * Driver for call-back functions for Linux KNET driver. - * - * This is sample code that demonstrates how to selectively strip VLAN tags - * from an incoming packet based on tag information in the DMA control block - * (DCB). The switch will automatically add a VLAN tag to packets that ingress - * without an outer VLAN tag. Outer tagged and double tagged packets are - * not modified. The call back defined here determines which packets have - * had tags added by those and strips only those tags from the packet. - * - * This is sample code, the customer is responsible for maintaining and - * modifying this code as necessary. + * Test driver for call-back functions in Linux KNET driver. * * The module can be built from the standard Linux user mode target * directories using the following command (assuming bash), e.g. * - * cd $SDK/systems/linux/user/ - * make BUILD_KNET_CB=1 + * cd $SDK/systems/linux/user/gto-2_6 + * BUILD_KNET_CB=1 make -s mod * */ #include /* Must be included first */ #include #include -#include MODULE_AUTHOR("Broadcom Corporation"); MODULE_DESCRIPTION("Broadcom Linux KNET Call-Back Driver"); MODULE_LICENSE("GPL"); - -static int debug; -LKM_MOD_PARAM(debug, "i", int, 0); -MODULE_PARM_DESC(debug, -"Debug level (default 0)"); - - /* Module Information */ #define MODULE_MAJOR 121 #define MODULE_NAME "linux-knet-cb" -/* set KNET_CB_DEBUG for debug info */ -#define KNET_CB_DEBUG - -#define FILTER_TAG_STRIP 0 -#define FILTER_TAG_KEEP 1 - -/* Maintain tag strip statistics */ -struct strip_stats_s { - unsigned long stripped; /* Number of packets that have been stripped */ - unsigned long checked; - unsigned long skipped; -}; - -static struct strip_stats_s strip_stats; - -/* Local function prototypes */ -static void strip_vlan_tag(struct sk_buff *skb); -static int get_tag_status(int dcb_type, void *meta); -static struct sk_buff *strip_tag_rx_cb(struct sk_buff *skb, int dev_no, void *meta); -static struct sk_buff *strip_tag_tx_cb(struct sk_buff *skb, int dev_no, void *meta); -static int strip_tag_filter_cb(uint8_t * pkt, int size, int dev_no, void *meta, - int chan, kcom_filter_t * kf); -static int _pprint(void); -static int _cleanup(void); -static int _init(void); - -/* Remove VLAN tag for select TPIDs */ static void -strip_vlan_tag(struct sk_buff *skb) +show_mac(struct sk_buff *skb) { - uint16_t vlan_proto = (uint16_t) ((skb->data[12] << 8) | skb->data[13]); - if ((vlan_proto == 0x8100) || (vlan_proto == 0x88a8) || (vlan_proto == 0x9100)) { - /* Move first 12 bytes of packet back by 4 */ - ((u32 *) skb->data)[3] = ((u32 *) skb->data)[2]; - ((u32 *) skb->data)[2] = ((u32 *) skb->data)[1]; - ((u32 *) skb->data)[1] = ((u32 *) skb->data)[0]; - skb_pull(skb, 4); /* Remove 4 bytes from start of buffer */ - } + printk("DMAC=%02X:%02X:%02X:%02X:%02X:%02X\n", + skb->data[0], skb->data[1], skb->data[2], + skb->data[3], skb->data[4], skb->data[5]); } -/* - * Location of tagging status in select DCB types found below: - * - * DCB type 14: word 12, bits 10.11 - * DCB type 19, 20, 21, 22, 30: word 12, bits 10..11 - * DCB type 23, 29: word 13, bits 0..1 - * DCB type 31, 34, 37: word 13, bits 0..1 - * DCB type 26, 32, 33, 35: word 13, bits 0..1 - * - * The function get_tag_status() returns the tag status for known DCB types. - * 0 = Untagged - * 1 = Single inner-tag - * 2 = Single outer-tag - * 3 = Double tagged. - * -1 = Unsupported DCB type - */ -static int -get_tag_status(int dcb_type, void *meta) -{ - uint32 *dcb = (uint32 *) meta; - int tag_status; - switch (dcb_type) { - case 14: - case 19: - case 20: - case 21: - case 22: - case 30: - tag_status = (dcb[12] > 10) & 0x3; - break; - case 23: - case 29: - case 31: - case 34: - case 37: - case 26: - case 32: - case 33: - case 35: - tag_status = dcb[13] & 0x3; - break; - case 36: - /* TD3 */ - tag_status = ((dcb[13] >> 9) & 0x3); - break; - break; - case 38: - { - /* untested */ - /* TH3 only parses outer tag. */ - const int tag_map[4] = { 0, 2, -1, -1 }; - tag_status = tag_map[(dcb[9] >> 13) & 0x3]; - } - break; - default: - tag_status = -1; - break; - } -#ifdef KNET_CB_DEBUG - if (debug & 0x1) { - gprintk("%s; DCB Type: %d; tag status: %d\n", __func__, dcb_type, tag_status); - } -#endif - return tag_status; -} - -/* Rx packet callback function */ static struct sk_buff * -strip_tag_rx_cb(struct sk_buff *skb, int dev_no, void *meta) +test_rx_cb(struct sk_buff *skb, int dev_no, void *meta) { - unsigned netif_flags = KNET_SKB_CB(skb)->netif_user_data; - unsigned filter_flags = KNET_SKB_CB(skb)->filter_user_data; - unsigned dcb_type; - int tag_status; - unsigned int strip_tag = 0; - /* Currently not using filter flags: - * unsigned filter_flags = KNET_SKB_CB(skb)->filter_user_data; - */ - -#ifdef KNET_CB_DEBUG - if (debug & 0x1) { - gprintk("%s Enter; netif Flags: %08X filter_flags %08X \n", - __func__, netif_flags, filter_flags); - } -#endif - - /* KNET implements this already */ - if (filter_flags == FILTER_TAG_KEEP) - { - strip_stats.skipped++; - return skb; - } - - /* SAI strip implies always strip. If the packet is untagged or - inner taged, SDK adds a .1q tag, so we need to strip tag - anyway */ - if (filter_flags == FILTER_TAG_STRIP) - { - strip_tag = 1; - } - /* Get DCB type for this packet, passed by KNET driver */ - dcb_type = KNET_SKB_CB(skb)->dcb_type; - - /* Get tag status from DCB */ - tag_status = get_tag_status(dcb_type, meta); - -#ifdef KNET_CB_DEBUG - if (debug & 0x1) { - gprintk("%s; DCB Type: %d; tag status: %d\n", __func__, dcb_type, tag_status); - } -#endif - - if (tag_status < 0) { - /* Unsupported DCB type */ - return skb; - } - - strip_stats.checked++; - - if (strip_tag) { -#ifdef KNET_CB_DEBUG - if (debug & 0x1) { - gprintk("%s; Stripping VLAN\n", __func__); - } -#endif - strip_stats.stripped++; - strip_vlan_tag(skb); + printk("rx_cb for dev %d\n", dev_no); + printk("netif user data 0x%x\n", KNET_SKB_CB(skb)->netif_user_data); + printk("filter user data 0x%x\n", KNET_SKB_CB(skb)->filter_user_data); + printk("dcb type 0x%x\n", KNET_SKB_CB(skb)->dcb_type); + if (skb->data[5] == 0x03) { + dev_kfree_skb(skb); + return NULL; } -#ifdef KNET_CB_DEBUG - else { - if (debug & 0x1) { - gprintk("%s; Preserve VLAN\n", __func__); - } - } -#endif - + show_mac(skb); return skb; } -/* Tx callback not used */ static struct sk_buff * -strip_tag_tx_cb(struct sk_buff *skb, int dev_no, void *meta) +test_tx_cb(struct sk_buff *skb, int dev_no, void *meta) { - /* Pass through for now */ + printk("tx_cb for dev %d\n", dev_no); + show_mac(skb); + skb->data[5] += 1; return skb; } -/* Filter callback not used */ static int -strip_tag_filter_cb(uint8_t * pkt, int size, int dev_no, void *meta, - int chan, kcom_filter_t *kf) +test_filter_cb(uint8_t *pkt, int size, int dev_no, void *meta, + int chan, kcom_filter_t *kf) { - /* Pass through for now */ + printk("filter_cb (%d) for dev %d\n", kf->dest_id, dev_no); + if (pkt[12] == 0x81 && pkt[13] == 0x00) { + printk(" VTAG %d\n", pkt[15]); + kf->dest_type = KCOM_DEST_T_NETIF; + kf->dest_id = pkt[15]; + return 1; + } return 0; } /* - * Get statistics. - * % cat /proc/linux-knet-cb + * Generic module functions */ + static int _pprint(void) { - pprintf("Broadcom Linux KNET Call-Back: Untagged VLAN Stripper\n"); - pprintf(" %lu stripped packets\n", strip_stats.stripped); - pprintf(" %lu packets checked\n", strip_stats.checked); - pprintf(" %lu packets skipped\n", strip_stats.skipped); + pprintf("Broadcom Linux KNET Call-Back Driver\n"); return 0; } @@ -274,9 +103,9 @@ _pprint(void) static int _cleanup(void) { - bkn_rx_skb_cb_unregister(strip_tag_rx_cb); - bkn_tx_skb_cb_unregister(strip_tag_tx_cb); - bkn_filter_cb_unregister(strip_tag_filter_cb); + bkn_rx_skb_cb_unregister(test_rx_cb); + bkn_tx_skb_cb_unregister(test_tx_cb); + bkn_filter_cb_unregister(test_filter_cb); return 0; } @@ -284,9 +113,9 @@ _cleanup(void) static int _init(void) { - bkn_rx_skb_cb_register(strip_tag_rx_cb); - bkn_tx_skb_cb_register(strip_tag_tx_cb); - bkn_filter_cb_register(strip_tag_filter_cb); + bkn_rx_skb_cb_register(test_rx_cb); + bkn_tx_skb_cb_register(test_tx_cb); + bkn_filter_cb_register(test_filter_cb); return 0; }