commit a7e3aa032f0737b9ef4f408396a9e0c0f0e6c088
parent 158d1dd768be6a6d2a428b1e7c9d31c000d62b1b
Author: Broadcom SDK Release <sdk.releases@broadcom.com>
Date: Wed, 12 Aug 2020 13:59:09 -0700
Added GPL modules
Diffstat:
131 files changed, 51539 insertions(+), 0 deletions(-)
diff --git a/sdk-6.5.16/src/gpl-modules/RELEASE b/sdk-6.5.16/src/gpl-modules/RELEASE
diff --git a/sdk-6.5.16/src/gpl-modules/include/ibde.h b/sdk-6.5.16/src/gpl-modules/include/ibde.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: ibde.h,v 1.27 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#ifndef __IBDE_H__
+#define __IBDE_H__
+
+#include <sal/types.h>
+
+/*
+ * Represents a collection of devices
+ */
+
+typedef struct ibde_dev_s {
+ uint16 device;
+ uint8 rev;
+ sal_vaddr_t base_address;
+ sal_vaddr_t base_address1;
+ sal_vaddr_t base_address2;
+} ibde_dev_t;
+
+
+typedef struct ibde_s {
+
+ const char *(*name)(void);
+
+ /* Returns the number of devices available */
+ /* Each device is is accessed through a handle */
+ /* Handles are assumed to index the array of devices */
+
+ /* Support SWITCH or ETHERNET or CPU devices */
+ int (*num_devices)(int type);
+#define BDE_ALL_DEVICES 0
+#define BDE_SWITCH_DEVICES 1
+#define BDE_ETHER_DEVICES 2
+#define BDE_CPU_DEVICES 3
+
+ const ibde_dev_t *(*get_dev)(int d);
+
+ /*
+ * Get types of underlaying devices.
+ * A combination of bus type and functional type is returned.
+ * In case of bus type, support PCI and SPI device types.
+ * In case of functional type, specify if underlaying device is
+ * a switching or ethernet device.
+ */
+ uint32 (*get_dev_type)(int d);
+#define BDE_PCI_DEV_TYPE SAL_PCI_DEV_TYPE /* PCI device */
+#define BDE_SPI_DEV_TYPE SAL_SPI_DEV_TYPE /* SPI device */
+#define BDE_EB_DEV_TYPE SAL_EB_DEV_TYPE /* EB device */
+#define BDE_ICS_DEV_TYPE SAL_ICS_DEV_TYPE /* ICS device */
+#define BDE_MII_DEV_TYPE SAL_MII_DEV_TYPE /* MII device */
+#define BDE_I2C_DEV_TYPE SAL_I2C_DEV_TYPE /* I2C device */
+#define BDE_AXI_DEV_TYPE SAL_AXI_DEV_TYPE /* AXI device */
+#define BDE_EMMI_DEV_TYPE SAL_EMMI_DEV_TYPE /* EMMI device */
+#define BDE_DEV_BUS_ALT SAL_DEV_BUS_ALT /* Alternate Access */
+#define BDE_DEV_BUS_MSI SAL_DEV_BUS_MSI /* Message-signaled interrupts */
+
+#define BDE_DEV_BUS_TYPE_MASK SAL_DEV_BUS_TYPE_MASK
+
+#define BDE_SWITCH_DEV_TYPE SAL_SWITCH_DEV_TYPE /* Switch device */
+#define BDE_ETHER_DEV_TYPE SAL_ETHER_DEV_TYPE /* Ethernet device */
+#define BDE_CPU_DEV_TYPE SAL_CPU_DEV_TYPE /* CPU device */
+
+#define BDE_BYTE_SWAP 0x01000000 /* SW byte swap */
+#define BDE_NO_IPROC 0x02000000 /* Device uses two BARs, but is not iProc */
+
+#define BDE_8MB_REG_SPACE 0x10000000 /* 8MB sized CMIC BAR */
+#define BDE_256K_REG_SPACE 0x20000000 /* Map 256K (v 64K) */
+#define BDE_128K_REG_SPACE 0x40000000 /* Map 128K (v 64K) */
+#define BDE_320K_REG_SPACE 0x80000000 /* Map 256K+64K */
+
+/* Bus supports only 16bit reads */
+#define BDE_DEV_BUS_RD_16BIT SAL_DEV_BUS_RD_16BIT
+
+/* Bus supports only 16bit writes */
+#define BDE_DEV_BUS_WR_16BIT SAL_DEV_BUS_WR_16BIT
+
+/* Backward compatibility */
+#define BDE_ET_DEV_TYPE BDE_MII_DEV_TYPE
+
+#define BDE_DEV_MEM_MAPPED(_d) \
+ ((_d) & (BDE_PCI_DEV_TYPE | BDE_ICS_DEV_TYPE | BDE_EB_DEV_TYPE |\
+ BDE_EMMI_DEV_TYPE | BDE_AXI_DEV_TYPE))
+
+ /*
+ * PCI Bus Access
+ */
+ uint32 (*pci_conf_read)(int d, uint32 addr);
+ int (*pci_conf_write)(int d, uint32 addr, uint32 data);
+ void (*pci_bus_features)(int d, int *be_pio, int *be_packet,
+ int *be_other);
+
+ uint32 (*read)(int d, uint32 addr);
+ int (*write)(int d, uint32 addr, uint32 data);
+
+ uint32* (*salloc)(int d, int size, const char *name);
+ void (*sfree)(int d, void *ptr);
+ int (*sflush)(int d, void *addr, int length);
+ int (*sinval)(int d, void *addr, int length);
+
+ int (*interrupt_connect)(int d, void (*)(void*), void *data);
+ int (*interrupt_disconnect)(int d);
+
+ sal_paddr_t (*l2p)(int d, void *laddr);
+ void* (*p2l)(int d, sal_paddr_t paddr);
+
+ /*
+ * SPI Access via SMP
+ */
+ int (*spi_read)(int d, uint32 addr, uint8 *buf, int len);
+ int (*spi_write)(int d, uint32 addr, uint8 *buf, int len);
+ /* Special SPI access addresses */
+#define BDE_DEV_OP_EMMI_INIT SAL_DEV_OP_EMMI_INIT
+
+ /*
+ * iProc register access
+ */
+ uint32 (*iproc_read)(int d, uint32 addr);
+ int (*iproc_write)(int d, uint32 addr, uint32 data);
+
+ /*
+ * Shared memory access
+ */
+ uint32 (*shmem_read)(int dev, uint32 addr, uint8 *buf, uint32 len);
+ void (*shmem_write)(int dev, uint32 addr, uint8 *buf, uint32 len);
+ sal_vaddr_t (*shmem_map)(int dev, uint32 addr, uint32 size);
+
+ /*
+ * cmic
+ */
+ int (*get_cmic_ver)(int d, uint32 *ver);
+
+ /*
+ * I2C operations on the Device, assuming it is connected by I2C to the CPU.
+ */
+ /* Read from the internal device Address space using I2C */
+ int (*i2c_device_read)(
+ int dev, /* The device ID to access */
+ uint32 addr, /* The address to access in the internal device address space */
+ uint32 *value);/* the value to be read. */
+ /* Write to the internal device Address space using I2C */
+ int (*i2c_device_write)(
+ int dev, /* The device ID to access */
+ uint32 addr, /* The address to access in the internal device address space */
+ uint32 value); /* the value to be written. */
+
+} ibde_t;
+
+
+/* System BDE */
+extern ibde_t *bde;
+
+
+#endif /* __IBDE_H__ */
diff --git a/sdk-6.5.16/src/gpl-modules/include/kcom.h b/sdk-6.5.16/src/gpl-modules/include/kcom.h
@@ -0,0 +1,567 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: kcom.h,v 1.9 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ * File: kcom.h
+ * Purpose: User/Kernel message definitions
+ */
+
+#ifndef _KCOM_H
+#define _KCOM_H
+
+#include <sal/types.h>
+
+#define KCOM_CHAN_KNET "KCOM_KNET"
+
+/*
+ * Message types
+ */
+#define KCOM_MSG_TYPE_CMD 1 /* Command */
+#define KCOM_MSG_TYPE_RSP 2 /* Command response */
+#define KCOM_MSG_TYPE_EVT 3 /* Unsolicited event */
+
+/*
+ * Message opcodes
+ */
+#define KCOM_M_NONE 0 /* Should not be used */
+#define KCOM_M_VERSION 1 /* Protocol version */
+#define KCOM_M_STRING 2 /* For debug messages */
+#define KCOM_M_HW_RESET 3 /* H/W not ready */
+#define KCOM_M_HW_INIT 4 /* H/W initialized */
+#define KCOM_M_ETH_HW_CONFIG 5 /* ETH HW config*/
+#define KCOM_M_DETACH 6 /* Detach kernel module */
+#define KCOM_M_REPROBE 7 /* Reprobe device */
+#define KCOM_M_NETIF_CREATE 11 /* Create network interface */
+#define KCOM_M_NETIF_DESTROY 12 /* Destroy network interface */
+#define KCOM_M_NETIF_LIST 13 /* Get list of network interface IDs */
+#define KCOM_M_NETIF_GET 14 /* Get network interface info */
+#define KCOM_M_FILTER_CREATE 21 /* Create Rx filter */
+#define KCOM_M_FILTER_DESTROY 22 /* Destroy Rx filter */
+#define KCOM_M_FILTER_LIST 23 /* Get list of Rx filter IDs */
+#define KCOM_M_FILTER_GET 24 /* Get Rx filter info */
+#define KCOM_M_DMA_INFO 31 /* Tx/Rx DMA info */
+#define KCOM_M_DBGPKT_SET 41 /* Enbale debug packet function */
+#define KCOM_M_DBGPKT_GET 42 /* Get debug packet function info */
+#define KCOM_M_WB_CLEANUP 51 /* Clean up for warmbooting */
+
+#define KCOM_VERSION 10 /* Protocol version */
+
+/*
+ * Message status codes
+ */
+#define KCOM_E_NONE 0 /* No errors */
+#define KCOM_E_PARAM 1 /* Invalid/unsupported parameter */
+#define KCOM_E_RESOURCE 2 /* Out of memory or other resource */
+#define KCOM_E_NOT_FOUND 3 /* Requested object not found */
+
+typedef struct kcom_msg_hdr_s {
+ uint8 type;
+ uint8 opcode;
+ uint8 seqno;
+ uint8 status;
+ uint8 unit;
+ uint8 reserved;
+ uint16 id;
+} kcom_msg_hdr_t;
+
+/*
+ * Object types
+ */
+
+/*
+ * System network interface
+ *
+ * Network interface types:
+ *
+ * KCOM_NETIF_T_VLAN
+ * Transmits to this interface will go to ingress PIPE of switch
+ * CPU port using specified VLAN ID. Packet will be switched.
+ *
+ * KCOM_NETIF_T_PORT
+ * Transmits to this interface will go to unmodified to specified
+ * physical switch port. All switching logic is bypassed.
+ *
+ * KCOM_NETIF_T_META
+ * Transmits to this interface will be done using raw meta data
+ * as DMA descriptors. Currently used for RCPU mode only.
+ *
+ * Network interface flags:
+ *
+ * KCOM_NETIF_F_ADD_TAG
+ * Add VLAN tag to packets sent directly to physical port.
+ *
+ * KCOM_NETIF_F_RCPU_ENCAP
+ * Use RCPU encapsulation for packets that enter and exit this
+ * interface.
+ */
+#define KCOM_NETIF_T_VLAN 0
+#define KCOM_NETIF_T_PORT 1
+#define KCOM_NETIF_T_META 2
+
+#define KCOM_NETIF_F_ADD_TAG (1U << 0)
+#define KCOM_NETIF_F_RCPU_ENCAP (1U << 1)
+/* If a netif has this flag, the packet sent to the netif can't be stripped tag or added tag */
+#define KCOM_NETIF_F_KEEP_RX_TAG (1U << 2)
+
+#define KCOM_NETIF_NAME_MAX 16
+
+/*
+ * Max size of Sand System Headers
+ * For DNX, Module Header(20B) + PTCH(2B) + ITMH(5B)
+ * For DPP, PTCH(2B) + ITMH(4B)
+ */
+#define KCOM_NETIF_SYSTEM_HEADERS_SIZE_MAX 27
+
+typedef struct kcom_netif_s {
+ uint16 id;
+ uint8 type;
+ uint8 flags;
+ uint32 cb_user_data;
+ uint8 port;
+ uint8 reserved;
+ uint16 vlan;
+ uint16 qnum;
+ uint8 macaddr[6];
+ uint8 ptch[2];
+ uint8 itmh[4];
+ uint8 system_headers[KCOM_NETIF_SYSTEM_HEADERS_SIZE_MAX];
+ uint8 system_headers_size;
+ char name[KCOM_NETIF_NAME_MAX];
+} kcom_netif_t;
+
+/*
+ * Packet filters
+ *
+ * Filters work like software TCAMs where a mask is applied to the
+ * source data, and the result is then compared to the filter data.
+ *
+ * Filters are checked in priority order with the lowest priority
+ * values being checked first (i.e. 0 is the highest priority).
+ *
+ * Filter types:
+ *
+ * KCOM_FILTER_T_RX_PKT
+ * Filter data and mask are applied to the Rx DMA control block
+ * as well as to the Rx packet contents.
+ *
+ * Destination types:
+ *
+ * KCOM_DEST_T_NULL
+ * Packet is dropped.
+ *
+ * KCOM_DEST_T_NETIF
+ * Packet is sent to network interface with ID <dest_id>.
+ *
+ * KCOM_DEST_T_API
+ * Packet is sent to Rx API through queue <dest_id>.
+ *
+ * KCOM_DEST_T_CB
+ * Packet destination is obtained from kernel call-back function.
+ *
+ * Filter flags:
+ *
+ * KCOM_FILTER_F_ANY_DATA
+ * When this flags is set the filter will match any packet on
+ * the associated unit.
+ *
+ * KCOM_FILTER_F_STRIP_TAG
+ * Strip VLAN tag before packet is sent to destination.
+ * This flag only applies to KCOM_DEST_T_NETIF.
+ *
+ */
+#define KCOM_FILTER_BYTES_MAX 256
+#define KCOM_FILTER_WORDS_MAX BYTES2WORDS(KCOM_FILTER_BYTES_MAX)
+
+#define KCOM_FILTER_T_RX_PKT 1
+
+#define KCOM_DEST_T_NULL 0
+#define KCOM_DEST_T_NETIF 1
+#define KCOM_DEST_T_API 2
+#define KCOM_DEST_T_CB 3
+
+#define KCOM_FILTER_F_ANY_DATA (1U << 0)
+#define KCOM_FILTER_F_STRIP_TAG (1U << 1)
+
+#define KCOM_FILTER_DESC_MAX 32
+
+typedef struct kcom_filter_s {
+ uint16 id;
+ uint8 type;
+ uint8 priority;
+ char desc[KCOM_FILTER_DESC_MAX];
+ uint32 flags;
+ uint32 cb_user_data;
+ uint16 dest_type;
+ uint16 dest_id;
+ uint16 dest_proto;
+ uint16 mirror_type;
+ uint16 mirror_id;
+ uint16 mirror_proto;
+ uint16 oob_data_offset;
+ uint16 oob_data_size;
+ uint16 pkt_data_offset;
+ uint16 pkt_data_size;
+ union {
+ uint8 b[KCOM_FILTER_BYTES_MAX];
+ uint32 w[KCOM_FILTER_WORDS_MAX];
+ } data;
+ union {
+ uint8 b[KCOM_FILTER_BYTES_MAX];
+ uint32 w[KCOM_FILTER_WORDS_MAX];
+ } mask;
+ /** Information to parse Dune system headers */
+ uint32 ftmh_lb_key_ext_size;
+ uint32 ftmh_stacking_ext_size;
+ uint32 pph_base_size;
+ uint32 pph_lif_ext_size[8];
+ uint8 udh_enable;
+ uint32 udh_length_type[4];
+} kcom_filter_t;
+
+/*
+ * DMA buffer information
+ *
+ * Cookie field is reserved use by application (32/64-bit pointer).
+ *
+ * For Tx operation the application will submit the start address of
+ * the Tx DCB chain which is queued for transfer by the kernel module.
+ * Once DMA is done a DMA event is returned to the application with an
+ * optional sequence number.
+ *
+ * For Rx operation the application will submit the start address of
+ * the Rx DCB chain which should be use for packet reception by the
+ * kernel module. Once DMA is done a DMA event is returned to the
+ * application with an optional sequence number.
+ *
+ * Cookie field is reserved use by application (32/64-bit pointer).
+ *
+ * Packet info types:
+ *
+ * KCOM_DMA_INFO_T_TX_DCB
+ * Data is physical start address of Tx DCB chain.
+ *
+ * KCOM_DMA_INFO_T_RX_DCB
+ * Data is physical start address of Rx DCB chain.
+ *
+ * Packet info flags:
+ *
+ * KCOM_DMA_INFO_F_TX_DONE
+ * This flag is set by the kernel module and means that one or more
+ * packets have been sent.
+ *
+ * KCOM_DMA_INFO_F_RX_DONE
+ * This flag is set by the kernel module and means that one or more
+ * Rx buffers contain valid packet data.
+ */
+#define KCOM_DMA_INFO_T_TX_DCB 1
+#define KCOM_DMA_INFO_T_RX_DCB 2
+
+#define KCOM_DMA_INFO_F_TX_DONE (1U << 0)
+#define KCOM_DMA_INFO_F_RX_DONE (1U << 1)
+
+typedef struct kcom_dma_info_s {
+ uint8 type;
+ uint8 cnt;
+ uint16 size;
+ uint16 chan;
+ uint16 flags;
+ union {
+ uint64 dcb_start;
+ struct {
+ uint32 tx;
+ uint32 rx;
+ } seqno;
+ } data;
+ union {
+ void *p;
+ uint8 b[8];
+ } cookie;
+ } kcom_dma_info_t;
+
+/* Default channel configuration */
+#define KCOM_DMA_TX_CHAN 0
+#define KCOM_DMA_RX_CHAN 1
+
+
+#define KCOM_ETH_HW_T_RESET 1
+#define KCOM_ETH_HW_T_INIT 2
+#define KCOM_ETH_HW_T_OTHER 3
+
+#define KCOM_ETH_HW_C_ALL 0xff
+
+#define KCOM_ETH_HW_RESET_F_TX (1U << 0)
+#define KCOM_ETH_HW_RESET_F_RX (1U << 1)
+#define KCOM_ETH_HW_RESET_F_TX_RECLAIM (1U << 2)
+#define KCOM_ETH_HW_RESET_F_RX_RECLAIM (1U << 3)
+
+#define KCOM_ETH_HW_INIT_F_TX (1U << 0)
+#define KCOM_ETH_HW_INIT_F_RX (1U << 1)
+#define KCOM_ETH_HW_INIT_F_RX_FILL (1U << 2)
+
+#define KCOM_ETH_HW_OTHER_F_FIFO_LOOPBACK (1U << 0)
+#define KCOM_ETH_HW_OTHER_F_INTERRUPT (1U << 1)
+
+typedef struct kcom_eth_hw_config_s {
+ uint8 type;
+ uint8 chan;
+ uint32 flags;
+ uint32 value;
+} kcom_eth_hw_config_t;
+
+/*
+ * Message types
+ */
+
+/*
+ * Request KCOM interface version of kernel module.
+ */
+typedef struct kcom_msg_version_s {
+ kcom_msg_hdr_t hdr;
+ uint32 version;
+ uint32 netif_max;
+ uint32 filter_max;
+} kcom_msg_version_t;
+
+/*
+ * Send literal string to/from kernel module.
+ * Mainly for debugging purposes.
+ */
+#define KCOM_MSG_STRING_MAX 128
+
+typedef struct kcom_msg_string_s {
+ kcom_msg_hdr_t hdr;
+ uint32 len;
+ char val[KCOM_MSG_STRING_MAX];
+} kcom_msg_string_t;
+
+/*
+ * Indicate that eth hardware is about to be reset. Active
+ * DMA operations should be aborted and DMA and interrupts
+ * should be disabled.
+ */
+/*
+ * Indicate that eth hardware has been properly initialized
+ * for DMA operation to commence.
+ */
+typedef struct kcom_msg_eth_hw_config_s {
+ kcom_msg_hdr_t hdr;
+ kcom_eth_hw_config_t config;
+} kcom_msg_eth_hw_config_t;
+
+/*
+ * Indicate that switch hardware is about to be reset. Active
+ * DMA operations should be aborted and DMA and interrupts
+ * should be disabled.
+ */
+typedef struct kcom_msg_hw_reset_s {
+ kcom_msg_hdr_t hdr;
+ uint32 channels;
+} kcom_msg_hw_reset_t;
+
+/*
+ * Indicate that switch hardware has been properly initialized
+ * for DMA operation to commence.
+ */
+typedef struct kcom_msg_hw_init_s {
+ kcom_msg_hdr_t hdr;
+ uint8 cmic_type;
+ uint8 dcb_type;
+ uint8 dcb_size;
+ uint8 pkt_hdr_size;
+ uint32 dma_hi;
+ uint32 cdma_channels;
+} kcom_msg_hw_init_t;
+
+/*
+ * Release blocked IOCTL threads and clean up as necessary.
+ */
+typedef struct kcom_msg_detach_s {
+ kcom_msg_hdr_t hdr;
+ uint32 flags;
+} kcom_msg_detach_t;
+
+/*
+ * Reprobe switch device.
+ */
+typedef struct kcom_msg_reprobe_s {
+ kcom_msg_hdr_t hdr;
+ uint32 flags;
+} kcom_msg_reprobe_t;
+
+/*
+ * Enable/Disable debugging packet function.
+ */
+typedef struct kcom_msg_dbg_pkt_set_s {
+ kcom_msg_hdr_t hdr;
+ int enable;
+} kcom_msg_dbg_pkt_set_t;
+
+/*
+ * Get debugging packet function info.
+ */
+typedef struct kcom_msg_dbg_pkt_get_s {
+ kcom_msg_hdr_t hdr;
+ int value;
+} kcom_msg_dbg_pkt_get_t;
+
+/*
+ * Clean up warmboot-related resources.
+ */
+typedef struct kcom_msg_wb_cleanup_s {
+ kcom_msg_hdr_t hdr;
+ uint32 flags;
+} kcom_msg_wb_cleanup_t;
+
+/*
+ * Create new system network interface. The network interface will
+ * be associated with the specified switch unit number.
+ * The interface id and name will be assigned by the kernel module.
+ */
+typedef struct kcom_msg_netif_create_s {
+ kcom_msg_hdr_t hdr;
+ kcom_netif_t netif;
+} kcom_msg_netif_create_t;
+
+/*
+ * Destroy system network interface.
+ */
+typedef struct kcom_msg_netif_destroy_s {
+ kcom_msg_hdr_t hdr;
+} kcom_msg_netif_destroy_t;
+
+/*
+ * Get list of currently defined system network interfaces.
+ */
+#ifndef KCOM_NETIF_MAX
+#define KCOM_NETIF_MAX 128
+#endif
+
+typedef struct kcom_msg_netif_list_s {
+ kcom_msg_hdr_t hdr;
+ uint32 ifcnt;
+ uint16 id[KCOM_NETIF_MAX];
+} kcom_msg_netif_list_t;
+
+/*
+ * Get detailed network interface information.
+ */
+typedef struct kcom_msg_netif_get_s {
+ kcom_msg_hdr_t hdr;
+ kcom_netif_t netif;
+} kcom_msg_netif_get_t;
+
+/*
+ * Create new packet filter.
+ * The filter id will be assigned by the kernel module.
+ */
+typedef struct kcom_msg_filter_create_s {
+ kcom_msg_hdr_t hdr;
+ kcom_filter_t filter;
+} kcom_msg_filter_create_t;
+
+/*
+ * Destroy packet filter.
+ */
+typedef struct kcom_msg_filter_destroy_s {
+ kcom_msg_hdr_t hdr;
+} kcom_msg_filter_destroy_t;
+
+/*
+ * Get list of currently defined packet filters.
+ */
+#ifndef KCOM_FILTER_MAX
+#define KCOM_FILTER_MAX 128
+#endif
+
+typedef struct kcom_msg_filter_list_s {
+ kcom_msg_hdr_t hdr;
+ uint32 fcnt;
+ uint16 id[KCOM_FILTER_MAX];
+} kcom_msg_filter_list_t;
+
+/*
+ * Get detailed packet filter information.
+ */
+typedef struct kcom_msg_filter_get_s {
+ kcom_msg_hdr_t hdr;
+ kcom_filter_t filter;
+} kcom_msg_filter_get_t;
+
+/*
+ * DMA info
+ */
+typedef struct kcom_msg_dma_info_s {
+ kcom_msg_hdr_t hdr;
+ kcom_dma_info_t dma_info;
+} kcom_msg_dma_info_t;
+
+/*
+ * All messages (e.g. for generic receive)
+ */
+typedef union kcom_msg_s {
+ kcom_msg_hdr_t hdr;
+ kcom_msg_version_t version;
+ kcom_msg_string_t string;
+ kcom_msg_hw_reset_t hw_reset;
+ kcom_msg_hw_init_t hw_init;
+ kcom_msg_eth_hw_config_t eth_hw_config;
+ kcom_msg_detach_t detach;
+ kcom_msg_reprobe_t reprobe;
+ kcom_msg_netif_create_t netif_create;
+ kcom_msg_netif_destroy_t netif_destroy;
+ kcom_msg_netif_list_t netif_list;
+ kcom_msg_netif_get_t netif_get;
+ kcom_msg_filter_create_t filter_create;
+ kcom_msg_filter_destroy_t filter_destroy;
+ kcom_msg_filter_list_t filter_list;
+ kcom_msg_filter_get_t filter_get;
+ kcom_msg_dma_info_t dma_info;
+ kcom_msg_dbg_pkt_set_t dbg_pkt_set;
+ kcom_msg_dbg_pkt_get_t dbg_pkt_get;
+ kcom_msg_wb_cleanup_t wb_cleanup;
+} kcom_msg_t;
+
+/*
+ * KCOM communication channel vectors
+ *
+ * open
+ * Open KCOM channel.
+ *
+ * close
+ * Close KCOM channel.
+ *
+ * send
+ * Send KCOM message. If bufsz is non-zero, a synchronous send will be
+ * performed (if supported) and the function will return the number of
+ * bytes in the response.
+ *
+ * recv
+ * Receive KCOM message. This function is used t oreceive unsolicited
+ * messages from the kernel. If synchronous send is not supported, this
+ * function is also used to retrieve responses to command messages.
+ */
+
+typedef struct kcom_chan_s {
+ void *(*open)(char *name);
+ int (*close)(void *handle);
+ int (*send)(void *handle, void *msg, unsigned int len, unsigned int bufsz);
+ int (*recv)(void *handle, void *msg, unsigned int bufsz);
+} kcom_chan_t;
+
+#endif /* _KCOM_H */
diff --git a/sdk-6.5.16/src/gpl-modules/include/sal/core/sync.h b/sdk-6.5.16/src/gpl-modules/include/sal/core/sync.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: sync.h,v 1.1 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#ifndef _SAL_SYNC_H
+#define _SAL_SYNC_H
+
+typedef struct sal_sem_s{
+ char sal_opaque_type;
+} *sal_sem_t;
+
+#define sal_sem_FOREVER (-1)
+#define sal_sem_BINARY 1
+#define sal_sem_COUNTING 0
+
+sal_sem_t sal_sem_create(char *desc, int binary, int initial_count);
+void sal_sem_destroy(sal_sem_t b);
+int sal_sem_take(sal_sem_t b, int usec);
+int sal_sem_give(sal_sem_t b);
+
+#endif /* !_SAL_SYNC_H */
diff --git a/sdk-6.5.16/src/gpl-modules/include/sal/core/thread.h b/sdk-6.5.16/src/gpl-modules/include/sal/core/thread.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: thread.h,v 1.1 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#ifndef _SAL_THREAD_H
+#define _SAL_THREAD_H
+
+#include <sal/types.h>
+
+void sal_usleep(uint32 usec);
+void sal_udelay(uint32 usec);
+
+#endif /* !_SAL_THREAD_H */
diff --git a/sdk-6.5.16/src/gpl-modules/include/sal/types.h b/sdk-6.5.16/src/gpl-modules/include/sal/types.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: types.h,v 1.3 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ * File: types.h
+ * Purpose: SAL type definitions
+ */
+
+#ifndef _SAL_TYPES_H
+#define _SAL_TYPES_H
+
+/*
+ * Define platform-independent types
+ */
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef DONT_CARE
+#define DONT_CARE 0
+#endif
+
+#define VOL volatile
+
+/*
+ * 64-bit type
+ */
+
+#ifdef LONGS_ARE_64BITS
+
+#define COMPILER_64BIT
+#define COMPILER_UINT64 unsigned long
+#define u64_H(v) (((uint32 *) &(v))[u64_MSW])
+#define u64_L(v) (((uint32 *) &(v))[u64_LSW])
+
+#else /* !LONGS_ARE_64BITS */
+
+#define COMPILER_64BIT
+#define COMPILER_UINT64 unsigned long long
+#define u64_H(v) (((uint32 *) &(v))[u64_MSW])
+#define u64_L(v) (((uint32 *) &(v))[u64_LSW])
+
+#endif /* LONGS_ARE_64BITS */
+
+/*
+ * Define unsigned and signed integers with guaranteed sizes.
+ * Adjust if your compiler uses different sizes for short or int.
+ */
+
+typedef unsigned char uint8; /* 8-bit quantity */
+typedef unsigned short uint16; /* 16-bit quantity */
+typedef unsigned int uint32; /* 32-bit quantity */
+typedef COMPILER_UINT64 uint64; /* 64-bit quantity */
+
+typedef signed char int8; /* 8-bit quantity */
+typedef signed short int16; /* 16-bit quantity */
+typedef signed int int32; /* 32-bit quantity */
+
+#define BITS2BYTES(x) (((x) + 7) / 8)
+#define BITS2WORDS(x) (((x) + 31) / 32)
+
+#define BYTES2BITS(x) ((x) * 8)
+#define BYTES2WORDS(x) (((x) + 3) / 4)
+
+#define WORDS2BITS(x) ((x) * 32)
+#define WORDS2BYTES(x) ((x) * 4)
+
+#define COUNTOF(ary) ((int) (sizeof (ary) / sizeof ((ary)[0])))
+
+typedef uint32 sal_paddr_t; /* Physical address (PCI address) */
+
+#ifdef PTRS_ARE_64BITS
+typedef uint64 sal_vaddr_t; /* Virtual address (Host address) */
+#define PTR_TO_INT(x) ((uint32)(((sal_vaddr_t)(x))&0xFFFFFFFF))
+#else
+typedef uint32 sal_vaddr_t; /* Virtual address (Host address) */
+#define PTR_TO_INT(x) ((uint32)(x))
+#endif
+
+#define INT_TO_PTR(x) ((void *)((sal_vaddr_t)(x)))
+
+#define PTR_TO_UINTPTR(x) ((sal_vaddr_t)(x))
+#define UINTPTR_TO_PTR(x) ((void *)(x))
+
+typedef union
+{
+ uint8 u8;
+ uint16 u16;
+ uint32 u32;
+ uint64 u64;
+ sal_paddr_t paddr;
+ sal_vaddr_t vaddr;
+ void *ptr;
+} any_t;
+
+/* Device bus types */
+#define SAL_PCI_DEV_TYPE 0x00001 /* PCI device */
+#define SAL_SPI_DEV_TYPE 0x00002 /* SPI device */
+#define SAL_EB_DEV_TYPE 0x00004 /* EB device */
+#define SAL_ICS_DEV_TYPE 0x00008 /* ICS device */
+#define SAL_MII_DEV_TYPE 0x00010 /* MII device */
+#define SAL_RCPU_DEV_TYPE 0x00020 /* RCPU device */
+#define SAL_I2C_DEV_TYPE 0x00040 /* I2C device */
+#define SAL_AXI_DEV_TYPE 0x00080 /* AXI device */
+#define SAL_EMMI_DEV_TYPE 0x10000 /* EMMI device */
+#define SAL_DEV_BUS_TYPE_MASK 0xf00ff /* Odd for historical reasons */
+
+/* Device types */
+#define SAL_SWITCH_DEV_TYPE 0x00100 /* Switch device */
+#define SAL_ETHER_DEV_TYPE 0x00200 /* Ethernet device */
+#define SAL_CPU_DEV_TYPE 0x00400 /* CPU device */
+#define SAL_DEV_TYPE_MASK 0x00f00
+
+/* Access types */
+#define SAL_DEV_BUS_RD_16BIT 0x01000 /* 16 bit reads on bus */
+#define SAL_DEV_BUS_WR_16BIT 0x02000 /* 16 bit writes on bus */
+#define SAL_DEV_BUS_ALT 0x04000 /* Alternate access */
+#define SAL_DEV_BUS_MSI 0x08000 /* Message-signaled interrupts */
+#define SAL_DEV_FLAG_MASK 0x0f000
+
+/* BDE reserved mask (cannot be used by SAL) */
+#define SAL_DEV_BDE_MASK 0xff000000
+
+/* Backward compatibility */
+#define SAL_ET_DEV_TYPE SAL_MII_DEV_TYPE
+
+/* Special access addresses */
+#define SAL_DEV_OP_EMMI_INIT 0x0fff1000
+
+#endif /* !_SAL_TYPES_H */
diff --git a/sdk-6.5.16/src/gpl-modules/include/sdk_config.h b/sdk-6.5.16/src/gpl-modules/include/sdk_config.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: sdk_config.h,v 1.5 Broadcom SDK $
+ * $Copyright: (c) 2006 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ *
+ */
+
+#ifndef __SDK_CONFIG_H__
+#define __SDK_CONFIG_H__
+
+/*
+ * Include custom overrides
+ */
+#ifdef SDK_INCLUDE_CUSTOM_CONFIG
+#include <sdk_custom_config.h>
+#endif
+
+
+/*
+ * Memory Barrier operation if required.
+ * Defaults to nothing.
+ */
+#ifndef SDK_CONFIG_MEMORY_BARRIER
+#define SDK_CONFIG_MEMORY_BARRIER
+#endif
+
+
+
+#endif /* __SDK_CONFIG_H__ */
diff --git a/sdk-6.5.16/src/gpl-modules/include/soc/cmic.h b/sdk-6.5.16/src/gpl-modules/include/soc/cmic.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: cmic.h,v 1.1 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ * File: cmic.h
+ * Purpose: Maps out structures used for CMIC operations and
+ * exports routines and constants.
+ */
+
+#ifndef _SOC_CMIC_H
+#define _SOC_CMIC_H
+
+/* IRQ Register (RO) */
+#define CMIC_IRQ_STAT 0x00000144
+
+/* IRQ Mask Registers (R/W) */
+#define CMIC_IRQ_MASK 0x00000148
+#define CMIC_IRQ_MASK_1 0x0000006C
+#define CMIC_IRQ_MASK_2 0x00000070
+
+#endif /* !_SOC_CMIC_H */
diff --git a/sdk-6.5.16/src/gpl-modules/include/soc/devids.h b/sdk-6.5.16/src/gpl-modules/include/soc/devids.h
@@ -0,0 +1,1826 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * Copyright: (c) 2019 Broadcom.
+ * All Rights Reserved.
+ */
+
+#ifndef _SOC_DEVIDS_H
+#define _SOC_DEVIDS_H
+
+
+#define BROADCOM_VENDOR_ID 0x14e4
+
+#define BCM5690_DEVICE_ID 0x5690
+#define BCM5690_A0_REV_ID 1
+#define BCM5690_A1_REV_ID 2
+#define BCM5690_A2_REV_ID 3
+
+#define BCM5691_DEVICE_ID 0x5691
+#define BCM5691_A0_REV_ID 1
+#define BCM5691_A1_REV_ID 2
+#define BCM5691_A2_REV_ID 3
+
+#define BCM5692_DEVICE_ID 0x5692
+#define BCM5692_A0_REV_ID 1
+#define BCM5692_A1_REV_ID 2
+#define BCM5692_A2_REV_ID 3
+
+#define BCM5693_DEVICE_ID 0x5693
+#define BCM5693_A0_REV_ID 1
+#define BCM5693_A1_REV_ID 2
+#define BCM5693_A2_REV_ID 3
+
+#define BCM5695_DEVICE_ID 0x5695
+#define BCM5695_A0_REV_ID 1
+#define BCM5695_A1_REV_ID 2
+#define BCM5695_B0_REV_ID 0x11
+
+#define BCM5696_DEVICE_ID 0x5696
+#define BCM5696_A0_REV_ID 1
+#define BCM5696_A1_REV_ID 2
+#define BCM5696_B0_REV_ID 0x11
+
+#define BCM5697_DEVICE_ID 0x5697
+#define BCM5697_A0_REV_ID 1
+#define BCM5697_A1_REV_ID 2
+#define BCM5697_B0_REV_ID 0x11
+
+#define BCM5698_DEVICE_ID 0x5698
+#define BCM5698_A0_REV_ID 1
+#define BCM5698_A1_REV_ID 2
+#define BCM5698_B0_REV_ID 0x11
+
+#define BCM5670_DEVICE_ID 0x5670
+#define BCM5670_A0_REV_ID 1
+#define BCM5670_A1_REV_ID 2
+
+#define BCM5671_DEVICE_ID 0x5671
+#define BCM5671_A0_REV_ID 1
+#define BCM5671_A1_REV_ID 2
+#define BCM5671_A2_REV_ID 3
+
+#define BCM5675_DEVICE_ID 0x5675
+#define BCM5675_A0_REV_ID 1
+#define BCM5675_A1_REV_ID 2
+
+#define BCM5676_DEVICE_ID 0x5676
+#define BCM5676_A0_REV_ID 1
+#define BCM5676_A1_REV_ID 2
+
+#define BCM5673_DEVICE_ID 0x5673
+#define BCM5673_A0_REV_ID 1
+#define BCM5673_A1_REV_ID 2
+#define BCM5673_A2_REV_ID 3
+
+#define BCM5674_DEVICE_ID 0x5674
+#define BCM5674_A0_REV_ID 1
+
+#define BCM56100_DEVICE_ID 0xb100
+#define BCM56100_A0_REV_ID 1
+#define BCM56100_A1_REV_ID 2
+#define BCM56101_DEVICE_ID 0xb101
+#define BCM56101_A0_REV_ID 1
+#define BCM56101_A1_REV_ID 2
+#define BCM56102_DEVICE_ID 0xb102
+#define BCM56102_A0_REV_ID 1
+#define BCM56102_A1_REV_ID 2
+#define BCM56105_DEVICE_ID 0xb105
+#define BCM56105_A0_REV_ID 1
+#define BCM56105_A1_REV_ID 2
+#define BCM56106_DEVICE_ID 0xb106
+#define BCM56106_A0_REV_ID 1
+#define BCM56106_A1_REV_ID 2
+#define BCM56107_DEVICE_ID 0xb107
+#define BCM56107_A0_REV_ID 1
+#define BCM56107_A1_REV_ID 2
+
+#define BCM56110_DEVICE_ID 0xb110
+#define BCM56110_A0_REV_ID 1
+#define BCM56111_DEVICE_ID 0xb111
+#define BCM56111_A0_REV_ID 1
+#define BCM56112_DEVICE_ID 0xb112
+#define BCM56112_A0_REV_ID 1
+#define BCM56115_DEVICE_ID 0xb115
+#define BCM56115_A0_REV_ID 1
+#define BCM56116_DEVICE_ID 0xb116
+#define BCM56116_A0_REV_ID 1
+#define BCM56117_DEVICE_ID 0xb117
+#define BCM56117_A0_REV_ID 1
+
+#define BCM56300_DEVICE_ID 0xb300
+#define BCM56300_A0_REV_ID 1
+#define BCM56300_A1_REV_ID 2
+#define BCM56300_B0_REV_ID 0x11
+#define BCM56300_B1_REV_ID 0x12
+#define BCM56301_DEVICE_ID 0xb301
+#define BCM56301_A0_REV_ID 1
+#define BCM56301_A1_REV_ID 2
+#define BCM56301_B0_REV_ID 0x11
+#define BCM56301_B1_REV_ID 0x12
+#define BCM56302_DEVICE_ID 0xb302
+#define BCM56302_A0_REV_ID 1
+#define BCM56302_A1_REV_ID 2
+#define BCM56302_B0_REV_ID 0x11
+#define BCM56302_B1_REV_ID 0x12
+#define BCM56303_DEVICE_ID 0xb303
+#define BCM56303_A1_REV_ID 2
+#define BCM56303_A0_REV_ID 1
+#define BCM56303_B0_REV_ID 0x11
+#define BCM56303_B1_REV_ID 0x12
+#define BCM56304_DEVICE_ID 0xb304
+#define BCM56304_A0_REV_ID 1
+#define BCM56304_A1_REV_ID 2
+#define BCM56304_B0_REV_ID 0x11
+#define BCM56304_B1_REV_ID 0x12
+#define BCM56404_DEVICE_ID 0xb404
+#define BCM56404_A0_REV_ID 1
+#define BCM56404_A1_REV_ID 2
+#define BCM56305_DEVICE_ID 0xb305
+#define BCM56305_A0_REV_ID 1
+#define BCM56305_A1_REV_ID 2
+#define BCM56305_B0_REV_ID 0x11
+#define BCM56305_B1_REV_ID 0x12
+#define BCM56306_DEVICE_ID 0xb306
+#define BCM56306_A0_REV_ID 1
+#define BCM56306_A1_REV_ID 2
+#define BCM56306_B0_REV_ID 0x11
+#define BCM56306_B1_REV_ID 0x12
+#define BCM56307_DEVICE_ID 0xb307
+#define BCM56307_A0_REV_ID 1
+#define BCM56307_A1_REV_ID 2
+#define BCM56307_B0_REV_ID 0x11
+#define BCM56307_B1_REV_ID 0x12
+#define BCM56308_DEVICE_ID 0xb308
+#define BCM56308_A0_REV_ID 1
+#define BCM56308_A1_REV_ID 2
+#define BCM56308_B0_REV_ID 0x11
+#define BCM56308_B1_REV_ID 0x12
+#define BCM56309_DEVICE_ID 0xb309
+#define BCM56309_A0_REV_ID 1
+#define BCM56309_A1_REV_ID 2
+#define BCM56309_B0_REV_ID 0x11
+#define BCM56309_B1_REV_ID 0x12
+
+#define BCM56310_DEVICE_ID 0xb310
+#define BCM56310_A0_REV_ID 1
+#define BCM56311_DEVICE_ID 0xb311
+#define BCM56311_A0_REV_ID 1
+#define BCM56312_DEVICE_ID 0xb312
+#define BCM56312_A0_REV_ID 1
+#define BCM56313_DEVICE_ID 0xb313
+#define BCM56313_A0_REV_ID 1
+#define BCM56314_DEVICE_ID 0xb314
+#define BCM56314_A0_REV_ID 1
+#define BCM56315_DEVICE_ID 0xb315
+#define BCM56315_A0_REV_ID 1
+#define BCM56316_DEVICE_ID 0xb316
+#define BCM56316_A0_REV_ID 1
+#define BCM56317_DEVICE_ID 0xb317
+#define BCM56317_A0_REV_ID 1
+#define BCM56318_DEVICE_ID 0xb318
+#define BCM56318_A0_REV_ID 1
+#define BCM56319_DEVICE_ID 0xb319
+#define BCM56319_A0_REV_ID 1
+
+#ifndef EXCLUDE_BCM56324
+#define BCM56322_DEVICE_ID 0xb322
+#define BCM56322_A0_REV_ID 1
+#define BCM56324_DEVICE_ID 0xb324
+#define BCM56324_A0_REV_ID 1
+#endif
+
+#define BCM53300_DEVICE_ID 0xb006
+#define BCM53300_A0_REV_ID 0x11
+#define BCM53300_A1_REV_ID 0x12
+#define BCM53301_DEVICE_ID 0xb206
+#define BCM53301_A0_REV_ID 0x11
+#define BCM53301_A1_REV_ID 0x12
+#define BCM53302_DEVICE_ID 0xb008
+#define BCM53302_A0_REV_ID 0x11
+#define BCM53302_A1_REV_ID 0x12
+
+#define BCM56500_DEVICE_ID 0xb500
+#define BCM56500_A0_REV_ID 1
+#define BCM56500_A1_REV_ID 2
+#define BCM56500_B0_REV_ID 0x11
+#define BCM56500_B1_REV_ID 0x12
+#define BCM56500_B2_REV_ID 0x13
+#define BCM56501_DEVICE_ID 0xb501
+#define BCM56501_A0_REV_ID 1
+#define BCM56501_A1_REV_ID 2
+#define BCM56501_B0_REV_ID 0x11
+#define BCM56501_B1_REV_ID 0x12
+#define BCM56501_B2_REV_ID 0x13
+#define BCM56502_DEVICE_ID 0xb502
+#define BCM56502_A0_REV_ID 1
+#define BCM56502_A1_REV_ID 2
+#define BCM56502_B0_REV_ID 0x11
+#define BCM56502_B1_REV_ID 0x12
+#define BCM56502_B2_REV_ID 0x13
+#define BCM56503_DEVICE_ID 0xb503
+#define BCM56503_A0_REV_ID 1
+#define BCM56503_A1_REV_ID 2
+#define BCM56503_B0_REV_ID 0x11
+#define BCM56503_B1_REV_ID 0x12
+#define BCM56503_B2_REV_ID 0x13
+#define BCM56504_DEVICE_ID 0xb504
+#define BCM56504_A0_REV_ID 1
+#define BCM56504_A1_REV_ID 2
+#define BCM56504_B0_REV_ID 0x11
+#define BCM56504_B1_REV_ID 0x12
+#define BCM56504_B2_REV_ID 0x13
+#define BCM56505_DEVICE_ID 0xb505
+#define BCM56505_A0_REV_ID 1
+#define BCM56505_A1_REV_ID 2
+#define BCM56505_B0_REV_ID 0x11
+#define BCM56505_B1_REV_ID 0x12
+#define BCM56505_B2_REV_ID 0x13
+#define BCM56506_DEVICE_ID 0xb506
+#define BCM56506_A0_REV_ID 1
+#define BCM56506_A1_REV_ID 2
+#define BCM56506_B0_REV_ID 0x11
+#define BCM56506_B1_REV_ID 0x12
+#define BCM56506_B2_REV_ID 0x13
+#define BCM56507_DEVICE_ID 0xb507
+#define BCM56507_A0_REV_ID 1
+#define BCM56507_A1_REV_ID 2
+#define BCM56507_B0_REV_ID 0x11
+#define BCM56507_B1_REV_ID 0x12
+#define BCM56507_B2_REV_ID 0x13
+#define BCM56508_DEVICE_ID 0xb508
+#define BCM56508_A0_REV_ID 1
+#define BCM56508_A1_REV_ID 2
+#define BCM56508_B0_REV_ID 0x11
+#define BCM56508_B1_REV_ID 0x12
+#define BCM56508_B2_REV_ID 0x13
+#define BCM56509_DEVICE_ID 0xb509
+#define BCM56509_A0_REV_ID 1
+#define BCM56509_A1_REV_ID 2
+#define BCM56509_B0_REV_ID 0x11
+#define BCM56509_B1_REV_ID 0x12
+#define BCM56509_B2_REV_ID 0x13
+
+#define BCM56600_DEVICE_ID 0xb600
+#define BCM56600_A0_REV_ID 1
+#define BCM56600_B0_REV_ID 0x11
+#define BCM56600_C0_REV_ID 0x21
+#define BCM56601_DEVICE_ID 0xb601
+#define BCM56601_A0_REV_ID 1
+#define BCM56601_B0_REV_ID 0x11
+#define BCM56601_C0_REV_ID 0x21
+#define BCM56602_DEVICE_ID 0xb602
+#define BCM56602_A0_REV_ID 1
+#define BCM56602_B0_REV_ID 0x11
+#define BCM56602_C0_REV_ID 0x21
+#define BCM56603_DEVICE_ID 0xb603
+#define BCM56603_A0_REV_ID 1
+#define BCM56603_B0_REV_ID 0x11
+#define BCM56603_C0_REV_ID 0x21
+#define BCM56605_DEVICE_ID 0xb605
+#define BCM56605_A0_REV_ID 1
+#define BCM56605_B0_REV_ID 0x11
+#define BCM56605_C0_REV_ID 0x21
+#define BCM56606_DEVICE_ID 0xb606
+#define BCM56606_A0_REV_ID 1
+#define BCM56606_B0_REV_ID 0x11
+#define BCM56606_C0_REV_ID 0x21
+#define BCM56607_DEVICE_ID 0xb607
+#define BCM56607_A0_REV_ID 1
+#define BCM56607_B0_REV_ID 0x11
+#define BCM56607_C0_REV_ID 0x21
+#define BCM56608_DEVICE_ID 0xb608
+#define BCM56608_A0_REV_ID 1
+#define BCM56608_B0_REV_ID 0x11
+#define BCM56608_C0_REV_ID 0x21
+
+#define BCM56580_DEVICE_ID 0xb580
+#define BCM56580_A0_REV_ID 1
+
+#define BCM56700_DEVICE_ID 0xb700
+#define BCM56700_A0_REV_ID 1
+#define BCM56701_DEVICE_ID 0xb701
+#define BCM56701_A0_REV_ID 1
+
+#define BCM56800_DEVICE_ID 0xb800
+#define BCM56800_A0_REV_ID 1
+#define BCM56801_DEVICE_ID 0xb801
+#define BCM56801_A0_REV_ID 1
+#define BCM56802_DEVICE_ID 0xb802
+#define BCM56802_A0_REV_ID 1
+#define BCM56803_DEVICE_ID 0xb803
+#define BCM56803_A0_REV_ID 1
+
+#define BCM56224_DEVICE_ID 0xb224
+#define BCM56224_A0_REV_ID 1
+#define BCM56224_B0_REV_ID 0x11
+#define BCM56225_DEVICE_ID 0xb225
+#define BCM56225_A0_REV_ID 1
+#define BCM56225_B0_REV_ID 0x11
+#define BCM56226_DEVICE_ID 0xb226
+#define BCM56226_A0_REV_ID 1
+#define BCM56226_B0_REV_ID 0x11
+#define BCM56227_DEVICE_ID 0xb227
+#define BCM56227_A0_REV_ID 1
+#define BCM56227_B0_REV_ID 0x11
+#define BCM56228_DEVICE_ID 0xb228
+#define BCM56228_A0_REV_ID 1
+#define BCM56228_B0_REV_ID 0x11
+#define BCM56229_DEVICE_ID 0xb229
+#define BCM56229_A0_REV_ID 1
+#define BCM56229_B0_REV_ID 0x11
+#define BCM56024_DEVICE_ID 0xb024
+#define BCM56024_A0_REV_ID 1
+#define BCM56024_B0_REV_ID 0x11
+#define BCM56025_DEVICE_ID 0xb025
+#define BCM56025_A0_REV_ID 1
+#define BCM56025_B0_REV_ID 0x11
+#define BCM53724_DEVICE_ID 0xc724
+#define BCM53724_A0_REV_ID 1
+#define BCM53724_B0_REV_ID 0x11
+#define BCM53726_DEVICE_ID 0xc726
+#define BCM53726_A0_REV_ID 1
+#define BCM53726_B0_REV_ID 0x11
+
+#define BCM53312_DEVICE_ID 0xc312
+#define BCM53312_A0_REV_ID 1
+#define BCM53312_B0_REV_ID 0x11
+#define BCM53313_DEVICE_ID 0xc313
+#define BCM53313_A0_REV_ID 1
+#define BCM53313_B0_REV_ID 0x11
+#define BCM53314_DEVICE_ID 0xc314
+#define BCM53314_A0_REV_ID 1
+#define BCM53314_B0_REV_ID 0x11
+
+#define BCM53322_DEVICE_ID 0xc322
+#define BCM53322_A0_REV_ID 1
+#define BCM53323_DEVICE_ID 0xc323
+#define BCM53323_A0_REV_ID 1
+#define BCM53324_DEVICE_ID 0xc324
+#define BCM53324_A0_REV_ID 1
+
+
+#define BCM56218_DEVICE_ID 0xB218
+#define BCM56218_A0_REV_ID 1
+#define BCM56218_A1_REV_ID 2
+#define BCM56218_A2_REV_ID 3
+#define BCM56218X_DEVICE_ID 0xc710
+#define BCM56218X_A0_REV_ID 1
+#define BCM56218X_A1_REV_ID 2
+#define BCM56218X_A2_REV_ID 3
+#define BCM56219_DEVICE_ID 0xB219
+#define BCM56219_A0_REV_ID 1
+#define BCM56219_A1_REV_ID 2
+#define BCM56219_A2_REV_ID 3
+#define BCM56218R_DEVICE_ID 0xB21A
+#define BCM56218R_A0_REV_ID 1
+#define BCM56218R_A1_REV_ID 2
+#define BCM56218R_A2_REV_ID 3
+#define BCM56219R_DEVICE_ID 0xB21B
+#define BCM56219R_A0_REV_ID 1
+#define BCM56219R_A1_REV_ID 2
+#define BCM56219R_A2_REV_ID 3
+#define BCM56214_DEVICE_ID 0xB214
+#define BCM56214_A0_REV_ID 1
+#define BCM56214_A1_REV_ID 2
+#define BCM56214_A2_REV_ID 3
+#define BCM56215_DEVICE_ID 0xB215
+#define BCM56215_A0_REV_ID 1
+#define BCM56215_A1_REV_ID 2
+#define BCM56215_A2_REV_ID 3
+#define BCM56214R_DEVICE_ID 0xB21C
+#define BCM56214R_A0_REV_ID 1
+#define BCM56214R_A1_REV_ID 2
+#define BCM56214R_A2_REV_ID 3
+#define BCM56215R_DEVICE_ID 0xB21D
+#define BCM56215R_A0_REV_ID 1
+#define BCM56215R_A1_REV_ID 2
+#define BCM56215R_A2_REV_ID 3
+#define BCM56216_DEVICE_ID 0xB216
+#define BCM56216_A0_REV_ID 1
+#define BCM56216_A1_REV_ID 2
+#define BCM56216_A2_REV_ID 3
+#define BCM56217_DEVICE_ID 0xB217
+#define BCM56217_A0_REV_ID 1
+#define BCM56217_A1_REV_ID 2
+#define BCM56217_A2_REV_ID 3
+#define BCM56212_DEVICE_ID 0xB212
+#define BCM56212_A0_REV_ID 1
+#define BCM56212_A1_REV_ID 2
+#define BCM56212_A2_REV_ID 3
+#define BCM56213_DEVICE_ID 0xB213
+#define BCM56213_A0_REV_ID 1
+#define BCM56213_A1_REV_ID 2
+#define BCM56213_A2_REV_ID 3
+#define BCM53718_DEVICE_ID 0xC71A
+#define BCM53718_A0_REV_ID 1
+#define BCM53718_A1_REV_ID 2
+#define BCM53718_A2_REV_ID 3
+#define BCM53714_DEVICE_ID 0xC71B
+#define BCM53714_A0_REV_ID 1
+#define BCM53714_A1_REV_ID 2
+#define BCM53714_A2_REV_ID 3
+#define BCM53716_DEVICE_ID 0xC716
+#define BCM53716_A0_REV_ID 1
+#define BCM53716_A1_REV_ID 2
+#define BCM53716_A2_REV_ID 3
+#define BCM56018_DEVICE_ID 0xB018
+#define BCM56018_A0_REV_ID 1
+#define BCM56018_A1_REV_ID 2
+#define BCM56018_A2_REV_ID 3
+#define BCM56014_DEVICE_ID 0xB014
+#define BCM56014_A0_REV_ID 1
+#define BCM56014_A1_REV_ID 2
+#define BCM56014_A2_REV_ID 3
+
+#define BCM56510_DEVICE_ID 0xb510
+#define BCM56510_A0_REV_ID 1
+#define BCM56511_DEVICE_ID 0xb511
+#define BCM56511_A0_REV_ID 1
+#define BCM56512_DEVICE_ID 0xb512
+#define BCM56512_A0_REV_ID 1
+#define BCM56513_DEVICE_ID 0xb513
+#define BCM56513_A0_REV_ID 1
+#define BCM56514_DEVICE_ID 0xb514
+#define BCM56514_A0_REV_ID 1
+#define BCM56516_DEVICE_ID 0xb516
+#define BCM56516_A0_REV_ID 1
+#define BCM56517_DEVICE_ID 0xb517
+#define BCM56517_A0_REV_ID 1
+#define BCM56518_DEVICE_ID 0xb518
+#define BCM56518_A0_REV_ID 1
+#define BCM56519_DEVICE_ID 0xb519
+#define BCM56519_A0_REV_ID 1
+
+#define BCM56620_DEVICE_ID 0xb620
+#define BCM56620_A0_REV_ID 1
+#define BCM56620_A1_REV_ID 2
+#define BCM56620_B0_REV_ID 0x11
+#define BCM56620_B1_REV_ID 0x12
+#define BCM56620_B2_REV_ID 0x13
+#define BCM56624_DEVICE_ID 0xb624
+#define BCM56624_A0_REV_ID 1
+#define BCM56624_A1_REV_ID 2
+#define BCM56624_B0_REV_ID 0x11
+#define BCM56624_B1_REV_ID 0x12
+#define BCM56624_B2_REV_ID 0x13
+#define BCM56626_DEVICE_ID 0xb626
+#define BCM56626_A0_REV_ID 1
+#define BCM56626_A1_REV_ID 2
+#define BCM56626_B0_REV_ID 0x11
+#define BCM56626_B1_REV_ID 0x12
+#define BCM56626_B2_REV_ID 0x13
+#define BCM56628_DEVICE_ID 0xb628
+#define BCM56628_A0_REV_ID 1
+#define BCM56628_A1_REV_ID 2
+#define BCM56628_B0_REV_ID 0x11
+#define BCM56628_B1_REV_ID 0x12
+#define BCM56628_B2_REV_ID 0x13
+#define BCM56629_DEVICE_ID 0xb629
+#define BCM56629_A0_REV_ID 1
+#define BCM56629_A1_REV_ID 2
+#define BCM56629_B0_REV_ID 0x11
+#define BCM56629_B1_REV_ID 0x12
+#define BCM56629_B2_REV_ID 0x13
+
+#define BCM56680_DEVICE_ID 0xb680
+#define BCM56680_A0_REV_ID 1
+#define BCM56680_A1_REV_ID 2
+#define BCM56680_B0_REV_ID 0x11
+#define BCM56680_B1_REV_ID 0x12
+#define BCM56680_B2_REV_ID 0x13
+#define BCM56684_DEVICE_ID 0xb684
+#define BCM56684_A0_REV_ID 1
+#define BCM56684_A1_REV_ID 2
+#define BCM56684_B0_REV_ID 0x11
+#define BCM56684_B1_REV_ID 0x12
+#define BCM56684_B2_REV_ID 0x13
+#define BCM56686_DEVICE_ID 0xb686
+#define BCM56686_B0_REV_ID 0x11
+#define BCM56686_B1_REV_ID 0x12
+#define BCM56686_B2_REV_ID 0x13
+
+#define BCM56820_DEVICE_ID 0xb820
+#define BCM56820_A0_REV_ID 1
+#define BCM56820_B0_REV_ID 0x11
+#define BCM56821_DEVICE_ID 0xb821
+#define BCM56821_A0_REV_ID 1
+#define BCM56821_B0_REV_ID 0x11
+#define BCM56822_DEVICE_ID 0xb822
+#define BCM56822_A0_REV_ID 1
+#define BCM56822_B0_REV_ID 0x11
+#define BCM56823_DEVICE_ID 0xb823
+#define BCM56823_A0_REV_ID 1
+#define BCM56823_B0_REV_ID 0x11
+#define BCM56825_DEVICE_ID 0xb825
+#define BCM56825_B0_REV_ID 0x11
+
+#define BCM56720_DEVICE_ID 0xb720
+#define BCM56720_A0_REV_ID 1
+#define BCM56720_B0_REV_ID 0x11
+#define BCM56721_DEVICE_ID 0xb721
+#define BCM56721_A0_REV_ID 1
+#define BCM56721_B0_REV_ID 0x11
+
+#define BCM56725_DEVICE_ID 0xb725
+#define BCM56725_A0_REV_ID 1
+#define BCM56725_B0_REV_ID 0x11
+
+#define BCM56630_DEVICE_ID 0xb630
+#define BCM56630_A0_REV_ID 1
+#define BCM56630_B0_REV_ID 0x11
+#define BCM56634_DEVICE_ID 0xb634
+#define BCM56634_A0_REV_ID 1
+#define BCM56634_B0_REV_ID 0x11
+#define BCM56636_DEVICE_ID 0xb636
+#define BCM56636_A0_REV_ID 1
+#define BCM56636_B0_REV_ID 0x11
+#define BCM56638_DEVICE_ID 0xb638
+#define BCM56638_A0_REV_ID 1
+#define BCM56638_B0_REV_ID 0x11
+#define BCM56639_DEVICE_ID 0xb639
+#define BCM56639_A0_REV_ID 1
+#define BCM56639_B0_REV_ID 0x11
+
+#define BCM56685_DEVICE_ID 0xb685
+#define BCM56685_A0_REV_ID 1
+#define BCM56685_B0_REV_ID 0x11
+#define BCM56689_DEVICE_ID 0xb689
+#define BCM56689_A0_REV_ID 1
+#define BCM56689_B0_REV_ID 0x11
+
+#define BCM56520_DEVICE_ID 0xb520
+#define BCM56520_A0_REV_ID 1
+#define BCM56520_B0_REV_ID 0x11
+#define BCM56521_DEVICE_ID 0xb521
+#define BCM56521_A0_REV_ID 1
+#define BCM56521_B0_REV_ID 0x11
+#define BCM56522_DEVICE_ID 0xb522
+#define BCM56522_A0_REV_ID 1
+#define BCM56522_B0_REV_ID 0x11
+#define BCM56524_DEVICE_ID 0xb524
+#define BCM56524_A0_REV_ID 1
+#define BCM56524_B0_REV_ID 0x11
+#define BCM56526_DEVICE_ID 0xb526
+#define BCM56526_A0_REV_ID 1
+#define BCM56526_B0_REV_ID 0x11
+
+#define BCM56534_DEVICE_ID 0xb534
+#define BCM56534_B0_REV_ID 0x11
+#define BCM56538_DEVICE_ID 0xb538
+#define BCM56538_B0_REV_ID 0x11
+
+#define BCM56331_DEVICE_ID 0xb331
+#define BCM56331_A0_REV_ID 1
+#define BCM56331_B0_REV_ID 0x11
+#define BCM56331_B1_REV_ID 0x12
+#define BCM56333_DEVICE_ID 0xb333
+#define BCM56333_A0_REV_ID 1
+#define BCM56333_B0_REV_ID 0x11
+#define BCM56333_B1_REV_ID 0x12
+#define BCM56334_DEVICE_ID 0xb334
+#define BCM56334_A0_REV_ID 1
+#define BCM56334_B0_REV_ID 0x11
+#define BCM56334_B1_REV_ID 0x12
+#define BCM56338_DEVICE_ID 0xb338
+#define BCM56338_A0_REV_ID 1
+#define BCM56338_B0_REV_ID 0x11
+#define BCM56338_B1_REV_ID 0x12
+
+#define BCM56320_DEVICE_ID 0xb320
+#define BCM56320_A0_REV_ID 1
+#define BCM56320_B0_REV_ID 0x11
+#define BCM56320_B1_REV_ID 0x12
+#define BCM56321_DEVICE_ID 0xb321
+#define BCM56321_A0_REV_ID 1
+#define BCM56321_B0_REV_ID 0x11
+#define BCM56321_B1_REV_ID 0x12
+
+
+#define BCM56548H_DEVICE_ID 0xB54A
+#define BCM56548H_A0_REV_ID 1
+#define BCM56548_DEVICE_ID 0xb548
+#define BCM56548_A0_REV_ID 1
+#define BCM56547_DEVICE_ID 0xb547
+#define BCM56547_A0_REV_ID 1
+
+#define BCM56346_DEVICE_ID 0xb346
+#define BCM56346_A0_REV_ID 1
+#define BCM56345_DEVICE_ID 0xb345
+#define BCM56345_A0_REV_ID 1
+#define BCM56344_DEVICE_ID 0xb344
+#define BCM56344_A0_REV_ID 1
+#define BCM56342_DEVICE_ID 0xb342
+#define BCM56342_A0_REV_ID 1
+#define BCM56340_DEVICE_ID 0xb340
+#define BCM56340_A0_REV_ID 1
+
+#define BCM56049_DEVICE_ID 0xb049
+#define BCM56049_A0_REV_ID 1
+#define BCM56048_DEVICE_ID 0xb048
+#define BCM56048_A0_REV_ID 1
+#define BCM56047_DEVICE_ID 0xb047
+#define BCM56047_A0_REV_ID 1
+
+#define BCM56042_DEVICE_ID 0xb042
+#define BCM56042_A0_REV_ID 1
+#define BCM56041_DEVICE_ID 0xb041
+#define BCM56041_A0_REV_ID 1
+#define BCM56040_DEVICE_ID 0xb040
+#define BCM56040_A0_REV_ID 1
+
+#define BCM56132_DEVICE_ID 0xb132
+#define BCM56132_A0_REV_ID 1
+#define BCM56132_B0_REV_ID 0x11
+#define BCM56132_B1_REV_ID 0x12
+#define BCM56134_DEVICE_ID 0xb134
+#define BCM56134_A0_REV_ID 1
+#define BCM56134_B0_REV_ID 0x11
+#define BCM56134_B1_REV_ID 0x12
+
+#define BCM56230_DEVICE_ID 0xb230
+#define BCM56230_B1_REV_ID 0x12
+#define BCM56231_DEVICE_ID 0xb231
+#define BCM56231_B1_REV_ID 0x12
+
+#define BCM56140_DEVICE_ID 0xb140
+#define BCM56140_A0_REV_ID 1
+#define BCM56142_DEVICE_ID 0xb142
+#define BCM56142_A0_REV_ID 1
+#define BCM56143_DEVICE_ID 0xb143
+#define BCM56143_A0_REV_ID 1
+#define BCM56144_DEVICE_ID 0xb144
+#define BCM56144_A0_REV_ID 1
+#define BCM56146_DEVICE_ID 0xb146
+#define BCM56146_A0_REV_ID 1
+#define BCM56147_DEVICE_ID 0xb147
+#define BCM56147_A0_REV_ID 1
+#define BCM56149_DEVICE_ID 0xb149
+#define BCM56149_A0_REV_ID 1
+
+#define BCM56840_DEVICE_ID 0xb840
+#define BCM56840_A0_REV_ID 1
+#define BCM56840_A1_REV_ID 2
+#define BCM56840_A2_REV_ID 3
+#define BCM56840_A3_REV_ID 4
+#define BCM56840_A4_REV_ID 5
+#define BCM56840_B0_REV_ID 0x11
+#define BCM56840_B1_REV_ID 0x12
+#define BCM56841_DEVICE_ID 0xb841
+#define BCM56841_A0_REV_ID 1
+#define BCM56841_A1_REV_ID 2
+#define BCM56841_A2_REV_ID 3
+#define BCM56841_A3_REV_ID 4
+#define BCM56841_A4_REV_ID 5
+#define BCM56841_B0_REV_ID 0x11
+#define BCM56841_B1_REV_ID 0x12
+#define BCM56843_DEVICE_ID 0xb843
+#define BCM56843_A0_REV_ID 1
+#define BCM56843_A1_REV_ID 2
+#define BCM56843_A2_REV_ID 3
+#define BCM56843_A3_REV_ID 4
+#define BCM56843_A4_REV_ID 5
+#define BCM56843_B0_REV_ID 0x11
+#define BCM56843_B1_REV_ID 0x12
+#define BCM56845_DEVICE_ID 0xb845
+#define BCM56845_A0_REV_ID 1
+#define BCM56845_A1_REV_ID 2
+#define BCM56845_A2_REV_ID 3
+#define BCM56845_A3_REV_ID 4
+#define BCM56845_A4_REV_ID 5
+#define BCM56845_B0_REV_ID 0x11
+#define BCM56845_B1_REV_ID 0x12
+
+#define BCM56743_DEVICE_ID 0xb743
+#define BCM56743_A0_REV_ID 1
+#define BCM56743_A1_REV_ID 2
+#define BCM56743_A2_REV_ID 3
+#define BCM56743_A3_REV_ID 4
+#define BCM56743_A4_REV_ID 5
+#define BCM56743_B0_REV_ID 0x11
+#define BCM56743_B1_REV_ID 0x12
+#define BCM56745_DEVICE_ID 0xb745
+#define BCM56745_A0_REV_ID 1
+#define BCM56745_A1_REV_ID 2
+#define BCM56745_A2_REV_ID 3
+#define BCM56745_A3_REV_ID 4
+#define BCM56745_A4_REV_ID 5
+#define BCM56745_B0_REV_ID 0x11
+#define BCM56745_B1_REV_ID 0x12
+
+#define BCM56260_DEVICE_ID 0xb260
+#define BCM56260_A0_REV_ID 1
+#define BCM56260_B0_REV_ID 0x11
+#define BCM56261_DEVICE_ID 0xb261
+#define BCM56261_A0_REV_ID 1
+#define BCM56261_B0_REV_ID 0x11
+#define BCM56262_DEVICE_ID 0xb262
+#define BCM56262_A0_REV_ID 1
+#define BCM56262_B0_REV_ID 0x11
+#define BCM56263_DEVICE_ID 0xb263
+#define BCM56263_A0_REV_ID 1
+#define BCM56263_B0_REV_ID 0x11
+
+#define BCM56265_DEVICE_ID 0xb265
+#define BCM56265_A0_REV_ID 1
+#define BCM56265_B0_REV_ID 0x11
+#define BCM56266_DEVICE_ID 0xb266
+#define BCM56266_A0_REV_ID 1
+#define BCM56266_B0_REV_ID 0x11
+#define BCM56267_DEVICE_ID 0xb267
+#define BCM56267_A0_REV_ID 1
+#define BCM56267_B0_REV_ID 0x11
+#define BCM56268_DEVICE_ID 0xb268
+#define BCM56268_A0_REV_ID 1
+#define BCM56268_B0_REV_ID 0x11
+
+#define BCM56233_DEVICE_ID 0xb233
+#define BCM56233_B0_REV_ID 0x11
+
+#define BCM56460_DEVICE_ID 0xb460
+#define BCM56460_A0_REV_ID 1
+#define BCM56460_B0_REV_ID 0x11
+#define BCM56461_DEVICE_ID 0xb461
+#define BCM56461_A0_REV_ID 1
+#define BCM56461_B0_REV_ID 0x11
+#define BCM56462_DEVICE_ID 0xb462
+#define BCM56462_A0_REV_ID 1
+#define BCM56462_B0_REV_ID 0x11
+#define BCM56463_DEVICE_ID 0xb463
+#define BCM56463_A0_REV_ID 1
+#define BCM56463_B0_REV_ID 0x11
+
+#define BCM56465_DEVICE_ID 0xb465
+#define BCM56465_A0_REV_ID 1
+#define BCM56465_B0_REV_ID 0x11
+#define BCM56466_DEVICE_ID 0xb466
+#define BCM56466_A0_REV_ID 1
+#define BCM56466_B0_REV_ID 0x11
+#define BCM56467_DEVICE_ID 0xb467
+#define BCM56467_A0_REV_ID 1
+#define BCM56467_B0_REV_ID 0x11
+#define BCM56468_DEVICE_ID 0xb468
+#define BCM56468_A0_REV_ID 1
+#define BCM56468_B0_REV_ID 0x11
+
+#define BCM56270_DEVICE_ID 0xb270
+#define BCM56270_A0_REV_ID 1
+#define BCM56271_DEVICE_ID 0xb271
+#define BCM56271_A0_REV_ID 1
+#define BCM56272_DEVICE_ID 0xb272
+#define BCM56272_A0_REV_ID 1
+
+#define BCM53460_DEVICE_ID 0x8460
+#define BCM53460_A0_REV_ID 1
+#define BCM53461_DEVICE_ID 0x8461
+#define BCM53461_A0_REV_ID 1
+
+#define BCM56842_DEVICE_ID 0xb842
+#define BCM56842_A0_REV_ID 1
+#define BCM56842_A1_REV_ID 2
+#define BCM56844_DEVICE_ID 0xb844
+#define BCM56844_A0_REV_ID 1
+#define BCM56844_A1_REV_ID 2
+#define BCM56846_DEVICE_ID 0xb846
+#define BCM56846_A0_REV_ID 1
+#define BCM56846_A1_REV_ID 2
+#define BCM56549_DEVICE_ID 0xb549
+#define BCM56549_A0_REV_ID 1
+#define BCM56549_A1_REV_ID 2
+#define BCM56053_DEVICE_ID 0xb053
+#define BCM56053_A0_REV_ID 1
+#define BCM56053_A1_REV_ID 2
+#define BCM56831_DEVICE_ID 0xb831
+#define BCM56831_A0_REV_ID 1
+#define BCM56831_A1_REV_ID 2
+#define BCM56835_DEVICE_ID 0xb835
+#define BCM56835_A0_REV_ID 1
+#define BCM56835_A1_REV_ID 2
+#define BCM56838_DEVICE_ID 0xb838
+#define BCM56838_A0_REV_ID 1
+#define BCM56838_A1_REV_ID 2
+#define BCM56847_DEVICE_ID 0xb847
+#define BCM56847_A0_REV_ID 1
+#define BCM56847_A1_REV_ID 2
+#define BCM56847_A2_REV_ID 3
+#define BCM56847_A3_REV_ID 4
+#define BCM56847_A4_REV_ID 5
+#define BCM56847_B0_REV_ID 0x11
+#define BCM56847_B1_REV_ID 0x12
+#define BCM56849_DEVICE_ID 0xb849
+#define BCM56849_A0_REV_ID 1
+#define BCM56849_A1_REV_ID 2
+
+#define BCM56742_DEVICE_ID 0xb742
+#define BCM56742_A0_REV_ID 1
+#define BCM56742_A1_REV_ID 2
+#define BCM56742_A2_REV_ID 3
+#define BCM56744_DEVICE_ID 0xb744
+#define BCM56744_A0_REV_ID 1
+#define BCM56744_A1_REV_ID 2
+#define BCM56746_DEVICE_ID 0xb746
+#define BCM56746_A0_REV_ID 1
+#define BCM56746_A1_REV_ID 2
+
+#define BCM88732_DEVICE_ID 0x0732
+#define BCM88732_A0_REV_ID 1
+#define BCM88732_A1_REV_ID 2
+#define BCM88732_A2_REV_ID 4
+#define BCM88732_B0_REV_ID 0x11
+#define BCM88732_B1_REV_ID 0x12
+#define BCM88732_B2_REV_ID 0x13
+
+#define BCM56640_DEVICE_ID 0xb640
+#define BCM56640_A0_REV_ID 1
+#define BCM56640_A1_REV_ID 2
+#define BCM56640_B0_REV_ID 0x11
+#define BCM56643_DEVICE_ID 0xb643
+#define BCM56643_A0_REV_ID 1
+#define BCM56643_A1_REV_ID 2
+#define BCM56643_B0_REV_ID 0x11
+#define BCM56644_DEVICE_ID 0xb644
+#define BCM56644_A0_REV_ID 1
+#define BCM56644_A1_REV_ID 2
+#define BCM56644_B0_REV_ID 0x11
+#define BCM56648_DEVICE_ID 0xb648
+#define BCM56648_A0_REV_ID 1
+#define BCM56648_A1_REV_ID 2
+#define BCM56648_B0_REV_ID 0x11
+#define BCM56649_DEVICE_ID 0xb649
+#define BCM56649_A0_REV_ID 1
+#define BCM56649_A1_REV_ID 2
+#define BCM56649_B0_REV_ID 0x11
+
+#define BCM56540_DEVICE_ID 0xb540
+#define BCM56540_A0_REV_ID 1
+#define BCM56540_A1_REV_ID 2
+#define BCM56540_B0_REV_ID 0x11
+#define BCM56541_DEVICE_ID 0xb541
+#define BCM56541_A0_REV_ID 1
+#define BCM56541_A1_REV_ID 2
+#define BCM56541_B0_REV_ID 0x11
+#define BCM56542_DEVICE_ID 0xb542
+#define BCM56542_A0_REV_ID 1
+#define BCM56542_A1_REV_ID 2
+#define BCM56542_B0_REV_ID 0x11
+#define BCM56543_DEVICE_ID 0xb543
+#define BCM56543_A0_REV_ID 1
+#define BCM56543_A1_REV_ID 2
+#define BCM56543_B0_REV_ID 0x11
+#define BCM56544_DEVICE_ID 0xb544
+#define BCM56544_A0_REV_ID 1
+#define BCM56544_A1_REV_ID 2
+#define BCM56544_B0_REV_ID 0x11
+
+#define BCM56545_DEVICE_ID 0xb545
+#define BCM56545_A0_REV_ID 1
+#define BCM56545_A1_REV_ID 2
+#define BCM56545_B0_REV_ID 0x11
+#define BCM56546_DEVICE_ID 0xb546
+#define BCM56546_A0_REV_ID 1
+#define BCM56546_A1_REV_ID 2
+#define BCM56546_B0_REV_ID 0x11
+
+#define BCM56044_DEVICE_ID 0xb044
+#define BCM56044_B0_REV_ID 0x11
+#define BCM56045_DEVICE_ID 0xb045
+#define BCM56045_A0_REV_ID 1
+#define BCM56045_A1_REV_ID 2
+#define BCM56045_B0_REV_ID 0x11
+#define BCM56046_DEVICE_ID 0xb046
+#define BCM56046_A0_REV_ID 1
+#define BCM56046_A1_REV_ID 2
+#define BCM56046_B0_REV_ID 0x11
+
+
+#define BCM56440_DEVICE_ID 0xb440
+#define BCM56440_A0_REV_ID 1
+#define BCM56440_B0_REV_ID 0x11
+#define BCM56441_DEVICE_ID 0xb441
+#define BCM56441_A0_REV_ID 1
+#define BCM56441_B0_REV_ID 0x11
+#define BCM56442_DEVICE_ID 0xb442
+#define BCM56442_A0_REV_ID 1
+#define BCM56442_B0_REV_ID 0x11
+#define BCM56443_DEVICE_ID 0xb443
+#define BCM56443_A0_REV_ID 1
+#define BCM56443_B0_REV_ID 0x11
+#define BCM56445_DEVICE_ID 0xb445
+#define BCM56445_A0_REV_ID 1
+#define BCM56445_B0_REV_ID 0x11
+#define BCM56446_DEVICE_ID 0xb446
+#define BCM56446_A0_REV_ID 1
+#define BCM56446_B0_REV_ID 0x11
+#define BCM56447_DEVICE_ID 0xb447
+#define BCM56447_A0_REV_ID 1
+#define BCM56447_B0_REV_ID 0x11
+#define BCM56448_DEVICE_ID 0xb448
+#define BCM56448_A0_REV_ID 1
+#define BCM56448_B0_REV_ID 0x11
+#define BCM56449_DEVICE_ID 0xb449
+#define BCM56449_A0_REV_ID 1
+#define BCM56449_B0_REV_ID 0x11
+#define BCM56240_DEVICE_ID 0xb240
+#define BCM56240_A0_REV_ID 1
+#define BCM56240_B0_REV_ID 0x11
+#define BCM56241_DEVICE_ID 0xb241
+#define BCM56241_A0_REV_ID 1
+#define BCM56241_B0_REV_ID 0x11
+#define BCM56242_DEVICE_ID 0xb242
+#define BCM56242_A0_REV_ID 1
+#define BCM56242_B0_REV_ID 0x11
+#define BCM56243_DEVICE_ID 0xb243
+#define BCM56243_A0_REV_ID 1
+#define BCM56243_B0_REV_ID 0x11
+#define BCM56245_DEVICE_ID 0xb245
+#define BCM56245_A0_REV_ID 1
+#define BCM56245_B0_REV_ID 0x11
+#define BCM56246_DEVICE_ID 0xb246
+#define BCM56246_A0_REV_ID 1
+#define BCM56246_B0_REV_ID 0x11
+#define BCM55440_DEVICE_ID 0xa440
+#define BCM55440_A0_REV_ID 1
+#define BCM55440_B0_REV_ID 0x11
+#define BCM55441_DEVICE_ID 0xa441
+#define BCM55441_A0_REV_ID 1
+#define BCM55441_B0_REV_ID 0x11
+
+#define BCM55450_DEVICE_ID 0xa450
+#define BCM55450_A0_REV_ID 1
+#define BCM55450_B0_REV_ID 0x11
+#define BCM55450_B1_REV_ID 0x12
+
+#define BCM55455_DEVICE_ID 0xa455
+#define BCM55455_A0_REV_ID 1
+#define BCM55455_B0_REV_ID 0x11
+#define BCM55455_B1_REV_ID 0x12
+
+#define BCM56248_DEVICE_ID 0xb248
+#define BCM56248_A0_REV_ID 1
+#define BCM56248_B0_REV_ID 0x11
+#define BCM56248_B1_REV_ID 0x12
+
+#define BCM56450_DEVICE_ID 0xb450
+#define BCM56450_A0_REV_ID 1
+#define BCM56450_B0_REV_ID 0x11
+#define BCM56450_B1_REV_ID 0x12
+
+#define BCM56452_DEVICE_ID 0xb452
+#define BCM56452_A0_REV_ID 1
+#define BCM56452_B0_REV_ID 0x11
+#define BCM56452_B1_REV_ID 0x12
+
+#define BCM56454_DEVICE_ID 0xb454
+#define BCM56454_A0_REV_ID 1
+#define BCM56454_B0_REV_ID 0x11
+#define BCM56454_B1_REV_ID 0x12
+
+#define BCM56455_DEVICE_ID 0xb455
+#define BCM56455_A0_REV_ID 1
+#define BCM56455_B0_REV_ID 0x11
+#define BCM56455_B1_REV_ID 0x12
+
+#define BCM56456_DEVICE_ID 0xb456
+#define BCM56456_A0_REV_ID 1
+#define BCM56456_B0_REV_ID 0x11
+#define BCM56456_B1_REV_ID 0x12
+
+#define BCM56457_DEVICE_ID 0xb457
+#define BCM56457_A0_REV_ID 1
+#define BCM56457_B0_REV_ID 0x11
+#define BCM56457_B1_REV_ID 0x12
+
+#define BCM56458_DEVICE_ID 0xb458
+#define BCM56458_A0_REV_ID 1
+#define BCM56458_B0_REV_ID 0x11
+#define BCM56458_B1_REV_ID 0x12
+
+#define BCM56850_DEVICE_ID 0xb850
+#define BCM56850_A0_REV_ID 1
+#define BCM56850_A1_REV_ID 2
+#define BCM56850_A2_REV_ID 3
+#define BCM56851_DEVICE_ID 0xb851
+#define BCM56851_A0_REV_ID 1
+#define BCM56851_A1_REV_ID 2
+#define BCM56851_A2_REV_ID 3
+#define BCM56852_DEVICE_ID 0xb852
+#define BCM56852_A0_REV_ID 1
+#define BCM56852_A1_REV_ID 2
+#define BCM56852_A2_REV_ID 3
+#define BCM56853_DEVICE_ID 0xb853
+#define BCM56853_A0_REV_ID 1
+#define BCM56853_A1_REV_ID 2
+#define BCM56853_A2_REV_ID 3
+#define BCM56854_DEVICE_ID 0xb854
+#define BCM56854_A0_REV_ID 1
+#define BCM56854_A1_REV_ID 2
+#define BCM56854_A2_REV_ID 3
+#define BCM56855_DEVICE_ID 0xb855
+#define BCM56855_A0_REV_ID 1
+#define BCM56855_A1_REV_ID 2
+#define BCM56855_A2_REV_ID 3
+#define BCM56834_DEVICE_ID 0xb834
+#define BCM56834_A0_REV_ID 1
+#define BCM56834_A1_REV_ID 2
+#define BCM56834_A2_REV_ID 3
+
+#define BCM56860_DEVICE_ID 0xb860
+#define BCM56860_A0_REV_ID 1
+#define BCM56860_A1_REV_ID 2
+#define BCM56861_DEVICE_ID 0xb861
+#define BCM56861_A0_REV_ID 1
+#define BCM56861_A1_REV_ID 2
+#define BCM56862_DEVICE_ID 0xb862
+#define BCM56862_A0_REV_ID 1
+#define BCM56862_A1_REV_ID 2
+#define BCM56864_DEVICE_ID 0xb864
+#define BCM56864_A0_REV_ID 1
+#define BCM56864_A1_REV_ID 2
+#define BCM56865_DEVICE_ID 0xb865
+#define BCM56865_A0_REV_ID 1
+#define BCM56865_A1_REV_ID 2
+#define BCM56866_DEVICE_ID 0xb866
+#define BCM56866_A0_REV_ID 1
+#define BCM56866_A1_REV_ID 2
+#define BCM56867_DEVICE_ID 0xb867
+#define BCM56867_A0_REV_ID 1
+#define BCM56867_A1_REV_ID 2
+#define BCM56868_DEVICE_ID 0xb868
+#define BCM56868_A0_REV_ID 1
+#define BCM56868_A1_REV_ID 2
+#define BCM56832_DEVICE_ID 0xb832
+#define BCM56832_A0_REV_ID 1
+#define BCM56832_A1_REV_ID 2
+#define BCM56833_DEVICE_ID 0xb833
+#define BCM56833_A0_REV_ID 1
+#define BCM56833_A1_REV_ID 2
+#define BCM56836_DEVICE_ID 0xb836
+#define BCM56836_A0_REV_ID 1
+#define BCM56836_A1_REV_ID 2
+
+
+#define BCM56750_DEVICE_ID 0xb750
+#define BCM56750_A0_REV_ID 1
+#define BCM56750_A1_REV_ID 2
+#define BCM56750_A2_REV_ID 3
+
+#define BCM56830_DEVICE_ID 0xb830
+#define BCM56830_A0_REV_ID 1
+#define BCM56830_A1_REV_ID 2
+#define BCM56830_A2_REV_ID 3
+
+#define BCM56150_DEVICE_ID 0xb150
+#define BCM56150_A0_REV_ID 1
+#define BCM56151_DEVICE_ID 0xb151
+#define BCM56151_A0_REV_ID 1
+#define BCM56152_DEVICE_ID 0xb152
+#define BCM56152_A0_REV_ID 1
+
+#define BCM53342_DEVICE_ID 0x8342
+#define BCM53342_A0_REV_ID 1
+#define BCM53343_DEVICE_ID 0x8343
+#define BCM53343_A0_REV_ID 1
+#define BCM53344_DEVICE_ID 0x8344
+#define BCM53344_A0_REV_ID 1
+#define BCM53346_DEVICE_ID 0x8346
+#define BCM53346_A0_REV_ID 1
+#define BCM53347_DEVICE_ID 0x8347
+#define BCM53347_A0_REV_ID 1
+
+#define BCM53333_DEVICE_ID 0x8333
+#define BCM53333_A0_REV_ID 1
+#define BCM53334_DEVICE_ID 0x8334
+#define BCM53334_A0_REV_ID 1
+
+#define BCM53393_DEVICE_ID 0x8393
+#define BCM53393_A0_REV_ID 1
+#define BCM53394_DEVICE_ID 0x8394
+#define BCM53394_A0_REV_ID 1
+
+#define BCM53400_DEVICE_ID 0x8400
+#define BCM53400_A0_REV_ID 1
+#define BCM56060_DEVICE_ID 0xb060
+#define BCM56060_A0_REV_ID 1
+#define BCM56062_DEVICE_ID 0xb062
+#define BCM56062_A0_REV_ID 1
+#define BCM56063_DEVICE_ID 0xb063
+#define BCM56063_A0_REV_ID 1
+#define BCM56064_DEVICE_ID 0xb064
+#define BCM56064_A0_REV_ID 1
+#define BCM56065_DEVICE_ID 0xb065
+#define BCM56065_A0_REV_ID 1
+#define BCM56066_DEVICE_ID 0xb066
+#define BCM56066_A0_REV_ID 1
+#define BCM53401_DEVICE_ID 0x8401
+#define BCM53411_DEVICE_ID 0x8411
+#define BCM53401_A0_REV_ID 1
+#define BCM53402_DEVICE_ID 0x8402
+#define BCM53412_DEVICE_ID 0x8412
+#define BCM53402_A0_REV_ID 1
+#define BCM53403_DEVICE_ID 0x8403
+#define BCM53413_DEVICE_ID 0x8413
+#define BCM53403_A0_REV_ID 1
+#define BCM53404_DEVICE_ID 0x8404
+#define BCM53414_DEVICE_ID 0x8414
+#define BCM53404_A0_REV_ID 1
+#define BCM53405_DEVICE_ID 0x8405
+#define BCM53415_DEVICE_ID 0x8415
+#define BCM53405_A0_REV_ID 1
+#define BCM53406_DEVICE_ID 0x8406
+#define BCM53416_DEVICE_ID 0x8416
+#define BCM53406_A0_REV_ID 1
+#define BCM53408_DEVICE_ID 0x8408
+#define BCM53418_DEVICE_ID 0x8418
+#define BCM53408_A0_REV_ID 1
+#define BCM53365_DEVICE_ID 0x8365
+#define BCM53365_A0_REV_ID 1
+#define BCM53369_DEVICE_ID 0x8369
+#define BCM53369_A0_REV_ID 1
+
+#define BCM53454_DEVICE_ID 0x8454
+#define BCM53455_DEVICE_ID 0x8455
+#define BCM53454_A0_REV_ID 1
+#define BCM53456_DEVICE_ID 0x8456
+#define BCM53457_DEVICE_ID 0x8457
+#define BCM53456_A0_REV_ID 1
+
+#define BCM53422_DEVICE_ID 0x8422
+#define BCM53422_A0_REV_ID 1
+#define BCM53424_DEVICE_ID 0x8424
+#define BCM53424_A0_REV_ID 1
+#define BCM53426_DEVICE_ID 0x8426
+#define BCM53426_A0_REV_ID 1
+
+#define BCM56960_DEVICE_ID 0xb960
+#define BCM56960_A0_REV_ID 1
+#define BCM56960_B0_REV_ID 0x11
+#define BCM56960_B1_REV_ID 0x12
+#define BCM56961_DEVICE_ID 0xb961
+#define BCM56961_A0_REV_ID 1
+#define BCM56961_B0_REV_ID 0x11
+#define BCM56961_B1_REV_ID 0x12
+#define BCM56962_DEVICE_ID 0xb962
+#define BCM56962_A0_REV_ID 1
+#define BCM56962_B0_REV_ID 0x11
+#define BCM56962_B1_REV_ID 0x12
+#define BCM56963_DEVICE_ID 0xb963
+#define BCM56963_A0_REV_ID 1
+#define BCM56963_B0_REV_ID 0x11
+#define BCM56963_B1_REV_ID 0x12
+#define BCM56930_DEVICE_ID 0xb930
+#define BCM56930_A0_REV_ID 1
+#define BCM56930_B0_REV_ID 0x11
+#define BCM56930_B1_REV_ID 0x12
+#define BCM56930_C0_REV_ID 0x21
+#define BCM56931_DEVICE_ID 0xb931
+#define BCM56931_A0_REV_ID 1
+#define BCM56931_B0_REV_ID 0x11
+#define BCM56931_C0_REV_ID 0x21
+#define BCM56935_DEVICE_ID 0xb935
+#define BCM56935_A0_REV_ID 1
+#define BCM56935_B0_REV_ID 0x11
+#define BCM56935_C0_REV_ID 0x21
+#define BCM56936_DEVICE_ID 0xb936
+#define BCM56936_A0_REV_ID 1
+#define BCM56936_B0_REV_ID 0x11
+#define BCM56936_C0_REV_ID 0x21
+#define BCM56939_DEVICE_ID 0xb939
+#define BCM56939_A0_REV_ID 1
+#define BCM56939_B0_REV_ID 0x11
+#define BCM56939_C0_REV_ID 0x21
+
+#define BCM56168_DEVICE_ID 0xb168
+#define BCM56168_A0_REV_ID 1
+#define BCM56168_B0_REV_ID 0x11
+#define BCM56168_B1_REV_ID 0x12
+#define BCM56169_DEVICE_ID 0xb169
+#define BCM56169_A0_REV_ID 1
+#define BCM56169_B0_REV_ID 0x11
+#define BCM56169_B1_REV_ID 0x12
+
+#define BCM56980_DEVICE_ID 0xb980
+#define BCM56980_A0_REV_ID 1
+#define BCM56980_B0_REV_ID 0x11
+#define BCM56981_DEVICE_ID 0xb981
+#define BCM56981_A0_REV_ID 1
+#define BCM56982_DEVICE_ID 0xb982
+#define BCM56982_A0_REV_ID 1
+#define BCM56982_B0_REV_ID 0x11
+#define BCM56983_DEVICE_ID 0xb983
+#define BCM56983_A0_REV_ID 1
+#define BCM56983_B0_REV_ID 0x11
+#define BCM56984_DEVICE_ID 0xb984
+#define BCM56984_A0_REV_ID 1
+#define BCM56984_B0_REV_ID 0x11
+
+#define BCM56968_DEVICE_ID 0xb968
+#define BCM56968_A0_REV_ID 1
+#define BCM56968_B0_REV_ID 0x11
+#define BCM56968_B1_REV_ID 0x12
+
+#define BCM56160_DEVICE_ID 0xb160
+#define BCM56160_A0_REV_ID 1
+#define BCM56160_B0_REV_ID 0x11
+#define BCM56162_DEVICE_ID 0xb162
+#define BCM56162_A0_REV_ID 1
+#define BCM56162_B0_REV_ID 0x11
+
+#define BCM56163_DEVICE_ID 0xb163
+#define BCM56163_A0_REV_ID 1
+#define BCM56163_B0_REV_ID 0x11
+#define BCM56164_DEVICE_ID 0xb164
+#define BCM56164_A0_REV_ID 1
+#define BCM56164_B0_REV_ID 0x11
+#define BCM56166_DEVICE_ID 0xb166
+#define BCM56166_A0_REV_ID 1
+#define BCM56166_B0_REV_ID 0x11
+
+#define BCM53440_DEVICE_ID 0x8440
+#define BCM53440_A0_REV_ID 1
+#define BCM53440_B0_REV_ID 0x11
+#define BCM53442_DEVICE_ID 0x8442
+#define BCM53442_A0_REV_ID 1
+#define BCM53442_B0_REV_ID 0x11
+#define BCM53443_DEVICE_ID 0x8443
+#define BCM53443_A0_REV_ID 1
+#define BCM53443_B0_REV_ID 0x11
+
+#define BCM53434_DEVICE_ID 0x8434
+#define BCM53434_A0_REV_ID 1
+#define BCM53434_B0_REV_ID 0x11
+
+#define BCM56560_DEVICE_ID 0xb560
+#define BCM56560_A0_REV_ID 1
+#define BCM56560_B0_REV_ID 0x11
+
+#define BCM56561_DEVICE_ID 0xb561
+#define BCM56561_A0_REV_ID 1
+#define BCM56561_B0_REV_ID 0x11
+
+#define BCM56562_DEVICE_ID 0xb562
+#define BCM56562_A0_REV_ID 1
+#define BCM56562_B0_REV_ID 0x11
+
+#define BCM56670_DEVICE_ID 0xb670
+#define BCM56670_A0_REV_ID 1
+#define BCM56670_B0_REV_ID 0x11
+
+#define BCM56671_DEVICE_ID 0xb671
+#define BCM56671_A0_REV_ID 1
+#define BCM56671_B0_REV_ID 0x11
+
+#define BCM56672_DEVICE_ID 0xb672
+#define BCM56672_A0_REV_ID 1
+#define BCM56672_B0_REV_ID 0x11
+
+#define BCM56675_DEVICE_ID 0xb675
+#define BCM56675_A0_REV_ID 1
+#define BCM56675_B0_REV_ID 0x11
+
+
+#define BCM56565_DEVICE_ID 0xb565
+#define BCM56565_A0_REV_ID 1
+#define BCM56565_B0_REV_ID 0x11
+
+#define BCM56566_DEVICE_ID 0xb566
+#define BCM56566_A0_REV_ID 1
+#define BCM56566_B0_REV_ID 0x11
+
+#define BCM56567_DEVICE_ID 0xb567
+#define BCM56567_A0_REV_ID 1
+#define BCM56567_B0_REV_ID 0x11
+
+#define BCM56568_DEVICE_ID 0xb568
+#define BCM56568_A0_REV_ID 1
+#define BCM56568_B0_REV_ID 0x11
+
+#define BCM56760_DEVICE_ID 0xb760
+#define BCM56760_A0_REV_ID 1
+#define BCM56760_A1_REV_ID 2
+#define BCM56760_B0_REV_ID 0x11
+
+#define BCM56761_DEVICE_ID 0xb761
+#define BCM56761_A0_REV_ID 1
+#define BCM56761_B0_REV_ID 0x11
+
+#define BCM56761_DEVICE_ID 0xb761
+#define BCM56761_A0_REV_ID 1
+#define BCM56761_A1_REV_ID 2
+#define BCM56761_B0_REV_ID 0x11
+#define BCM56761_B1_REV_ID 0x12
+
+#define BCM56762_DEVICE_ID 0xb762
+#define BCM56762_A0_REV_ID 1
+#define BCM56762_B0_REV_ID 0x11
+
+#define BCM56764_DEVICE_ID 0xb764
+#define BCM56764_A0_REV_ID 1
+#define BCM56764_B0_REV_ID 0x11
+
+#define BCM56765_DEVICE_ID 0xb765
+#define BCM56765_A0_REV_ID 1
+#define BCM56765_B0_REV_ID 0x11
+
+#define BCM56766_DEVICE_ID 0xb766
+#define BCM56766_A0_REV_ID 1
+#define BCM56766_B0_REV_ID 0x11
+
+#define BCM56768_DEVICE_ID 0xb768
+#define BCM56768_A0_REV_ID 1
+#define BCM56768_B0_REV_ID 0x11
+
+#define BCM56068_DEVICE_ID 0xb068
+#define BCM56068_A0_REV_ID 1
+#define BCM56068_B0_REV_ID 0x11
+
+#define BCM56068_DEVICE_ID 0xb068
+#define BCM56068_A0_REV_ID 1
+#define BCM56068_B0_REV_ID 0x11
+#define BCM56068_B1_REV_ID 0x12
+
+#define BCM56069_DEVICE_ID 0xb069
+#define BCM56069_A0_REV_ID 1
+#define BCM56069_B0_REV_ID 0x11
+
+#define BCM56170_DEVICE_ID 0xb170
+#define BCM56170_A0_REV_ID 1
+#define BCM56170_B0_REV_ID 0x11
+#define BCM56172_DEVICE_ID 0xb172
+#define BCM56172_A0_REV_ID 1
+#define BCM56172_B0_REV_ID 0x11
+#define BCM56174_DEVICE_ID 0xb174
+#define BCM56174_A0_REV_ID 1
+#define BCM56174_B0_REV_ID 0x11
+
+#define BCM53570_DEVICE_ID 0x8570
+#define BCM53570_A0_REV_ID 1
+#define BCM53570_B0_REV_ID 0x11
+#define BCM53575_DEVICE_ID 0x8575
+#define BCM53575_A0_REV_ID 1
+#define BCM53575_B0_REV_ID 0x11
+
+
+#define BCM56965_DEVICE_ID 0xb965
+#define BCM56965_A0_REV_ID 1
+#define BCM56965_A1_REV_ID 2
+#define BCM56969_DEVICE_ID 0xb969
+#define BCM56969_A0_REV_ID 1
+#define BCM56966_DEVICE_ID 0xb966
+#define BCM56966_A0_REV_ID 1
+#define BCM56967_DEVICE_ID 0xb967
+#define BCM56967_A0_REV_ID 1
+
+#define BCM56970_DEVICE_ID 0xb970
+#define BCM56970_A0_REV_ID 1
+#define BCM56970_B0_REV_ID 0x11
+#define BCM56971_DEVICE_ID 0xb971
+#define BCM56971_A0_REV_ID 1
+#define BCM56971_B0_REV_ID 0x11
+#define BCM56972_DEVICE_ID 0xb972
+#define BCM56972_A0_REV_ID 1
+#define BCM56972_B0_REV_ID 0x11
+#define BCM56974_DEVICE_ID 0xb974
+#define BCM56974_A0_REV_ID 1
+#define BCM56974_B0_REV_ID 0x11
+#define BCM56975_DEVICE_ID 0xb975
+#define BCM56975_A0_REV_ID 1
+#define BCM56975_B0_REV_ID 0x11
+
+#define BCM56870_DEVICE_ID 0xb870
+#define BCM56870_A0_REV_ID 1
+#define BCM56873_DEVICE_ID 0xb873
+#define BCM56873_A0_REV_ID 1
+
+#define BCM56370_DEVICE_ID 0xb370
+#define BCM56370_A0_REV_ID 1
+#define BCM56370_A1_REV_ID 0x02
+
+#define BCM56371_DEVICE_ID 0xb371
+#define BCM56371_A0_REV_ID 1
+#define BCM56371_A1_REV_ID 0x02
+
+#define BCM56372_DEVICE_ID 0xb372
+#define BCM56372_A0_REV_ID 1
+#define BCM56372_A1_REV_ID 0x02
+
+#define BCM56374_DEVICE_ID 0xb374
+#define BCM56374_A0_REV_ID 1
+#define BCM56374_A1_REV_ID 0x02
+
+#define BCM56375_DEVICE_ID 0xb375
+#define BCM56375_A0_REV_ID 1
+#define BCM56375_A1_REV_ID 0x02
+
+#define BCM56376_DEVICE_ID 0xb376
+#define BCM56376_A0_REV_ID 1
+#define BCM56376_A1_REV_ID 0x02
+
+#define BCM56377_DEVICE_ID 0xb377
+#define BCM56377_A0_REV_ID 1
+#define BCM56377_A1_REV_ID 0x02
+
+#define BCM56577_DEVICE_ID 0xb577
+#define BCM56577_A0_REV_ID 1
+#define BCM56577_A1_REV_ID 0x02
+
+#define BCM56578_DEVICE_ID 0xb578
+#define BCM56578_A0_REV_ID 1
+#define BCM56578_A1_REV_ID 0x02
+
+#define BCM56579_DEVICE_ID 0xb579
+#define BCM56579_A0_REV_ID 1
+#define BCM56579_A1_REV_ID 0x02
+
+#define BCM56770_DEVICE_ID 0xb770
+#define BCM56770_A0_REV_ID 1
+
+#define BCM56771_DEVICE_ID 0xb771
+#define BCM56771_A0_REV_ID 1
+
+#define BCM53540_DEVICE_ID 0x8540
+#define BCM53540_A0_REV_ID 1
+#define BCM53547_DEVICE_ID 0x8547
+#define BCM53547_A0_REV_ID 1
+#define BCM53548_DEVICE_ID 0x8548
+#define BCM53548_A0_REV_ID 1
+#define BCM53549_DEVICE_ID 0x8549
+#define BCM53549_A0_REV_ID 1
+
+#define BCM5665_DEVICE_ID 0x5665
+#define BCM5665_A0_REV_ID 1
+#define BCM5665_B0_REV_ID 0x11
+
+
+#define BCM5655_DEVICE_ID 0x5655
+#define BCM5655_A0_REV_ID 1
+#define BCM5655_B0_REV_ID 0x11
+
+
+#define BCM5650_DEVICE_ID 0x5650
+#define BCM5650_A0_REV_ID 1
+#define BCM5650_B0_REV_ID 0x11
+#define BCM5650_C0_REV_ID 0x21
+
+#define BROADCOM_PHYID_HIGH 0x0040
+
+#define GEDI_DEVICE_ID 0xa100
+#define GEDI_REV_ID 0x0001
+#define ARAD_DEVICE_ID 0x8650
+#define ARAD_A0_REV_ID 0x0000
+#define ARAD_B0_REV_ID 0x0011
+#define ARAD_B1_REV_ID 0x0012
+#define BCM88650_DEVICE_ID ARAD_DEVICE_ID
+#define BCM88650_A0_REV_ID ARAD_A0_REV_ID
+#define BCM88650_B0_REV_ID ARAD_B0_REV_ID
+#define BCM88650_B1_REV_ID ARAD_B1_REV_ID
+#define BCM88750_DEVICE_ID 0x8750
+#define BCM88750_A0_REV_ID 0x0000
+#define BCM88750_B0_REV_ID 0x0011
+#define BCM88753_DEVICE_ID 0x8753
+#define BCM88753_A0_REV_ID 0x0000
+#define BCM88753_B0_REV_ID 0x0011
+#define BCM88754_DEVICE_ID 0x8754
+#define BCM88754_A0_REV_ID 0x0000
+#define BCM88754_ORIGINAL_VENDOR_ID 0x16FC
+#define BCM88754_ORIGINAL_DEVICE_ID 0x020F
+#define BCM88754_A0_ORIGINAL_REV_ID 0x0001
+#define BCM88755_DEVICE_ID 0x8755
+#define BCM88755_B0_REV_ID 0x0011
+#define BCM88770_DEVICE_ID 0x8770
+#define BCM88770_A1_REV_ID 0x0002
+#define BCM88773_DEVICE_ID 0x8773
+#define BCM88773_A1_REV_ID 0x0002
+#define BCM88774_DEVICE_ID 0x8774
+#define BCM88774_A1_REV_ID 0x0002
+#define BCM88775_DEVICE_ID 0x8775
+#define BCM88775_A1_REV_ID 0x0002
+#define BCM88776_DEVICE_ID 0x8776
+#define BCM88776_A1_REV_ID 0x0002
+#define BCM88777_DEVICE_ID 0x8777
+#define BCM88777_A1_REV_ID 0x0002
+#define BCM88950_DEVICE_ID 0x8950
+#define BCM88950_A0_REV_ID 0x0001
+#define BCM88950_A1_REV_ID 0x0002
+#define BCM88953_DEVICE_ID 0x8953
+#define BCM88953_A1_REV_ID 0x0002
+#define BCM88954_DEVICE_ID 0x8954
+#define BCM88954_A1_REV_ID 0x0002
+#define BCM88955_DEVICE_ID 0x8955
+#define BCM88955_A1_REV_ID 0x0002
+#define BCM88956_DEVICE_ID 0x8956
+#define BCM88956_A1_REV_ID 0x0002
+#define DNXC_A0_REV_ID 0x0001
+#define DNXC_A1_REV_ID 0x0002
+#define DNXC_B0_REV_ID 0x0011
+#define DNXC_B1_REV_ID 0x0012
+#define BCM88790_DEVICE_ID 0x8790
+#define BCM88790_A0_REV_ID DNXC_A0_REV_ID
+#define BCM88790_B0_REV_ID DNXC_B0_REV_ID
+#define BCM88791_DEVICE_ID 0x8791
+#define BCM88792_DEVICE_ID 0x8792
+#define BCM88793_DEVICE_ID 0x8793
+#define BCM88794_DEVICE_ID 0x8794
+#define BCM88795_DEVICE_ID 0x8795
+#define BCM88796_DEVICE_ID 0x8796
+#define BCM88797_DEVICE_ID 0x8797
+#define BCM88798_DEVICE_ID 0x8798
+#define BCM88799_DEVICE_ID 0x8799
+#define BCM8879A_DEVICE_ID 0x879A
+#define BCM8879B_DEVICE_ID 0x879B
+#define BCM8879C_DEVICE_ID 0x879C
+#define BCM8879D_DEVICE_ID 0x879D
+#define BCM8879E_DEVICE_ID 0x879E
+#define BCM8879F_DEVICE_ID 0x879F
+#define BCM_DNXF_DEVID_MASK 0xFFF0
+#define ARADPLUS_DEVICE_ID 0x8660
+#define ARADPLUS_A0_REV_ID 0x0001
+#define BCM88660_DEVICE_ID ARADPLUS_DEVICE_ID
+#define BCM88660_A0_REV_ID ARADPLUS_A0_REV_ID
+#define JERICHO_DEVICE_ID 0x8675
+#define JERICHO_A0_REV_ID 0x0001
+#define JERICHO_B0_REV_ID 0x0011
+#define JERICHO_A1_REV_ID 0x0002
+#define BCM88670_DEVICE_ID 0x8670
+#define BCM88670_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88670_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88671_DEVICE_ID 0x8671
+#define BCM88671_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88671_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88671M_DEVICE_ID 0x867A
+#define BCM88671M_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88671M_A1_REV_ID JERICHO_A1_REV_ID
+
+#define BCM88670_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88671_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88671M_B0_REV_ID JERICHO_B0_REV_ID
+
+#define BCM88672_DEVICE_ID 0x8672
+#define BCM88672_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88672_A1_REV_ID JERICHO_A1_REV_ID
+
+#define BCM88672_B0_REV_ID JERICHO_B0_REV_ID
+
+#define BCM88673_DEVICE_ID 0x8673
+#define BCM88673_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88673_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88674_DEVICE_ID 0x8674
+#define BCM88674_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88674_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88675_DEVICE_ID JERICHO_DEVICE_ID
+#define BCM88675_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88675_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88675M_DEVICE_ID 0x867B
+#define BCM88675M_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88675M_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88676_DEVICE_ID 0x8676
+#define BCM88676_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88676_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88676M_DEVICE_ID 0x867C
+#define BCM88676M_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88676M_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88677_DEVICE_ID 0x8677
+#define BCM88677_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88677_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88678_DEVICE_ID 0x8678
+#define BCM88678_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88678_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88679_DEVICE_ID 0x8679
+#define BCM88679_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88679_A1_REV_ID JERICHO_A1_REV_ID
+
+#define BCM88673_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88674_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88675_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88675M_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88676_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88676M_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88677_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88678_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88679_B0_REV_ID JERICHO_B0_REV_ID
+#define QMX_DEVICE_ID 0x8375
+#define QMX_A0_REV_ID 0x0001
+#define QMX_B0_REV_ID 0x0011
+#define QMX_A1_REV_ID 0x0002
+#define BCM88370_DEVICE_ID 0x8370
+#define BCM88370_A0_REV_ID QMX_A0_REV_ID
+#define BCM88370_A1_REV_ID QMX_A1_REV_ID
+#define BCM88371_DEVICE_ID 0x8371
+#define BCM88371_A0_REV_ID QMX_A0_REV_ID
+#define BCM88371_A1_REV_ID QMX_A1_REV_ID
+#define BCM88371M_DEVICE_ID 0x837A
+#define BCM88371M_A0_REV_ID QMX_A0_REV_ID
+#define BCM88371M_A1_REV_ID QMX_A1_REV_ID
+#define BCM88375_DEVICE_ID QMX_DEVICE_ID
+#define BCM88375_A0_REV_ID QMX_A0_REV_ID
+#define BCM88375_A1_REV_ID QMX_A1_REV_ID
+#define BCM88376_DEVICE_ID 0x8376
+#define BCM88376_A0_REV_ID QMX_A0_REV_ID
+#define BCM88376_A1_REV_ID QMX_A1_REV_ID
+#define BCM88376M_DEVICE_ID 0x837B
+#define BCM88376M_A0_REV_ID QMX_A0_REV_ID
+#define BCM88376M_A1_REV_ID QMX_A1_REV_ID
+#define BCM88377_DEVICE_ID 0x8377
+#define BCM88377_A0_REV_ID QMX_A0_REV_ID
+#define BCM88377_A1_REV_ID QMX_A1_REV_ID
+#define BCM88378_DEVICE_ID 0x8378
+#define BCM88378_A0_REV_ID QMX_A0_REV_ID
+#define BCM88378_A1_REV_ID QMX_A1_REV_ID
+#define BCM88379_DEVICE_ID 0x8379
+#define BCM88379_A0_REV_ID QMX_A0_REV_ID
+#define BCM88379_A1_REV_ID QMX_A1_REV_ID
+
+#define BCM88370_B0_REV_ID QMX_B0_REV_ID
+#define BCM88371_B0_REV_ID QMX_B0_REV_ID
+#define BCM88371M_B0_REV_ID QMX_B0_REV_ID
+#define BCM88375_B0_REV_ID QMX_B0_REV_ID
+#define BCM88376_B0_REV_ID QMX_B0_REV_ID
+#define BCM88376M_B0_REV_ID QMX_B0_REV_ID
+#define BCM88377_B0_REV_ID QMX_B0_REV_ID
+#define BCM88378_B0_REV_ID QMX_B0_REV_ID
+#define BCM88379_B0_REV_ID QMX_B0_REV_ID
+
+
+#define JERICHO_PLUS_DEVICE_ID 0x8680
+#define JERICHO_PLUS_A0_REV_ID 0x0001
+#define BCM88680_DEVICE_ID JERICHO_PLUS_DEVICE_ID
+#define BCM88680_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+#define BCM88680_A1_REV_ID 0x0002
+
+
+#define BCM88681_DEVICE_ID 0x8681
+#define BCM88681_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+
+#define BCM88682_DEVICE_ID 0x8682
+#define BCM88682_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+
+#define BCM88683_DEVICE_ID 0x8683
+#define BCM88683_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+
+#define BCM88684_DEVICE_ID 0x8684
+#define BCM88684_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+
+#define BCM88685_DEVICE_ID 0x8685
+#define BCM88685_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+
+#define BCM88380_DEVICE_ID 0x8380
+#define BCM88380_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+#define BCM88381_DEVICE_ID 0x8381
+#define BCM88381_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+
+#define JERICHO_2_DEVICE_ID 0x8690
+#define JERICHO_2_A0_REV_ID DNXC_A0_REV_ID
+#define JERICHO_2_B0_REV_ID DNXC_B0_REV_ID
+#define JERICHO_2_B1_REV_ID DNXC_B1_REV_ID
+#define BCM88690_DEVICE_ID JERICHO_2_DEVICE_ID
+#define BCM88690_A0_REV_ID JERICHO_2_A0_REV_ID
+#define BCM88690_B0_REV_ID JERICHO_2_B0_REV_ID
+#define BCM88690_B1_REV_ID JERICHO_2_B1_REV_ID
+#define BCM88691_DEVICE_ID 0x8691
+#define BCM88692_DEVICE_ID 0x8692
+#define BCM88693_DEVICE_ID 0x8693
+#define BCM88694_DEVICE_ID 0x8694
+#define BCM88695_DEVICE_ID 0x8695
+#define BCM88696_DEVICE_ID 0x8696
+#define BCM88697_DEVICE_ID 0x8697
+#define BCM88698_DEVICE_ID 0x8698
+#define BCM88699_DEVICE_ID 0x8699
+#define BCM8869A_DEVICE_ID 0x869A
+#define BCM8869B_DEVICE_ID 0x869B
+#define BCM8869C_DEVICE_ID 0x869C
+#define BCM8869D_DEVICE_ID 0x869D
+#define BCM8869E_DEVICE_ID 0x869E
+#define BCM8869F_DEVICE_ID 0x869F
+#define BCM_JR2_DEVID_MASK 0xFFF0
+
+#define J2C_DEVICE_ID 0x8800
+#define J2C_A0_REV_ID DNXC_A0_REV_ID
+#define BCM88800_DEVICE_ID J2C_DEVICE_ID
+#define BCM88800_A0_REV_ID J2C_A0_REV_ID
+
+#define QAX_DEVICE_ID 0x8470
+#define QAX_A0_REV_ID 0x0001
+#define QAX_B0_REV_ID 0x0011
+#define BCM88470_DEVICE_ID QAX_DEVICE_ID
+#define BCM88470_B0_REV_ID QAX_B0_REV_ID
+#define BCM88470P_DEVICE_ID 0x847C
+#define BCM88471_DEVICE_ID 0x8471
+#define BCM88473_DEVICE_ID 0x8473
+#define BCM88474_DEVICE_ID 0x8474
+#define BCM88474H_DEVICE_ID 0x847B
+#define BCM88476_DEVICE_ID 0x8476
+#define BCM88477_DEVICE_ID 0x8477
+
+
+
+
+#define BCM88470_A0_REV_ID QAX_A0_REV_ID
+
+#define QUX_DEVICE_ID 0x8270
+#define QUX_A0_REV_ID 0x0001
+#define QUX_A1_REV_ID 0x0002
+#define QUX_B0_REV_ID 0x0011
+#define BCM88270_DEVICE_ID QUX_DEVICE_ID
+#define BCM88270_A0_REV_ID QUX_A0_REV_ID
+#define BCM88270_A1_REV_ID QUX_A1_REV_ID
+#define BCM88272_DEVICE_ID 0x8272
+#define BCM88273_DEVICE_ID 0x8273
+#define BCM88274_DEVICE_ID 0x8274
+#define BCM88278_DEVICE_ID 0x8278
+#define BCM88279_DEVICE_ID 0x8279
+
+#define FLAIR_DEVICE_ID 0xF000
+#define FLAIR_A0_REV_ID 0x0001
+#define BCM8206_DEVICE_ID FLAIR_DEVICE_ID
+#define BCM8206_A0_REV_ID FLAIR_A0_REV_ID
+
+#define ARDON_DEVICE_ID 0x8202
+#define ARDON_A0_REV_ID 0x0000
+#define BCM88202_DEVICE_ID ARDON_DEVICE_ID
+#define BCM88202_A0_REV_ID ARDON_A0_REV_ID
+#define ARDON_A1_REV_ID 0x0001
+#define BCM88202_A1_REV_ID ARDON_A1_REV_ID
+#define ARDON_A2_REV_ID 0x0002
+#define BCM88202_A2_REV_ID ARDON_A2_REV_ID
+#define BCM2801PM_DEVICE_ID 0x2801
+#define BCM2801PM_A0_REV_ID 0x0000
+#define BCM88360_DEVICE_ID 0x8360
+#define BCM88360_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88361_DEVICE_ID 0x8361
+#define BCM88361_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88363_DEVICE_ID 0x8363
+#define BCM88363_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88460_DEVICE_ID 0x8460
+#define BCM88460_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88461_DEVICE_ID 0x8461
+#define BCM88461_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88560_DEVICE_ID 0x8560
+#define BCM88560_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88561_DEVICE_ID 0x8561
+#define BCM88561_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88562_DEVICE_ID 0x8562
+#define BCM88562_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88661_DEVICE_ID 0x8661
+#define BCM88661_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88664_DEVICE_ID 0x8664
+#define BCM88664_A0_REV_ID ARADPLUS_A0_REV_ID
+
+
+#define BCM88350_DEVICE_ID 0x8350
+#define BCM88350_B1_REV_ID ARAD_B1_REV_ID
+#define BCM88351_DEVICE_ID 0x8351
+#define BCM88351_B1_REV_ID ARAD_B1_REV_ID
+#define BCM88450_DEVICE_ID 0x8450
+#define BCM88450_B1_REV_ID ARAD_B1_REV_ID
+#define BCM88451_DEVICE_ID 0x8451
+#define BCM88451_B1_REV_ID ARAD_B1_REV_ID
+#define BCM88550_DEVICE_ID 0x8550
+#define BCM88550_B1_REV_ID ARAD_B0_REV_ID
+#define BCM88551_DEVICE_ID 0x8551
+#define BCM88551_B1_REV_ID ARAD_B1_REV_ID
+#define BCM88552_DEVICE_ID 0x8552
+#define BCM88552_B1_REV_ID ARAD_B1_REV_ID
+#define BCM88651_DEVICE_ID 0x8651
+#define BCM88651_B1_REV_ID ARAD_B1_REV_ID
+#define BCM88654_DEVICE_ID 0x8654
+#define BCM88654_B1_REV_ID ARAD_B1_REV_ID
+
+#define BCM88772_DEVICE_ID 0x8772
+#define BCM88952_DEVICE_ID 0x8952
+#define BCM88772_A1_REV_ID 0x0002
+#define BCM88952_A0_REV_ID 0x0001
+#define BCM88952_A1_REV_ID 0x0002
+
+#define BCM88752_DEVICE_ID 0x8752
+#define BCM88752_A0_REV_ID 0x0000
+#define BCM88752_B0_REV_ID 0x0011
+
+
+#define BCM83207_DEVICE_ID 0x3207
+#define BCM83208_DEVICE_ID 0x3208
+#define BCM83207_A0_REV_ID 0x0001
+#define BCM83208_A0_REV_ID 1
+
+#define PCP_PCI_VENDOR_ID 0x1172
+#define PCP_PCI_DEVICE_ID 0x4
+
+#define ACP_PCI_VENDOR_ID 0x10ee
+#define ACP_PCI_DEVICE_ID 0x7011
+#define ACP_PCI_REV_ID 0x0001
+
+#define PLX9056_DEVICE_ID 0x9056
+
+#endif
+
diff --git a/sdk-6.5.16/src/gpl-modules/make/Make.config b/sdk-6.5.16/src/gpl-modules/make/Make.config
@@ -0,0 +1,358 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Make.config,v 1.3 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+
+ifneq ($(strip $(override-target)),)
+override TARGET=$(override-target)
+endif
+
+export TARGET
+
+#
+# Set up the target name, and the target base variables.
+#
+# target = The full name of the target such as vxworks-bmw
+# targetbase = 1st part of target (e.g. vxworks)
+# targetplat = 2nd part of target (e.g. x86) if any; otherwise same as 1st
+#
+target = ${TARGET}
+targetsplt = $(subst -, , ${target}) # change hyphens to spaces
+targetbase = $(word 1,${targetsplt})
+targetplat = $(subst ${targetbase}-,,${TARGET})
+
+#
+# Common configuration for all platforms
+# (Additional platform-dependent configurations are in Makefile.xxx)
+#
+
+#
+# THIS FILE SHOULD NOT BE MODIFIED LOCALLY, to override, add a file
+# $SDK/make/Make.local that sets your local settings, and/or provide
+# a path to your settings using the MAKE_LOCAL variable. If
+# either of these files exists, their values will override those in this makefile.
+#
+ifdef MAKE_LOCAL
+-include ${MAKE_LOCAL}
+endif
+
+-include ${SDK}/make/Make.local
+
+ifdef ALL_CHIPS
+ ESW_CHIPS = 1
+endif # ALL_CHIPS
+
+#
+# By default, turn off the "changing directory" message.
+#
+MAKEFLAGS += --no-print-directory
+
+#
+# Use gmake by default
+#
+
+include ${SDK}/make/Make.tools
+include ${SDK}/make/Makefile.${target}
+
+# use QUIET=1 to control printing of compilation lines
+ifdef QUIET
+Q:=@
+else
+Q:=
+endif
+
+#
+# Suffix to add to the "target" files to allow local builds with different
+# flags. Set "target_suffix" to XXX to cause the build to put built objects
+# in ${target}${target_suffix}. This allows things like building a debug
+# version with different flags. This may also be set in another Makefile.
+#
+
+#target_suffix :=
+
+#
+# Optional suffix to add to the build directory and output binary files
+# to allow multiple builds to co-exist for various reasons.
+#
+#chip_suffix := -$(shell echo $(CHIP) | tr A-Z a-z)
+
+#
+# Combined suffixes
+#
+all_suffix = ${chip_suffix}${target_suffix}
+
+#
+# Default location to place binaries and make depend files for building
+# purposes.
+#
+ifeq "$(HOSTTYPE)" "Windows2000PC"
+BLDROOTWITHDRIVE = ${SDK}/build/${target}${all_suffix}${bldroot_suffix}
+BLDROOT = ${SDK_NO_DRIVE_NAME}/build/${target}${all_suffix}${bldroot_suffix}
+else # ifeq "$(HOSTTYPE)" "Windows2000PC"
+
+ifndef SDKBUILD
+SDKBUILD :=build
+endif
+
+BLDROOT = ${SDK}/${SDKBUILD}/$(if ${BLDCONFIG},${BLDCONFIG}/)${target}${all_suffix}${bldroot_suffix}
+
+endif # ifeq "$(HOSTTYPE)" "Windows2000PC"
+
+# This is needed because we cannot include Make.vxworks before Make.config
+ifndef DEST_DIR_SUFFIX
+export DEST_DIR_SUFFIX :=$(subst $(realpath $(SDK))/systems,,$(realpath $(CURDIR)/$(dir ($(firstword $(MAKEFILE_LIST))))))
+ifeq ($(MAKELEVEL),0)
+endif
+endif
+
+ifeq ($(DEST_DIR),)
+export DEST_DIR :=${SDK}/${SDKBUILD}$(if ${BLDCONFIG},/${BLDCONFIG})$(DEST_DIR_SUFFIX)
+endif
+
+ifdef LOCALDIR
+BLDDIR = ${BLDROOT}/${LOCALDIR}
+ifeq "$(HOSTTYPE)" "Windows2000PC"
+BLDDIRWITHDRIVE = ${BLDROOTWITHDRIVE}/${LOCALDIR}
+endif
+else # ifdef LOCALDIR
+BLDDIR = ${BLDROOT}
+ifeq "$(HOSTTYPE)" "Windows2000PC"
+BLDDIRWITHDRIVE = ${BLDROOTWITHDRIVE}
+endif
+endif # ifdef LOCALDIR
+
+LIBDIR = ${BLDROOT}
+
+#
+# Export directory, where build objects used by the outside world are
+# placed (exported header files, libs, bins)
+#
+EXPDIR = ${SDK}/export/${target}${all_suffix}
+
+#
+# Standard include paths
+#
+INCDIR = ${SDK}/include
+
+#
+# Compilation Flags
+#
+# Flags may be added to (see below)
+#
+
+INCFLAGS = -I${INCDIR} -I${SDK}/systems
+
+CFLAGS += ${INCFLAGS}
+CXXFLAGS += ${INCFLAGS}
+CPPFLAGS += ${INCFLAGS}
+
+#
+# Debug #ifdef control
+#
+# Compiling out #ifdef DEBUG code saves about 1.3% on executable size.
+# It is recommended to leave debug enabled when developing applications.
+#
+ifndef DEBUG_IFDEFS
+DEBUG_IFDEFS=TRUE
+endif
+
+ifeq ($(DEBUG_IFDEFS),TRUE)
+CFLAGS += -DBROADCOM_DEBUG
+CXXFLAGS += -DBROADCOM_DEBUG
+CPPFLAGS += -DBROADCOM_DEBUG
+endif
+
+#
+# Debug symbol information control
+#
+ifndef DEBUG_SYMBOLS
+DEBUG_SYMBOLS=TRUE
+endif
+
+ifeq ($(DEBUG_SYMBOLS),TRUE)
+CFLAGS += -g
+CXXFLAGS += -g
+CPPFLAGS += -g
+endif
+
+#
+# If DEBUG_CFLAGS is set, add its contents to CFLAGS.
+# May be useful for setting on the command line or adding to Make.local.
+# Example: gmake DEBUG_CFLAGS=-save-temps system.c
+#
+
+ifneq ($(DEBUG_CFLAGS),)
+CFLAGS += $(DEBUG_CFLAGS)
+CXXFLAGS += $(DEBUG_CFLAGS)
+CPPFLAGS += $(DEBUG_CFLAGS)
+endif
+
+#
+# Optimization level
+#
+# Set DEBUG_OPTIMIZE to TRUE (default) to use a normal optimization
+# determined by OPTFLAGS_DEFAULT in the platform Makefile.
+# Set DEBUG_OPTIMIZE to FALSE to use no optimization,
+# strongly recommended when using any debugger.
+# Set DEBUG_OPTIMIZE to any other option string to request specific
+# optimization flags (for example -O2).
+#
+ifndef DEBUG_OPTIMIZE
+DEBUG_OPTIMIZE=TRUE
+endif
+
+ifeq ($(DEBUG_OPTIMIZE),TRUE)
+OPTFLAGS += $(OPTFLAGS_DEFAULT)
+else
+ifneq ($(DEBUG_OPTIMIZE),FALSE)
+OPTFLAGS += $(DEBUG_OPTIMIZE)
+endif
+endif
+
+#
+# Debug assertion control.
+#
+# Compiling out assert() saves about 1.1% on executable size,
+# however doing so is VERY MUCH discouraged.
+#
+ifndef DEBUG_ASSERTS
+DEBUG_ASSERTS=TRUE
+endif
+
+ifeq ($(DEBUG_ASSERTS),FALSE)
+CFLAGS += -DNDEBUG
+CXXFLAGS += -DNDEBUG
+CPPFLAGS += -DNDEBUG
+endif
+
+#
+# GCC pedantic mode.
+#
+ifeq ($(DEBUG_PEDANTIC),TRUE)
+CFGFLAGS += -D__PEDANTIC__
+CFLAGS += --pedantic
+CXXFLAGS += --pedantic
+endif
+
+#
+# In each directory, build a list of local sources, objects, and headers
+#
+LSRCS = $(wildcard *.c *.cpp *.s *.cc *.C)
+LOBJS = $(addsuffix .o, $(basename ${LSRCS}))
+BOBJS = $(addprefix ${BLDDIR}/,${LOBJS})
+LHDRS = $(wildcard *.h *.H)
+LDOTIS = $(wildcard *.i)
+
+
+#
+# Rule to create object file (build) directory
+#
+
+.PHONY: all install clean distclean
+
+.PRECIOUS: ${BLDDIR}/.tree
+
+%/.tree:
+ @$(ECHO) 'Creating build directory $(dir $@)'
+ @$(MKDIR) $(dir $@)
+ @$(ECHO) "Build Directory for ${LOCALDIR} Created" > $@
+
+# Rule allowing build through CPP only, creates .E file from .c file.
+
+%.E: %.c
+ $Q${CC} -E ${CFLAGS} $< | sed -e '/^ *$$/d' -e p -e d > $@
+
+# Rule allowing build through source only, creates .s file from .c file.
+
+%.s: %.c
+ $Q${CC} -S ${CFLAGS} $<
+
+#
+# Default Build rules for .c --> .o, leaving the binary in BLDDIR/X.o,
+# even if file not built from directory of source.
+#
+ifeq ($(FAST),1)
+${BLDDIR}/%.o: %.c
+else
+ifdef GENERATE_C_FILES
+${BLDDIR}/%.o: %.c
+else
+${BLDDIR}/%.o: %.c
+endif
+endif
+ifdef QUIET
+ @${ECHO} Compiling ${LOCALDIR}/$<
+endif
+ifdef LOCAL_D_FILE
+ $Q$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -o $@ -c $< --write-user-dependencies
+ -@/bin/cp $*.d $(BLDDIR)/$*.d
+ -@/bin/rm -f $*.d
+else
+ $Q$(CC) -MD -MF $(BLDDIR)/$*.d $(CFLAGS) $(EXTRA_CFLAGS) -o $@ -c $<
+endif
+ @/bin/cp $(BLDDIR)/$*.d $(BLDDIR)/$*.tmp;\
+ /bin/sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
+ -e '/^$$/ d' -e 's/$$/ :/' \
+ < $(BLDDIR)/$*.d >> $(BLDDIR)/$*.tmp; \
+ /bin/sed \
+ -e 's| \([0-9a-zA-Z]\)| '$(SDK)/$(LOCALDIR)'\/\1|g' \
+ -e 's|^\([0-9a-zA-Z]\)|'$(SDK)/$(LOCALDIR)'/\1|g' \
+ -e 's| \(\.\.\/\)| '$(SDK)/$(LOCALDIR)'\/\1|g' \
+ -e 's|'$(SDK)'|'$$\{SDK\}'|g' \
+ -e 's/\w*\/\.\.\/*//g' \
+ -e 's/\w*\/\.\.\/*//g' \
+ -e 's/\w*\/\.\.\/*//g' \
+ < $(BLDDIR)/$*.tmp > $(BLDDIR)/$*.P; \
+ /bin/rm -f $(BLDDIR)/$*.d $(BLDDIR)/$*.tmp
+
+${BLDDIR}/%.o: %.s
+ifdef QUIET
+ @${ECHO} Assembling ${LOCALDIR}/$<
+endif
+ $Q${CC} ${CFLAGS} ${EXTRA_CFLAGS} -c $< -o $@
+
+${BLDDIR}/%.o: %.cpp
+ifdef QUIET
+ @${ECHO} Compiling ${LOCALDIR}/$<
+endif
+ $Q${CXX} -c ${CXXFLAGS} -c $< -o $@
+
+${BLDDIR}/%.o: %.cc ${BLDDIR}/.tree
+ifdef QUIET
+ @${ECHO} Compiling ${LOCALDIR}/$<
+endif
+ $Q${CXX} -c ${CXXFLAGS} -c $< -o $@
+
+#
+# Cause "make foo.o" in any subdirectory to put the object in the build
+# directory instead of the local directory.
+#
+%.o: ${BLDDIR}/%.o
+ @
+
+#
+# List of directories where built objects live.
+# (we are not making the export directories for now)
+#
+#DIRS = ${BLDDIR} ${EXPDIR}/lib ${EXPDIR}/bin ${EXPDIR}/include
+DIRS = ${BLDDIR}
+
+ifeq (C_COMPILER,$(MAKECMDGOALS))
+C_COMPILER:
+ @echo $(CC)
+endif
diff --git a/sdk-6.5.16/src/gpl-modules/make/Make.depend b/sdk-6.5.16/src/gpl-modules/make/Make.depend
@@ -0,0 +1,108 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Make.depend,v 1.14 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+# Default rule to build dependencies. This builds a x.d file for each
+# x.c file that describes the dependencies. We then conditionally include
+# the generated .d files.
+#
+
+#
+# If making 'clean', do not include any .d files. If they are included,
+# gmake intrinsically tries to remake them all.
+#
+ifeq (,$(findstring clean,$(MAKECMDGOALS)))
+
+ZFS :=$(wildcard *.zf)
+ZFC := $(ZFS:.zf=.c)
+
+ifdef GENERATE_C_FILES
+ifndef GEN_INCS
+$(error "GEN_INCS was not defined")
+endif
+
+ZF_GEN = ${SDK}/tools/zFrameCodeGen.pl
+
+# 1=.zf
+define ZFS_RULE
+$(1:.zf=Console.c) : $(1:.zf=.c)
+ @echo updated $$@ from $$?
+
+$(1:.zf=.c) : $(1) $(ZF_GEN)
+ @$(PERL) $(ZF_GEN) -s -z . -p . -g $1 -t c
+ @echo generated ${LOCALDIR}/$$@ from $(1)
+ @mv $$(*F).cx $$@
+ @if [ -e $$(*F)Console.cx ] ; then \
+ mv $$(*F)Console.cx $$(*F)Console.c; \
+ echo Created $$(*F)Console.c ;\
+ fi
+ @if [ -e $$(*F)Console.hx ] ; then \
+ echo Created $(GEN_INCS)/$$(*F)Console.hx ;\
+ mv $$(*F)Console.hx $(GEN_INCS)/ ; \
+ fi
+ @mv $$(*F).hx $(GEN_INCS)/
+endef
+
+$(foreach zf,$(ZFS),$(eval $(call ZFS_RULE,$(zf))))
+
+${BLDDIR}/%.P : ${BLDDIR}/.tree %.c
+
+.PHONY: GENFILES
+GENFILES: $(ZFC)
+
+$(BOBJS) : $(ZFC)
+
+else
+#
+# Attempt to build the depend files. If it fails, the depend file is
+# removed so that it is not included in later builds.
+#
+${BLDDIR}/%.P : %.c ${BLDDIR}/.tree
+ @$(ECHO) Dependencies for ${LOCALDIR}/$<
+
+${BLDDIR}/%.P : %.cc ${BLDDIR}/.tree
+ @$(ECHO) Dependencies for ${LOCALDIR}/$<
+
+endif
+
+#
+# If there are C or C++ files in this directory, include the
+# depend files for them.
+#
+
+ifeq ($(findstring _COMPILER,$(MAKECMDGOALS))$(findstring variable,$(MAKECMDGOALS)),)
+ifneq ($(strip ${LSRCS}),)
+ifneq (,$(findstring .o,$(MAKECMDGOALS)))
+-include $(addprefix ${BLDDIR}/,$(MAKECMDGOALS:.o=.P)) $(addprefix ${BLDDIR}/,$(MAKECMDGOALS:.o=.sig))
+else
+-include $(addprefix ${BLDDIR}/,$(addsuffix .P,$(basename $(LSRCS)))) $(addprefix ${BLDDIR}/,$(addsuffix .sig,$(basename $(LSRCS))))
+endif
+endif
+endif
+
+endif # !CLEANING
+
+clean_d::
+ifdef QUIET
+ @$(ECHO) Cleaning dependencies for ${LOCALDIR}
+endif
+ifdef GENERATE_C_FILES
+ $Q$(RM) $(ZFC:%=$(SDK)/$(LOCALDIR)/%) $(ZFC:%.c=$(SDK)/$(LOCALDIR)/%Console.c)
+endif
+
+clean:: clean_d
diff --git a/sdk-6.5.16/src/gpl-modules/make/Make.kernlib b/sdk-6.5.16/src/gpl-modules/make/Make.kernlib
@@ -0,0 +1,69 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Make.kernlib,v 1.7 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+# Make rules/targets for handling libraries
+
+.SECONDARY:: ${BOBJS}
+
+targetlibsoname = ${lib}.so.${SHAREDLIBVER}
+targetlibrealname = ${targetlibsoname}
+targetlibso = ${LIBDIR}/${targetlibrealname}
+
+ifeq ($(TOOLS),Borland)
+
+LIBSUFFIX=lib
+
+${LIBDIR}/%.lib: ${BORLAND_BOBJS}
+ $(RM) $@
+ $(FOREACH) -subdir "$(LIBDIR)" \
+ "tlib $@ $(foreach obj, $(BORLAND_LOBJS), +-$(obj))"
+
+else # !Borland
+
+LIBSUFFIX=a
+
+${LIBDIR}/%.a: ${BOBJS}
+ifdef QUIET
+ @$(ECHO) Building library $(notdir $@)
+endif
+ $Q$(RM) $@
+ $Q$(AR) ${ARFLAGS} $@ $(sort ${BOBJS})
+ifeq ($(LINUX_MAKE_SHARED_LIB),1)
+ifeq ($(targetbase),unix)
+ $(CC) -shared -Wl,-soname,${targetlibsoname} -o ${targetlibso} ${BOBJS} -lc
+endif
+endif # LINUX_MAKE_SHARED_LIB #
+endif # !Borland
+
+targetlib = ${LIBDIR}/${lib}.${LIBSUFFIX}
+
+all:: ${BLDDIR}/.tree ${targetlib}
+
+install:: all
+
+clean::
+ifdef QUIET
+ @$(ECHO) Cleaning objects for ${LOCALDIR} and ${lib}
+endif
+ $Q$(RM) ${BOBJS}
+ $Q$(RM) ${targetlib}
+ $Q$(RM) ${targetlibso}
+
+distclean:: clean
+
diff --git a/sdk-6.5.16/src/gpl-modules/make/Make.lib b/sdk-6.5.16/src/gpl-modules/make/Make.lib
@@ -0,0 +1,80 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Make.lib,v 1.14 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+# Make rules/targets for handling libraries
+
+.SECONDARY:: ${BOBJS}
+
+BOBJS_FAST = ${BOBJS}
+BOBJS_MAKE_CMD =
+
+ifeq ($(FAST),1)
+ ifneq ($(strip $(BOBJS)),)
+ BOBJS_FAST =
+ BOBJS_ARGS = -j9
+ BOBJS_MAKE_CMD = pwd && make LSRUN=$(SDK)/tools/lsrun.pl $(BOBJS_ARGS) ${BOBJS}
+ endif
+endif
+
+ifeq ($(TOOLS),Borland)
+
+LIBSUFFIX=lib
+
+${LIBDIR}/%.lib: ${BORLAND_BOBJS}
+ $(RM) $@
+ $(FOREACH) -subdir "$(LIBDIR)" \
+ "tlib $@ $(foreach obj, $(BORLAND_LOBJS), +-$(obj))"
+
+else # !Borland
+
+ifeq ($(LINUX_MAKE_SHARED_LIB),1)
+LIBSUFFIX=so.${SHAREDLIBVER}
+else
+LIBSUFFIX=a
+endif
+
+targetlib = ${LIBDIR}/${lib}.${LIBSUFFIX}
+
+all:: ${BLDDIR}/.tree ${targetlib}
+
+${LIBDIR}/%.${LIBSUFFIX}: ${BOBJS_FAST}
+ $(BOBJS_MAKE_CMD)
+ifdef QUIET
+ @$(ECHO) Building library $(notdir $@)
+endif
+ $Q$(RM) $@
+ifeq ($(LINUX_MAKE_SHARED_LIB),1)
+ $(CC) -shared -Wl,-soname,${lib}.${LIBSUFFIX}${EXTRA_LIB_LDFLAGS} -o ${targetlib} ${BOBJS} -lc
+else
+ ${Q}cd $(dir $(word 1,${BOBJS}));$(AR) ${ARFLAGS} $@ $(sort $(notdir ${BOBJS}))
+endif
+
+endif # !Borland
+
+
+install:: all
+
+clean::
+ifdef QUIET
+ @$(ECHO) Cleaning objects for ${LOCALDIR} and ${lib}
+endif
+ $Q$(RM) ${BOBJS}
+ $Q$(RM) ${targetlib}
+
+distclean:: clean
diff --git a/sdk-6.5.16/src/gpl-modules/make/Make.linux b/sdk-6.5.16/src/gpl-modules/make/Make.linux
@@ -0,0 +1,97 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+#
+# $Id: Make.linux,v 1.18 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+# Common make targets for Linux user and kernel builds included by top
+# level Linux makefiles
+#
+# Variables referenced:
+#
+# LINUX_MAKE_FLAGS
+# Additional flags passed to Make
+#
+# LINUX_MAKE_USER
+# Defined: user build
+# Undefined: kernel build
+#
+# LINUX_MAKE_DIR
+# Common makefile location, if it is not ../common
+#
+#
+
+export DEST_DIR_SUFFIX :=$(subst $(realpath $(SDK))/systems,,$(realpath $(CURDIR)/$(dir ($(firstword $(MAKEFILE_LIST))))))
+
+ifeq (,$(kernel_version))
+kernel_version=2_4
+endif
+
+ifndef LINUX_MAKE_SHARED_LIB
+LINUX_MAKE_SHARED_LIB=0
+endif
+
+ifeq (,$(SHAREDLIBVER))
+SHAREDLIBVER=1
+endif
+
+ifndef LINUX_MAKE_DIR
+ifdef LINUX_MAKE_USER
+LINUX_MAKE_DIR := $(SDK)/systems/linux/user/common
+else
+LINUX_MAKE_DIR := $(SDK)/systems/linux/kernel/common
+endif
+endif
+
+ifdef LINUX_MAKE_USER
+ CMD = $(LINUX_MAKE_FLAGS) -C $(LINUX_MAKE_DIR) \
+ platform=$(platform) bldroot_suffix=/$(platform) kernel_version=$(kernel_version) \
+ LINUX_MAKE_SHARED_LIB=$(LINUX_MAKE_SHARED_LIB) SHAREDLIBVER=$(SHAREDLIBVER)
+else
+ export LINUX_MAKE_KERNEL := 1
+ CMD = $(LINUX_MAKE_FLAGS) -C $(LINUX_MAKE_DIR) \
+ platform=$(platform) kernel_version=$(kernel_version)
+endif
+
+ifneq (,$(MIPS_TOOLS_DIR))
+ CMD += MIPS_TOOLS_DIR=$(MIPS_TOOLS_DIR)
+endif
+
+ifneq (,$(MIPS_CROSS_COMPILE))
+ CMD += MIPS_CROSS_COMPILE=$(MIPS_CROSS_COMPILE)
+endif
+
+ifneq (,$(LINUX_INCLUDE))
+ CMD += LINUX_INCLUDE=$(LINUX_INCLUDE)
+endif
+
+# gmake does not understand $(CMD) to be a submake
+# options are to +$(CMD) or $(MAKE) $(CMD)
+# trying the latter
+build:
+ $(MAKE) $(CMD)
+
+DELIVER clean C_COMPILER CXX_COMPILER variable mod bcm user:
+ $(MAKE) $(CMD) $@
+
+clean_d: clean
+
+distclean:
+ $(MAKE) $(CMD) $@
+
+.PHONY: build clean distclean clean_d DELIVER variable mod bcm user
+
diff --git a/sdk-6.5.16/src/gpl-modules/make/Make.subdirs b/sdk-6.5.16/src/gpl-modules/make/Make.subdirs
@@ -0,0 +1,44 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Make.subdirs,v 1.8 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+# Make rules/targets for handling subdirectories
+
+.PHONY: ${subdirs}
+
+all:: ${subdirs}
+ifdef QUIET
+ @$(ECHO) Subdirectory build for ${subdirs}
+endif
+
+${subdirs}::
+ $Q$(MAKE) -C $@ kernel_version=$(kernel_version) LINUX_MAKE_SHARED_LIB=${LINUX_MAKE_SHARED_LIB} SHAREDLIBVER=${SHAREDLIBVER}
+
+ifeq "$(HOSTTYPE)" "Windows2000PC"
+clean clean_d install distclean::
+ifdef QUIET
+ @$(ECHO) Subdirectory $@ for ${subdirs}
+endif
+ $Q$(FOREACH) "$(subdirs)" "${MAKE} -C ## $@"
+else
+clean clean_d install distclean::
+ifdef QUIET
+ @$(ECHO) Subdirectory $@ for ${subdirs}
+endif
+ @(for name in $(subdirs); do $(MAKE) -C $$name $@; done)
+endif
diff --git a/sdk-6.5.16/src/gpl-modules/make/Make.tools b/sdk-6.5.16/src/gpl-modules/make/Make.tools
@@ -0,0 +1,38 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Make.tools,v 1.2 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+SYSNAME := $(shell uname -s)
+HCC ?=/usr/bin/gcc
+SED = /bin/sed
+COMPRESS = /usr/bin/compress
+PERL = /usr/bin/perl
+LN = /bin/ln
+HOSTTYPE= i386-linux
+
+#
+# Platform Independent
+#
+MKTOOL = $(PERL) ${SDK}/tools/mktool.pl
+RM = $(MKTOOL) -rm
+MKDIR = $(MKTOOL) -md
+FOREACH = $(MKTOOL) -foreach
+CP = $(MKTOOL) -cp
+MAKEDEP = $(MKTOOL) -dep
+ECHO = $(MKTOOL) -echo
+MKBEEP = ${MKTOOL} -beep
diff --git a/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-iproc b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-iproc
@@ -0,0 +1,94 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-iproc Exp $
+# $Copyright: (c) 2007 Broadcom Corp.
+# All Rights Reserved.$
+# Makefile for iproc-CMICd
+
+# User must select one platform from below.By default ARM_LINUX is selected. .
+ifeq (,$(BUILD_PLATFORM))
+BUILD_PLATFORM=ARM_LINUX
+endif
+
+# TOOLCHAIN_BASE_DIR Toolchain base directory for iPROC-CMICd devices
+# TARGET_ARCHITECTURE Compiler for target architecture
+# KERNDIR Kernel directory for iPROC-CMICd devices
+ifeq (BE,$(ENDIAN_MODE))
+TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk50-be/XLDK32
+TARGET_ARCHITECTURE:=armeb-broadcom-linux-uclibcgnueabi
+KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux
+else
+TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk50/XLDK32
+TARGET_ARCHITECTURE:= arm-broadcom-linux-uclibcgnueabi
+KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux
+endif
+
+ifeq (,$(CROSS_COMPILE))
+CROSS_COMPILE:= $(TARGET_ARCHITECTURE)-
+endif
+
+# arm9tools
+TOOLCHAIN_BIN_DIR=$(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/bin
+override PATH:=$(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/$(TARGET_ARCHITECTURE)/bin:$(TOOLCHAIN_BIN_DIR):$(PATH)
+LD_LIBRARY_PATH=$(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/lib
+
+export TOOLCHAIN_BIN_DIR LD_LIBRARY_PATH
+
+# Default Linux include directory
+ifeq (,$(LINUX_INCLUDE))
+LINUX_INCLUDE := $(KERNDIR)/include
+endif
+
+ifeq (BE,$(ENDIAN_MODE))
+CFGFLAGS += -DSYS_BE_PIO=1 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=1
+ENDIAN = BE_HOST=1
+else
+CFGFLAGS += -DSYS_BE_PIO=0 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=0
+ENDIAN = LE_HOST=1
+endif
+
+CFLAGS += -fno-aggressive-loop-optimizations
+
+CFGFLAGS += -D$(ENDIAN) -DIPROC_CMICD
+CFGFLAGS += -DBCM_PLATFORM_STRING=\"IPROC_CMICD\"
+
+ARCH = arm
+KBUILD_VERBOSE = 1
+
+export ARCH KBUILD_VERBOSE
+
+comma = ,
+basetarget = $(basename $(notdir $@))
+modname = $(basetarget)
+
+# Extra variables.
+EXTRA_CFLAGS = -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+
+name-fix = $(subst $(comma),_,$(subst -,_,$1))
+basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
+modname_flags = $(if $(filter 1,$(words $(modname))),\
+ -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+
+KFLAG_INCLD ?= $(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/lib/gcc/$(TARGET_ARCHITECTURE)/4.9.4/include
+
+ifeq (,$(KFLAGS))
+KFLAGS := -D__LINUX_ARM_ARCH__=7 -D__KERNEL__ -nostdinc -isystem $(KFLAG_INCLD) -I$(LINUX_INCLUDE) -include $(LINUX_INCLUDE)/generated/autoconf.h -I$(KERNDIR)/arch/arm/include -I$(KERNDIR)/arch/arm/include/generated -I$(KERNDIR)/arch/arm/mach-iproc/include -Wall -Wstrict-prototypes -Wno-trigraphs -Os -fno-strict-aliasing -fno-common -marm -mabi=aapcs-linux -fno-pic -pipe -msoft-float -ffreestanding -march=armv7-a -mfpu=vfp -mfloat-abi=softfp -fomit-frame-pointer -g -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign -mlong-calls
+KFLAGS += -I$(LINUX_INCLUDE)/uapi -I$(LINUX_INCLUDE)/generated/uapi -I$(KERNDIR)/arch/arm/include/uapi -I$(KERNDIR)/arch/arm/include/generated/uapi
+endif
+
+ifneq ($(targetplat),user)
+include ${SDK}/make/Makefile.linux-kernel-3_6
+endif
diff --git a/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-iproc-3_14 b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-iproc-3_14
@@ -0,0 +1,103 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-iproc-3_6,v 1.1 Broadcom SDK $
+# $Copyright: (c) 2007 Broadcom Corp.
+# All Rights Reserved.$
+# Makefile for iproc-CMICd
+
+# User must select one platform from below.By default ARM_LINUX is selected. .
+ifeq (,$(BUILD_PLATFORM))
+BUILD_PLATFORM=ARM_LINUX
+endif
+
+# TOOLCHAIN_BASE_DIR Toolchain base directory for iPROC-CMICd devices
+# TARGET_ARCHITECTURE Compiler for target architecture
+# KERNDIR Kernel directory for iPROC-CMICd devices
+ifeq (BE,$(ENDIAN_MODE))
+TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk37-be/buildroot-2013.11-gcc48-opt-broadcom
+TARGET_ARCHITECTURE:=armeb-buildroot-linux-gnueabi
+KERNDIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk37-be/XLDK/kernel/linux
+else
+TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk37/XLDK
+TARGET_ARCHITECTURE:= arm-broadcom-linux-uclibcgnueabi
+KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux
+endif
+
+
+ifeq (,$(CROSS_COMPILE))
+CROSS_COMPILE:= $(TARGET_ARCHITECTURE)-
+endif
+
+# arm9tools
+ifeq (BE,$(ENDIAN_MODE))
+TOOLCHAIN_BIN_DIR=$(TOOLCHAIN_BASE_DIR)/host/usr/bin
+override PATH:=$(TOOLCHAIN_BASE_DIR)/host/usr/$(TARGET_ARCHITECTURE)/bin:$(TOOLCHAIN_BIN_DIR):$(PATH)
+LD_LIBRARY_PATH=$(TOOLCHAIN_BASE_DIR)/host/usr/lib
+else
+TOOLCHAIN_BIN_DIR=$(TOOLCHAIN_BASE_DIR)/buildroot/usr/bin
+override PATH:=$(TOOLCHAIN_BASE_DIR)/buildroot/usr/$(TARGET_ARCHITECTURE)/bin:$(TOOLCHAIN_BIN_DIR):$(PATH)
+LD_LIBRARY_PATH=$(TOOLCHAIN_BASE_DIR)/buildroot/usr/lib
+endif
+
+export TOOLCHAIN_BIN_DIR LD_LIBRARY_PATH
+
+# Default Linux include directory
+ifeq (,$(LINUX_INCLUDE))
+LINUX_INCLUDE := $(KERNDIR)/include
+endif
+
+ifeq (BE,$(ENDIAN_MODE))
+CFGFLAGS += -DSYS_BE_PIO=1 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=1
+ENDIAN = BE_HOST=1
+else
+CFGFLAGS += -DSYS_BE_PIO=0 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=0
+ENDIAN = LE_HOST=1
+endif
+
+CFGFLAGS += -D$(ENDIAN) -DIPROC_CMICD
+CFGFLAGS += -DBCM_PLATFORM_STRING=\"IPROC_CMICD\"
+
+ARCH = arm
+KBUILD_VERBOSE = 1
+
+export ARCH KBUILD_VERBOSE
+
+comma = ,
+basetarget = $(basename $(notdir $@))
+modname = $(basetarget)
+
+# Extra variables.
+EXTRA_CFLAGS = -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+
+name-fix = $(subst $(comma),_,$(subst -,_,$1))
+basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
+modname_flags = $(if $(filter 1,$(words $(modname))),\
+ -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+
+ifeq (BE,$(ENDIAN_MODE))
+KFLAG_INCLD ?= $(TOOLCHAIN_BASE_DIR)/host/usr/lib/gcc/$(TARGET_ARCHITECTURE)/4.8.2/include
+else
+KFLAG_INCLD ?= $(TOOLCHAIN_BASE_DIR)/buildroot/usr/lib/gcc/$(TARGET_ARCHITECTURE)/4.7.2/include
+endif
+
+ifeq (,$(KFLAGS))
+KFLAGS := -D__LINUX_ARM_ARCH__=7 -D__KERNEL__ -nostdinc -isystem $(KFLAG_INCLD) -I$(LINUX_INCLUDE) -include $(LINUX_INCLUDE)/generated/autoconf.h -I$(KERNDIR)/arch/arm/include -I$(KERNDIR)/arch/arm/include/generated -I$(KERNDIR)/arch/arm/mach-northstar/include -I$(KERNDIR)/arch/arm/plat-iproc/include -Wall -Wstrict-prototypes -Wno-trigraphs -Os -fno-strict-aliasing -fno-common -marm -mabi=aapcs-linux -fno-pic -pipe -msoft-float -ffreestanding -march=armv7-a -mfpu=vfp -mfloat-abi=softfp -fomit-frame-pointer -g -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign -mlong-calls
+KFLAGS += -I$(LINUX_INCLUDE)/uapi -I$(LINUX_INCLUDE)/generated/uapi -I$(KERNDIR)/arch/arm/include/uapi -I$(KERNDIR)/arch/arm/include/generated/uapi
+endif
+
+ifneq ($(targetplat),user)
+include ${SDK}/make/Makefile.linux-kernel-3_6
+endif
diff --git a/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel
@@ -0,0 +1,112 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-kernel,v 1.27 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+# Configuration Flags
+
+# Filter out features that cannot or should not be supported in kernel mode
+_FEATURE_EXCLUDE_LIST += EDITLINE TCL OOB_RCPU CINT APIMODE DUNE_UI C_UNIT
+FEATURE_EXCLUDE_LIST = $(sort $(_FEATURE_EXCLUDE_LIST))
+# Tools
+
+CC = $(CROSS_COMPILE)gcc
+CXX = $(CROSS_COMPILE)g++
+LD = $(CROSS_COMPILE)ld
+AR = $(CROSS_COMPILE)ar
+ARFLAGS = -rc
+STRIP = $(CROSS_COMPILE)strip
+RANLIB = $(CROSS_COMPILE)ranlib
+OBJCOPY = $(CROSS_COMPILE)objcopy
+
+# Handle differences between gcc 2.x and gcc 3.x
+gcc-tune-flag = $(shell if ${CC} -dumpspecs | grep mcpu >/dev/null; then echo cpu; else echo tune; fi)
+
+# Configuration Variables
+
+# OSType Defines: This defines the type of RTOS or microkernel which you
+# are compiling the SAL (and its associated driver) for. New platforms
+# can be created by porting the routines (system.c) to your platform and
+# adding the define in this Makefile.
+
+OSTYPE = LINUX
+
+#
+# ORIGIN is used to Optionally select different CFLAGS. It is used to import
+# source from other vendors. If SOURCE=Broadcom, then the BCM_ flags are added
+# to those passed to the compiler. If SOURCE != Broadcom, BCM_ flags are NOT
+# added.
+#
+# Default specifies Broadcom
+#
+ifndef ORIGIN
+ ORIGIN = Broadcom
+endif
+
+#
+# STD_{C|CPP|CXX}FLAGS - Standard flags used by ALL compilations
+# BCM_{C|CPP|CXX}FLAGS - Flags used for Broadcom source files
+# OPT_{C|CPP|CXX}FLAGS - Defined in local make files BEFORE inclusion of
+# this Makefile, to define local "Extra" flags.
+#
+
+CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \
+ -I$(SDK)/systems/bde/linux/include \
+ -I$(LINUX_INCLUDE)
+
+CFGFLAGS += -DNO_FILEIO -DNO_CTRL_C -DNO_MEMTUNE
+
+CFGFLAGS += -D$(OSTYPE)
+
+# No user sal for the linux kernel
+# NO_SAL_APPL=1
+
+STD_CFLAGS = $(KFLAGS) $(CFGFLAGS)
+
+
+STD_CPPFLAGS = ${STD_CFLAGS}
+STD_CXXFLAGS = ${STD_CFLAGS}
+
+BCM_CFLAGS = -Wall -Werror
+BCM_CPPFLAGS = ${BCM_CFLAGS}
+BCM_CXXFLAGS = ${BCM_CFLAGS}
+
+ifeq (${ORIGIN}, Broadcom)
+ CFLAGS += ${STD_CFLAGS} ${BCM_CFLAGS} ${OPT_CFLAGS}
+ CPPFLAGS += ${STD_CPPFLAGS} ${BCM_CPPFLAGS} ${OPT_CPPFLAGS}
+ CXXFLAGS += ${STD_CXXFLAGS} ${BCM_CXXFLAGS} ${OPT_CXXFLAGS}
+else
+ CFLAGS += ${STD_CFLAGS} ${OPT_CFLAGS}
+ CPPFLAGS += ${STD_CPPFLAGS} ${OPT_CPPFLAGS}
+ CXXFLAGS += ${STD_CXXFLAGS} ${OPT_CXXFLAGS}
+endif
+
+#
+# Ignore pedantic flag for kernel modules
+#
+ifdef DEBUG_PEDANTIC
+DEBUG_PEDANTIC = FALSE
+endif
+
+#
+# DEPEND is used as a command to generate the list of dependencies.
+# The format of the output must be
+# "file.o : file.c a/b/c.h d/e/f.h ...",
+# if it is on multiple lines, each line must end in a backslash.
+# The output MUST be on standard out.
+#
+DEPEND = ${CC} -M $(CFLAGS) $<
diff --git a/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel-2_6 b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel-2_6
@@ -0,0 +1,148 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-kernel-2_6,v 1.40 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+# Configuration Flags
+
+# Filter out features that cannot or should not be supported in kernel mode
+
+_FEATURE_EXCLUDE_LIST += EDITLINE TCL OOB_RCPU CINT APIMODE DUNE_UI C_UNIT
+FEATURE_EXCLUDE_LIST = $(sort $(_FEATURE_EXCLUDE_LIST))
+
+# Tools
+
+# Conditionally Replaces DEFAULT var
+ifeq ($(origin CC),default)
+CC = $(LSRUN) $(CROSS_COMPILE)gcc
+endif
+
+ifeq ($(origin CXX),default)
+CXX = $(CROSS_COMPILE)g++
+endif
+
+ifeq ($(origin LD),default)
+LD = $(CROSS_COMPILE)ld
+endif
+
+ifeq ($(origin AR),default)
+AR = $(CROSS_COMPILE)ar
+endif
+
+ifeq ($(origin AS),default)
+AS = $(CROSS_COMPILE)as
+endif
+
+ifeq ($(origin ARFLAGS),default)
+ ARFLAGS = -rc
+endif
+
+STRIP = $(CROSS_COMPILE)strip
+RANLIB = $(CROSS_COMPILE)ranlib
+OBJCOPY = $(CROSS_COMPILE)objcopy
+NM = $(CROSS_COMPILE)nm
+
+# Handle differences between gcc 2.x and gcc 3.x
+gcc-tune-flag = $(shell if ${CC} -dumpspecs | grep mcpu >/dev/null; then echo cpu; else echo tune; fi)
+
+# Configuration Variables
+
+# OSType Defines: This defines the type of RTOS or microkernel which you
+# are compiling the SAL (and its associated driver) for. New platforms
+# can be created by porting the routines (system.c) to your platform and
+# adding the define in this Makefile.
+
+OSTYPE = LINUX
+
+#
+# ORIGIN is used to Optionally select different CFLAGS. It is used to import
+# source from other vendors. If SOURCE=Broadcom, then the BCM_ flags are added
+# to those passed to the compiler. If SOURCE != Broadcom, BCM_ flags are NOT
+# added.
+#
+# Default specifies Broadcom
+#
+ifndef ORIGIN
+ ORIGIN = Broadcom
+endif
+
+#
+# STD_{C|CPP|CXX}FLAGS - Standard flags used by ALL compilations
+# BCM_{C|CPP|CXX}FLAGS - Flags used for Broadcom source files
+# OPT_{C|CPP|CXX}FLAGS - Defined in local make files BEFORE inclusion of
+# this Makefile, to define local "Extra" flags.
+#
+
+ifdef IPROC_BUILD
+CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \
+ -I$(SDK)/systems/bde/linux/include \
+ -I$(LINUX_INCLUDE) \
+ -I$(KERNDIR)/arch/$(ARCH)
+else
+CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \
+ -I$(SDK)/systems/bde/linux/include \
+ -I$(LINUX_INCLUDE) \
+ -I$(LINUX_INCLUDE)/asm/gcc \
+ -I$(LINUX_INCLUDE)/asm/mach-generic \
+ -I$(KERNDIR)/arch/$(ARCH)
+endif
+
+CFGFLAGS += -DNO_FILEIO -DNO_CTRL_C -DNO_MEMTUNE
+
+CFGFLAGS += -D$(OSTYPE)
+
+# No user sal for the linux kernel
+# NO_SAL_APPL=1
+
+STD_CFLAGS = $(KFLAGS) $(CFGFLAGS)
+
+
+STD_CPPFLAGS = ${STD_CFLAGS}
+STD_CXXFLAGS = ${STD_CFLAGS}
+
+ifndef BCM_CFLAGS
+BCM_CFLAGS = -Wall -Werror
+endif
+
+BCM_CPPFLAGS = ${BCM_CFLAGS}
+BCM_CXXFLAGS = ${BCM_CFLAGS}
+
+ifeq (${ORIGIN}, Broadcom)
+ CFLAGS += ${STD_CFLAGS} ${BCM_CFLAGS} ${OPT_CFLAGS}
+ CPPFLAGS += ${STD_CPPFLAGS} ${BCM_CPPFLAGS} ${OPT_CPPFLAGS}
+ CXXFLAGS += ${STD_CXXFLAGS} ${BCM_CXXFLAGS} ${OPT_CXXFLAGS}
+else
+ CFLAGS += ${STD_CFLAGS} ${OPT_CFLAGS}
+ CPPFLAGS += ${STD_CPPFLAGS} ${OPT_CPPFLAGS}
+ CXXFLAGS += ${STD_CXXFLAGS} ${OPT_CXXFLAGS}
+endif
+
+#
+# Ignore pedantic flag for kernel modules
+#
+ifdef DEBUG_PEDANTIC
+DEBUG_PEDANTIC = FALSE
+endif
+
+#
+# DEPEND is used as a command to generate the list of dependencies.
+# The format of the output must be
+# "file.o : file.c a/b/c.h d/e/f.h ...",
+# if it is on multiple lines, each line must end in a backslash.
+# The output MUST be on standard out.
+#
+DEPEND = ${CC} -M $(CFLAGS) $<
diff --git a/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel-3_6 b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel-3_6
@@ -0,0 +1,148 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-kernel-3_6,v 1.2 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+# Configuration Flags
+
+# Filter out features that cannot or should not be supported in kernel mode
+
+_FEATURE_EXCLUDE_LIST += EDITLINE TCL OOB_RCPU CINT APIMODE DUNE_UI
+FEATURE_EXCLUDE_LIST = $(sort $(_FEATURE_EXCLUDE_LIST))
+
+# Tools
+
+# Conditionally Replaces DEFAULT var
+ifeq ($(origin CC),default)
+CC = $(LSRUN) $(CROSS_COMPILE)gcc
+endif
+
+ifeq ($(origin CXX),default)
+CXX = $(CROSS_COMPILE)g++
+endif
+
+ifeq ($(origin LD),default)
+LD = $(CROSS_COMPILE)ld
+endif
+
+ifeq ($(origin AR),default)
+AR = $(CROSS_COMPILE)ar
+endif
+
+ifeq ($(origin AS),default)
+AS = $(CROSS_COMPILE)as
+endif
+
+ifeq ($(origin ARFLAGS),default)
+ ARFLAGS = -rc
+endif
+
+STRIP = $(CROSS_COMPILE)strip
+RANLIB = $(CROSS_COMPILE)ranlib
+OBJCOPY = $(CROSS_COMPILE)objcopy
+NM = $(CROSS_COMPILE)nm
+
+# Handle differences between gcc 2.x and gcc 3.x
+gcc-tune-flag = $(shell if ${CC} -dumpspecs | grep mcpu >/dev/null; then echo cpu; else echo tune; fi)
+
+# Configuration Variables
+
+# OSType Defines: This defines the type of RTOS or microkernel which you
+# are compiling the SAL (and its associated driver) for. New platforms
+# can be created by porting the routines (system.c) to your platform and
+# adding the define in this Makefile.
+
+OSTYPE = LINUX
+
+#
+# ORIGIN is used to Optionally select different CFLAGS. It is used to import
+# source from other vendors. If SOURCE=Broadcom, then the BCM_ flags are added
+# to those passed to the compiler. If SOURCE != Broadcom, BCM_ flags are NOT
+# added.
+#
+# Default specifies Broadcom
+#
+ifndef ORIGIN
+ ORIGIN = Broadcom
+endif
+
+#
+# STD_{C|CPP|CXX}FLAGS - Standard flags used by ALL compilations
+# BCM_{C|CPP|CXX}FLAGS - Flags used for Broadcom source files
+# OPT_{C|CPP|CXX}FLAGS - Defined in local make files BEFORE inclusion of
+# this Makefile, to define local "Extra" flags.
+#
+
+ifdef IPROC_BUILD
+CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \
+ -I$(SDK)/systems/bde/linux/include \
+ -I$(LINUX_INCLUDE) \
+ -I$(KERNDIR)/arch/$(ARCH)
+else
+CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \
+ -I$(SDK)/systems/bde/linux/include \
+ -I$(LINUX_INCLUDE) \
+ -I$(LINUX_INCLUDE)/asm/gcc \
+ -I$(LINUX_INCLUDE)/asm/mach-generic \
+ -I$(KERNDIR)/arch/$(ARCH)
+endif
+
+CFGFLAGS += -DNO_FILEIO -DNO_CTRL_C -DNO_MEMTUNE
+
+CFGFLAGS += -D$(OSTYPE)
+
+# No user sal for the linux kernel
+# NO_SAL_APPL=1
+
+STD_CFLAGS = $(KFLAGS) $(CFGFLAGS)
+
+
+STD_CPPFLAGS = ${STD_CFLAGS}
+STD_CXXFLAGS = ${STD_CFLAGS}
+
+ifndef BCM_CFLAGS
+BCM_CFLAGS = -Wall -Werror
+endif
+
+BCM_CPPFLAGS = ${BCM_CFLAGS}
+BCM_CXXFLAGS = ${BCM_CFLAGS}
+
+ifeq (${ORIGIN}, Broadcom)
+ CFLAGS += ${STD_CFLAGS} ${BCM_CFLAGS} ${OPT_CFLAGS}
+ CPPFLAGS += ${STD_CPPFLAGS} ${BCM_CPPFLAGS} ${OPT_CPPFLAGS}
+ CXXFLAGS += ${STD_CXXFLAGS} ${BCM_CXXFLAGS} ${OPT_CXXFLAGS}
+else
+ CFLAGS += ${STD_CFLAGS} ${OPT_CFLAGS}
+ CPPFLAGS += ${STD_CPPFLAGS} ${OPT_CPPFLAGS}
+ CXXFLAGS += ${STD_CXXFLAGS} ${OPT_CXXFLAGS}
+endif
+
+#
+# Ignore pedantic flag for kernel modules
+#
+ifdef DEBUG_PEDANTIC
+DEBUG_PEDANTIC = FALSE
+endif
+
+#
+# DEPEND is used as a command to generate the list of dependencies.
+# The format of the output must be
+# "file.o : file.c a/b/c.h d/e/f.h ...",
+# if it is on multiple lines, each line must end in a backslash.
+# The output MUST be on standard out.
+#
+DEPEND = ${CC} -M $(CFLAGS) $<
diff --git a/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel-4_4 b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kernel-4_4
@@ -0,0 +1,157 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-kernel-2_6,v 1.40 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+# Configuration Flags
+
+# Filter out features that cannot or should not be supported in kernel mode
+
+_FEATURE_EXCLUDE_LIST += EDITLINE TCL OOB_RCPU CINT APIMODE DUNE_UI C_UNIT
+FEATURE_EXCLUDE_LIST = $(sort $(_FEATURE_EXCLUDE_LIST))
+
+# Tools
+
+# Conditionally Replaces DEFAULT var
+ifeq ($(origin CC),default)
+CC = $(LSRUN) $(CROSS_COMPILE)gcc
+endif
+
+ifeq ($(origin CXX),default)
+CXX = $(CROSS_COMPILE)g++
+endif
+
+ifeq ($(origin LD),default)
+LD = $(CROSS_COMPILE)ld
+endif
+
+ifeq ($(origin AR),default)
+AR = $(CROSS_COMPILE)ar
+endif
+
+ifeq ($(origin AS),default)
+AS = $(CROSS_COMPILE)as
+endif
+
+ifeq ($(origin ARFLAGS),default)
+ ARFLAGS = -rc
+endif
+
+STRIP = $(CROSS_COMPILE)strip
+RANLIB = $(CROSS_COMPILE)ranlib
+OBJCOPY = $(CROSS_COMPILE)objcopy
+NM = $(CROSS_COMPILE)nm
+
+# Handle differences between gcc 2.x and gcc 3.x
+gcc-tune-flag = $(shell if ${CC} -dumpspecs | grep mcpu >/dev/null; then echo cpu; else echo tune; fi)
+
+# Configuration Variables
+
+# OSType Defines: This defines the type of RTOS or microkernel which you
+# are compiling the SAL (and its associated driver) for. New platforms
+# can be created by porting the routines (system.c) to your platform and
+# adding the define in this Makefile.
+OSTYPE = LINUX
+
+#
+# ORIGIN is used to Optionally select different CFLAGS. It is used to import
+# source from other vendors. If SOURCE=Broadcom, then the BCM_ flags are added
+# to those passed to the compiler. If SOURCE != Broadcom, BCM_ flags are NOT
+# added.
+#
+# Default specifies Broadcom
+#
+ifndef ORIGIN
+ ORIGIN = Broadcom
+endif
+
+#
+# STD_{C|CPP|CXX}FLAGS - Standard flags used by ALL compilations
+# BCM_{C|CPP|CXX}FLAGS - Flags used for Broadcom source files
+# OPT_{C|CPP|CXX}FLAGS - Defined in local make files BEFORE inclusion of
+# this Makefile, to define local "Extra" flags.
+#
+ifdef IPROC_BUILD
+CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \
+ -I$(SDK)/systems/bde/linux/include \
+ -I$(LINUX_INCLUDE) \
+ -I$(LINUX_INCLUDE)/uapi \
+ -I$(LINUX_INCLUDE)/generated/uapi \
+ -I$(KERNDIR)/arch/$(ARCH) \
+ -I$(KERNDIR)/arch/$(ARCH)/include/uapi \
+ -I$(KERNDIR)/arch/$(ARCH)/include/generated \
+ -I$(KERNDIR)/arch/$(ARCH)/include/generated/uapi
+else
+CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \
+ -I$(SDK)/systems/bde/linux/include \
+ -I$(LINUX_INCLUDE) \
+ -I$(LINUX_INCLUDE)/asm/gcc \
+ -I$(LINUX_INCLUDE)/asm/mach-generic \
+ -I$(LINUX_INCLUDE)/uapi \
+ -I$(LINUX_INCLUDE)/generated/uapi \
+ -I$(KERNDIR)/arch/$(ARCH) \
+ -I$(KERNDIR)/arch/$(ARCH)/include/uapi \
+ -I$(KERNDIR)/arch/$(ARCH)/include/generated \
+ -I$(KERNDIR)/arch/$(ARCH)/include/generated/uapi
+endif
+
+CFGFLAGS += -DNO_FILEIO -DNO_CTRL_C -DNO_MEMTUNE
+
+CFGFLAGS += -D$(OSTYPE)
+
+# No user sal for the linux kernel
+# NO_SAL_APPL=1
+
+STD_CFLAGS = $(KFLAGS) $(CFGFLAGS)
+
+
+STD_CPPFLAGS = ${STD_CFLAGS}
+STD_CXXFLAGS = ${STD_CFLAGS}
+
+ifndef BCM_CFLAGS
+BCM_CFLAGS = -Wall -Werror
+endif
+
+BCM_CPPFLAGS = ${BCM_CFLAGS}
+BCM_CXXFLAGS = ${BCM_CFLAGS}
+
+ifeq (${ORIGIN}, Broadcom)
+ CFLAGS += ${STD_CFLAGS} ${BCM_CFLAGS} ${OPT_CFLAGS}
+ CPPFLAGS += ${STD_CPPFLAGS} ${BCM_CPPFLAGS} ${OPT_CPPFLAGS}
+ CXXFLAGS += ${STD_CXXFLAGS} ${BCM_CXXFLAGS} ${OPT_CXXFLAGS}
+else
+ CFLAGS += ${STD_CFLAGS} ${OPT_CFLAGS}
+ CPPFLAGS += ${STD_CPPFLAGS} ${OPT_CPPFLAGS}
+ CXXFLAGS += ${STD_CXXFLAGS} ${OPT_CXXFLAGS}
+endif
+
+#
+# Ignore pedantic flag for kernel modules
+#
+ifdef DEBUG_PEDANTIC
+DEBUG_PEDANTIC = FALSE
+endif
+
+#
+# DEPEND is used as a command to generate the list of dependencies.
+# The format of the output must be
+# "file.o : file.c a/b/c.h d/e/f.h ...",
+# if it is on multiple lines, each line must end in a backslash.
+# The output MUST be on standard out.
+#
+DEPEND = ${CC} -M $(CFLAGS) $<
+
diff --git a/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kmodule b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-kmodule
@@ -0,0 +1,81 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-kmodule-3_6,v 1.2 Broadcom SDK $
+# $Copyright: (c) 2006 Broadcom Corp.
+# All Rights Reserved.$
+
+# Due to the extensive use of driver libraries, the SDK usually builds
+# kernel modules from a precompiled object. To avoid various warnings
+# and conflicts, the pre-compiled object must be named differently
+# from the target module, and the object file itself should be
+# appended with "_shipped".
+
+# If a module exports any symbols, then the exporting source file must
+# be compiled within the kernel source tree for correct generation of
+# module symbol versions. The symbol source file should be passed to
+# this Makefile via the MODULE_SYM variable.
+
+MODULE := $(MOD_NAME).o
+KMODULE := $(MOD_NAME).ko
+PRE_COMPILED_OBJ := obj_$(MOD_NAME).o
+
+obj-m := $(MODULE)
+$(MOD_NAME)-y := $(MODULE_SYM) $(PRE_COMPILED_OBJ)
+
+
+ifeq (,$(CROSS_COMPILE))
+
+export CROSS_COMPILE
+
+endif
+
+SAVE_CFLAGS := ${CFLAGS}
+
+include $(SDK)/make/Make.config
+
+PWD := $(shell pwd)
+
+ifneq ($(ARCH),)
+# ELDK does not seem to `automatically' define ARCH where other gccs may
+A := ARCH=$(ARCH)
+export ARCH
+endif
+
+# Provide an option in case kernel was built in separate directory
+KERNBLDDIR ?= $(KERNDIR)
+
+# Standard SDK include path for building source files that export
+# kernel symbols.
+
+override EXTRA_CFLAGS = -I${SDK}/include -I${SDK}/systems/linux/kernel/modules/include -I${SDK}/systems/bde/linux/include
+
+# The precopiled object needs a dummy command file to avoid warnings
+# from the Kbuild scripts (modpost stage).
+# Kernels before 2.6.17 do not support external module symbols files,
+# so we create a dummy to prevent build failures.
+
+$(KMODULE):
+ rm -f *.o *.ko .*.cmd
+ rm -fr .tmp_versions
+ ln -s $(LIBDIR)/$(MODULE) $(PRE_COMPILED_OBJ)_shipped
+ if [ ! -f $(KERNBLDDIR)/NO_SUPRESS ]; then echo "# suppress warning" > .$(PRE_COMPILED_OBJ).cmd; fi
+ $(MAKE) -C $(KERNBLDDIR) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) modules
+ if [ ! -f Module.symvers ]; then echo "old kernel (pre-2.6.17)" > Module.symvers; fi
+ cp -f $(KMODULE) $(LIBDIR)
+ rm -f $(PRE_COMPILED_OBJ)_shipped
+
+EXTRA_CFLAGS = $(CFLAGS)
+CFLAGS := ${SAVE_CFLAGS}
diff --git a/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-x86-common-2_6 b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-x86-common-2_6
@@ -0,0 +1,44 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-x86-common-2_6,v 1.13 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+CFGFLAGS += -DSYS_BE_PIO=0 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=0
+ENDIAN = LE_HOST=1
+CFGFLAGS += -D$(ENDIAN)
+CFGFLAGS += -DBCM_PLATFORM_STRING=\"X86\"
+ifeq (,$(findstring -DSAL_BDE_DMA_MEM_DEFAULT,$(CFGFLAGS)))
+CFGFLAGS += -DSAL_BDE_DMA_MEM_DEFAULT=16
+endif
+
+# Extra variables.
+EXTRA_CFLAGS = -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+
+comma = ,
+basetarget = $(basename $(notdir $@))
+modname = $(basetarget)
+
+name-fix = $(subst $(comma),_,$(subst -,_,$1))
+basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
+modname_flags = $(if $(filter 1,$(words $(modname))),\
+-D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+
+ifneq ($(targetplat),user)
+# By default we exclude -Werror from x86 kernel builds
+BCM_CFLAGS = -Wall
+include ${SDK}/make/Makefile.linux-kernel-2_6
+endif
diff --git a/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-x86-generic-common-2_6 b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-x86-generic-common-2_6
@@ -0,0 +1,51 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-x86-generic-common-2_6,v 1.2 Broadcom SDK $
+# $Copyright: (c) 2008 Broadcom Corp.
+# All Rights Reserved.$
+
+# Default kernel source directory
+ifeq (,$(KERNDIR))
+KERNDIR := /lib/modules/$(shell uname -r)/build
+export KERNDIR
+endif
+
+# Default architecture
+ifeq (,$(ARCH))
+ARCH = $(shell uname -p)
+ifneq (x86_64,$(ARCH))
+ARCH = i386
+endif
+endif
+
+# Noisy kernel build
+KBUILD_VERBOSE = 1
+
+export ARCH KBUILD_VERBOSE KERNDIR
+
+# Default Linux include directory
+ifeq (,$(LINUX_INCLUDE))
+LINUX_INCLUDE := $(KERNDIR)/include
+endif
+
+# autoconf.h was moved in later kernels
+AUTOCONF = $(KERNDIR)/include/generated/autoconf.h
+ifeq (,$(shell ls $(AUTOCONF) 2>/dev/null))
+AUTOCONF = $(KERNDIR)/include/linux/autoconf.h
+endif
+
+# gcc system include path
+SYSINC = $(shell gcc -print-search-dirs | grep install | cut -c 10-)include
diff --git a/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-x86-smp_generic_64-2_6 b/sdk-6.5.16/src/gpl-modules/make/Makefile.linux-x86-smp_generic_64-2_6
@@ -0,0 +1,37 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-x86-smp_generic_64-2_6,v 1.5 Broadcom SDK $
+# $Copyright: (c) 2008 Broadcom Corp.
+# All Rights Reserved.$
+
+CFGFLAGS += -DLONGS_ARE_64BITS
+CFGFLAGS += -DPTRS_ARE_64BITS
+CFGFLAGS += -DPHYS_ADDRS_ARE_64BITS
+CFGFLAGS += -DSAL_SPL_LOCK_ON_IRQ
+
+include ${SDK}/make/Makefile.linux-x86-generic-common-2_6
+
+ifeq (,$(KFLAGS))
+KFLAGS := -nostdinc -isystem $(SYSINC) -I$(KERNDIR)/include -I$(KERNDIR)/arch/x86/include -include $(AUTOCONF) -D__KERNEL__ -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -fno-delete-null-pointer-checks -Os -m64 -mtune=generic -mno-red-zone -mcmodel=kernel -funit-at-a-time -maccumulate-outgoing-args -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -fno-stack-protector -fomit-frame-pointer -g -Wdeclaration-after-statement -Wno-pointer-sign
+endif
+
+
+LINUX_UAPI = $(LINUX_INCLUDE)/uapi
+ifneq (,$(shell ls $(LINUX_UAPI) 2>/dev/null))
+KFLAGS += -I$(LINUX_INCLUDE)/uapi -I$(LINUX_INCLUDE)/generated/uapi -I$(KERNDIR)/arch/x86/include/generated -I$(KERNDIR)/arch/x86/include/uapi -I$(KERNDIR)/arch/x86/include/generated/uapi
+endif
+
+include ${SDK}/make/Makefile.linux-x86-common-2_6
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/include/linux-bde.h b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/include/linux-bde.h
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/***********************************************************************
+ *
+ * $Id: linux-bde.h,v 1.24 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ * Linux Broadcom Device Enumerators
+ *
+ *
+ * There are two Linux BDEs:
+ *
+ * 1. Linux Kernel BDE
+ *
+ * This is a kernel module implementing a BDE
+ * for the driver running as part of the kernel.
+ *
+ * It manages the devices through the linux PCI interfaces,
+ * and manages a chunk of contiguous, boot-time allocated
+ * DMA memory. This is all that is needed if the BCM driver
+ * is run as part of the kernel (in another module).
+ *
+ * 2. Linux User BDE
+ *
+ * This is a kernel module and userland library which implement
+ * a complete BDE for applications running in userland.
+ *
+ * The kernel module relies upon the real kernel bde,
+ * and allows a user space application (through the user library)
+ * to talk directly to the devices. It also virtualized the device
+ * interrupts, so the entire driver can be run as a userspace
+ * application.
+ *
+ * While this causes a significant degradation in performance,
+ * because the system runs as a user application, the development
+ * and debugging process is about a gillion times easier.
+ * After the core logic is debugged, it can be retargeted using
+ * only the kernel bde and run in the kernel.
+ *
+ *
+ **********************************************************************/
+
+#ifndef __LINUX_BDE_H__
+#define __LINUX_BDE_H__
+
+#include <sal/types.h>
+
+#include <ibde.h>
+
+
+/*
+ * Device Major Numbers
+ *
+ * The kernel and user bdes need unique major numbers
+ * on systems that do not use devfs.
+ *
+ * They are defined here, along with the module names,
+ * to document them if you need to mknod them (or open) them,
+ * and to keep them unique.
+ *
+ */
+
+#include <linux/version.h>
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+/* Key stone and Raptor has 2.6.21 but don't have definition */
+#if defined(KEYSTONE) || defined(RAPTOR)
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21))
+ #ifdef PHYS_ADDRS_ARE_64BITS
+ typedef u64 phys_addr_t;
+ #else
+ typedef u32 phys_addr_t;
+ #endif
+ #endif
+#endif
+#endif
+
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))
+#define LINUX_BDE_DMA_DEVICE_SUPPORT
+#endif
+
+#define LINUX_KERNEL_BDE_NAME "linux-kernel-bde"
+#define LINUX_KERNEL_BDE_MAJOR 127
+
+#define LINUX_USER_BDE_NAME "linux-user-bde"
+#define LINUX_USER_BDE_MAJOR 126
+
+
+/* Max devices */
+/* 16 switch chips + 2 out-of-band Ethernet + 2 CPUs */
+#define LINUX_BDE_MAX_SWITCH_DEVICES 16
+#define LINUX_BDE_MAX_ETHER_DEVICES 2
+#define LINUX_BDE_MAX_CPU_DEVICES 2
+#define LINUX_BDE_MAX_DEVICES (LINUX_BDE_MAX_SWITCH_DEVICES + \
+ LINUX_BDE_MAX_ETHER_DEVICES + \
+ LINUX_BDE_MAX_CPU_DEVICES)
+
+/*
+ * PCI devices will be initialized by the Linux Kernel,
+ * regardless of architecture.
+ *
+ * You need only provide bus endian settings.
+ */
+
+typedef struct linux_bde_bus_s {
+ int be_pio;
+ int be_packet;
+ int be_other;
+} linux_bde_bus_t;
+
+
+
+/* Device state used for PCI hot swap case. */
+/*
+ * BDE_DEV_STATE_NORMAL : A device is probed normally. Or when the device
+ * resource has been updated after "CHANGED", the state will move back to
+ * "NORMAL".
+ */
+#define BDE_DEV_STATE_NORMAL (0)
+/*
+ * BDE_DEV_STATE_REMOVED : A previous probed device was removed.
+ * We will avoid any device access while the device is in this state.
+ * The state will be moved to "CHANGED" if the device is re-inserted
+ * and re-probed.
+ */
+#define BDE_DEV_STATE_REMOVED (1)
+/*
+ * BDE_DEV_STATE_CHANGED : The device is re-probed after having been removed.
+ * The resouces assigned to the device might have been changed after
+ * re-probing, so we need to re-initialize our resource database accordingly.
+ * The state will change to "NORMAL" when the resource have been updated.
+ */
+#define BDE_DEV_STATE_CHANGED (2)
+
+extern int linux_bde_create(linux_bde_bus_t* bus, ibde_t** bde);
+extern int linux_bde_destroy(ibde_t* bde);
+#ifdef BCM_INSTANCE_SUPPORT
+extern int linux_bde_instance_attach(unsigned int dev_mask,unsigned int dma_size);
+#endif
+
+#ifdef __KERNEL__
+
+/*
+ * Backdoors provided by the kernel bde
+ *
+ */
+
+/*
+ * The user bde needs to get cpu physical address for
+ * the userland code to mmap.
+ * And the second address is bus address, it is either
+ * identical to cpu physical address or another address
+ * (IOVA) translated by IOMMU.
+ */
+extern int lkbde_get_dma_info(phys_addr_t *cpu_pbase, phys_addr_t *dma_pbase, ssize_t *size);
+extern uint32 lkbde_get_dev_phys(int d);
+extern uint32 lkbde_get_dev_phys_hi(int d);
+
+/*
+ * Virtual device address needed by kernel space
+ * interrupt handler.
+ */
+extern void *lkbde_get_dev_virt(int d);
+
+/*
+ * The user bde needs to get some physical addresses for
+ * the userland code to mmap. The following functions
+ * supports multiple resources for a single device.
+ */
+extern int lkbde_get_dev_resource(int d, int rsrc, uint32 *flags,
+ uint32 *phys_lo, uint32 *phys_hi);
+
+/*
+ * Backdoor to retrieve OS device structure to be used for
+ * DMA operations.
+ */
+extern void *lkbde_get_dma_dev(int d);
+
+/*
+ * Backdoor to retrieve original hardware/OS device.
+ */
+extern void *lkbde_get_hw_dev(int d);
+
+/*
+ * Backdoor to retrieve number of switch devices probed.
+ */
+extern int lkbde_get_num_devices(int type);
+
+/*
+ * Retrive the device state from Kernel BDE.
+ * Used for KNET and User BDE for pci hot swap case.
+ */
+extern int lkbde_dev_state_get(int d, uint32 *state);
+extern int lkbde_dev_state_set(int d, uint32 state);
+
+/*
+ * Retrive the mapping between emulated HW device and instance id
+ */
+extern int lkbde_dev_instid_get(int d, uint32 *instid);
+extern int lkbde_dev_instid_set(int d, uint32 instid);
+
+/*
+ * Functions that allow an interrupt handler in user mode to
+ * coexist with interrupt handler in kernel module.
+ */
+extern int lkbde_irq_mask_set(int d, uint32 addr, uint32 mask, uint32 fmask);
+extern int lkbde_irq_mask_get(int d, uint32 *mask, uint32 *fmask);
+
+#ifdef BCM_SAND_SUPPORT
+extern int lkbde_cpu_write(int d, uint32 addr, uint32 *buf);
+extern int lkbde_cpu_read(int d, uint32 addr, uint32 *buf);
+extern int lkbde_cpu_pci_register(int d);
+#endif
+
+/*
+ * This flag must be OR'ed onto the device number when calling
+ * interrupt_connect/disconnect and irq_mask_set functions from
+ * a secondary device driver.
+ */
+#define LKBDE_ISR2_DEV 0x8000
+/*
+ * This flag should be OR'ed onto the device number when calling
+ * irq_mask_set functions from a secondary device driver if the
+ * mask register is iProc register.
+ */
+#define LKBDE_IPROC_REG 0x4000
+
+#ifdef BCM_SAND_SUPPORT
+#include <linux/version.h>
+#if defined(__DUNE_LINUX_BCM_CPU_PCIE__) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+#ifndef _SIMPLE_MEMORY_ALLOCATION_
+#define _SIMPLE_MEMORY_ALLOCATION_ 1
+#endif
+#endif
+#endif
+
+#if defined(IPROC_CMICD) && defined(CONFIG_CMA)
+#ifndef _SIMPLE_MEMORY_ALLOCATION_
+#define _SIMPLE_MEMORY_ALLOCATION_ 1
+#endif
+#endif
+
+/* Don't use _SIMPLE_MEMORY_ALLOCATION_ method for newer kernel than 3.10.0 */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
+#ifndef _SIMPLE_MEMORY_ALLOCATION_
+#define _SIMPLE_MEMORY_ALLOCATION_ 0
+#endif
+#endif
+
+/* Allocation via dma_alloc_coherent is turned off by default */
+#ifndef _SIMPLE_MEMORY_ALLOCATION_
+#define _SIMPLE_MEMORY_ALLOCATION_ 9 /* compile in the allocation method, but do not use it by default */
+#endif
+
+/* By default we use our private mmap for DMA pool */
+#ifndef USE_LINUX_BDE_MMAP
+#define USE_LINUX_BDE_MMAP 1
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* __LINUX_BDE_H__ */
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/include/linux_dma.h b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/include/linux_dma.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/***********************************************************************
+ *
+ * $Id: linux_dma.h,v 1.24 Broadcom SDK $
+ * $Copyright: (c) 2016 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ **********************************************************************/
+
+#ifndef __LINUX_DMA_H__
+#define __LINUX_DMA_H__
+
+#include <sal/types.h>
+
+#ifdef __KERNEL__
+
+#ifdef SAL_BDE_XLP
+#define KMALLOC(size, flags) __kmalloc(size, flags)
+#else
+#define KMALLOC(size, flags) kmalloc(size, flags)
+#endif
+
+#if defined(CONFIG_IDT_79EB334) || defined(CONFIG_BCM4702)
+/* ioremap is broken in kernel */
+#define IOREMAP(addr, size) ((void *)KSEG1ADDR(addr))
+#else
+#define IOREMAP(addr, size) ioremap_nocache(addr, size)
+#endif
+
+#if defined (__mips__)
+#if defined(CONFIG_NONCOHERENT_IO) || defined(CONFIG_DMA_NONCOHERENT)
+/* Use flush/invalidate for cached memory */
+#define NONCOHERENT_DMA_MEMORY
+/* Remap virtual DMA addresses to non-cached segment */
+#define REMAP_DMA_NONCACHED
+#endif /* CONFIG_NONCOHERENT_IO || CONFIG_DMA_NONCOHERENT */
+#endif /* __mips__ */
+
+#if defined(BCM958525) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,5))
+#define REMAP_DMA_NONCACHED
+#endif
+
+#ifndef DMA_BIT_MASK
+#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
+#endif
+
+extern void _dma_init(int dev_index);
+extern int _dma_cleanup(void);
+extern void _dma_pprint(void);
+extern uint32_t *_salloc(int d, int size, const char *name);
+extern void _sfree(int d, void *ptr);
+extern int _sinval(int d, void *ptr, int length);
+extern int _sflush(int d, void *ptr, int length);
+extern sal_paddr_t _l2p(int d, void *vaddr);
+extern void *_p2l(int d, sal_paddr_t paddr);
+extern int _dma_pool_allocated(void);
+extern int _dma_mmap(struct file *filp, struct vm_area_struct *vma);
+
+#endif /* __KERNEL__ */
+
+#endif /* __LINUX_DMA_H__ */
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/include/mpool.h b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/include/mpool.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: mpool.h,v 1.2 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#ifndef __MPOOL_H__
+#define __MPOOL_H__
+
+struct mpool_mem_s;
+typedef struct mpool_mem_s* mpool_handle_t;
+
+extern int mpool_init(void);
+extern mpool_handle_t mpool_create(void* base_address, int size);
+extern void* mpool_alloc(mpool_handle_t pool, int size);
+extern void mpool_free(mpool_handle_t pool, void* ptr);
+extern int mpool_destroy(mpool_handle_t pool);
+
+extern int mpool_usage(mpool_handle_t pool);
+
+#endif /* __MPOOL_H__ */
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/Makefile b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/Makefile
@@ -0,0 +1,92 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.18 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+# Makefile for Linux kernel BDE
+#
+LOCALDIR = systems/bde/linux/kernel
+
+# Make sure we build for the kernel if this is a user-mode build
+ifneq ($(platform), )
+override-target=linux-$(platform)
+endif
+
+include $(SDK)/make/Make.config
+
+LIBS = $(LIBDIR)/libkern.a
+
+BDE = linux-kernel-bde.o
+
+# need to add vpath sources
+VPATH = ../shared
+
+# Add the srcs to be found by vpath
+LSRCS += mpool.c
+
+# Add shared BDE sources
+VPATH += ../../shared
+LSRCS += shbde_pci.c shbde_iproc.c shbde_mdio.c
+CFLAGS += -I../../shared/include
+
+LHDRS += mpool.h
+LOBJS = $(addsuffix .o, $(basename $(LSRCS)))
+BOBJS = $(addprefix $(BLDDIR)/,$(LOBJS))
+
+ifneq ($(kernel_version),2_4)
+KERNEL_MODULE_DIR = kernel_module
+
+THIS_MOD_NAME := linux-kernel-bde
+MODULE = $(LIBDIR)/$(THIS_MOD_NAME).o
+KMODULE = $(LIBDIR)/$(THIS_MOD_NAME).ko
+
+build: kernel_libs $(MODULE) $(KMODULE)
+else
+MODULE = $(LIBDIR)/linux-kernel-bde.o
+
+build: kernel_libs $(MODULE)
+endif
+
+$(MODULE): $(BLDDIR)/.tree kernel_libs $(BOBJS)
+ mkdir -p $(@D)
+ $(LD) $(MODULE_LDFLAGS) -r -d $(BOBJS) $(LIBS) -o $@
+ifneq ($(kernel_version),2_4)
+$(KMODULE): $(MODULE)
+ rm -fr $(BLDDIR)/$(KERNEL_MODULE_DIR)
+ mkdir $(BLDDIR)/$(KERNEL_MODULE_DIR)
+ cp ${SDK}/make/Makefile.linux-kmodule $(BLDDIR)/$(KERNEL_MODULE_DIR)/Makefile
+ MOD_NAME=$(THIS_MOD_NAME) $(MAKE) -C $(BLDDIR)/$(KERNEL_MODULE_DIR) $(THIS_MOD_NAME).ko
+endif
+
+kernel_libs:
+ $(MAKE) -C $(SDK)/systems/linux/kernel/modules/shared
+
+include $(SDK)/make/Make.depend
+
+# Make.depend is before clean:: so that Make.depend's clean:: runs first.
+
+clean::
+ $(MAKE) -C $(SDK)/systems/linux/kernel/modules/shared $@
+ $(RM) $(BOBJS) $(MODULE)
+ $(RM) $(BLDDIR)/$(KERNEL_MODULE_DIR)
+
+distclean::
+
+ifneq ($(kernel_version),2_4)
+.PHONY: build kernel_libs
+endif
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux-kernel-bde.c b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux-kernel-bde.c
@@ -0,0 +1,4361 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: linux-kernel-bde.c,v 1.414 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ * Linux Kernel BDE
+ *
+ */
+
+#include <gmodule.h>
+#include <linux-bde.h>
+#include <linux_dma.h>
+#include <mpool.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <sdk_config.h>
+#include <soc/devids.h>
+#include <soc/cmic.h>
+#include <soc/drv.h>
+#include <linux/version.h>
+
+#include "linux_shbde.h"
+
+
+#ifdef __GNUC__
+#if __GNUC__ == 8
+/*
+ * Prevent gcc 8.1.10 using a compiler inline memcpy even if using -fno-builtin or
+ * -fno-builtin-memcpy .
+ * __inline_memcpy and __memcpy are kernel functions that may be used instead,
+ * for either an inline or non-inline implementations of the function
+ */
+#define MEMCPY __inline_memcpy
+#else
+#define MEMCPY memcpy
+#endif /* __GNUC__ == 8 */
+#else /* ifdef __GNUC__ */
+#define MEMCPY memcpy
+#endif /* ifdef __GNUC__ */
+
+#define PCI_USE_INT_NONE (-1)
+#define PCI_USE_INT_INTX (0)
+#define PCI_USE_INT_MSI (1)
+#define PCI_USE_INT_MSIX (2)
+#ifdef CONFIG_PCI_MSI
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,110))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+#define msix_table_size(flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1)
+#endif
+#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
+#endif
+#endif
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Kernel BDE");
+MODULE_LICENSE("GPL");
+
+/* PCIe max payload */
+int maxpayload = 256;
+LKM_MOD_PARAM(maxpayload, "i", int, 0);
+MODULE_PARM_DESC(maxpayload,
+"Limit maximum payload size and request size on PCIe devices");
+
+/* Use MSI or MSIX interrupts */
+int usemsi = -1;
+LKM_MOD_PARAM(usemsi, "i", int, 0);
+MODULE_PARM_DESC(usemsi,
+"Use MSI/ MSIX interrupts if supported by kernel");
+
+/* Ignore all recognized devices (for debug purposes) */
+int nodevices;
+LKM_MOD_PARAM(nodevices, "i", int, 0);
+MODULE_PARM_DESC(nodevices,
+"Ignore all recognized devices (default no)");
+
+int msixcnt = 1;
+
+/*
+ * This usually is defined at /usr/include/linux/pci_ids.h
+ * But this ID is newer.
+ */
+#ifndef PCI_DEVICE_ID_PLX_9656
+#define PCI_DEVICE_ID_PLX_9656 0x9656
+#endif
+
+#ifndef PCI_DEVICE_ID_PLX_9056
+#define PCI_DEVICE_ID_PLX_9056 0x9056
+#endif
+
+/* For 2.4.x kernel support */
+#ifndef IRQF_SHARED
+#define IRQF_SHARED SA_SHIRQ
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+typedef unsigned long resource_size_t;
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */
+
+#ifdef BCM_ICS
+#define BCM_ICS_CMIC_BASE 0x08000000
+#else
+
+/* Force interrupt line */
+static int forceirq = -1;
+static uint32_t forceirqubm = 0xffffffff;
+LKM_MOD_PARAM(forceirq, "i", int, 0);
+LKM_MOD_PARAM(forceirqubm, "i", uint, 0);
+MODULE_PARM_DESC(forceirq,
+"Override IRQ line assigned by boot loader");
+MODULE_PARM_DESC(forceirqubm,
+"Bitmap for overriding the IRQ line assigned by boot loader for given units");
+
+/* Create SPI slave device (cannot be probed) */
+static uint32_t spi_devid = 0;
+LKM_MOD_PARAM(spi_devid, "i", uint, 0);
+MODULE_PARM_DESC(spi_devid,
+"Create SPI slave device using this device ID");
+
+/* Select SPI device revision (cannot be probed) */
+static uint32_t spi_revid = 1;
+LKM_MOD_PARAM(spi_revid, "i", uint, 0);
+MODULE_PARM_DESC(spi_revid,
+"Select device revision for SPI slave device");
+
+#endif /* BCM_ICS */
+
+/* Debug output */
+static int debug;
+LKM_MOD_PARAM(debug, "i", int, 0);
+MODULE_PARM_DESC(debug,
+"Set debug level (default 0");
+/* Use high memory for DMA */
+
+/* module param for probing EB devices. */
+static char *eb_bus;
+LKM_MOD_PARAM(eb_bus, "s", charp, 0);
+MODULE_PARM_DESC(eb_bus,
+"List of EB devices on platform. Input format (BA=%x IRQ=%d RD16=%d WR16=%d");
+
+#ifdef KEYSTONE
+/* Force SPI Frequency */
+static int spifreq = 0;
+LKM_MOD_PARAM(spifreq, "i", int, 0);
+MODULE_PARM_DESC(spifreq,
+"Force SPI Frequency for Keystone CPU (0 for default frequency)");
+#endif
+
+
+/* Compatibility */
+#ifdef LKM_2_4
+#define _ISR_RET void
+#define _ISR_PARAMS(_i,_d,_r) int _i, void *_d, struct pt_regs *_r
+#define IRQ_NONE
+#define IRQ_HANDLED
+#define SYNC_IRQ(_i) synchronize_irq()
+#else /* LKM_2_6 */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
+#define _ISR_RET irqreturn_t
+#else
+#define _ISR_RET int
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19))
+#define _ISR_PARAMS(_i,_d,_r) int _i, void *_d
+#else
+#define _ISR_PARAMS(_i,_d,_r) int _i, void *_d, struct pt_regs *_r
+typedef irqreturn_t (*irq_handler_t)(int _i, void *_d, struct pt_regs *_r);
+#endif
+#define SYNC_IRQ(_i) synchronize_irq(_i)
+char * ___strtok;
+char * strtok(char * s,const char * ct)
+{
+ char *sbegin, *send;
+ sbegin = s ? s : ___strtok;
+ if (!sbegin) {
+ return NULL;
+ }
+ sbegin += strspn(sbegin,ct);
+ if (*sbegin == '\0') {
+ ___strtok = NULL;
+ return( NULL );
+ }
+ send = strpbrk( sbegin, ct);
+ if (send && *send != '\0')
+ *send++ = '\0';
+ ___strtok = send;
+ return (sbegin);
+}
+LKM_EXPORT_SYM(___strtok);
+LKM_EXPORT_SYM(strtok);
+#endif /* LKM_2_x */
+
+/* PCIe capabilities */
+#ifndef PCI_CAP_ID_EXP
+#define PCI_CAP_ID_EXP 0x10
+#endif
+#ifndef PCI_EXP_DEVCAP
+#define PCI_EXP_DEVCAP 4
+#endif
+#ifndef PCI_EXP_DEVCTL
+#define PCI_EXP_DEVCTL 8
+#endif
+#ifndef PCI_EXT_CAP_START
+#define PCI_EXT_CAP_START 0x100
+#endif
+#ifndef PCI_EXT_CAP_ID
+#define PCI_EXT_CAP_ID(_hdr) (_hdr & 0x0000ffff)
+#endif
+#ifndef PCI_EXT_CAP_VER
+#define PCI_EXT_CAP_VER(_hdr) ((_hdr >> 16) & 0xf)
+#endif
+#ifndef PCI_EXT_CAP_NEXT
+#define PCI_EXT_CAP_NEXT(_hdr) ((_hdr >> 20) & 0xffc)
+#endif
+#ifndef PCI_EXT_CAP_ID_VNDR
+#define PCI_EXT_CAP_ID_VNDR 0x0b
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+#define PCI_FIND_DEV(_d, _v, _fr) pci_find_device(_d, _v, _fr)
+#else
+#define PCI_FIND_DEV(_d, _v, _fr) pci_get_device(_d, _v, _fr)
+#endif
+
+#if defined(CONFIG_RESOURCES_64BIT) || defined(CONFIG_PHYS_ADDR_T_64BIT)
+#define PHYS_ADDR_IS_64BIT
+#endif
+
+/* Structure of private SPI device */
+struct spi_dev {
+ uint8 cid; /* Chip ID */
+ uint32 part; /* Part number of the chip */
+ uint8 rev; /* Revision of the chip */
+ void *robo; /* ptr to robo info required to access SPI */
+ unsigned short phyid_high; /* PHYID HIGH in MII regs of detected chip */
+ unsigned short phyid_low; /* PHYID LOW in MII regs of detected chip */
+};
+
+struct bde_spi_device_id {
+ unsigned short phyid_high; /* PHYID HIGH in MII regs of detected chip */
+ unsigned short phyid_low; /* PHYID LOW in MII regs of detected chip */
+ uint32 model_info;
+ uint32 rev_info;
+ uint32 spifreq;
+};
+
+/* Control Data */
+typedef struct bde_ctrl_s {
+ struct list_head list;
+
+ /* Specify the type of device, pci, spi, switch, ether ... */
+ uint32 dev_type;
+
+ int domain_no;
+ int bus_no;
+ int be_pio;
+ int use_msi;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+ struct msix_entry *entries;
+#endif
+ int msix_cnt;
+ union {
+ /* Linux PCI device pointer */
+ struct pci_dev* _pci_dev;
+
+ /* SPI device pointer */
+ struct spi_dev* _spi_dev;
+ } dev;
+#define pci_device dev._pci_dev
+#define spi_device dev._spi_dev
+
+#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT
+ struct device *dma_dev;
+#endif
+
+ /* Physical addresses */
+ resource_size_t phys_address;
+ resource_size_t phys_address1;
+ resource_size_t phys_address2;
+
+ /* Secondary mapped base address */
+ sal_vaddr_t alt_base_addr;
+
+ /* BDE device description */
+ ibde_dev_t bde_dev;
+
+ /* Interrupt Handling */
+ int iLine; /* Interrupt line */
+ void (*isr)(void *);
+ void *isr_data;
+
+ /*
+ * Controls to allow two drivers to share a single set of
+ * hardware registers. Typically a kernel driver will handle
+ * a subset of hardware interrupts and a user mode driver
+ * will handle the remaining interrupts.
+ */
+ void (*isr2)(void *);
+ void *isr2_data;
+ uint32_t fmask; /* Interrupts controlled by secondary handler */
+ uint32_t imask; /* Enabled interrupts for primary handler */
+ uint32_t imask2; /* Enabled interrupts for secondary handler */
+ spinlock_t lock; /* Lock for IRQ mask synchronization */
+
+ /* Hardware abstraction for shared BDE functions */
+ shbde_hal_t shbde;
+
+ /* Device state : BDE_DEV_STATE_REMOVED/CHANGED */
+ uint32 dev_state;
+
+ /* inst_id */
+ uint32 inst_id;
+} bde_ctrl_t;
+
+static bde_ctrl_t _devices[LINUX_BDE_MAX_DEVICES];
+static int _ndevices = 0;
+static int _switch_ndevices = 0;
+static int _ether_ndevices = 0;
+static int _cpu_ndevices = 0;
+
+#define VALID_DEVICE(_n) ((_n >= 0) && (_n < _ndevices))
+
+#if defined(IPROC_CMICD) && defined(CONFIG_OF)
+#define ICFG_CHIP_ID_REG 0x10236000
+#define IHOST_CMICX_MAX_INTRS 128
+static uint32 iproc_cmicx_irqs[IHOST_CMICX_MAX_INTRS];
+#endif
+
+/* CPU MMIO area used with CPU cards provided on demo boards */
+#if defined(BCM_SAND_SUPPORT) && (defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__))
+static void *cpu_address = NULL;
+#endif
+
+
+/* Broadcom BCM4704 */
+#define BCM4704_VENDOR_ID 0x14E4
+#define BCM4704_DEVICE_ID 0x4704
+
+/* SiByte PCI Host */
+#define SIBYTE_PCI_VENDOR_ID 0x166D
+#define SIBYTE_PCI_DEVICE_ID 0x0001
+
+/* Intel 21150 PCI-PCI Bridge */
+#define DC21150_VENDOR_ID 0x1011
+#define DC21150_DEVICE_ID 0x0022
+
+/* HiNT HB4 PCI-PCI Bridge (21150 clone) */
+#define HINT_HB4_VENDOR_ID 0x3388
+#define HINT_HB4_DEVICE_ID 0x0022
+
+/* Pericom PI7C8150 PCI-PCI Bridge (21150 clone) */
+#define PI7C8150_VENDOR_ID 0x12D8
+#define PI7C8150_DEVICE_ID 0x8150
+
+/* Pericom PI7C9X130 PCI-PCIE Bridge */
+#define PCI_VNDID_PERICOM 0x12D8
+#define PCI_DEVID_PI7C9X130 0xE130
+#define DEV_CTRL_REG 0xb8
+
+#define MAX_PAYLOAD_256B (1 << 5)
+#define MAX_PAYLOAD_512B (2 << 5)
+#define MAX_READ_REQ_256B (1 << 12)
+
+
+/* Freescale 8548 PCI-E host Bridge */
+#define FSL_VENDOR_ID 0x1957
+#define FSL8548PCIE_DEVICE_ID 0x0013
+#define FSL2020EPCIE_DEVICE_ID 0x0070
+#define FSL8548PCIE_DEV_CTRL_REG 0x54
+
+/* 4716 PCI-E host Bridge */
+#define BCM4716_VENDOR_ID 0x14e4
+#define BCM4716PCIE_DEVICE_ID 0x4716
+#define BCM4716PCIE_DEV_CAP_REG 0xd4
+#define BCM4716PCIE_DEV_CTRL_REG 0xd8
+#define BCM53000_VENDOR_ID 0x14e4
+#define BCM53000PCIE_DEVICE_ID 0x5300
+
+#define BCM53000PCIE_DEV(port) ((port == 0) ? pcie0 : pcie1)
+#define BCM53000PCIE_BASE(port) ((port == 0) ? 0xb8005000 : 0xb800e000)
+#define BCM53000PCIE_FUNC0_COFIG_SPACE 0x400
+#define BCM53000PCIE_SROM_SPACE 0x800
+#define BCM53000PCIE_DEV_CAP_REG 0xd4
+#define BCM53000PCIE_DEV_CTRL_REG 0xd8
+#define BCM53000PCIE_MAX_PAYLOAD_MASK 0x7
+#define BCM53000PCIE_CAP_MAX_PAYLOAD_256B (1 << 0)
+#define BCM53000PCIE_DEFAULT_STATUS 0x00100146
+
+/* 16bit wide register. offset 14, 14*2 = 0x1c */
+#define BCM53000PCIE_SPROM_OFFSET 0x1c
+/* bit 15:13 spromData.MaxPayloadSize. 1: 256 bytes */
+#define BCM53000PCIE_SPROM_MAX_PAYLOAD_MASK 0xe000
+#define BCM53000PCIE_SPROM_MAX_PAYLOAD_256B (1 << 13)
+
+
+/* Intel 21150, HiNT HB4 and other 21150-compatible */
+#define PCI_CFG_DEC21150_SEC_CLK 0x68
+
+#define BCM4704_ENUM_BASE 0x18000000
+#define BCM4704_MEMC_BASE (BCM4704_ENUM_BASE+0x8000)
+#define BCM4704_MEMC_PRIORINV 0x18
+
+/* PLX PCI-E Switch */
+#define PLX_PEX8608_DEV_ID 0x8608
+#define PLX_PEX8617_DEV_ID 0x8617
+#define PLX_PEX86XX_DEV_CTRL_REG 0x70
+
+/* Broadcom BCM58525 */
+#define BCM58525_PCI_VENDOR_ID 0x14E4
+#define BCM58525_PCI_DEVICE_ID 0x8025
+#define BCM58522_PCI_DEVICE_ID 0x8022
+
+/* Broadcom BCM58712 */
+#define BCM58712_PCI_VENDOR_ID 0x14E4
+#define BCM58712_PCI_DEVICE_ID 0x168E
+
+/* Default gicd address if not available in DTB */
+#define IHOST_GICD_REG_ADDR 0x10781100
+#define IHOST_GICD_REG_REMAP_LEN 0x100
+
+#define IHOST_GICD_REG_ADDR_VALID(d, addr) \
+ (_devices[d].bde_dev.base_address1 && \
+ (addr & 0xFFFFFF00) == _devices[d].phys_address1)
+
+#define IHOST_GICD_REG_ADDR_REMAP(d, addr) \
+ (void *)(_devices[d].bde_dev.base_address1 + (addr - _devices[d].phys_address1))
+
+static uint32_t _read(int d, uint32_t addr);
+
+#ifdef BCM_ICS
+#else
+/* Used to determine overall memory limits across all devices */
+static uint32_t _pci_mem_start = 0xFFFFFFFF;
+static uint32_t _pci_mem_end = 0;
+
+/* Used to control MSI interrupts */
+static int use_msi = 0;
+#endif
+
+#ifdef BCM_PLX9656_LOCAL_BUS
+
+#define CPLD_OFFSET 0x00800000
+#define CPLD_REVISION_REG 0x0000
+#define CPLD_REVISION_MASK 0xffff
+#define CPLD_RESET_REG 0x0004
+#define CPLD_RESET_NONE 0x0000
+
+#define PL0_OFFSET 0x00800000
+#define PL0_SIZE 0x00040000
+#define PL0_REVISION_REG 0x0000
+
+/* Assume there's only one PLX PCI-to-Local bus bridge if any */
+static bde_ctrl_t plx_ctrl;
+static int num_plx = 0;
+
+#endif /* BCM_PLX9656_LOCAL_BUS */
+
+static spinlock_t bus_lock;
+
+static int
+_parse_eb_args(char *str, char * format, ...)
+ __attribute__ ((format (scanf, 2, 3)));
+
+static int
+_parse_eb_args(char *str, char * format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vsscanf(str, format, args);
+ va_end(args);
+
+ return 0;
+}
+
+static void
+_bde_add_device(void)
+{
+ int add_switch_device = 0;
+ if (_devices[_ndevices].dev_type & BDE_SWITCH_DEV_TYPE) {
+ _switch_ndevices++;
+ add_switch_device = 1;
+ } else if (_devices[_ndevices].dev_type & BDE_ETHER_DEV_TYPE) {
+ _ether_ndevices++;
+ } else if (_devices[_ndevices].dev_type & BDE_CPU_DEV_TYPE) {
+ _cpu_ndevices++;
+ } else {
+ return;
+ }
+ _ndevices++;
+
+ /*
+ * In order to be backward compatible with the user mode BDE
+ * (specifically the interrupt IOCTLs) and the CM, switch devices
+ * *must* come first. If this is not the case (due to the probing
+ * order), we let the non-switch device(s) drop down to the end of
+ * the device array.
+ */
+ if (add_switch_device) {
+ bde_ctrl_t tmp_dev;
+ int i, s = 0;
+
+ while (s < _switch_ndevices) {
+ if (_devices[s].dev_type & BDE_SWITCH_DEV_TYPE) {
+ s++;
+ continue;
+ }
+ tmp_dev = _devices[s];
+ for (i = s; i < _ndevices - 1; i++) {
+ _devices[i] = _devices[i+1];
+ }
+ _devices[i] = tmp_dev;
+ }
+
+ _dma_init(_switch_ndevices-1);
+ }
+
+ /* Initialize device locks */
+ spin_lock_init(&_devices[_ndevices-1].lock);
+}
+
+static int
+_eb_device_create(resource_size_t paddr, int irq, int rd_hw, int wr_hw)
+{
+ bde_ctrl_t *ctrl;
+ uint32 dev_rev_id = 0x0, dev_id;
+
+ dev_id = _ndevices;
+
+ ctrl = _devices + _ndevices;
+
+ ctrl->dev_type |= BDE_EB_DEV_TYPE | BDE_SWITCH_DEV_TYPE;
+ ctrl->pci_device = NULL; /* No PCI bus */
+
+ if(rd_hw) {
+ ctrl->dev_type |= BDE_DEV_BUS_RD_16BIT;
+ }
+
+ if (wr_hw) {
+ ctrl->dev_type |= BDE_DEV_BUS_WR_16BIT;
+ }
+
+ /* Map in the device */
+ ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(paddr, 0x10000);
+ ctrl->phys_address = paddr;
+
+ dev_rev_id = _read(dev_id, 0x178); /* CMIC_DEV_REV_ID */
+
+ ctrl->bde_dev.device = dev_rev_id & 0xFFFF;
+ ctrl->bde_dev.rev = (dev_rev_id >> 16) & 0xFF;
+
+ ctrl->iLine = irq;
+ ctrl->isr = NULL;
+ ctrl->isr_data = NULL;
+
+ gprintk("Created EB device at BA=%x IRQ=%d RD16=%d WR16=%d device=0x%x\n",
+ (unsigned int)paddr, irq, rd_hw, wr_hw, ctrl->bde_dev.device);
+
+ _bde_add_device();
+
+ return 0;
+}
+
+#ifdef BCM_SAND_SUPPORT
+
+#include <soc/devids.h>
+
+static int
+sand_device_create(void)
+{
+ bde_ctrl_t* ctrl;
+
+ ctrl = _devices; /* FIX_ME: on petra, take first device */
+
+#ifndef __DUNE_LINUX_BCM_CPU_PCIE__
+ ctrl->dev_type |= BDE_PCI_DEV_TYPE | BDE_SWITCH_DEV_TYPE;
+ ctrl->pci_device = NULL; /* No PCI bus */
+
+ /* Map in the device */ /* FIX_ME: not realy map anything */
+ ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(0x40000000, 0x100000);
+ ctrl->phys_address = 0x40000000;
+
+ ctrl->iLine = 0;
+ ctrl->isr = NULL;
+ ctrl->isr_data = NULL;
+
+ ctrl->bde_dev.device = BCM88950_DEVICE_ID;
+ ctrl->bde_dev.rev = BCM88950_A0_REV_ID;
+#endif
+
+ /* Map CPU regs */
+#ifdef __DUNE_WRX_BCM_CPU__
+ cpu_address = IOREMAP(0x18000000, 0x4000000);
+#elif defined(__DUNE_GTO_BCM_CPU__)
+ cpu_address = IOREMAP(0xe0000000, 0x100000);
+#endif
+
+ if ((ctrl->bde_dev.device == PCP_PCI_DEVICE_ID)) {
+ ctrl->bde_dev.device = GEDI_DEVICE_ID;
+ ctrl->bde_dev.rev = GEDI_REV_ID;
+ }
+
+ if ((ctrl->bde_dev.device == ACP_PCI_DEVICE_ID)) {
+ ctrl->dev_type |= BDE_PCI_DEV_TYPE | BDE_SWITCH_DEV_TYPE;
+ }
+
+#ifndef __DUNE_LINUX_BCM_CPU_PCIE__
+ _bde_add_device();
+#endif
+
+ return 0;
+}
+#endif /* BCM_SAND_SUPPORT */
+
+#ifdef IPROC_CMICD
+static void
+iproc_cmicd_get_irqres(ibde_dev_t bde_dev, struct resource *res_irq)
+{
+ shbde_iproc_config_t iproc_config, *icfg = &iproc_config;
+
+ /* iProc configuration parameters */
+ memset(icfg, 0, sizeof(*icfg));
+ shbde_iproc_config_init(icfg, bde_dev.device, bde_dev.rev);
+
+ if ((icfg->iproc_ver == 0) && (debug >= 1)) {
+ gprintk("Unable to determine iProc version\n");
+ }
+
+ if (icfg->iproc_ver == 7) {
+ res_irq->start = 221;
+ } else if (icfg->iproc_ver == 10) {
+ res_irq->start = 184;
+ }
+
+}
+
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+extern int iproc_platform_driver_register(struct platform_driver *drv);
+extern void iproc_platform_driver_unregister(struct platform_driver *drv);
+extern int iproc_platform_device_register(struct platform_device *drv);
+extern void iproc_platform_device_unregister(struct platform_device *drv);
+
+extern struct resource *
+iproc_platform_get_resource(struct platform_device *dev, unsigned int type,
+ unsigned int num);
+
+#define IPROC_CHIPCOMMONA_BASE 0x18000000
+#define IPROC_CMICD_BASE 0x48000000
+#define IPROC_CMICD_SIZE 0x40000
+#define IPROC_CMICD_INT 194
+
+#define IPROC_CMICD_COMPATIBLE "brcm,iproc-cmicd"
+#define IPROC_CMICX_COMPATIBLE "brcm,iproc-cmicx"
+
+static int
+iproc_cmicd_probe(struct platform_device *pldev)
+{
+ bde_ctrl_t *ctrl;
+ uint32 size, dev_rev_id;
+ struct resource *memres, *irqres;
+#ifdef CONFIG_OF
+ if (debug >= 1) {
+ gprintk("iproc_cmicd_probe %s\n", pldev->dev.of_node ? "with device node":"");
+ }
+#endif
+ memres = iproc_platform_get_resource(pldev, IORESOURCE_MEM, 0);
+ if (memres == NULL) {
+ gprintk("Unable to retrieve iProc CMIC resources");
+ return -1;
+ }
+ size = memres->end - memres->start + 1;
+
+ ctrl = _devices + _ndevices;
+
+ ctrl->dev_type = BDE_AXI_DEV_TYPE | BDE_SWITCH_DEV_TYPE | BDE_256K_REG_SPACE;
+ ctrl->pci_device = NULL; /* No PCI bus */
+
+ /* Map CMIC block in the AXI memory space into CPU address space */
+ ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(memres->start, size);
+ if (!ctrl->bde_dev.base_address) {
+ gprintk("Error mapping iProc CMIC registers");
+ return -1;
+ }
+ ctrl->phys_address = memres->start;
+
+#ifdef CONFIG_OF
+ if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) {
+ uint32 *icfg_chip_id;
+ icfg_chip_id = (uint32 *)IOREMAP(ICFG_CHIP_ID_REG, 2 * sizeof(uint32));
+ if (icfg_chip_id == NULL) {
+ gprintk("Error mapping ICFG_CHIP_ID_REG\n");
+ return -1;
+ }
+ ctrl->bde_dev.device = readl(icfg_chip_id) & 0xffff;
+ ctrl->bde_dev.rev = readl(icfg_chip_id+1) & 0xff;
+ iounmap(icfg_chip_id);
+ /* Map GICD block in the AXI memory space into CPU address space */
+ memres = iproc_platform_get_resource(pldev, IORESOURCE_MEM, 1);
+ if (memres) {
+ ctrl->bde_dev.base_address1 = (sal_vaddr_t)IOREMAP(memres->start, memres->end - memres->start + 1);
+ ctrl->phys_address1 = memres->start;
+ } else {
+ /* Use default address if not available in DTB */
+ ctrl->bde_dev.base_address1 = (sal_vaddr_t)IOREMAP(IHOST_GICD_REG_ADDR, IHOST_GICD_REG_REMAP_LEN);
+ ctrl->phys_address1 = IHOST_GICD_REG_ADDR;
+ }
+ if (ctrl->bde_dev.base_address1) {
+ if (debug >= 1) {
+ gprintk("base_address1:0x%lx phys_address1:0x%lx\n",
+ (unsigned long)ctrl->bde_dev.base_address1, (unsigned long)ctrl->phys_address1);
+ }
+ } else {
+ gprintk("Error mapping ihost GICD registers\n");
+ }
+ } else
+#endif
+ {
+ /* Read switch device ID from CMIC */
+ dev_rev_id = *((uint32 *)(ctrl->bde_dev.base_address + 0x10224));
+#if defined(BCM_CMICM_SUPPORT) && defined(BE_HOST)
+ ctrl->bde_dev.device = ( (((dev_rev_id >> 16) & 0xff) << 8) |
+ ((dev_rev_id >> 24) & 0xff));
+ ctrl->bde_dev.rev = (dev_rev_id >> 8) & 0xff ;
+#else
+ ctrl->bde_dev.device = dev_rev_id & 0xffff;
+ ctrl->bde_dev.rev = (dev_rev_id >> 16) & 0xff;
+#endif
+ ctrl->bde_dev.base_address1 = 0;
+ }
+
+#ifdef CONFIG_OF
+ if (!pldev->dev.of_node)
+#endif
+ {
+ /* Assign locally if not available from device node */
+ iproc_cmicd_get_irqres(ctrl->bde_dev, &pldev->resource[0]);
+ }
+
+#ifdef CONFIG_OF
+ if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) {
+ int i;
+ for (i = 0; i < IHOST_CMICX_MAX_INTRS; i++) {
+ irqres = iproc_platform_get_resource(pldev, IORESOURCE_IRQ, i);
+ iproc_cmicx_irqs[i] = irqres->start;
+ if (debug >= 1) {
+ gprintk("iproc_cmicx_irqs[%d] = %d\n", i, iproc_cmicx_irqs[i]);
+ }
+ }
+ ctrl->iLine = iproc_cmicx_irqs[0];
+ } else
+#endif
+ {
+ irqres = iproc_platform_get_resource(pldev, IORESOURCE_IRQ, 0);
+ ctrl->iLine = irqres->start;
+ }
+
+ ctrl->isr = NULL;
+ ctrl ->isr_data = NULL;
+
+#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT
+ ctrl->dma_dev = &pldev->dev;
+#endif
+
+ /* Let's boogie */
+ _bde_add_device();
+ return 0;
+}
+
+static int
+iproc_cmicd_remove(struct platform_device *pldev)
+{
+ return 0;
+}
+#ifdef CONFIG_OF
+static const struct of_device_id iproc_cmicd_of_match[] = {
+ { .compatible = IPROC_CMICD_COMPATIBLE },
+ { .compatible = IPROC_CMICX_COMPATIBLE },
+ {},
+};
+MODULE_DEVICE_TABLE(of, iproc_cmicd_of_match);
+#endif
+static char iproc_cmicd_string[] = "bcmiproc-cmicd";
+
+static struct platform_driver iproc_cmicd_driver =
+{
+ .probe = iproc_cmicd_probe,
+ .remove = iproc_cmicd_remove,
+ .driver =
+ {
+ .name = iproc_cmicd_string,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = iproc_cmicd_of_match,
+#endif
+ },
+};
+
+typedef enum {
+ IPROC_CMICD_RES_INTR = 0,
+ IPROC_CMICD_RES_MEM
+} IPROC_CMICD_RES_E;
+
+static struct resource iproc_cmicd_resources[] = {
+ [IPROC_CMICD_RES_INTR] = {
+ .flags = IORESOURCE_IRQ,
+ .start = IPROC_CMICD_INT,
+ },
+ [IPROC_CMICD_RES_MEM] = {
+ .flags = IORESOURCE_MEM,
+ .start = IPROC_CMICD_BASE,
+ .end = IPROC_CMICD_BASE+IPROC_CMICD_SIZE-1,
+ },
+};
+
+static void
+iproc_cmicd_release(struct device *dev)
+{
+}
+
+static u64 iproc_cmicd_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device iproc_cmicd_pdev = {
+ .name = iproc_cmicd_string,
+ .id = 0,
+ .dev = {
+ .release = iproc_cmicd_release,
+ .init_name = iproc_cmicd_string,
+ .dma_mask = &iproc_cmicd_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = iproc_cmicd_resources,
+ .num_resources = ARRAY_SIZE(iproc_cmicd_resources),
+};
+
+static int
+iproc_has_cmicd(void)
+{
+ void *iproc_cca_base;
+ uint32 cca_cid;
+
+ /* Read ChipcommonA chip id register to identify current SOC */
+ iproc_cca_base = IOREMAP(IPROC_CHIPCOMMONA_BASE, 0x3000);
+ if (iproc_cca_base == NULL) {
+ gprintk("iproc_has_cmicd: ioremap of ChipcommonA registers failed");
+ return 0;
+ }
+ cca_cid = readl((uint32 *)iproc_cca_base);
+ cca_cid &= 0xffff;
+ iounmap(iproc_cca_base);
+
+ /* Only allowed accessing CMICD module if the SOC has it */
+ switch (cca_cid) {
+ default:
+ break;
+ }
+
+ /* Device has CMIC */
+ return 1;
+}
+
+#define IPROC_CHIPCOMMONA_EROM_PTR_OFFSET (0x180000fc)
+#define EROM_MAX_SIZE (0x1000)
+#define EROM_PARTNUM_CMICD (0x14)
+
+#define EROM_DESC_COMPIDENT (0x1)
+#define EROM_DESC_MASTER (0x3)
+#define EROM_DESC_ADDR (0x5)
+#define EROM_DESC_END (0xF)
+#define EROM_DESC_EMPTY (0)
+
+#define EROM_IS_DESC_COMPIDENT(x) ((x & 0x7) == EROM_DESC_COMPIDENT)
+#define EROM_IS_DESC_MASTER(x) ((x & 0x7) == EROM_DESC_MASTER)
+#define EROM_IS_DESC_ADDR(x) ((x & 0x7) == EROM_DESC_ADDR)
+#define EROM_IS_DESC_END(x) ((x & 0xF) == EROM_DESC_END)
+
+#define EROM_GET_PARTNUM(x) ((x >> 8) & (0xFFF)) /* Bit 8~19 */
+#define EROM_GET_ADDRESS(x) ((x >> 12) & (0xFFFFF)) /* Bit 12~31 */
+#define EROM_GET_SIZETYPE(x) ((x >> 4) & (0x3)) /* Bit 4~5 */
+#define EROM_GET_AG32(x) ((x >> 3) & (0x1)) /* Bit 3 */
+#define EROM_GET_SIZE(x) ((x >> 12) & (0xFFFFF)) /* Bit 12~31 */
+#define EROM_GET_SG32(x) ((x >> 3) & (0x1)) /* Bit 3 */
+
+#define EROM_ADDR_SIZETYPE_4K (0)
+#define EROM_ADDR_SIZETYPE_8K (1)
+#define EROM_ADDR_SIZETYPE_16K (2)
+#define EROM_ADDR_SIZETYPE_MORE (3)
+
+#define EROM_ADDR_FLAG_AG32 (1) /* Address space greater than 32 bit */
+#define EROM_ADDR_FLAG_SIZE (2) /* Addition size descriptor */
+#define EROM_ADDR_FLAG_SG32 (4) /* Size descriptor greater than 32 bit */
+
+static void
+iproc_cmicd_get_memregion(struct resource *res_mem)
+{
+ void *erom_ptr_oft;
+ uint32_t erom_phy_addr;
+ uint32_t *erom_base;
+ uint32_t i = 0;
+ uint32_t word = 0;
+ uint8_t more_addr_word = 0; /* bit 0: AG32; bit 1: SIZE; bit 2: SG32 */
+ uint8_t found_cmicd_dev = 0;
+ uint8_t size_type = 0;
+ bool is_compident_a = 1; /* 1: CompidentA; o/w: CompidentB */
+
+ erom_ptr_oft = IOREMAP(IPROC_CHIPCOMMONA_EROM_PTR_OFFSET, 0x100);
+
+ erom_phy_addr = readl((uint32 *)(erom_ptr_oft));
+ iounmap(erom_ptr_oft);
+
+ erom_base = IOREMAP(erom_phy_addr, EROM_MAX_SIZE);
+
+ while (1) {
+ word = readl((uint32 *)(erom_base + i));
+
+ if (EROM_IS_DESC_ADDR(word) || more_addr_word) {
+ if (more_addr_word == 0) { /* Normal Addr Desc */
+ if (EROM_GET_AG32(word) == 1) {
+ more_addr_word |= EROM_ADDR_FLAG_AG32;
+ }
+
+ size_type = EROM_GET_SIZETYPE(word);
+ if (size_type == EROM_ADDR_SIZETYPE_MORE) {
+ more_addr_word |= EROM_ADDR_FLAG_SIZE;
+ }
+
+ if (found_cmicd_dev == 1) {
+ res_mem->start = EROM_GET_ADDRESS(word) << 12;
+ if (size_type < EROM_ADDR_SIZETYPE_MORE) {
+ res_mem->end = res_mem->start + 4096 * (1 << size_type) - 1;
+ }
+ }
+ }
+ else if (more_addr_word & EROM_ADDR_FLAG_AG32) { /* UpperAddr Desc */
+ more_addr_word &= ~EROM_ADDR_FLAG_AG32;
+
+ if (found_cmicd_dev == 1) {
+ /* res_mem->start |= word << 32; */
+ gprintk("Expect cmicd address to be 32-bit\n");
+ }
+ }
+ else if (more_addr_word & EROM_ADDR_FLAG_SIZE) { /* Size Desc */
+ if (EROM_GET_SG32(word) == 1) {
+ more_addr_word |= EROM_ADDR_FLAG_SG32;
+ }
+
+ more_addr_word &= ~EROM_ADDR_FLAG_SIZE;
+
+ if (found_cmicd_dev == 1) {
+ res_mem->end = res_mem->start + (EROM_GET_SIZE(word) << 12) - 1;
+ }
+ }
+ else if (more_addr_word & EROM_ADDR_FLAG_SG32) { /* UpperSize Desc */
+ more_addr_word &= ~EROM_ADDR_FLAG_SG32;
+
+ if (found_cmicd_dev == 1) {
+ /* res_mem->end += (word) << 32; */
+ gprintk("Expect cmicd size to be 32-bit\n");
+ }
+ }
+
+ if (found_cmicd_dev == 1 && more_addr_word == 0) {
+ break; /* We have gotten all necessary information, exit the loop */
+ }
+ }
+ else if (EROM_IS_DESC_COMPIDENT(word)) {
+ if (is_compident_a == 1) {
+ if (EROM_GET_PARTNUM(word) == EROM_PARTNUM_CMICD) {
+ found_cmicd_dev = 1;
+ }
+ }
+
+ is_compident_a = 1 - is_compident_a;
+ }
+ else if (EROM_IS_DESC_END(word)) {
+ break;
+ }
+
+ i++;
+ }
+ iounmap(erom_base);
+
+ if (debug >= 1) {
+ gprintk("CMICD info by %s: cmicd_mem.start=%lx, cmicd_mem.end=%lx\n",
+ found_cmicd_dev ? "EROM" : "Default",
+ (unsigned long)iproc_cmicd_resources[IPROC_CMICD_RES_MEM].start,
+ (unsigned long)iproc_cmicd_resources[IPROC_CMICD_RES_MEM].end);
+ }
+}
+#endif /* IPROC_CMICD */
+
+#ifdef BCM_ICS
+static int
+_ics_bde_create(void)
+{
+ bde_ctrl_t *ctrl;
+ uint32 dev_rev_id = 0x0;
+ resource_size_t paddr;
+
+ if (_ndevices == 0) {
+ ctrl = _devices + _ndevices;
+
+ ctrl->dev_type |= BDE_ICS_DEV_TYPE | BDE_SWITCH_DEV_TYPE;
+ ctrl->pci_device = NULL; /* No PCI bus */
+
+ /* Map in the device */
+ paddr = BCM_ICS_CMIC_BASE;
+ ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(paddr, 0x10000);
+ ctrl->phys_address = paddr;
+
+ dev_rev_id = *((unsigned int *)(KSEG1ADDR(paddr + 0x178)));
+
+ ctrl->bde_dev.device = dev_rev_id & 0xFFFF;
+ ctrl->bde_dev.rev = (dev_rev_id >> 16) & 0xFF;
+
+ ctrl->iLine = 5; /* From raptor linux BSP */
+
+ ctrl->isr = NULL;
+ ctrl->isr_data = NULL;
+ printk("Created ICS device ..%x\n", ctrl->bde_dev.base_address);
+ _bde_add_device();
+ }
+
+ return 0;
+}
+
+#else /* !BCM_ICS */
+
+extern struct pci_bus *pci_find_bus(int domain, int busnr);
+
+/*
+ * PCI device table.
+ * Populated from the include/soc/devids.h file.
+ */
+
+static const struct pci_device_id _id_table[] = {
+ { BROADCOM_VENDOR_ID, BCM5675_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM5676_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56218X_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56218_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56219_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56218R_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56219R_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56214_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56215_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56214R_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56215R_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56216_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56217_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56212_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56213_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56230_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56231_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53718_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53714_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53716_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56018_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56014_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56224_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56225_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56226_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56227_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56228_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56229_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56024_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56025_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53724_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53726_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56100_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56101_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56102_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56105_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56106_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56107_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56110_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56111_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56112_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56115_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56116_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56117_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56300_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56301_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56302_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56303_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56304_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56404_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56305_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56306_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56307_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56308_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56309_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56310_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56311_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56312_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56313_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56314_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56315_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56316_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56317_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56318_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56319_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#ifndef EXCLUDE_BCM56324
+ { BROADCOM_VENDOR_ID, BCM56322_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56324_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#endif /* EXCLUDE_BCM56324 */
+ { BROADCOM_VENDOR_ID, BCM53312_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53313_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53314_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53324_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53333_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53334_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53342_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53343_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53344_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53346_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53347_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53393_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53394_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53300_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53301_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53302_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56500_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56501_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56502_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56503_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56504_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56505_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56506_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56507_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56508_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56509_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56510_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56511_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56512_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56513_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56514_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56516_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56517_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56518_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56519_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56580_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56620_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56624_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56626_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56628_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56629_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56680_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56684_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56700_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56701_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56720_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56721_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56725_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56800_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56801_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56802_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56803_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56820_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56821_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56822_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56823_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56825_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56630_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56634_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56636_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56638_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56639_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56538_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56520_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56521_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56522_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56524_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56526_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56534_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56685_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56689_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56331_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56333_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56334_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56338_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56320_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56321_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56132_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56134_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88732_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56140_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56142_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56143_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56144_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56146_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56147_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56149_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56150_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56151_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56152_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56930_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56931_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56936_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56939_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56840_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56841_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56842_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56843_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56844_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56845_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56846_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56847_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56549_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56053_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56838_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56831_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56835_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56849_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56742_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56743_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56744_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56745_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56746_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56640_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56548_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56547_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56346_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56345_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56344_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56342_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56340_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56049_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56048_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56047_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56042_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56041_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56040_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56643_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56644_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56648_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56649_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56540_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56541_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56542_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56543_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56544_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56545_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56546_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56044_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56045_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56046_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM55440_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56440_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56441_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56442_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56443_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56445_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56446_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56447_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56448_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56449_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56240_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56241_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56242_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56243_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56245_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56246_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM55450_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM55455_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56260_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56270_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56271_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56272_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53460_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53461_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56261_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56262_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56263_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56265_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56266_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56267_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56268_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56233_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56460_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56461_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56462_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56463_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56465_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56466_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56467_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56468_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56246_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56248_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56450_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56452_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56454_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56455_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56456_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56457_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56458_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56850_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56851_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56852_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56853_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56854_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56855_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56834_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56750_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56830_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM55440_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM55441_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56060_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56062_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56063_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56064_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56065_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56066_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53401_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53411_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53402_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53412_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53403_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53413_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53404_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53414_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53405_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53415_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53406_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53416_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53408_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53418_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53454_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53455_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53456_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53457_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53422_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53424_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53426_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53365_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53369_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56960_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56961_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56962_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56963_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56930_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56968_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56970_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56971_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56972_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56974_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56975_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56168_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56169_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56560_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56561_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56562_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56565_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56566_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56567_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56670_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56671_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56672_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56675_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56568_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56670_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56760_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56761_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56762_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56764_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56765_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56766_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56768_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56069_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56068_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56160_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56162_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56163_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56164_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56166_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53440_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53443_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53442_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53434_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56965_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56969_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56966_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56967_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56170_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56172_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56174_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53570_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53575_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9656, PCI_ANY_ID, PCI_ANY_ID },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9056, PCI_ANY_ID, PCI_ANY_ID },
+ { BCM53000_VENDOR_ID, BCM53000PCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#ifdef BCM_PETRA_SUPPORT
+ { BROADCOM_VENDOR_ID, BCM88650_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88350_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88351_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88450_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88451_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88550_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88551_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88552_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88651_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88654_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { PCP_PCI_VENDOR_ID, PCP_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { ACP_PCI_VENDOR_ID, ACP_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88660_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88670_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88671_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88671M_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88672_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88673_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88674_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88675_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88675M_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88676_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88676M_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88677_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88678_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88679_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88370_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88371_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88371M_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88375_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88470_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88470P_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88471_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88473_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88474_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88474H_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88476_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88477_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+
+
+ { BROADCOM_VENDOR_ID, BCM88270_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88272_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88273_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88274_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88278_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88279_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+
+ { BROADCOM_VENDOR_ID, BCM8206_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+
+ { BROADCOM_VENDOR_ID, BCM88376_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88376M_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88377_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88378_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88379_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88680_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88681_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88682_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88683_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88684_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88685_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88380_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88381_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88202_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88360_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88361_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88363_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88460_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88461_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88560_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88561_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88562_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88661_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88664_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#endif
+#ifdef BCM_DNX_SUPPORT
+ { BROADCOM_VENDOR_ID, BCM88690_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88690_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88691_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88692_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88693_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88694_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88695_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88696_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88697_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88698_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88699_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8869A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8869B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8869C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8869D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8869F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88800_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#endif /* BCM_DNX_SUPPORT */
+#ifdef BCM_DFE_SUPPORT
+ { BROADCOM_VENDOR_ID, BCM88750_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88753_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88755_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88770_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88773_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88774_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88775_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88776_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88777_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#ifndef DNX_IGNORE_FE3200
+ { BROADCOM_VENDOR_ID, BCM88950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#endif
+ { BROADCOM_VENDOR_ID, BCM88953_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88954_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88955_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88956_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88752_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88772_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88952_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#endif
+#ifdef BCM_DNXF_SUPPORT
+ { BROADCOM_VENDOR_ID, BCM88790_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88791_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88792_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88793_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88794_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88795_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88796_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88797_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88798_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88799_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8879A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8879B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8879C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8879D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8879F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#endif
+ { BROADCOM_VENDOR_ID, BCM56860_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56861_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56862_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56864_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56865_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56866_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56867_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56868_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56833_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56832_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56836_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56870_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56370_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56371_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56372_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56374_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56375_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56376_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56377_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56577_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56578_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56579_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56873_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56770_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56771_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56980_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56981_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56982_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56983_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56984_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53540_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53547_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53548_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53549_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { 0, 0, 0, 0 }
+};;
+
+MODULE_DEVICE_TABLE(pci, _id_table);
+
+#define pci_bus_b(n) list_entry(n, struct pci_bus, node)
+#define pci_dev_b(n) list_entry(n, struct pci_dev, bus_list)
+#define MAX_RC_NUM 4
+
+static struct pci_bus *
+pci_do_bus_find(struct pci_bus* bus, int rc, int vendor, int device)
+{
+ struct list_head *tmp;
+ struct pci_dev *dev;
+ struct pci_bus *sub_bus;
+ int func = 0;
+
+ if (unlikely(list_empty(&bus->children))) {
+ return NULL;
+ }
+ list_for_each(tmp, &bus->children) {
+ sub_bus = pci_bus_b(tmp);
+ dev = sub_bus->self;
+ func = dev->devfn & 0x7;
+ if (dev->vendor == vendor && dev->device == device && rc == func) {
+ if (debug >= 1) {
+ gprintk("pci_do_bus_find: dev->vendor = 0x%x, dev->device = 0x%x on rc(%d)\n",
+ dev->vendor, dev->device, rc);
+ }
+ return sub_bus;
+ }
+ }
+ return NULL;
+}
+
+static struct pci_dev *
+_pci_do_bus_dev_find(struct pci_bus* bus, unsigned int vendor, unsigned int device)
+{
+ struct list_head *tmp;
+ struct pci_dev *dev;
+
+ if (unlikely(list_empty(&bus->devices))) {
+ return NULL;
+ }
+ list_for_each(tmp, &bus->devices) {
+ dev = pci_dev_b(tmp);
+ if (dev->vendor == vendor && (device == PCI_ANY_ID || dev->device == device)) {
+ if (debug >= 1) {
+ gprintk("_pci_do_rc_dev_find: vendor = %x, device = %x\n", vendor, device);
+ }
+ return dev;
+ }
+ }
+ return NULL;
+}
+
+static struct pci_dev *
+pci_do_rc_dev_find(int rc)
+{
+ struct pci_bus *root_bus = pci_find_bus(0,0);
+ struct pci_bus *bus_rc = NULL;
+ struct pci_dev *dev_on_rc = NULL;
+ unsigned int pci_dev_id = 0;
+
+ if(NULL == root_bus) {
+ if (debug >= 1) gprintk("Not find root bus\n");
+ return NULL;
+ }
+ bus_rc = pci_do_bus_find(root_bus, rc, 0x184e, 0x1004);
+ if (NULL == bus_rc) {
+ if (debug >= 1) {
+ gprintk("Not find vendor(0x184e) device(0x1004) bus\n");
+ }
+ return NULL;
+ }
+ for(pci_dev_id = 0; pci_dev_id < sizeof(_id_table)/sizeof(struct pci_device_id); pci_dev_id++) {
+ dev_on_rc = _pci_do_bus_dev_find(bus_rc, _id_table[pci_dev_id].vendor, _id_table[pci_dev_id].device);
+ if (NULL != dev_on_rc) {
+ return dev_on_rc;
+ }
+ }
+ if (debug >= 1) {
+ gprintk("Not find device at rc(%d)\n", rc);
+ }
+ return NULL;
+}
+
+/*
+ * Function: p2p_bridge
+ *
+ * Purpose:
+ * Finalize initialization secondary PCI-PCI bridge.
+ * Parameters:
+ * membase - start of memory address space for secondary PCI bus
+ * Returns:
+ * 0
+ * Notes:
+ * The membase depends on the processor architecture, and is
+ * derived from the memory space addresses set up by the kernel.
+ */
+static int
+p2p_bridge(void)
+{
+ struct pci_dev *dev, *dev_on_rc;
+ uint16 cmd;
+ uint16 mem_base;
+ uint16 mem_limit;
+ uint8 bridge_ctrl;
+ uint8 rc_index;
+
+ if ((dev = PCI_FIND_DEV(DC21150_VENDOR_ID, DC21150_DEVICE_ID, NULL)) != NULL ||
+ (dev = PCI_FIND_DEV(HINT_HB4_VENDOR_ID, HINT_HB4_DEVICE_ID, NULL)) != NULL ||
+ (dev = PCI_FIND_DEV(PI7C8150_VENDOR_ID, PI7C8150_DEVICE_ID, NULL)) != NULL) {
+
+ if (debug >= 1) gprintk("fixing up PCI-to-PCI bridge\n");
+ /* Adjust command register */
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ /* Disable device */
+ pci_write_config_word(dev, PCI_COMMAND, 0);
+ /* Initialize non-prefetchable memory window if needed */
+ pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base);
+ if (mem_base == 0) {
+ mem_base = (uint16)((_pci_mem_start & 0xFFF00000) >> 16);
+ mem_limit = (uint16)((_pci_mem_end & 0xFFF00000) >> 16);
+ pci_write_config_word(dev, PCI_MEMORY_BASE, mem_base);
+ pci_write_config_word(dev, PCI_MEMORY_LIMIT, mem_limit);
+ }
+ /* Enable PCI clocks on remote end */
+ pci_write_config_word(dev, PCI_CFG_DEC21150_SEC_CLK, 0);
+ /* Re-enable config space */
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+ /* Avoid DMA data corruption */
+ if (dev->vendor == HINT_HB4_VENDOR_ID) {
+ /* Fix for HiNT bridge and BCM4704 DMA problem */
+ if ((dev = PCI_FIND_DEV(BCM4704_VENDOR_ID, BCM4704_DEVICE_ID, NULL)) != NULL) {
+ /* Reset PrefetchEn (PE) */
+ pci_write_config_dword(dev, 0x8c, 1);
+ if (debug >= 1) {
+ gprintk("reset PrefetchEn on BCM4704 when HiNT bridge is present\n");
+ }
+ }
+ }
+ }
+ /* Enable fast back-to-back read/write */
+ if ((dev = PCI_FIND_DEV(PI7C8150_VENDOR_ID, PI7C8150_DEVICE_ID, NULL)) != NULL) {
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_FAST_BACK;
+ pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bridge_ctrl);
+ bridge_ctrl |= PCI_BRIDGE_CTL_FAST_BACK;
+ pci_write_config_word(dev, PCI_COMMAND, 0);
+ pci_write_config_byte(dev, PCI_BRIDGE_CONTROL, bridge_ctrl);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ /* Netlogic XLP CPU */
+ for(rc_index = 0; rc_index < MAX_RC_NUM; rc_index++) {
+ dev_on_rc = pci_do_rc_dev_find(rc_index);
+ if (dev_on_rc != NULL ) {
+ dev = PCI_FIND_DEV(0x184e, 0x1004, NULL);
+ if (dev != NULL ) {
+ pci_write_config_dword(dev,0x78,MAX_PAYLOAD_256B |
+ MAX_READ_REQ_256B);
+ }
+ }
+ }
+ if ((dev = PCI_FIND_DEV(0x14e4, 0xb634, NULL)) != NULL) {
+ pci_write_config_dword(dev,0x78,MAX_PAYLOAD_256B |
+ MAX_READ_REQ_256B);
+ }
+
+ if ((dev = PCI_FIND_DEV(PCI_VNDID_PERICOM, PCI_DEVID_PI7C9X130, NULL)) != NULL) {
+ /*
+ * Configure the PCIE cap: Max payload size: 256, Max Read
+ * Request size: 256, disabling relax ordering.
+ * Writes to the PCIE capability device control register
+ */
+ pci_write_config_dword(dev, DEV_CTRL_REG,
+ MAX_PAYLOAD_256B | MAX_READ_REQ_256B);
+ }
+
+ if ((dev = PCI_FIND_DEV(FSL_VENDOR_ID, FSL8548PCIE_DEVICE_ID, NULL)) != NULL ||
+ (dev = PCI_FIND_DEV(FSL_VENDOR_ID, FSL2020EPCIE_DEVICE_ID, NULL)) != NULL) {
+ /*
+ * Configure the PCIE cap: Max payload size: 256, Max Read
+ * Request size: 256, disabling relax ordering.
+ * Writes to the PCIE capability device control register
+ */
+ pci_write_config_dword(dev, FSL8548PCIE_DEV_CTRL_REG,
+ MAX_PAYLOAD_256B | MAX_READ_REQ_256B);
+ }
+ if ((dev = PCI_FIND_DEV(BCM4716_VENDOR_ID, BCM4716PCIE_DEVICE_ID, NULL)) != NULL ||
+ (dev = PCI_FIND_DEV(BCM53000_VENDOR_ID, BCM53000PCIE_DEVICE_ID, NULL)) != NULL) {
+ uint32 tmp, maxpayld, device_bmp=0, mask;
+ unsigned long addr;
+ uint16 tmp16, tmp161;
+ int i, bus0 = -1, bus1 = -1, port;
+ struct pci_dev *pcie0, *pcie1;
+
+ pcie0 = dev;
+ bus0 = dev->bus->number;
+ if ((pcie1 = PCI_FIND_DEV(BCM53000_VENDOR_ID, BCM53000PCIE_DEVICE_ID, pcie0)) != NULL) {
+ bus1 = pcie1->bus->number;
+ }
+
+ for(i = 0; i < _ndevices; i++) {
+ bde_ctrl_t *ctrl = _devices + i;
+
+ mask = BDE_SWITCH_DEV_TYPE | BDE_PCI_DEV_TYPE;
+ if ((ctrl->dev_type & mask) == mask) {
+ if (ctrl->pci_device->bus->number == bus0) {
+ device_bmp |= 1 << 0;
+ }
+ if (ctrl->pci_device->bus->number == bus1) {
+ device_bmp |= 1 << 1;
+ }
+ }
+ }
+
+ /* configure the PCIE cap: Max payload size: 256, Max Read
+ * Request size: 256, disabling relax ordering.
+ * Writes to the PCIE capability device control register
+ */
+
+ i = 0;
+ while(device_bmp) {
+ if (device_bmp & (1 << i)){
+ port = i ;
+ pci_read_config_dword(BCM53000PCIE_DEV(port),
+ BCM53000PCIE_DEV_CAP_REG, &tmp);
+ maxpayld = (tmp & BCM53000PCIE_MAX_PAYLOAD_MASK);
+ if (debug >= 1) {
+ gprintk("port %d\n",port);
+ gprintk("DevCap (@%x): 0x%x%c\n", BCM53000PCIE_DEV_CAP_REG, tmp,
+ (maxpayld != BCM53000PCIE_CAP_MAX_PAYLOAD_256B) ? ' ':'\n');
+ }
+ if (maxpayld != BCM53000PCIE_CAP_MAX_PAYLOAD_256B) {
+ addr = BCM53000PCIE_BASE(port);
+ addr |= (BCM53000PCIE_SROM_SPACE | BCM53000PCIE_SPROM_OFFSET);
+ tmp16 = *((uint16 *)addr);
+ if (debug >= 1){
+ gprintk("addr %lx spromData.MaxPayloadSize: 0x%x\n", addr, tmp16);
+ }
+ mask = BCM53000PCIE_SPROM_MAX_PAYLOAD_MASK;
+ if ((tmp16 & mask) != BCM53000PCIE_SPROM_MAX_PAYLOAD_256B) {
+ tmp161 = (tmp16 & ~mask) | BCM53000PCIE_SPROM_MAX_PAYLOAD_256B;
+ *((uint16 *)addr) = tmp161;
+ if (debug >= 1) {
+ tmp16 = 0;
+ tmp16 = *((uint16 *)addr);
+ gprintk("Enable spromData.MaxPayloadSize to 1 (256 bytes): "
+ "0x%x (%s w/ 0x%x)\n", tmp161,
+ ((tmp16 & mask) == BCM53000PCIE_SPROM_MAX_PAYLOAD_256B) ?
+ "Success":"Fail",
+ tmp16);
+ }
+ }
+ pci_read_config_dword(BCM53000PCIE_DEV(port),
+ BCM53000PCIE_DEV_CAP_REG, &tmp);
+ if (debug >= 1){
+ gprintk("DevCap (@%x): now is 0x%x\n\n",
+ BCM53000PCIE_DEV_CAP_REG, tmp);
+ }
+ }
+
+ addr = BCM53000PCIE_BASE(port);
+ addr |= (BCM53000PCIE_FUNC0_COFIG_SPACE | BCM53000PCIE_DEV_CTRL_REG);
+ tmp16 = *((uint16 *)addr);
+ if (debug >= 1) {
+ gprintk("DevControl (@%x): 0x%x\n", BCM53000PCIE_DEV_CTRL_REG, tmp16);
+ }
+ if (!(tmp16 & MAX_PAYLOAD_256B) || !(tmp16 & MAX_READ_REQ_256B)) {
+ tmp161 = tmp16 | MAX_PAYLOAD_256B | MAX_READ_REQ_256B;
+ *((uint16 *)addr) = tmp161;
+ if (debug >= 1) {
+ tmp16 = 0;
+ tmp16 = *((uint16 *)addr);
+ gprintk("addr %lx Enable DevControl MaxPayloadSize to 1 (256 bytes): "
+ "0x%x (%s w/ 0x%x)\n", addr, tmp161,
+ (tmp16 & MAX_PAYLOAD_256B) ? "Success":"Fail",
+ tmp16);
+ gprintk("Enable DevControl MaxReadRequestSize to 1 (256 bytes): "
+ "0x%x (%s w/ 0x%x)\n\n", tmp161,
+ (tmp16 & MAX_READ_REQ_256B) ? "Success":"Fail",
+ tmp16);
+ }
+ }
+ device_bmp &= ~(1 << i);
+ }
+ i++;
+ }
+ }
+
+ /*
+ * Configure max payload to 512 on all ports in the PLX8608/PLX8617.
+ * The device supports 128, 512, and 1024 max payload sizes.
+ */
+ dev = NULL;
+ while ((dev = PCI_FIND_DEV(PCI_VENDOR_ID_PLX, PCI_ANY_ID, dev)) != NULL) {
+ if ((dev->device == PLX_PEX8608_DEV_ID) ||
+ (dev->device == PLX_PEX8617_DEV_ID)) {
+ uint16 ctrl_reg;
+ pci_read_config_word(dev, PLX_PEX86XX_DEV_CTRL_REG, &ctrl_reg);
+ ctrl_reg = (ctrl_reg & ~(7<<5)) | MAX_PAYLOAD_512B;
+ pci_write_config_word(dev, PLX_PEX86XX_DEV_CTRL_REG, ctrl_reg);
+ }
+ }
+ return 0;
+}
+
+#ifdef BCM_PLX9656_LOCAL_BUS
+
+#define PLX_LAS0_BA 0x00000004 /* LAS0 Local Base Address Remap */
+#define PLX_LAS1_BA 0x000000f4 /* LAS1 Local Base Address Remap */
+#define PLX_LAS_EN 0x00000001 /* Space Enable bit */
+
+#define PLX_MMAP_PCIBAR0 0 /* Memory-Mapped Config (PCIBAR0) */
+#define PLX_LAS0_PCIBAR2 2 /* Local Address Space 0 (PCIBAR2) */
+#define PLX_LAS1_PCIBAR3 3 /* Local Address Space 1 (PCIBAR3) */
+
+STATIC int
+_plx_las_bar_get(struct pci_dev *dev)
+{
+ void *local_config_addr;
+ int bar = -1;
+
+ local_config_addr = IOREMAP(pci_resource_start(dev, PLX_MMAP_PCIBAR0),
+ pci_resource_len(dev, PLX_MMAP_PCIBAR0));
+ if (local_config_addr) {
+ uint32 las_remap_reg;
+ /*
+ * Make sure LAS0BA or LAS1BA is enabled before returning
+ * BAR that will be used to access the Local Bus
+ */
+ las_remap_reg = ioread32(local_config_addr + PLX_LAS0_BA);
+ if (las_remap_reg & PLX_LAS_EN) {
+ bar = PLX_LAS0_PCIBAR2;
+ } else {
+ las_remap_reg = ioread32(local_config_addr + PLX_LAS1_BA);
+ if (las_remap_reg & PLX_LAS_EN) {
+ bar = PLX_LAS1_PCIBAR3;
+ }
+ }
+ }
+ iounmap(local_config_addr);
+ return bar;
+}
+#endif /* BCM_PLX9656_LOCAL_BUS */
+
+static void
+_shbde_log_func(int level, const char *str, int param)
+{
+ level = (level >= SHBDE_DBG) ? 1 : 0;
+ if (debug >= level) {
+ gprintk("%s (%d)\n", str, param);
+ }
+}
+/*
+ * Function: _device_rescan_validate
+ *
+ * Purpose:
+ * Check if the device is ever probed or not.
+ * Parameters:
+ * dev - Linux PCI device structure
+ * Returns:
+ * >= 0 : dev is ever probed
+ * reutrn value is the index point to the _devices[]
+ * -1 : dev is not probed before.
+ */
+static int
+_device_rescan_validate(struct pci_dev *dev)
+{
+ bde_ctrl_t *ctrl;
+ int i;
+
+ if (PCI_FUNC(dev->devfn) > 0) {
+ return -1;
+ }
+ ctrl = NULL;
+ for (i = 0; i < _ndevices; i ++) {
+ ctrl = _devices + i;
+ /* check the device id */
+ if (dev->device == ctrl->bde_dev.device) {
+ /* check the bus number */
+ if ((dev->bus)) {
+ if ((dev->bus->number == ctrl->bus_no) &&
+ (pci_domain_nr(dev->bus) == ctrl->domain_no)) {
+ return i;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+#ifdef CONFIG_PCI_MSI
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+/**
+ * _pci_msix_table_size - return the number of device's MSI-X table entries
+ * @dev: pointer to the pci_dev data structure of MSI-X device function
+ */
+static int
+_pci_msix_table_size(struct pci_dev *dev)
+{
+ int nr_entries = 0;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,110))
+ u16 control;
+ int pos;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+ if (pos) {
+ pci_read_config_word(dev, msi_control_reg(pos), &control);
+ nr_entries = msix_table_size(control);
+ }
+#else
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0))
+{
+ /* Pass large entry value to enable MSIX to get # of entires */
+ struct msix_entry *entries;
+ entries = kmalloc(sizeof(struct msix_entry) *
+ PCI_MSIX_FLAGS_QSIZE, GFP_KERNEL);
+ if (entries != NULL) {
+ nr_entries = pci_enable_msix(dev,
+ entries, PCI_MSIX_FLAGS_QSIZE);
+ if (nr_entries < 0) {
+ nr_entries = 0;
+ }
+ pci_disable_msix(dev);
+ kfree(entries);
+ }
+}
+#else
+ nr_entries = pci_msix_vec_count(dev);
+#endif
+#endif
+
+ return nr_entries;
+}
+#endif
+
+static int
+_msi_connect(bde_ctrl_t *ctrl)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+ int ret;
+ if (ctrl->use_msi == PCI_USE_INT_MSIX) {
+ int i;
+
+ ret = _pci_msix_table_size(ctrl->pci_device);
+ if (ret == 0) {
+ /* MSI-X failed */
+ gprintk("MSI-X not supported.\n");
+ goto er_intx;
+ }
+ ctrl->entries = kcalloc(ret, sizeof(struct msix_entry), GFP_KERNEL);
+
+ if (!ctrl->entries) {
+ goto er_intx;
+ }
+ /* Only one vector is mapped by default */
+ /* May be more in future, can be controlled using module param */
+ ctrl->msix_cnt = msixcnt;
+ if (unlikely(debug > 1))
+ gprintk("MSIX Table size = %d\n", ctrl->msix_cnt);
+ for (i = 0; i < ctrl->msix_cnt; i++)
+ ctrl->entries[i].entry = i;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0)
+ ret = pci_enable_msix_range(ctrl->pci_device,
+ ctrl->entries, ctrl->msix_cnt, ctrl->msix_cnt);
+#else
+ ret = pci_enable_msix(ctrl->pci_device,
+ ctrl->entries, ctrl->msix_cnt);
+ if (ret > 0) {
+ /* Not enough vectors available , Retry MSI-X */
+ gprintk("Retrying with MSI-X interrupts = %d\n", ret);
+ ctrl->msix_cnt = ret;
+ msixcnt = ret;
+ ret = pci_enable_msix(ctrl->pci_device,
+ ctrl->entries, ctrl->msix_cnt);
+ if (ret != 0)
+ goto er_intx_free;
+ }
+#endif
+ if (ret < 0) {
+ /* Error */
+ goto er_intx_free;
+ } else {
+ gprintk("Enabled MSI-X interrupts = %d\n", ctrl->msix_cnt);
+ return 0;
+ }
+ }
+#endif
+
+ if (ctrl->use_msi == PCI_USE_INT_MSI) {
+ if (pci_enable_msi(ctrl->pci_device) == 0) {
+ ctrl->iLine = ctrl->pci_device->irq;
+ } else {
+ /* MSI failed */
+ gprintk("Failed to initialize MSI interrupts.\n");
+ goto er_intx;
+ }
+ } else {
+ /* failed */
+ gprintk("Not MSI/MSIX interrupt.\n");
+ goto er_intx;
+ }
+ return 0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+er_intx_free:
+ gprintk("Failed to enable MSI-X interrupts = %d\n", ret);
+ kfree(ctrl->entries);
+#endif
+er_intx:
+ return -1;
+
+}
+
+static int
+_msi_disconnect(bde_ctrl_t *ctrl)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+ if (ctrl->use_msi == PCI_USE_INT_MSIX) {
+ if (ctrl->msix_cnt) {
+ pci_disable_msix(ctrl->pci_device);
+ kfree(ctrl->entries);
+ ctrl->entries = NULL;
+ ctrl->msix_cnt = 0;
+ }
+ }
+#endif
+ if (ctrl->use_msi == PCI_USE_INT_MSI) {
+ pci_disable_msi(ctrl->pci_device);
+ } else {
+ gprintk("MSI not used\n");
+ }
+ return 0;
+}
+
+#endif
+
+
+static void
+config_pci_intr_type(struct pci_dev *dev, bde_ctrl_t *ctrl, int iproc)
+{
+#ifdef CONFIG_PCI_MSI
+ int ret;
+ shbde_iproc_config_t icfg;
+
+ /* Each device follows global policy by default */
+ ctrl->use_msi = use_msi;
+
+ if (unlikely(debug > 1))
+ gprintk("%s: msi = %d\n", __func__, ctrl->use_msi);
+
+ /* Check IPROC version for MSIX support */
+ if (iproc && ctrl->bde_dev.base_address1 &&
+ (ctrl->use_msi == PCI_USE_INT_MSIX)) {
+ if (shbde_pci_iproc_version_get(&ctrl->shbde, dev, &icfg.iproc_ver,
+ &icfg.cmic_ver, &icfg.cmic_rev)) {
+ if (icfg.iproc_ver < 0xe) {
+ gprintk("%s: MSI-X not supported, using MSI.\n", __func__);
+ ctrl->use_msi = PCI_USE_INT_MSI;
+ }
+ }
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+ if (ctrl->use_msi == PCI_USE_INT_MSIX) {
+ /* check for support MSIX vector */
+ ret = _pci_msix_table_size(ctrl->pci_device);
+ if (ret == 0) {
+ gprintk("%s: Zero MSIX table size\n", __func__);
+ ctrl->use_msi = PCI_USE_INT_MSI;
+ }
+ }
+#endif
+
+ if (ctrl->use_msi == PCI_USE_INT_MSI) {
+ /* check for support MSI vector */
+ ret = pci_enable_msi(ctrl->pci_device);
+ if (ret < 0) {
+ ctrl->use_msi = PCI_USE_INT_INTX;
+ gprintk("%s: Failed to enable MSI, using INTx.\n", __func__);
+ } else {
+ pci_disable_msi(ctrl->pci_device);
+ }
+ }
+#else
+ ctrl->use_msi = PCI_USE_INT_INTX;
+#endif
+}
+
+/*
+ * Function: _pci_probe
+ *
+ * Purpose:
+ * Device initialization callback used by the Linux PCI
+ * subsystem. Called as a result of pci_register_driver().
+ * Parameters:
+ * dev - Linux PCI device structure
+ * Returns:
+ * 0
+ */
+static int
+_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
+{
+ bde_ctrl_t *ctrl;
+ resource_size_t paddr;
+ uint16 cmd = 0;
+ uint32 bar_len;
+ int cmic_bar;
+ int baroff = 0;
+ int iproc = 0;
+ int plx_dev = 0;
+ int eth_dev = 0;
+ int cpu_dev = 0;
+ int update_devid = 0;
+ int paxb_core = 0;
+ int add_dev = 0, rescan = 0, rescan_idx = -1;
+ shbde_hal_t shared_bde, *shbde = &shared_bde;
+
+ if (debug >= 4) {gprintk("probing: vendor_id=0x%x, device_id=0x%x\n", dev->vendor, dev->device);}
+ if (nodevices == 1) {
+ return 0;
+ }
+
+ /* Initialize Linux hardware abstraction for shared BDE functions */
+ linux_shbde_hal_init(shbde, _shbde_log_func);
+
+ /*
+ * If an AXI-based switch device has been found already, then it means
+ * that the AXI bus has been probed, and that we should ignore devices
+ * found on PCI bus zero.
+ */
+
+#if defined(IPROC_CMICD)
+ if ((dev->bus) && (dev->bus->number == 0)) {
+ int i;
+ uint32 mask = BDE_SWITCH_DEV_TYPE | BDE_AXI_DEV_TYPE;
+
+ for (i = 0; i < _ndevices; i++) {
+ ctrl = _devices + i;
+
+ if ((ctrl->dev_type & mask) == mask) {
+ return 0;
+ }
+ }
+ }
+#endif /* IPROC_CMICD */
+
+ /*
+ * Note that a few supported devices have a non-Broadcom PCI vendor ID,
+ * but since none of their associated PCI device IDs collide with the
+ * Broadcom device IDs, the probe code below only checks the device ID.
+ */
+
+ switch (dev->device) {
+ case PCI_DEVICE_ID_PLX_9056:
+#ifdef DNX_TEST_BOARD
+ break; /* a PCIe bridge to a non PCIe device should be treated as the device */
+#endif /* DNX_TEST_BOARD */
+ case PCI_DEVICE_ID_PLX_9656:
+ plx_dev = 1;
+ break;
+ case BCM53000PCIE_DEVICE_ID:
+ cpu_dev = 1;
+ break;
+ /*
+ * The device ID for 56500, 56100 and 56300 family of devices may
+ * be incorrect just after a PCI HW reset. It needs to be read
+ * again after stabilization.
+ */
+ case BCM56102_DEVICE_ID:
+ case BCM56504_DEVICE_ID:
+ case BCM56304_DEVICE_ID:
+ case BCM56314_DEVICE_ID:
+ case BCM56112_DEVICE_ID:
+ update_devid = 1;
+ break;
+ default:
+ break;
+ }
+
+ /* Check if the device is ever probed. */
+ rescan_idx = _device_rescan_validate(dev);
+ if (rescan_idx != -1) {
+ rescan = 1;
+ }
+
+ ctrl = NULL;
+ if (plx_dev) {
+#if defined(BCM_PLX9656_LOCAL_BUS)
+ /* PLX chip itself won't be part of _devices[]. */
+ baroff = _plx_las_bar_get(dev);
+ if (baroff == -1) {
+ gprintk("No Local Address Space enabled in PLX\n");
+ return 0;
+ }
+ ctrl = &plx_ctrl;
+ num_plx++;
+#endif
+ } else if (eth_dev) {
+ if (_ether_ndevices >= LINUX_BDE_MAX_ETHER_DEVICES) {
+ return 0;;
+ }
+ ctrl = _devices + _ndevices;
+ ctrl->dev_type |= BDE_ETHER_DEV_TYPE;
+ ctrl->iLine = dev->irq;
+ add_dev = 1;
+ if (debug >= 1)
+ gprintk("Found PCI device %04x:%04x as Ethernet device\n",
+ dev->vendor, dev->device);
+ } else if (cpu_dev) {
+ if (_cpu_ndevices >= LINUX_BDE_MAX_CPU_DEVICES) {
+ return 0;;
+ }
+ ctrl = _devices + _ndevices;
+ ctrl->dev_type |= BDE_CPU_DEV_TYPE;
+ add_dev = 1;
+ if (debug >= 1)
+ gprintk("Found PCI device %04x:%04x as CPU device\n",
+ dev->vendor, dev->device);
+ } else {
+ if (PCI_FUNC(dev->devfn) > 0) {
+ return 0;
+ }
+ if (_switch_ndevices >= LINUX_BDE_MAX_SWITCH_DEVICES) {
+ return 0;
+ }
+
+ if (rescan) {
+ if (debug >= 1) {
+ gprintk("PCI device %04x:%04x is re-probed \n",
+ dev->vendor, dev->device);
+ }
+ ctrl = _devices + rescan_idx;
+ ctrl->dev_state = BDE_DEV_STATE_CHANGED;
+ } else {
+ ctrl = _devices + _ndevices;
+ ctrl->dev_type |= BDE_SWITCH_DEV_TYPE;
+ ctrl->domain_no = pci_domain_nr(dev->bus);
+ ctrl->bus_no = dev->bus->number;
+ ctrl->dev_state = BDE_DEV_STATE_NORMAL;
+ add_dev = 1;
+ }
+
+ /* Save shared BDE HAL in device structure */
+ MEMCPY(&ctrl->shbde, shbde, sizeof(ctrl->shbde));
+
+ if (update_devid) {
+ /* Re-read the device ID */
+ pci_read_config_word(dev,
+ PCI_DEVICE_ID,
+ &ctrl->bde_dev.device);
+ dev->device = ctrl->bde_dev.device;
+ }
+
+ if (debug >= 4) {gprintk("Enabling PCI device : vendor_id=0x%x, device_id=0x%x\n", dev->vendor, dev->device);}
+ if (pci_enable_device(dev)) {
+ gprintk("Cannot enable PCI device : vendor_id = %x, device_id = %x\n",
+ dev->vendor, dev->device);
+ }
+
+ /* FIXME: "workarounds" previously called "total h_acks" */
+ /*
+ * These are workarounds to get around some existing
+ * kernel problems :(
+ */
+
+ /*
+ * While probing we determine the overall limits for the PCI
+ * memory windows across all devices. These limits are used
+ * later on by the PCI-PCI bridge code.
+ */
+ if (pci_resource_start(dev, baroff) < _pci_mem_start) {
+ _pci_mem_start = pci_resource_start(dev, baroff);
+ }
+ if (pci_resource_end(dev, baroff) > _pci_mem_end) {
+ _pci_mem_end = pci_resource_end(dev, baroff);
+ }
+
+#ifdef CONFIG_SANDPOINT
+ /*
+ * Something wrong with the PCI subsystem in the mousse kernel.
+ * The device is programmed correctly, but the irq in the pci
+ * structure is hosed. This checks for the hosed-ness and fixes it.
+ */
+ if (dev->irq > 100) {
+ dev->irq = 2;
+ gprintk("irq problem: setting irq = %d\n", dev->irq);
+ }
+#endif
+
+#ifdef CONFIG_BMW
+ /*
+ * PCI subsystem does not always program the system correctly.
+ */
+ if (dev->irq < 16 && dev->irq != 2) {
+ dev->irq = 2;
+ gprintk("irq problem: setting irq = %d\n", dev->irq);
+ }
+#endif
+
+#ifdef CONFIG_IDT_79EB334
+ /*
+ * IDT kernel is not currently mapping interrupts correctly
+ * Hardwired to core mips interrupt, irq 3 for kernel 2.4.18
+ */
+ if (dev->irq != 3) {
+ dev->irq = 3;
+ gprintk("irq problem: setting irq = %d\n", dev->irq);
+ }
+#endif
+
+#ifdef CONFIG_BCM94702_CPCI
+ /*
+ * Hardwired to core mips interrupt irq 6 on MBZ
+ */
+ if (dev->irq != 6) {
+ dev->irq = 6;
+ gprintk("irq problem: setting irq = %d\n", dev->irq);
+ }
+#endif
+
+ if ((PCI_FIND_DEV(BCM4704_VENDOR_ID, BCM4704_DEVICE_ID, NULL)) != NULL) {
+ /*
+ * Decrease the PCI bus priority for the CPU for better overall
+ * system performance. This change significantly reduces the
+ * number of PCI retries from other devices on the PCI bus.
+ */
+ void * _mc_vbase = IOREMAP(BCM4704_MEMC_BASE, 0x1000);
+ int priorinv = 0x80;
+ static int done = 0;
+ if (!done) {
+ done = 1;
+ writel(priorinv, _mc_vbase + BCM4704_MEMC_PRIORINV);
+ if (debug >= 1)
+ gprintk("set BCM4704 PriorInvTim register to 0x%x\n", priorinv);
+ iounmap(_mc_vbase);
+ }
+ }
+
+ if ((PCI_FIND_DEV(SIBYTE_PCI_VENDOR_ID, SIBYTE_PCI_DEVICE_ID, NULL)) != NULL) {
+ /*
+ * The BCM91125CPCI CPU boards with a PCI-PCI bridge use the same
+ * interrupt line for all switch ships behind the bridge.
+ */
+ if (PCI_FIND_DEV(DC21150_VENDOR_ID, DC21150_DEVICE_ID, NULL) ||
+ PCI_FIND_DEV(HINT_HB4_VENDOR_ID, HINT_HB4_DEVICE_ID, NULL) ||
+ PCI_FIND_DEV(PI7C8150_VENDOR_ID, PI7C8150_DEVICE_ID, NULL)) {
+ /*
+ * By default we try to guess the correct IRQ based on the design.
+ * For now we only look at the bridge vendor, but it may be necessary
+ * to look at the switch chip configuration as well.
+ */
+ if (forceirq == -1) {
+ if ((PCI_FIND_DEV(HINT_HB4_VENDOR_ID, HINT_HB4_DEVICE_ID, NULL)) ||
+ ((dev->device == BCM5674_DEVICE_ID) &&
+ (PCI_FIND_DEV(PI7C8150_VENDOR_ID, PI7C8150_DEVICE_ID, NULL)))) {
+ forceirq = 58;
+ } else {
+ forceirq = 56;
+ }
+ }
+ }
+ }
+
+ if (((PCI_FIND_DEV(BCM58525_PCI_VENDOR_ID, BCM58525_PCI_DEVICE_ID, NULL)) != NULL) ||
+ ((PCI_FIND_DEV(BCM58525_PCI_VENDOR_ID, BCM58522_PCI_DEVICE_ID, NULL)) != NULL) ||
+ ((PCI_FIND_DEV(BCM58712_PCI_VENDOR_ID, BCM58712_PCI_DEVICE_ID, NULL)) != NULL) ) {
+ /* BCM58525/BCM58712 CPU boards support 128 Max payload size */
+ if (maxpayload) {
+ maxpayload = 128;
+ if (debug >= 1) gprintk("force max payload size to 128\n");
+ }
+ }
+
+ if (forceirq > 0 && dev->irq != (uint32) forceirq) {
+ if (forceirqubm & (1U << (_ndevices - 1))) {
+ dev->irq = forceirq;
+ if (debug >= 1) gprintk("force irq to %d\n", forceirq);
+ }
+ } else if (debug >= 1) gprintk("found irq %d\n", dev->irq);
+
+ ctrl->iLine = dev->irq;
+ if (unlikely(debug > 1))
+ gprintk("%s:irq = %d\n",__func__, ctrl->iLine);
+
+ if (shbde_pci_is_pcie(shbde, dev)) {
+ /* Set PCIe max payload */
+ shbde_pci_max_payload_set(shbde, dev, maxpayload);
+ } else {
+ /* Set PCI retry to infinite on non-PCIe switch device */
+ pci_write_config_word(dev, 0x40, 0x0080);
+ if (debug >= 1) gprintk("set DMA retry to infinite on switch device\n");
+ }
+ }
+
+#if defined(BCM_DFE_SUPPORT)
+ switch (dev->device) {
+ case BCM88750_DEVICE_ID:
+ case BCM88753_DEVICE_ID:
+ case BCM88755_DEVICE_ID:
+ case BCM88770_DEVICE_ID:
+ case BCM88773_DEVICE_ID:
+ case BCM88774_DEVICE_ID:
+ case BCM88775_DEVICE_ID:
+ case BCM88776_DEVICE_ID:
+ case BCM88777_DEVICE_ID:
+ case BCM88950_DEVICE_ID:
+ case BCM88953_DEVICE_ID:
+ case BCM88954_DEVICE_ID:
+ case BCM88955_DEVICE_ID:
+ case BCM88956_DEVICE_ID:
+ case BCM88752_DEVICE_ID:
+ case BCM88772_DEVICE_ID:
+ case BCM88952_DEVICE_ID:
+
+ /*
+ * For DMA transactions - set Max_Payload_Size and
+ * Max_Read_Request_Size to 128 bytes.
+ */
+ pci_write_config_byte(dev, 0xb5, 0x0c);
+ pci_write_config_byte(dev, 0xb4, 0x0);
+ break;
+ default:
+ break;
+ }
+#endif /* BCM_DFE_SUPPORT */
+
+#if defined(BCM_DNXF_SUPPORT)
+ /*All Ramon devices from 0x8790 to 0x879F*/
+ if ((dev->device & BCM_DNXF_DEVID_MASK) == BCM88790_DEVICE_ID) {
+ /*
+ * For DMA transactions - set Max_Payload_Size and
+ * Max_Read_Request_Size to 128 bytes.
+ */
+ pci_write_config_byte(dev, 0xb5, 0x0c);
+ pci_write_config_byte(dev, 0xb4, 0x0);
+
+ }
+#endif
+
+ /* Prevent compiler warning */
+ if (ctrl == NULL) {
+ return 0;
+ }
+
+ ctrl->be_pio = 0;
+ ctrl->dev_type |= BDE_PCI_DEV_TYPE;
+ ctrl->pci_device = dev;
+ pci_set_drvdata(dev, ctrl);
+
+ /* Check for iProc device */
+ if (shbde_pci_is_iproc(shbde, dev, &cmic_bar)) {
+ iproc = 1;
+ if (cmic_bar >= 0) {
+ baroff = cmic_bar;
+ }
+ }
+#ifdef DNX_TEST_BOARD
+ else if (dev->device == PLX9056_DEVICE_ID && baroff == 0) {
+ baroff = 2;
+ ctrl->dev_type |= BDE_NO_IPROC/* | BDE_BYTE_SWAP*/;
+ }
+#endif /* DNX_TEST_BOARD */
+
+ /* Get the device revision */
+ pci_read_config_byte(dev, PCI_REVISION_ID, &ctrl->bde_dev.rev);
+
+ /* Map in the device */
+ ctrl->bde_dev.device = dev->device;
+ paddr = pci_resource_start(dev, baroff);
+
+ switch (dev->device) {
+#if defined(BCM_PETRA_SUPPORT) && defined(__DUNE_LINUX_BCM_CPU_PCIE__)
+ case GEDI_DEVICE_ID:
+ case PCP_PCI_DEVICE_ID:
+ bar_len = 0x1000000;
+ break;
+#endif
+ default:
+ bar_len = pci_resource_len(dev, baroff);
+ break;
+ }
+
+ ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(paddr, bar_len);
+ ctrl->phys_address = paddr;
+ if (debug >= 3) {
+ gprintk("BAR %d: kernel addr:0x%lx phys addr:0x%lx length:%lx\n",
+ baroff, (unsigned long)ctrl->bde_dev.base_address, (unsigned long)paddr, (unsigned long)bar_len);
+ }
+
+ /* Map secondary address spaces */
+ if (iproc
+#ifdef DNX_TEST_BOARD
+ || (dev->device == PLX9056_DEVICE_ID && baroff == 2)
+#endif /* DNX_TEST_BOARD */
+ ) {
+ paddr = pci_resource_start(dev, 0);
+ bar_len = pci_resource_len(dev, 0);
+ ctrl->bde_dev.base_address1 = (sal_vaddr_t)IOREMAP(paddr, bar_len);
+ ctrl->phys_address1 = paddr;
+ if (debug >= 3) {
+ gprintk("BAR 0: kernel addr:0x%lx phys addr:0x%lx length:%lx\n",
+ (unsigned long)ctrl->bde_dev.base_address1, (unsigned long)paddr, (unsigned long)bar_len);
+ }
+ }
+
+ /* configure interrupt type */
+ config_pci_intr_type(dev, ctrl, iproc);
+
+ /* Configure iProc PCI-AXI bridge */
+ if (iproc && ctrl->bde_dev.base_address1) {
+ void *iproc_regs;
+ shbde_iproc_config_t *icfg = &shbde->icfg;
+
+ /* Mapped iProc regs in PCI BAR 0 */
+ iproc_regs = (void *)ctrl->bde_dev.base_address1;
+
+ /* iProc configuration parameters */
+ (void)shbde_pci_iproc_version_get(shbde, dev, &icfg->iproc_ver,
+ &icfg->cmic_ver, &icfg->cmic_rev);
+ shbde_iproc_config_init(icfg, ctrl->bde_dev.device, ctrl->bde_dev.rev);
+
+ if (debug >= 2) {
+ gprintk("iproc version = %x dma_hi_bits = %x\n", icfg->iproc_ver, icfg->dma_hi_bits);
+ }
+ icfg->use_msi = ctrl->use_msi;
+
+ /* Call shared function */
+ paxb_core = shbde_iproc_paxb_init(shbde, iproc_regs, icfg);
+
+ /* Save PCI core information for CMIC */
+ if (paxb_core == 1) {
+ ctrl->dev_type |= BDE_DEV_BUS_ALT;
+ }
+
+ /* Save MSI enable state information */
+ if (ctrl->use_msi) {
+ ctrl->dev_type |= BDE_DEV_BUS_MSI;
+ }
+
+ /* iProc PCIe preemphasis */
+ shbde_iproc_pcie_preemphasis_set(shbde, iproc_regs, icfg, dev);
+ }
+
+ /* Save shared BDE HAL in device structure */
+ MEMCPY(&ctrl->shbde, shbde, sizeof(ctrl->shbde));
+
+
+ ctrl->isr = NULL;
+ ctrl->isr_data = NULL;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ if (!(cmd & PCI_COMMAND_MEMORY) || !(cmd & PCI_COMMAND_MASTER)) {
+ cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ if (debug >= 1) gprintk("enable PCI resources 0x%x (PCI_COMMAND)\n", cmd);
+ }
+
+ /* Check if we need 256 KB memory window (default is 64 KB) */
+ bar_len = pci_resource_len(dev, baroff);
+ if (bar_len == 0x40000) {
+ ctrl->dev_type |= BDE_256K_REG_SPACE;
+ if (debug >= 1) gprintk("PCI resource len 256K\n");
+ } else if (bar_len == 0x800000) {
+ ctrl->dev_type |= BDE_256K_REG_SPACE | BDE_8MB_REG_SPACE;
+ if (debug >= 1) gprintk("PCI resource len 8MB\n");
+ }
+
+
+#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT
+ ctrl->dma_dev = &dev->dev;
+#endif
+
+ if (debug >= 2) {
+ gprintk("_pci_probe: configured dev:0x%x rev:0x%x with base_addresses: 0x%lx 0x%lx\n",
+ (unsigned)ctrl->bde_dev.device, (unsigned)ctrl->bde_dev.rev,
+ (unsigned long)ctrl->bde_dev.base_address, (unsigned long)ctrl->bde_dev.base_address1);
+ }
+
+ if (add_dev) {
+ _bde_add_device();
+ }
+ /* Let's boogie */
+ return 0;
+}
+
+/*
+ * Function: _pci_remove
+ *
+ * Purpose:
+ * Detach driver from device. Called from pci_unregister_driver().
+ * Parameters:
+ * dev - Linux PCI device structure
+ * Returns:
+ * 0
+ */
+static void
+_pci_remove(struct pci_dev* dev)
+{
+ bde_ctrl_t *ctrl;
+
+ if (nodevices == 1) {
+ return;
+ }
+
+#if defined(BCM_DFE_SUPPORT)
+ if (dev->device == PCI_DEVICE_ID_PLX_9056) {
+ return;
+ }
+#endif
+
+ ctrl = (bde_ctrl_t *) pci_get_drvdata(dev);
+
+ if (ctrl == NULL) {
+ /* Unused device */
+ return;
+ }
+ ctrl->dev_state = BDE_DEV_STATE_REMOVED;
+ if (debug >= 1) {
+ gprintk("PCI device %04x:%04x is removed. \n",
+ dev->vendor, dev->device);
+ }
+ if (ctrl->bde_dev.base_address1) {
+ iounmap((void *)ctrl->bde_dev.base_address1);
+ }
+ if (ctrl->bde_dev.base_address) {
+ iounmap((void *)ctrl->bde_dev.base_address);
+ }
+
+ /* Free our interrupt handler, if we have one */
+ if (ctrl->isr || ctrl->isr2) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+ if (ctrl->use_msi >= PCI_USE_INT_MSIX) {
+ int i;
+ for (i = 0; i < ctrl->msix_cnt; i++)
+ free_irq(ctrl->entries[i].vector, ctrl);
+ }
+ else
+#endif
+ {
+ free_irq(ctrl->iLine, ctrl);
+ }
+ }
+#ifdef CONFIG_PCI_MSI
+ _msi_disconnect(ctrl);
+#endif
+ ctrl->isr = NULL;
+ ctrl->isr_data = NULL;
+ ctrl->isr2 = NULL;
+ ctrl->isr2_data = NULL;
+}
+
+static struct pci_driver _device_driver = {
+ probe: _pci_probe,
+ remove: _pci_remove,
+ id_table: _id_table,
+ /* The rest are dynamic */
+};
+
+static void
+_spi_device_setup(void) {
+ bde_ctrl_t *ctrl;
+ ctrl = _devices + _ndevices;
+ ctrl->dev_type |= BDE_SWITCH_DEV_TYPE;
+ ctrl->iLine = 0xa3;
+ ctrl->be_pio = 0;
+ ctrl->dev_type |= BDE_SPI_DEV_TYPE;
+ ctrl->bde_dev.device = spi_devid;
+ ctrl->bde_dev.rev = spi_revid;
+ if (debug >= 1) {
+ gprintk("SPI Slave Mode: force ctrl->bde_dev.device=0x%x\n",ctrl->bde_dev.device);
+ gprintk("SPI Slave Mode: force ctrl->bde_dev.rev=0x%x\n",ctrl->bde_dev.rev);
+ gprintk("SPI Slave Mode: force ctrl->dev_type=0x%x\n",ctrl->dev_type);
+ }
+ _bde_add_device();
+}
+#endif /* BCM_ICS */
+
+
+
+
+#if defined(BCM_METROCORE_LOCAL_BUS)
+static bde_ctrl_t*
+map_local_bus(uint64_t addr, uint32_t size)
+{
+ bde_ctrl_t *ctrl;
+
+ ctrl = _devices + _ndevices;
+
+ /*
+ * For now: use EB type as `local bus'
+ * (memory mapped, no DMA, no interrupts)
+ * metrocore local bus supports interrupts, but we don't use them.
+ */
+ ctrl->dev_type |= BDE_EB_DEV_TYPE | BDE_SWITCH_DEV_TYPE
+ | (size > 64 * 1024 ? BDE_128K_REG_SPACE : 0);
+ ctrl->pci_device = NULL; /* No PCI bus */
+
+ /* Map in the device */
+ ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(addr, size);
+ ctrl->phys_address = addr;
+
+ _bde_add_device();
+ return(ctrl);
+}
+
+#define BME_REVISION_OFFSET (0x0)
+
+#endif
+
+#ifdef BCM_PLX9656_LOCAL_BUS
+
+#if 1
+#define DEV_REG_BASE_OFFSET PL0_OFFSET /* Polaris register base */
+#define DEV_REG_DEVID 0 /* Device ID is first register */
+#endif
+
+/*
+ * The difference at map_local_bus2:
+ *
+ * The PLX9656 PCI-to-LOCAL bridge chip already has been iomapped the
+ * whole address space. So the devices off local bus don't need to be
+ * mapped again. They only need to claim their own sub-space.
+ */
+static bde_ctrl_t *
+map_local_bus2(bde_ctrl_t *plx_ctrl, uint32_t dev_base, uint32_t size)
+{
+ uint32_t dev_rev_id;
+ uint8_t *addr;
+ bde_ctrl_t *ctrl;
+
+ ctrl = _devices + _ndevices;
+
+ /*
+ * For now: use EB type as `local bus'
+ * (memory mapped, no DMA, no interrupts)
+ * metrocore local bus supports interrupts, but we don't use them.
+ */
+ ctrl->dev_type |= BDE_EB_DEV_TYPE | BDE_SWITCH_DEV_TYPE;
+ ctrl->dev_type |= BDE_320K_REG_SPACE; /* Polaris 18 bits address + FPGA */
+ ctrl->pci_device = NULL; /* No PCI bus */
+
+ /* Map in the device */
+ ctrl->bde_dev.base_address = plx_ctrl->bde_dev.base_address + dev_base;
+ ctrl->phys_address = plx_ctrl->phys_address + (resource_size_t)dev_base;
+
+#if 1
+ addr = (uint8_t *)ctrl->bde_dev.base_address + PL0_REVISION_REG;
+#endif
+ dev_rev_id = readl(addr);
+ ctrl->bde_dev.device = dev_rev_id >> 16;
+ ctrl->bde_dev.rev = (dev_rev_id & 0xFF);
+
+
+ _bde_add_device();
+
+ switch (ctrl->bde_dev.device) {
+ default:
+ return 0;
+ }
+ return(ctrl);
+}
+
+static int
+probe_plx_local_bus(void)
+{
+ bde_ctrl_t *ctrl;
+ uint32_t val;
+ uint8_t *addr;
+ char addr_hi_str[16];
+
+ if (num_plx > 1) {
+ printk(KERN_ERR "There's more than one PLX 9656/9056 chip\n");
+ return -1;
+ }
+ addr_hi_str[0] = 0;
+#ifdef PHYS_ADDR_IS_64BIT
+ sprintf(addr_hi_str, "%08x", (uint32_t)(plx_ctrl.phys_address >> 32));
+#endif
+ printk(KERN_ERR "Found PLX %04x:%04x vir: 0x%08x phy: 0x%s%08x\n",
+ plx_ctrl.bde_dev.device, plx_ctrl.bde_dev.rev,
+ plx_ctrl.bde_dev.base_address, addr_hi_str,
+ (uint32_t)(plx_ctrl.phys_address));
+
+ addr = (uint8_t *)plx_ctrl.bde_dev.base_address + CPLD_OFFSET + CPLD_REVISION_REG;
+ val = readl(addr);
+ printk(KERN_ERR "plx: CPLD revision %d\n", val & CPLD_REVISION_MASK);
+#if 000
+ addr = (uint8_t *)plx_ctrl.bde_dev.base_address + CPLD_OFFSET + CPLD_RESET_REG;
+ writel(CPLD_RESET_NONE, addr);
+#endif
+#if 1
+ ctrl = map_local_bus2(&plx_ctrl, PL0_OFFSET, PL0_SIZE);
+#endif
+ if (ctrl == 0)
+ return -1;
+
+ /* Uses PLX IRQ for Polaris LC */
+ ctrl->iLine = 48;
+ ctrl->isr = NULL;
+ ctrl->isr_data = NULL;
+
+ return 0;
+}
+
+#endif /* BCM_PLX9656_LOCAL_BUS */
+
+
+
+
+/*
+ * Generic module functions
+ */
+
+/*
+ * Function: _init
+ *
+ * Purpose:
+ * Module initialization.
+ * Attaches to kernel BDE.
+ * Parameters:
+ * None
+ * Returns:
+ * 0 on success, < 0 on error.
+ */
+static int
+_init(void)
+{
+#ifdef IPROC_CMICD
+#ifdef CONFIG_OF
+ if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) {
+ iproc_platform_driver_register(&iproc_cmicd_driver);
+ } else
+#endif
+ if (iproc_has_cmicd()) {
+ iproc_cmicd_get_memregion(&iproc_cmicd_resources[IPROC_CMICD_RES_MEM]);
+ iproc_platform_driver_register(&iproc_cmicd_driver);
+#ifdef CONFIG_OF
+ if (!of_find_compatible_node(NULL, NULL, IPROC_CMICD_COMPATIBLE))
+#endif
+ {
+ /* Register platform device if no device node in dtb */
+ iproc_platform_device_register(&iproc_cmicd_pdev);
+ }
+ }
+#endif /* IPROC_CMICD */
+
+#ifdef BCM_ICS
+ _ics_bde_create();
+#else /* PCI */
+ /* Register our goodies */
+ _device_driver.name = LINUX_KERNEL_BDE_NAME;
+
+
+ /* Configure MSI interrupt support */
+ use_msi = usemsi;
+
+#ifdef CONFIG_PCI_MSI
+ if (use_msi == PCI_USE_INT_NONE) {
+ /* Compilation flag determines default value */
+#ifdef BDE_LINUX_USE_MSIX_INTERRUPT
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+ use_msi = PCI_USE_INT_MSIX;
+#else
+ use_msi = PCI_USE_INT_MSI;
+#endif
+#elif defined(BDE_LINUX_USE_MSI_INTERRUPT)
+ use_msi = PCI_USE_INT_MSI;
+#else
+ use_msi = PCI_USE_INT_INTX;
+#endif
+ }
+#else
+ if (use_msi > PCI_USE_INT_INTX) {
+ /* Warn if invalid configuration */
+ gprintk("MSI interrupts not supported by kernel\n");
+ }
+ use_msi = PCI_USE_INT_INTX;
+#endif /* CONFIG_PCI_MSI */
+
+ if (unlikely(debug >= 1))
+ gprintk("%s(%d):use_msi = %d\n", __func__, __LINE__, use_msi);
+ if (spi_devid) {
+ _spi_device_setup();
+ } else {
+ if (pci_register_driver(&_device_driver) < 0) {
+ return -ENODEV;
+ }
+ }
+
+ /* Note: PCI-PCI bridge uses results from pci_register_driver */
+ p2p_bridge();
+
+#ifdef BCM_METROCORE_LOCAL_BUS
+ if (probe_metrocore_local_bus()) {
+ return -1;
+ }
+#endif
+#ifdef BCM_PLX9656_LOCAL_BUS
+ if (num_plx > 0) {
+ probe_plx_local_bus();
+ }
+#endif
+#endif /* BCM_ICS */
+
+
+#ifdef BCM_SAND_SUPPORT
+ sand_device_create();
+#endif
+
+ /*
+ * Probe for EB Bus devices.
+ */
+ if (eb_bus) {
+ char *tok;
+ uint irq = -1, eb_rd16bit=0, eb_wr16bit =0;
+ unsigned int eb_ba = 0x0;
+
+ gprintk("EB bus info: %s\n", eb_bus);
+ tok = strtok(eb_bus,",");
+ while (tok) {
+ _parse_eb_args(tok, "BA=%x IRQ=%d RD16=%d WR16=%d",
+ &eb_ba, &irq, &eb_rd16bit, &eb_wr16bit);
+ _eb_device_create(eb_ba, irq, eb_rd16bit, eb_wr16bit);
+ tok = strtok(NULL,",");
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Function: _cleanup
+ *
+ * Purpose:
+ * Module cleanup function.
+ * Parameters:
+ * None
+ * Returns:
+ * Always 0
+ */
+static int
+_cleanup(void)
+{
+ int i;
+
+ _dma_cleanup();
+
+#ifdef IPROC_CMICD
+#ifdef CONFIG_OF
+ if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) {
+ iproc_platform_driver_unregister(&iproc_cmicd_driver);
+ } else
+#endif
+ if (iproc_has_cmicd()) {
+#ifdef CONFIG_OF
+ if (!of_find_compatible_node(NULL, NULL, IPROC_CMICD_COMPATIBLE))
+#endif
+ {
+ iproc_platform_device_unregister(&iproc_cmicd_pdev);
+ }
+ iproc_platform_driver_unregister(&iproc_cmicd_driver);
+ }
+#endif
+
+ for (i = 0; i < _ndevices; i++) {
+ bde_ctrl_t *ctrl = _devices + i;
+
+ /* free allocated kernel space memory */
+ if (ctrl->dev_type & BDE_SPI_DEV_TYPE) {
+ if (ctrl->spi_device) {
+ kfree(ctrl->spi_device);
+ }
+ }
+ }
+#if defined(BCM_SAND_SUPPORT) && (defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__))
+ if (cpu_address) { /* unmap CPU card MMIO */
+ iounmap(cpu_address);
+ cpu_address = NULL;
+ }
+#endif
+
+#ifdef BCM_ICS
+#else
+ pci_unregister_driver(&_device_driver);
+#endif /* BCM_ICS */
+ return 0;
+}
+
+/*
+ * Function: _pprint
+ *
+ * Purpose:
+ * Print proc filesystem information.
+ * Parameters:
+ * None
+ * Returns:
+ * Always 0
+ */
+static int
+_pprint(void)
+{
+ int i = 0;
+
+ pprintf("Broadcom Device Enumerator (%s)\n", LINUX_KERNEL_BDE_NAME);
+
+ _dma_pprint();
+
+ if (_ndevices == 0) {
+ pprintf("No devices found\n");
+ } else {
+ pprintf("Devices:\n");
+ }
+ for (i = 0; i < _ndevices; i++) {
+ bde_ctrl_t *ctrl = _devices + i;
+
+ if (ctrl->dev_type & BDE_SWITCH_DEV_TYPE) {
+ pprintf("\t%d (swi) : ", i);
+ } else if (ctrl->dev_type & BDE_ETHER_DEV_TYPE) {
+ pprintf("\t%d (eth) : ", i);
+ } else if (ctrl->dev_type & BDE_CPU_DEV_TYPE) {
+ pprintf("\t%d (cpu) : ", i);
+ } else {
+ pprintf("\t%d (?) : ", i);
+ }
+
+ if (ctrl->dev_state == BDE_DEV_STATE_REMOVED) {
+ pprintf("PCI device 0x%x:0x%x:%d REMOVED\n",
+ ctrl->pci_device->vendor,
+ ctrl->pci_device->device,
+ ctrl->bde_dev.rev);
+ continue;
+ }
+ if (ctrl->dev_type & BDE_PCI_DEV_TYPE) {
+ pprintf("PCI device %02x:%02x.%x 0x%x:0x%x:%d:0x%.8lx:0x%.8lx:%d%s\n",
+ (unsigned int)ctrl->pci_device->bus->number,
+ PCI_SLOT(ctrl->pci_device->devfn),
+ PCI_FUNC(ctrl->pci_device->devfn),
+ ctrl->pci_device->vendor,
+ ctrl->pci_device->device,
+ ctrl->bde_dev.rev,
+ (unsigned long)pci_resource_start(ctrl->pci_device, 0),
+ (unsigned long)pci_resource_start(ctrl->pci_device, 2),
+ ctrl->pci_device->irq,
+ ctrl->use_msi ? " (MSI)" : "");
+ } else if (ctrl->dev_type & BDE_SPI_DEV_TYPE) {
+ pprintf("SPI Device %d:%x:%x:0x%x:0x%x:%d\n",
+ ctrl->spi_device->cid,
+ ctrl->spi_device->part,
+ ctrl->spi_device->rev,
+ ctrl->spi_device->phyid_high,
+ ctrl->spi_device->phyid_low,
+ ctrl->bde_dev.rev);
+ } else if (ctrl->dev_type & BDE_ICS_DEV_TYPE) {
+ pprintf("ICS Device 0x%x:0x%x\n",
+ ctrl->bde_dev.device,
+ ctrl->bde_dev.rev);
+ } else if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ pprintf("AXI Device 0x%x:0x%x:0x%.8lx:%d\n",
+ ctrl->bde_dev.device,
+ ctrl->bde_dev.rev,
+ (unsigned long)ctrl->phys_address,
+ ctrl->iLine);
+ } else if (ctrl->dev_type & BDE_EB_DEV_TYPE) {
+ pprintf("EB Bus Device 0x%x:0x%x\n",
+ ctrl->bde_dev.device,
+ ctrl->bde_dev.rev);
+ }
+ if (debug >= 1) {
+ pprintf("\t\timask:imask2:fmask 0x%x:0x%x:0x%x\n",
+ ctrl->imask,
+ ctrl->imask2,
+ ctrl->fmask);
+ }
+ }
+ return 0;
+}
+
+/* Workaround for broken Busybox/PPC insmod */
+static char _modname[] = LINUX_KERNEL_BDE_NAME;
+
+static gmodule_t _gmodule = {
+ name: LINUX_KERNEL_BDE_NAME,
+ major: LINUX_KERNEL_BDE_MAJOR,
+ init: _init,
+ cleanup: _cleanup,
+ pprint: _pprint,
+ mmap: _dma_mmap,
+};
+
+gmodule_t *
+gmodule_get(void)
+{
+ _gmodule.name = _modname;
+ return &_gmodule;
+}
+
+
+/*
+ * BDE Interface
+ */
+
+static const char *
+_name(void)
+{
+ return LINUX_KERNEL_BDE_NAME;
+}
+
+static int
+_num_devices(int type)
+{
+ switch (type) {
+ case BDE_ALL_DEVICES:
+ return _ndevices;
+ case BDE_SWITCH_DEVICES:
+ return _switch_ndevices;
+ case BDE_ETHER_DEVICES:
+ return _ether_ndevices;
+ case BDE_CPU_DEVICES:
+ return _cpu_ndevices;
+ }
+
+ return 0;
+}
+
+static const ibde_dev_t *
+_get_dev(int d)
+{
+ if (!VALID_DEVICE(d)) {
+ gprintk("_get_dev: Invalid device index %d\n", d);
+ return NULL;
+ }
+
+ return &_devices[d].bde_dev;
+}
+
+static uint32
+_get_dev_type(int d)
+{
+ if (!VALID_DEVICE(d)) {
+ gprintk("_get_dev: Invalid device index %d\n", d);
+ return 0;
+ }
+
+ return _devices[d].dev_type;
+}
+
+static uint32
+_pci_conf_read(int d, uint32 addr)
+{
+#ifdef BCM_ICS
+ return 0xFFFFFFFF;
+#else
+ uint32 rc = 0;
+
+ if (!VALID_DEVICE(d)) {
+ gprintk("_pci_conf_read: Invalid device index %d\n", d);
+ return 0xFFFFFFFF;
+ }
+
+ if (!(_devices[d].dev_type & BDE_PCI_DEV_TYPE)) {
+ gprintk("_pci_conf_read: Not PCI device %d, type %x\n",
+ d, _devices[d].dev_type);
+ return 0xFFFFFFFF;
+ }
+
+ pci_read_config_dword(_devices[d].pci_device, addr, &rc);
+ return rc;
+#endif /* BCM_ICS */
+}
+
+static int
+_pci_conf_write(int d, uint32 addr, uint32 data)
+{
+#ifdef BCM_ICS
+ return -1;
+#else
+ if (!VALID_DEVICE(d)) {
+ gprintk("_pci_conf_write: Invalid device index %d\n", d);
+ return -1;
+ }
+
+ if (!(_devices[d].dev_type & BDE_PCI_DEV_TYPE)) {
+ gprintk("_pci_conf_write: Not PCI device %d, type %x\n",
+ d, _devices[d].dev_type);
+ return -1;
+ }
+
+ pci_write_config_dword(_devices[d].pci_device, addr, data);
+ return 0;
+#endif /* BCM_ICS */
+}
+
+/* Initialized when the bde is created */
+static linux_bde_bus_t _bus;
+
+static void
+_pci_bus_features(int unit, int *be_pio, int *be_packet, int *be_other)
+{
+ if ((_devices[unit].bde_dev.device & 0xFF00) != 0x5600 &&
+ (_devices[unit].bde_dev.device & 0xF000) != 0xc000 &&
+ (_devices[unit].bde_dev.device & 0xF000) != 0xb000 &&
+ (_devices[unit].bde_dev.device & 0xF000) != 0x8000 &&
+ (_devices[unit].bde_dev.device & 0xFFF0) != 0x0230 &&
+ (_devices[unit].bde_dev.device & 0xFFF0) != 0xa440) {
+ if (be_pio) *be_pio = 0;
+ if (be_packet) *be_packet = 0;
+ if (be_other) *be_other = 0;
+ } else {
+ if (be_pio) *be_pio = _bus.be_pio;
+ if (be_packet) *be_packet = _bus.be_packet;
+ if (be_other) *be_other = _bus.be_other;
+ }
+#if defined(BCM_METROCORE_LOCAL_BUS)
+ if (_devices[unit].dev_type & BDE_EB_DEV_TYPE && be_pio) {
+ *be_pio = 1;
+ }
+#endif
+
+}
+
+static uint32_t
+_read(int d, uint32_t addr)
+{
+ unsigned long flags;
+ volatile uint16 msb, lsb;
+ uint32 sl_addr, data;
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ return -1;
+ }
+
+ if (_devices[d].dev_type & BDE_DEV_BUS_RD_16BIT) {
+ /*
+ * Adjust the address presented to Eb slave. Move A15:A0 to A16:A1.
+ */
+ sl_addr = (addr & 0xffff0000) | ((addr & 0xffff) << 1);
+ /* Disable interrupts */
+ spin_lock_irqsave(&bus_lock, flags);
+
+ lsb = *((uint16 *)(_devices[d].bde_dev.base_address + sl_addr));
+ msb = *((uint16 *)(_devices[d].bde_dev.base_address + sl_addr));
+ spin_unlock_irqrestore(&bus_lock, flags);
+
+ return (msb << 16) | lsb;
+ } else {
+ data = ((VOL uint32_t *)_devices[d].bde_dev.base_address)[addr / 4];
+#if defined(CMIC_SOFT_BYTE_SWAP)
+ data = CMIC_SWAP32(data);
+#endif
+ return data;
+ }
+}
+
+static int
+_write(int d, uint32_t addr, uint32_t data)
+{
+ unsigned long flags;
+ uint32 sl_addr;
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ return -1;
+ }
+
+ if (_devices[d].dev_type & BDE_DEV_BUS_WR_16BIT) {
+ /*
+ * Adjust the address presented to Eb slave. Move A15:A0 to A16:A1.
+ */
+ sl_addr = (addr & 0xffff0000) | ((addr & 0xffff) << 1);
+
+ /* Disable interrupts */
+ spin_lock_irqsave(&bus_lock, flags);
+
+ *((VOL uint16 *)(_devices[d].bde_dev.base_address + sl_addr)) =
+ data & 0xffff;
+ *((VOL uint16 *)(_devices[d].bde_dev.base_address + sl_addr)) =
+ (data >> 16) & 0xffff;
+ spin_unlock_irqrestore(&bus_lock, flags);
+ } else {
+#if defined(CMIC_SOFT_BYTE_SWAP)
+ data = CMIC_SWAP32(data);
+#endif
+ ((VOL uint32_t *)_devices[d].bde_dev.base_address)[addr / 4] = data;
+#ifdef KEYSTONE
+ /* Enforce PCIe transaction ordering. Commit the write transaction */
+ __asm__ __volatile__("sync");
+#endif
+ }
+ return 0;
+
+}
+
+static _ISR_RET
+_isr(_ISR_PARAMS(irq, dev_id, iregs))
+{
+ bde_ctrl_t *ctrl = (bde_ctrl_t *) dev_id;
+
+ if (ctrl && ctrl->isr) {
+ ctrl->isr(ctrl->isr_data);
+ }
+ if (ctrl && ctrl->isr2) {
+ ctrl->isr2(ctrl->isr2_data);
+ }
+ return IRQ_HANDLED;
+}
+
+static int
+_interrupt_connect(int d,
+ void (*isr)(void *),
+ void *isr_data)
+{
+ bde_ctrl_t *ctrl;
+ unsigned long irq_flags;
+ int isr2_dev;
+ int isr_active;
+ int ret = 0;
+
+ isr2_dev = d & LKBDE_ISR2_DEV;
+ d &= ~LKBDE_ISR2_DEV;
+
+ if (!VALID_DEVICE(d)) {
+ gprintk("_interrupt_connect: Invalid device index %d\n", d);
+ return -1;
+ }
+ if (debug >= 1) {
+ gprintk("_interrupt_connect d %d\n", d);
+ }
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ gprintk("_interrupt_connect: Not PCI device %d, type %x\n",
+ d, _devices[d].dev_type);
+ return -1;
+ }
+
+ ctrl = _devices + d;
+
+ isr_active = (ctrl->isr || ctrl->isr2) ? 1 : 0;
+
+ if (unlikely(debug > 1))
+ gprintk("%s:isr_active = %d\n", __func__, isr_active);
+
+ if (isr2_dev) {
+ if (debug >= 1) {
+ gprintk("connect secondary isr\n");
+ }
+ ctrl->isr2_data = isr_data;
+ ctrl->isr2 = isr;
+ if (isr_active) {
+ /* Main handler (_isr) already installed */
+ return 0;
+ }
+ } else {
+ if (debug >= 1) {
+ gprintk("connect primary isr\n");
+ }
+ ctrl->isr = isr;
+ ctrl->isr_data = isr_data;
+ if (isr_active) {
+ /* Main handler (_isr) already installed */
+ return 0;
+ }
+ }
+
+ if (ctrl->iLine != -1) {
+ irq_flags = IRQF_SHARED;
+#ifdef CONFIG_PCI_MSI
+ if (ctrl->use_msi >= PCI_USE_INT_MSI) {
+ ret = _msi_connect(ctrl);
+ if(ret != 0)
+ goto msi_exit;
+ }
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+ if (ctrl->use_msi == PCI_USE_INT_MSIX) {
+ int i;
+ for (i = 0; i < ctrl->msix_cnt; i++) {
+ if (unlikely(debug >= 1)) {
+ gprintk("%s(%d):device# = %d, irq = %d\n",
+ __func__, __LINE__, d, ctrl->entries[i].vector);
+ }
+ ret = request_irq(ctrl->entries[i].vector, (irq_handler_t)_isr, 0,
+ LINUX_KERNEL_BDE_NAME, ctrl);
+ if (ret < 0)
+ break;
+ }
+ if (ret < 0) {
+ while (i >= 0)
+ free_irq(ctrl->entries[i--].vector, ctrl);
+
+ goto err_disable_msi;
+ }
+ }
+ else
+#endif
+ {
+#if defined(IPROC_CMICD) && defined(CONFIG_OF)
+ if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) {
+ int i, j;
+ for (i = 0; i < IHOST_CMICX_MAX_INTRS; i++) {
+ if (unlikely(debug >= 1))
+ gprintk("%s(%d):device# = %d, request_irq(%d)\n",
+ __func__, __LINE__, d, iproc_cmicx_irqs[i]);
+ ret = request_irq(iproc_cmicx_irqs[i], (irq_handler_t)_isr,
+ irq_flags, LINUX_KERNEL_BDE_NAME, ctrl);
+ if (ret < 0) {
+ gprintk("request_irq(%d) failed(%d)\n", iproc_cmicx_irqs[i], ret);
+ break;
+ }
+ }
+ if (ret < 0) {
+ for (j = 0; j < i; j++) {
+ free_irq(iproc_cmicx_irqs[j], ctrl);
+ }
+ goto err_disable_msi;
+ }
+ } else
+#endif
+ {
+ ret = request_irq(ctrl->iLine, _isr, irq_flags,
+ LINUX_KERNEL_BDE_NAME, ctrl);
+ if (ret < 0)
+ goto err_disable_msi;
+
+ if (unlikely(debug >= 1))
+ gprintk("%s(%d):device# = %d, irq_flags = %lu, irq = %d\n",
+ __func__, __LINE__, d,
+ irq_flags, ctrl->pci_device ? ctrl->pci_device->irq : ctrl->iLine);
+ }
+ }
+ }
+ return 0;
+
+err_disable_msi:
+#ifdef CONFIG_PCI_MSI
+ _msi_disconnect(ctrl);
+
+msi_exit:
+#endif
+ gprintk("could not request IRQ\n");
+ ctrl->isr = NULL;
+ ctrl->isr_data = NULL;
+ ctrl->isr2 = NULL;
+ ctrl->isr2_data = NULL;
+
+ return -1;
+}
+
+static int
+_interrupt_disconnect(int d)
+{
+ bde_ctrl_t *ctrl;
+ int isr2_dev;
+ int isr_active;
+
+ isr2_dev = d & LKBDE_ISR2_DEV;
+ d &= ~LKBDE_ISR2_DEV;
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ if (debug >= 1) {
+ gprintk("_interrupt_disconnect d %d\n", d);
+ }
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ gprintk("_interrupt_disconnect: Not PCI device %d, type %x\n",
+ d, _devices[d].dev_type);
+ return -1;
+ }
+
+ ctrl = _devices + d;
+
+ isr_active = (ctrl->isr || ctrl->isr2) ? 1 : 0;
+
+ if (unlikely(debug > 1))
+ gprintk("%s: isr_active = %d\n", __func__, isr_active);
+
+ if (isr2_dev) {
+ if (debug >= 1) {
+ gprintk("disconnect secondary isr\n");
+ }
+ ctrl->isr2 = NULL;
+ ctrl->isr2_data = NULL;
+ ctrl->fmask = 0;
+ if (ctrl->isr) {
+ /* Primary handler still active */
+ SYNC_IRQ(ctrl->iLine);
+ return 0;
+ }
+ } else {
+ if (debug >= 1) {
+ gprintk("disconnect primary isr\n");
+ }
+ ctrl->isr = NULL;
+ ctrl->isr_data = NULL;
+ if (ctrl->isr2) {
+ /* Secondary handler still active */
+ SYNC_IRQ(ctrl->iLine);
+ return 0;
+ }
+ }
+
+ if (isr_active) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+ if (ctrl->use_msi >= PCI_USE_INT_MSIX) {
+ int i;
+ for (i = 0; i < ctrl->msix_cnt; i++) {
+ if (unlikely(debug > 1)) {
+ gprintk("%s(%d):device# = %d, irq = %d\n",
+ __func__, __LINE__, d, ctrl->entries[i].vector);
+ }
+ free_irq(ctrl->entries[i].vector, ctrl);
+ }
+ }
+ else
+#endif
+#if defined(IPROC_CMICD) && defined(CONFIG_OF)
+ if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) {
+ int i;
+ for (i = 0; i < IHOST_CMICX_MAX_INTRS; i++) {
+ if (unlikely(debug > 1)) {
+ gprintk("%s(%d):device# = %d, free_irq(%d)\n",
+ __func__, __LINE__, d, iproc_cmicx_irqs[i]);
+ }
+ free_irq(iproc_cmicx_irqs[i], ctrl);
+ }
+ } else
+#endif
+ {
+ free_irq(ctrl->iLine, ctrl);
+ }
+#ifdef CONFIG_PCI_MSI
+ if (ctrl->use_msi >= PCI_USE_INT_MSI) {
+ _msi_disconnect(ctrl);
+ }
+#endif
+ }
+
+ return 0;
+}
+
+static uint32_t
+_iproc_ihost_read(int d, uint32_t addr)
+{
+ uint32_t *mapaddr;
+ uint32_t reg_val;
+ mapaddr = IOREMAP(addr, sizeof(uint32_t));
+ if (mapaddr == NULL) {
+ return -1;
+ }
+ reg_val = readl(mapaddr);
+ iounmap(mapaddr);
+ return reg_val;
+}
+
+static int
+_iproc_ihost_write(int d, uint32_t addr, uint32_t data)
+{
+ uint32_t *mapaddr;
+ mapaddr = IOREMAP(addr, sizeof(uint32_t));
+ if (mapaddr == NULL) {
+ return -1;
+ }
+ writel(data, mapaddr);
+ iounmap(mapaddr);
+ return 0;
+}
+
+static uint32_t
+_iproc_read(int d, uint32_t addr)
+{
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ return -1;
+ }
+
+ if (_devices[d].dev_type & BDE_AXI_DEV_TYPE) {
+ if (IHOST_GICD_REG_ADDR_VALID(d, addr)) {
+ return readl(IHOST_GICD_REG_ADDR_REMAP(d, addr));
+ }
+ return _iproc_ihost_read(d, addr);
+ }
+
+ return shbde_iproc_pci_read(&_devices[d].shbde,
+ (void *)_devices[d].bde_dev.base_address1,
+ addr);
+}
+
+static int
+_iproc_write(int d, uint32_t addr, uint32_t data)
+{
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ return -1;
+ }
+
+ if (_devices[d].dev_type & BDE_AXI_DEV_TYPE) {
+ if (IHOST_GICD_REG_ADDR_VALID(d, addr)) {
+ writel(data, IHOST_GICD_REG_ADDR_REMAP(d, addr));
+ return 0;
+ }
+ return _iproc_ihost_write(d, addr, data);
+ }
+
+ shbde_iproc_pci_write(&_devices[d].shbde,
+ (void *)_devices[d].bde_dev.base_address1,
+ addr, data);
+
+ return 0;
+}
+
+static int
+_get_cmic_ver(int d , uint32_t *ver)
+{
+
+ unsigned int cap_base;
+ uint32_t rval = 0;
+
+ if (!VALID_DEVICE(d)) {
+ gprintk("%s: Invalid device index %d\n", __func__, d);
+ return -1;
+ }
+
+ if (!(_devices[d].dev_type & BDE_PCI_DEV_TYPE)) {
+ gprintk("%s: Not PCI device %d, type %x\n", __func__,
+ d, _devices[d].dev_type);
+ return -1;
+ }
+
+ /* Look for PCIe vendor-specific extended capability (VSEC) */
+ cap_base = PCI_EXT_CAP_START;
+ while (cap_base) {
+ pci_read_config_dword(_devices[d].pci_device, cap_base, &rval);
+ if (rval == 0xffffffff) {
+ /* Assume PCI HW read error */
+ gprintk("%s: PCI HW read error\n", __func__);
+ return -1;
+ }
+
+ if (PCI_EXT_CAP_ID(rval) == PCI_EXT_CAP_ID_VNDR) {
+ break;
+ }
+ cap_base = PCI_EXT_CAP_NEXT(rval);
+ }
+ if (cap_base) {
+ /*
+ * VSEC layout:
+ *
+ * 0x00: PCI Express Extended Capability Header
+ * 0x04: Vendor-Specific Header
+ * 0x08: Vendor-Specific Register 1
+ * 0x0c: Vendor-Specific Register 2
+ * ...
+ * 0x24: Vendor-Specific Register 8
+ */
+ pci_read_config_dword(_devices[d].pci_device, cap_base + 8, &rval);
+ if (unlikely(debug > 1))
+ gprintk("%s:Found VSEC = %u\n", __func__, rval);
+
+ /* Determine if CMICX */
+ rval = ((rval >> 12) & 0xf);
+ *ver = rval;
+
+ return 0;
+ } else {
+ gprintk("%s:VSEC not found\n", __func__);
+ }
+
+ return -1;
+}
+
+#ifdef BCM_SAND_SUPPORT
+int
+lkbde_cpu_write(int d, uint32 addr, uint32 *buf)
+{
+#if defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__)
+ *((uint32_t*)((uint8_t*)cpu_address + addr)) = *buf;
+#endif
+
+ return 0;
+}
+
+int
+lkbde_cpu_read(int d, uint32 addr, uint32 *buf)
+{
+#if defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__)
+ *buf = *((uint32_t*)((uint8_t*)cpu_address + addr));
+#else
+ *buf = (uint32_t)(-1);
+#endif
+
+ return 0;
+}
+
+int
+lkbde_cpu_pci_register(int d)
+{
+ bde_ctrl_t* ctrl;
+ uint16 cmd = 0;
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ ctrl = &_devices[d];
+
+ /* enable device */
+ if (pci_enable_device(ctrl->pci_device)) {
+ gprintk("Cannot enable pci device : vendor_id = %x, device_id = %x\n",
+ ctrl->pci_device->vendor, ctrl->pci_device->device);
+ }
+
+ /* Add PCI_COMMAND_MEMORY and PCI_COMMAND_MASTER */
+ pci_read_config_word(ctrl->pci_device, PCI_COMMAND, &cmd);
+ if (!(cmd & PCI_COMMAND_MEMORY) || !(cmd & PCI_COMMAND_MASTER)) {
+ cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ pci_write_config_word(ctrl->pci_device, PCI_COMMAND, cmd);
+ }
+
+ switch (ctrl->bde_dev.device) {
+ case GEDI_DEVICE_ID:
+ /* Fix bar 0 address */ /* FIXME: write full phy address */
+ pci_write_config_byte(ctrl->pci_device, 0x13, 0x60);
+
+ /* Fix Max payload size */
+ pci_write_config_byte(ctrl->pci_device, 0x88, 0x2f);
+ pci_write_config_byte(ctrl->pci_device, 0x89, 0x10);
+ break;
+ case BCM88750_DEVICE_ID:
+ case BCM88753_DEVICE_ID:
+ case BCM88755_DEVICE_ID:
+ case BCM88770_DEVICE_ID:
+ case BCM88773_DEVICE_ID:
+ case BCM88774_DEVICE_ID:
+ case BCM88775_DEVICE_ID:
+ case BCM88776_DEVICE_ID:
+ case BCM88777_DEVICE_ID:
+ case BCM88950_DEVICE_ID:
+ case BCM88953_DEVICE_ID:
+ case BCM88954_DEVICE_ID:
+ case BCM88955_DEVICE_ID:
+ case BCM88956_DEVICE_ID:
+ case BCM88752_DEVICE_ID:
+ case BCM88772_DEVICE_ID:
+ case BCM88952_DEVICE_ID:
+ case ACP_PCI_DEVICE_ID:
+ case BCM88650_DEVICE_ID:
+
+ case BCM88670_DEVICE_ID:
+ case BCM88671_DEVICE_ID:
+ case BCM88671M_DEVICE_ID:
+ case BCM88672_DEVICE_ID:
+ case BCM88673_DEVICE_ID:
+ case BCM88674_DEVICE_ID:
+ case BCM88675_DEVICE_ID:
+ case BCM88675M_DEVICE_ID:
+ case BCM88676_DEVICE_ID:
+ case BCM88676M_DEVICE_ID:
+ case BCM88677_DEVICE_ID:
+ case BCM88678_DEVICE_ID:
+ case BCM88679_DEVICE_ID:
+
+ case BCM88370_DEVICE_ID:
+ case BCM88371_DEVICE_ID:
+ case BCM88371M_DEVICE_ID:
+ case BCM88375_DEVICE_ID:
+ case BCM88376_DEVICE_ID:
+ case BCM88376M_DEVICE_ID:
+ case BCM88377_DEVICE_ID:
+ case BCM88378_DEVICE_ID:
+ case BCM88379_DEVICE_ID:
+ case BCM88681_DEVICE_ID:
+ case BCM88682_DEVICE_ID:
+ case BCM88683_DEVICE_ID:
+ case BCM88684_DEVICE_ID:
+ case BCM88685_DEVICE_ID:
+ case BCM88380_DEVICE_ID:
+ case BCM88381_DEVICE_ID:
+ case BCM88680_DEVICE_ID:
+ case BCM88800_DEVICE_ID:
+ case BCM88470_DEVICE_ID:
+ case BCM88470P_DEVICE_ID:
+ case BCM88471_DEVICE_ID:
+ case BCM88473_DEVICE_ID:
+ case BCM88474_DEVICE_ID:
+ case BCM88474H_DEVICE_ID:
+ case BCM88476_DEVICE_ID:
+ case BCM88477_DEVICE_ID:
+ case BCM88270_DEVICE_ID:
+ case BCM88272_DEVICE_ID:
+ case BCM88273_DEVICE_ID:
+ case BCM88274_DEVICE_ID:
+ case BCM88278_DEVICE_ID:
+ case BCM8206_DEVICE_ID:
+ case BCM88350_DEVICE_ID:
+ case BCM88351_DEVICE_ID:
+ case BCM88450_DEVICE_ID:
+ case BCM88451_DEVICE_ID:
+ case BCM88550_DEVICE_ID:
+ case BCM88551_DEVICE_ID:
+ case BCM88552_DEVICE_ID:
+ case BCM88651_DEVICE_ID:
+ case BCM88654_DEVICE_ID:
+ case BCM88660_DEVICE_ID:
+ case BCM88360_DEVICE_ID:
+ case BCM88361_DEVICE_ID:
+ case BCM88363_DEVICE_ID:
+ case BCM88460_DEVICE_ID:
+ case BCM88461_DEVICE_ID:
+ case BCM88560_DEVICE_ID:
+ case BCM88561_DEVICE_ID:
+ case BCM88562_DEVICE_ID:
+ case BCM88661_DEVICE_ID:
+ case BCM88664_DEVICE_ID:
+ /* Fix bar 0 address */ /* FIXME: write full phy address */
+ pci_write_config_byte(ctrl->pci_device, 0x12, 0x10);
+ pci_write_config_byte(ctrl->pci_device, 0x13, 0x60);
+
+ /*
+ * For DMA transactions - set Max_Payload_Size and
+ * Max_Read_Request_Size to 128 bytes.
+ */
+ pci_write_config_byte(ctrl->pci_device, 0xb5, 0x0c);
+ pci_write_config_byte(ctrl->pci_device, 0xb4, 0x0);
+ break;
+ default:
+ break;
+ }
+
+#ifdef BCM_DNX_SUPPORT
+ /*All Jericho 2 devices from 0x8690 to 0x869F*/
+ if (SOC_IS_JERICHO_2_TYPE(ctrl->bde_dev.device)) {
+ /* Fix bar 0 address */ /* FIXME: write full phy address */
+ pci_write_config_byte(ctrl->pci_device, 0x12, 0x10);
+ pci_write_config_byte(ctrl->pci_device, 0x13, 0x60);
+
+ /*
+ * For DMA transactions - set Max_Payload_Size and
+ * Max_Read_Request_Size to 128 bytes.
+ */
+ pci_write_config_byte(ctrl->pci_device, 0xb5, 0x0c);
+ pci_write_config_byte(ctrl->pci_device, 0xb4, 0x0);
+ }
+#endif
+
+ /* Redo ioremap */
+ if (ctrl->bde_dev.base_address) {
+ iounmap((void *)ctrl->bde_dev.base_address);
+ }
+ ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(ctrl->phys_address, 0x1000000);
+
+ if (debug >= 1) {
+ gprintk("%s, %s(): info:\n", __FILE__, __FUNCTION__);
+ gprintk("_ndevices=%d, _switch_ndevices=%d\n",
+ _ndevices, _switch_ndevices);
+ gprintk("ctrl->dev_type=0x%x, ctrl->phys_address=0x%lx\n",
+ ctrl->dev_type, (unsigned long)ctrl->phys_address);
+ gprintk("ctrl->bde_dev.device=0x%x, ctrl->bde_dev.rev=0x%x, "
+ "ctrl->bde_dev.base_address=0x%lx\n",
+ ctrl->bde_dev.device, ctrl->bde_dev.rev,
+ (unsigned long)ctrl->bde_dev.base_address);
+ }
+
+ return 0;
+}
+
+/*
+ * Export Low level access function - currently for PCP DMA Kernel module.
+ */
+int
+lkbde_mem_write(int d, uint32 addr, uint32 *buf)
+{
+ bde_ctrl_t* ctrl;
+ void *full_addr;
+
+ if (!VALID_DEVICE(d)) return -1;
+ ctrl = &_devices[d];
+
+ full_addr = (void *)ctrl->bde_dev.base_address + addr;
+ *((uint32_t*)full_addr) = *buf;
+ return 0;
+}
+LKM_EXPORT_SYM(lkbde_mem_write);
+
+int
+lkbde_mem_read(int d, uint32 addr, uint32 *buf)
+{
+ bde_ctrl_t* ctrl;
+ void *full_addr;
+
+ if (!VALID_DEVICE(d)) return -1;
+ ctrl = &_devices[d];
+
+ full_addr = (void *)ctrl->bde_dev.base_address + addr;
+ *buf = *((uint32_t*)full_addr);
+ return 0;
+}
+LKM_EXPORT_SYM(lkbde_mem_read);
+#endif /* BCM_SAND_SUPPORT */
+
+static ibde_t _ibde = {
+ name: _name,
+ num_devices: _num_devices,
+ get_dev: _get_dev,
+ get_dev_type: _get_dev_type,
+ pci_conf_read: _pci_conf_read,
+ pci_conf_write: _pci_conf_write,
+ pci_bus_features: _pci_bus_features,
+ read: _read,
+ write: _write,
+ salloc: _salloc,
+ sfree: _sfree,
+ sinval: _sinval,
+ sflush: _sflush,
+ interrupt_connect: _interrupt_connect,
+ interrupt_disconnect: _interrupt_disconnect,
+ l2p: _l2p,
+ p2l: _p2l,
+
+ NULL,
+ NULL,
+ iproc_read: _iproc_read,
+ iproc_write: _iproc_write,
+ get_cmic_ver: _get_cmic_ver,
+};
+
+/*
+ * Function: linux_bde_create
+ *
+ * Purpose:
+ * Creator function for this BDE interface.
+ * Parameters:
+ * bus - pointer to the bus features structure you want this
+ * bde to export. Depends on the system.
+ * ibde - pointer to a location to recieve the bde interface pointer.
+ * Returns:
+ * 0 on success
+ * -1 on failure.
+ * Notes:
+ * This is the main BDE create function for this interface.
+ * Used by the external system initialization code.
+ */
+int
+linux_bde_create(linux_bde_bus_t *bus, ibde_t **ibde)
+{
+
+ memset(&_bus, 0, sizeof(_bus));
+
+ if (bus) {
+ _bus = *bus;
+ }
+#ifdef NONCOHERENT_DMA_MEMORY
+#ifdef REMAP_DMA_NONCACHED
+ /*
+ * If we have a non-cached DMA memory pool
+ * there is no need to flush and invalidate.
+ */
+ if (_dma_pool_allocated()) {
+ _ibde.sinval = NULL;
+ _ibde.sflush = NULL;
+ }
+#endif
+#else
+ _ibde.sinval = NULL;
+ _ibde.sflush = NULL;
+#endif
+ *ibde = &_ibde;
+ return 0;
+}
+
+/*
+ * Function: linux_bde_destroy
+ *
+ * Purpose:
+ * destroy this bde
+ * Parameters:
+ * BDE interface pointer
+ * Returns:
+ * 0 on success, < 0 on error.
+ */
+int
+linux_bde_destroy(ibde_t *ibde)
+{
+ /* nothing */
+ return 0;
+}
+
+/*
+ * Backdoors provided by the kernel bde
+ */
+
+uint32_t
+lkbde_get_dev_phys(int d)
+{
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ gprintk("lkbde_get_dev_phys: Not PCI device %d, type %x\n",
+ d, _devices[d].dev_type);
+ return 0;
+ }
+ return _devices[d].phys_address;
+}
+
+uint32_t
+lkbde_get_dev_phys_hi(int d)
+{
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ gprintk("lkbde_get_dev_phys: Not PCI device %d, type %x\n",
+ d, _devices[d].dev_type);
+ return 0;
+ }
+#ifdef PHYS_ADDR_IS_64BIT
+ return (uint32_t)(_devices[d].phys_address >> 32);
+#else
+ return 0;
+#endif
+}
+
+void *
+lkbde_get_dev_virt(int d)
+{
+ if (!VALID_DEVICE(d)) {
+ return NULL;
+ }
+
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ gprintk("lkbde_get_dev_virt: Not PCI device %d, type %x\n",
+ d, _devices[d].dev_type);
+ return 0;
+ }
+
+ if (_devices[d].alt_base_addr) {
+ return (void *)_devices[d].alt_base_addr;
+ }
+
+ return (void *)_devices[d].bde_dev.base_address;
+}
+
+int
+lkbde_get_dev_resource(int d, int rsrc, uint32_t *flags,
+ uint32_t *phys_lo, uint32_t *phys_hi)
+{
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ *flags = 0;
+ *phys_lo = 0;
+ *phys_hi = 0;
+
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ gprintk("lkbde_get_dev_phys: Not PCI device %d, type %x\n",
+ d, _devices[d].dev_type);
+ return 0;
+ }
+
+ switch (rsrc) {
+ case 0:
+ *phys_lo = (uint32_t)(_devices[d].phys_address);
+#ifdef PHYS_ADDR_IS_64BIT
+ *phys_hi = (uint32_t)(_devices[d].phys_address >> 32);
+#endif
+ break;
+ case 1:
+ *phys_lo = (uint32_t)(_devices[d].phys_address1);
+#ifdef PHYS_ADDR_IS_64BIT
+ *phys_hi = (uint32_t)(_devices[d].phys_address1 >> 32);
+#endif
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+void *
+lkbde_get_dma_dev(int d)
+{
+ if (!VALID_DEVICE(d)) {
+ return NULL;
+ }
+
+#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT
+ return (void *)_devices[d].dma_dev;
+#else
+ return (void *)_devices[d].pci_device;
+#endif
+}
+
+void *
+lkbde_get_hw_dev(int d)
+{
+ if (!VALID_DEVICE(d)) {
+ return NULL;
+ }
+
+ return (void *)_devices[d].pci_device;
+}
+
+int
+lkbde_dev_state_set(int d, uint32 state)
+{
+ bde_ctrl_t *ctrl;
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+ ctrl = _devices + d;
+ ctrl->dev_state = state;
+ return 0;
+}
+
+int
+lkbde_dev_state_get(int d, uint32 *state)
+{
+ bde_ctrl_t *ctrl;
+ if (!VALID_DEVICE(d)) {
+ gprintk("_get_dev: Invalid device index %d\n", d);
+ return -1;
+ }
+ ctrl = _devices + d;
+
+ *state = ctrl->dev_state;
+ return 0;
+}
+
+int
+lkbde_dev_instid_set(int d, uint32 instid)
+{
+ bde_ctrl_t *ctrl;
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+ ctrl = _devices + d;
+ ctrl->inst_id = instid;
+
+ return 0;
+}
+
+int
+lkbde_dev_instid_get(int d, uint32 *instid)
+{
+ bde_ctrl_t *ctrl;
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+ ctrl = _devices + d;
+ *instid = ctrl->inst_id;
+
+ return 0;
+}
+/*
+ * When a secondary interrupt handler is installed this function
+ * is used for synchronizing hardware access to the IRQ mask
+ * register. The secondary driver will supply a non-zero fmask
+ * (filter mask) to indicate which interrupt bits it controls.
+ * The fmask is ignored for the primary driver.
+ */
+int
+lkbde_irq_mask_set(int d, uint32_t addr, uint32_t mask, uint32_t fmask)
+{
+ bde_ctrl_t *ctrl;
+ int isr2_dev, iproc_reg;
+ unsigned long flags;
+
+ isr2_dev = d & LKBDE_ISR2_DEV;
+ iproc_reg = d & LKBDE_IPROC_REG;
+ d &= ~(LKBDE_ISR2_DEV | LKBDE_IPROC_REG);
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ ctrl = _devices + d;
+
+ /* Lock is required to synchronize access from user space */
+ spin_lock_irqsave(&ctrl->lock, flags);
+
+ if (isr2_dev) {
+ /* This is the secondary interrupt handler */
+ ctrl->fmask = fmask;
+ ctrl->imask2 = mask & ctrl->fmask;
+ } else {
+ /* This is the primary interrupt handler */
+ ctrl->imask = mask & ~ctrl->fmask;
+ }
+
+ if (iproc_reg) {
+ _iproc_write(d, addr, ctrl->imask | ctrl->imask2);
+ } else {
+ _write(d, addr, ctrl->imask | ctrl->imask2);
+ }
+
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+
+ return 0;
+}
+
+/*
+ * When a secondary interrupt handler is installed, this function
+ * is used to avoid activating the user mode interrupt handler
+ * thread if all pending interrupts are handled in kernel space.
+ *
+ * The mask returned is the mask of all interrupts, it can be used
+ * to do a logical AND with fmask, the result will tell you if
+ * the user mode interrupt handler needs to be invoked.
+ *
+ * Note that if no secondary handler is installed, the value of
+ * "mask & fmask" will be zero, and hence there will be no need to read the
+ * current interrupt status from hardware (from kernel space).
+ */
+int
+lkbde_irq_mask_get(int d, uint32_t *mask, uint32_t *fmask)
+{
+ bde_ctrl_t *ctrl;
+
+ d &= ~(LKBDE_ISR2_DEV | LKBDE_IPROC_REG);
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ if (mask == NULL || fmask == NULL) {
+ return -1;
+ }
+
+ ctrl = _devices + d;
+
+ *fmask = ctrl->fmask;
+ *mask = ctrl->imask | ctrl->imask2;
+
+ return 0;
+}
+
+int
+lkbde_get_num_devices(int type)
+{
+ return _num_devices(type);
+}
+
+/*
+ * Export functions
+ */
+LKM_EXPORT_SYM(linux_bde_create);
+LKM_EXPORT_SYM(linux_bde_destroy);
+LKM_EXPORT_SYM(lkbde_get_dev_phys);
+LKM_EXPORT_SYM(lkbde_get_dev_virt);
+LKM_EXPORT_SYM(lkbde_get_dev_resource);
+LKM_EXPORT_SYM(lkbde_get_hw_dev);
+LKM_EXPORT_SYM(lkbde_get_dma_dev);
+LKM_EXPORT_SYM(lkbde_irq_mask_set);
+LKM_EXPORT_SYM(lkbde_irq_mask_get);
+LKM_EXPORT_SYM(lkbde_get_dev_phys_hi);
+LKM_EXPORT_SYM(lkbde_dev_state_set);
+LKM_EXPORT_SYM(lkbde_dev_state_get);
+LKM_EXPORT_SYM(lkbde_dev_instid_set);
+LKM_EXPORT_SYM(lkbde_dev_instid_get);
+#ifdef BCM_SAND_SUPPORT
+LKM_EXPORT_SYM(lkbde_cpu_write);
+LKM_EXPORT_SYM(lkbde_cpu_read);
+LKM_EXPORT_SYM(lkbde_cpu_pci_register);
+#endif
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux_dma.c b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux_dma.c
@@ -0,0 +1,1007 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: linux_dma.c,v 1.414 Broadcom SDK $
+ * $Copyright: (c) 2016 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ * Linux Kernel BDE DMA memory allocation
+ *
+ *
+ * DMA memory allocation modes
+ * ===========================
+ *
+ * 1. Using private pool in kernel memory
+ * --------------------------------------
+ * In this mode the BDE module will try to assemble a physically contiguous
+ * of memory using the kernel page allocator. This memory block is then
+ * administered by the mpool allocation functions. Note that once a system
+ * has been running for a while, the memory fragmentation may prevent the
+ * allocator from assembling a contiguous memory block, however, if the
+ * module is loaded shortly after system startup, it is very unlikely to
+ * fail.
+ *
+ * This allocation method is used by default.
+ *
+ * 2. Using private pool in high memory
+ * ------------------------------------
+ * In this mode the BDE module will assume that unused physical memory is
+ * present at the high_memory address, i.e. memory not managed by the Linux
+ * memory manager. This memory block is mapped into kernel space and
+ * administered by the mpool allocation functions. High memory must be
+ * reserved using either the mem=xxx kernel parameter (recommended), or by
+ * hardcoding the memory limit in the kernel image.
+ *
+ * The module parameter himem=1 enables this allocation mode.
+ *
+ * 3. Using kernel allocators (kmalloc, __get_free_pages)
+ * ------------------------------------------------------
+ * In this mode all DMA memory is allocated from the kernel on the fly, i.e.
+ * no private DMA memory pool will be created. If large memory blocks are
+ * only allocated at system startup (or not at all), this allocation method
+ * is the most flexible and memory-efficient, however, it is not recommended
+ * for non-coherent memory platforms due to an overall system performance
+ * degradation arising from the use of cache flush/invalidate instructions.
+ *
+ * The module parameter dmasize=0M enables this allocation mode, however if
+ * DMA memory is requested from a user mode application, a private memory
+ * pool will be created and used irrespectively.
+ */
+
+#include <gmodule.h>
+#include <linux-bde.h>
+#include <linux_dma.h>
+#include <mpool.h>
+#include <sdk_config.h>
+
+#ifdef BCM_PLX9656_LOCAL_BUS
+#include <asm/cacheflush.h>
+#endif
+
+/* allocation types/methods for the DMA memory pool */
+#define ALLOC_TYPE_CHUNK 0 /* use small allocations and join them */
+#define ALLOC_TYPE_API 1 /* use one allocation */
+#if _SIMPLE_MEMORY_ALLOCATION_
+#include <linux/dma-mapping.h>
+#if defined(IPROC_CMICD) && defined(CONFIG_CMA) && defined(CONFIG_CMA_SIZE_MBYTES)
+#define DMA_MAX_ALLOC_SIZE (CONFIG_CMA_SIZE_MBYTES * 1024 * 1024)
+#else
+#define DMA_MAX_ALLOC_SIZE (1 << (MAX_ORDER - 1 + PAGE_SHIFT)) /* Maximum size the kernel can allocate in one allocation */
+#endif
+#endif /* _SIMPLE_MEMORY_ALLOCATION_ */
+
+#if _SIMPLE_MEMORY_ALLOCATION_ == 1
+#define ALLOC_METHOD_DEFAULT ALLOC_TYPE_API
+#if defined(__arm__)
+#define USE_DMA_MMAP_COHERENT
+#define _PGPROT_NONCACHED(x) x = pgprot_noncached((x))
+#elif defined(__aarch64__ )
+#define USE_DMA_MMAP_COHERENT
+#define _PGPROT_NONCACHED(x) x = pgprot_writecombine((x))
+#endif
+#else
+#define ALLOC_METHOD_DEFAULT ALLOC_TYPE_CHUNK
+#endif
+
+#ifndef _PGPROT_NONCACHED
+#ifdef REMAP_DMA_NONCACHED
+#define _PGPROT_NONCACHED(x) x = pgprot_noncached((x))
+#else
+#define _PGPROT_NONCACHED(x)
+#endif
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
+#include <linux/slab.h>
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))
+#define VIRT_TO_PAGE(p) virt_to_page((void*)(p))
+#else
+#define VIRT_TO_PAGE(p) virt_to_page((p))
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
+#define DMA_MAPPING_ERROR(d, p) dma_mapping_error((d),(p))
+#else
+#define DMA_MAPPING_ERROR(d, p) dma_mapping_error((p))
+#endif
+
+#ifndef KMALLOC_MAX_SIZE
+#define KMALLOC_MAX_SIZE (1UL << (MAX_ORDER - 1 + PAGE_SHIFT))
+#endif
+
+/* Compatibility */
+#ifdef LKM_2_4
+#define MEM_MAP_RESERVE mem_map_reserve
+#define MEM_MAP_UNRESERVE mem_map_unreserve
+#else /* LKM_2_6 */
+#define MEM_MAP_RESERVE SetPageReserved
+#define MEM_MAP_UNRESERVE ClearPageReserved
+#endif /* LKM_2_x */
+
+#ifndef GFP_DMA32
+#define GFP_DMA32 0
+#endif
+
+/* Flags for memory allocations */
+#ifdef SAL_BDE_XLP
+static int mem_flags = GFP_ATOMIC | GFP_KERNEL | GFP_DMA;
+#else
+#if defined(CONFIG_ZONE_DMA32)
+static int mem_flags = GFP_ATOMIC | GFP_DMA32;
+#else
+static int mem_flags = GFP_ATOMIC | GFP_DMA;
+#endif
+#endif
+
+/* Debug output */
+static int dma_debug = 0;
+module_param(dma_debug, int, 0);
+MODULE_PARM_DESC(dma_debug,
+"DMA debug output enable (default 0).");
+
+/* DMA memory pool size */
+static char *dmasize;
+LKM_MOD_PARAM(dmasize, "s", charp, 0);
+MODULE_PARM_DESC(dmasize,
+"Specify DMA memory size (default 4MB)");
+
+/* Select DMA memory pool allocation method */
+static int dmaalloc = ALLOC_METHOD_DEFAULT;
+LKM_MOD_PARAM(dmaalloc, "i", int, 0);
+MODULE_PARM_DESC(dmaalloc, "Select DMA memory allocation method");
+
+/* Use high memory for DMA */
+static char *himem;
+LKM_MOD_PARAM(himem, "s", charp, 0);
+MODULE_PARM_DESC(himem,
+"Use high memory for DMA (default no)");
+
+/* Physical high memory address to use for DMA */
+static char *himemaddr = 0;
+LKM_MOD_PARAM(himemaddr, "s", charp, 0);
+MODULE_PARM_DESC(himemaddr,
+"Physical address to use for high memory DMA");
+
+/* DMA memory allocation */
+
+#define ONE_KB 1024
+#define ONE_MB (1024*1024)
+#define ONE_GB (1024*1024*1024)
+
+/* Default DMA memory size */
+#ifdef SAL_BDE_DMA_MEM_DEFAULT
+#define DMA_MEM_DEFAULT (SAL_BDE_DMA_MEM_DEFAULT * ONE_MB)
+#else
+#define DMA_MEM_DEFAULT (8 * ONE_MB)
+#endif
+
+/* We try to assemble a contiguous segment from chunks of this size */
+#define DMA_BLOCK_SIZE (512 * ONE_KB)
+
+typedef struct _dma_segment {
+ struct list_head list;
+ unsigned long req_size; /* Requested DMA segment size */
+ unsigned long blk_size; /* DMA block size */
+ unsigned long blk_order; /* DMA block size in alternate format */
+ unsigned long seg_size; /* Current DMA segment size */
+ unsigned long seg_begin; /* Logical address of segment */
+ unsigned long seg_end; /* Logical end address of segment */
+ unsigned long *blk_ptr; /* Array of logical DMA block addresses */
+ int blk_cnt_max; /* Maximum number of block to allocate */
+ int blk_cnt; /* Current number of blocks allocated */
+} dma_segment_t;
+
+static unsigned int _dma_mem_size = DMA_MEM_DEFAULT;
+static mpool_handle_t _dma_pool = NULL;
+static void __iomem *_dma_vbase = NULL;
+/* cpu physical address for mmap */
+static phys_addr_t _cpu_pbase = 0;
+/*
+ * DMA bus address, it is either identical to cpu physical address
+ * or another address(IOVA) translated by IOMMU.
+ */
+static phys_addr_t _dma_pbase = 0;
+static int _use_himem = 0;
+static unsigned long _himemaddr = 0;
+static int _use_dma_mapping = 0;
+static LIST_HEAD(_dma_seg);
+
+#define DMA_DEV_INDEX 0 /* Device index to allocate memory pool */
+#define DMA_DEV(n) lkbde_get_dma_dev(n)
+#define BDE_NUM_DEVICES(t) lkbde_get_num_devices(t)
+
+/*
+ * Function: _find_largest_segment
+ *
+ * Purpose:
+ * Find largest contiguous segment from a pool of DMA blocks.
+ * Parameters:
+ * dseg - DMA segment descriptor
+ * Returns:
+ * 0 on success, < 0 on error.
+ * Notes:
+ * Assembly stops if a segment of the requested segment size
+ * has been obtained.
+ *
+ * Lower address bits of the DMA blocks are used as follows:
+ * 0: Untagged
+ * 1: Discarded block
+ * 2: Part of largest contiguous segment
+ * 3: Part of current contiguous segment
+ */
+static int
+_find_largest_segment(dma_segment_t *dseg)
+{
+ int i, j, blks, found;
+ unsigned long b, e, a;
+
+ blks = dseg->blk_cnt;
+ /* Clear all block tags */
+ for (i = 0; i < blks; i++) {
+ dseg->blk_ptr[i] &= ~3;
+ }
+ for (i = 0; i < blks && dseg->seg_size < dseg->req_size; i++) {
+ /* First block must be an untagged block */
+ if ((dseg->blk_ptr[i] & 3) == 0) {
+ /* Initial segment size is the block size */
+ b = dseg->blk_ptr[i];
+ e = b + dseg->blk_size;
+ dseg->blk_ptr[i] |= 3;
+ /* Loop looking for adjacent blocks */
+ do {
+ found = 0;
+ for (j = i + 1; j < blks && (e - b) < dseg->req_size; j++) {
+ a = dseg->blk_ptr[j];
+ /* Check untagged blocks only */
+ if ((a & 3) == 0) {
+ if (a == (b - dseg->blk_size)) {
+ /* Found adjacent block below current segment */
+ dseg->blk_ptr[j] |= 3;
+ b = a;
+ found = 1;
+ } else if (a == e) {
+ /* Found adjacent block above current segment */
+ dseg->blk_ptr[j] |= 3;
+ e += dseg->blk_size;
+ found = 1;
+ }
+ }
+ }
+ } while (found);
+ if ((e - b) > dseg->seg_size) {
+ /* The current block is largest so far */
+ dseg->seg_begin = b;
+ dseg->seg_end = e;
+ dseg->seg_size = e - b;
+ /* Re-tag current and previous largest segment */
+ for (j = 0; j < blks; j++) {
+ if ((dseg->blk_ptr[j] & 3) == 3) {
+ /* Tag current segment as the largest */
+ dseg->blk_ptr[j] &= ~1;
+ } else if ((dseg->blk_ptr[j] & 3) == 2) {
+ /* Discard previous largest segment */
+ dseg->blk_ptr[j] ^= 3;
+ }
+ }
+ } else {
+ /* Discard all blocks in current segment */
+ for (j = 0; j < blks; j++) {
+ if ((dseg->blk_ptr[j] & 3) == 3) {
+ dseg->blk_ptr[j] &= ~2;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * Function: _alloc_dma_blocks
+ *
+ * Purpose:
+ * Allocate DMA blocks and add them to the pool.
+ * Parameters:
+ * dseg - DMA segment descriptor
+ * blks - number of DMA blocks to allocate
+ * Returns:
+ * 0 on success, < 0 on error.
+ * Notes:
+ * DMA blocks are allocated using the page allocator.
+ */
+static int
+_alloc_dma_blocks(dma_segment_t *dseg, int blks)
+{
+ int i, start;
+ unsigned long addr;
+
+ if (dseg->blk_cnt + blks > dseg->blk_cnt_max) {
+ gprintk("No more DMA blocks\n");
+ return -1;
+ }
+ start = dseg->blk_cnt;
+ for (i = 0; i < blks; i++) {
+ /*
+ * Note that we cannot use pci_alloc_consistent when we
+ * want to be able to map DMA memory to user space.
+ *
+ * The GFP_DMA flag is omitted as this imposes the ISA
+ * addressing limitations on x86 platforms. As long as
+ * we have less than 1GB of memory, we can do PCI DMA
+ * to all physical RAM locations.
+ */
+ addr = __get_free_pages(mem_flags, dseg->blk_order);
+ if (addr) {
+ dseg->blk_ptr[start + i] = addr;
+ ++dseg->blk_cnt;
+ } else {
+ gprintk("DMA allocation failed: allocated %d of %d "
+ "requested blocks\n", i, blks);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Function: _dma_segment_alloc
+ *
+ * Purpose:
+ * Allocate large physically contiguous DMA segment.
+ * Parameters:
+ * size - requested DMA segment size
+ * blk_size - assemble segment from blocks of this size
+ * Returns:
+ * DMA segment descriptor.
+ * Notes:
+ * Since we cannot allocate large blocks of contiguous
+ * memory from the kernel, we simply keep allocating
+ * smaller chunks until we can assemble a contiguous
+ * block of the desired size.
+ *
+ * When system allowed maximum bytes of memory has been allocated
+ * without a successful assembly of a contiguous DMA
+ * segment, the allocation function will return the
+ * largest contiguous segment found so far. It is up
+ * to the calling function to decide whether this
+ * amount is sufficient to proceed.
+ */
+static dma_segment_t *
+_dma_segment_alloc(size_t size, size_t blk_size)
+{
+ dma_segment_t *dseg;
+ int i, blk_ptr_size;
+ unsigned long page_addr;
+ struct sysinfo si;
+
+ /* Sanity check */
+ if (size == 0 || blk_size == 0) {
+ return NULL;
+ }
+ /* Allocate an initialize DMA segment descriptor */
+ if ((dseg = kmalloc(sizeof(dma_segment_t), GFP_KERNEL)) == NULL) {
+ return NULL;
+ }
+ memset(dseg, 0, sizeof(dma_segment_t));
+ dseg->req_size = size;
+ dseg->blk_size = PAGE_ALIGN(blk_size);
+ while ((PAGE_SIZE << dseg->blk_order) < dseg->blk_size) {
+ dseg->blk_order++;
+ }
+
+ si_meminfo(&si);
+ dseg->blk_cnt_max = (si.totalram << PAGE_SHIFT) / dseg->blk_size;
+ blk_ptr_size = dseg->blk_cnt_max * sizeof(unsigned long);
+ if (blk_ptr_size > KMALLOC_MAX_SIZE) {
+ blk_ptr_size = KMALLOC_MAX_SIZE;
+ dseg->blk_cnt_max = KMALLOC_MAX_SIZE / sizeof(unsigned long);
+ }
+ /* Allocate an initialize DMA block pool */
+ dseg->blk_ptr = KMALLOC(blk_ptr_size, GFP_KERNEL);
+ if (dseg->blk_ptr == NULL) {
+ kfree(dseg);
+ return NULL;
+ }
+ memset(dseg->blk_ptr, 0, blk_ptr_size);
+ /* Allocate minimum number of blocks */
+ if (_alloc_dma_blocks(dseg, dseg->req_size / dseg->blk_size) != 0) {
+ gprintk("Failed to allocate minimum number of DMA blocks\n");
+ /*
+ * _alloc_dma_blocks() returns -1 if it fails to allocate the requested
+ * number of blocks, but it may still have allocated something. Fall
+ * through and return dseg filled in with as much memory as we could
+ * allocate.
+ */
+ }
+ /* Allocate more blocks until we have a complete segment */
+ do {
+ _find_largest_segment(dseg);
+ if (dseg->seg_size >= dseg->req_size) {
+ break;
+ }
+ } while (_alloc_dma_blocks(dseg, 8) == 0);
+ /* Reserve all pages in the DMA segment and free unused blocks */
+ for (i = 0; i < dseg->blk_cnt; i++) {
+ if ((dseg->blk_ptr[i] & 3) == 2) {
+ dseg->blk_ptr[i] &= ~3;
+ for (page_addr = dseg->blk_ptr[i];
+ page_addr < dseg->blk_ptr[i] + dseg->blk_size;
+ page_addr += PAGE_SIZE) {
+ MEM_MAP_RESERVE(VIRT_TO_PAGE(page_addr));
+ }
+ } else if (dseg->blk_ptr[i]) {
+ dseg->blk_ptr[i] &= ~3;
+ free_pages(dseg->blk_ptr[i], dseg->blk_order);
+ dseg->blk_ptr[i] = 0;
+ }
+ }
+ return dseg;
+}
+
+/*
+ * Function: _dma_segment_free
+ *
+ * Purpose:
+ * Release resources used by DMA segment.
+ * Parameters:
+ * dseg - DMA segment descriptor
+ * Returns:
+ * Nothing.
+ */
+static void
+_dma_segment_free(dma_segment_t *dseg)
+{
+ int i;
+ unsigned long page_addr;
+
+ if (dseg->blk_ptr) {
+ for (i = 0; i < dseg->blk_cnt; i++) {
+ if (dseg->blk_ptr[i]) {
+ for (page_addr = dseg->blk_ptr[i];
+ page_addr < dseg->blk_ptr[i] + dseg->blk_size;
+ page_addr += PAGE_SIZE) {
+ MEM_MAP_UNRESERVE(VIRT_TO_PAGE(page_addr));
+ }
+ free_pages(dseg->blk_ptr[i], dseg->blk_order);
+ }
+ }
+ kfree(dseg->blk_ptr);
+ kfree(dseg);
+ }
+}
+
+/*
+ * Function: _pgalloc
+ *
+ * Purpose:
+ * Allocate DMA memory using page allocator
+ * Parameters:
+ * size - number of bytes to allocate
+ * Returns:
+ * Pointer to allocated DMA memory or NULL if failure.
+ * Notes:
+ * For any sizes less than DMA_BLOCK_SIZE, we ask the page
+ * allocator for the entire memory block, otherwise we try
+ * to assemble a contiguous segment ourselves.
+ */
+static void *
+_pgalloc(size_t size)
+{
+ dma_segment_t *dseg;
+ size_t blk_size;
+
+ blk_size = (size < DMA_BLOCK_SIZE) ? size : DMA_BLOCK_SIZE;
+ if ((dseg = _dma_segment_alloc(size, blk_size)) == NULL) {
+ return NULL;
+ }
+ if (dseg->seg_size < size) {
+ /* If we didn't get the full size then forget it */
+ gprintk("_pgalloc() failed to get requested size %zu: "
+ "only got %lu contiguous across %d blocks\n",
+ size, dseg->seg_size, dseg->blk_cnt);
+ _dma_segment_free(dseg);
+ return NULL;
+ }
+ list_add(&dseg->list, &_dma_seg);
+ return (void *)dseg->seg_begin;
+}
+
+/*
+ * Function: _pgfree
+ *
+ * Purpose:
+ * Free memory allocated by _pgalloc
+ * Parameters:
+ * ptr - pointer returned by _pgalloc
+ * Returns:
+ * 0 if succesfully freed, otherwise -1.
+ */
+static int
+_pgfree(void *ptr)
+{
+ struct list_head *pos;
+ list_for_each(pos, &_dma_seg) {
+ dma_segment_t *dseg = list_entry(pos, dma_segment_t, list);
+ if (ptr == (void *)dseg->seg_begin) {
+ list_del(&dseg->list);
+ _dma_segment_free(dseg);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/*
+ * Function: _pgcleanup
+ *
+ * Purpose:
+ * Free all memory allocated by _pgalloc
+ * Parameters:
+ * None
+ * Returns:
+ * Nothing.
+ */
+static void
+_pgcleanup(void)
+{
+ switch (dmaalloc) {
+#if _SIMPLE_MEMORY_ALLOCATION_
+ case ALLOC_TYPE_API:
+ if (_dma_vbase) {
+ if (dma_debug >= 1) gprintk("freeing v=%p p=0x%lx size=0x%lx\n", _dma_vbase,(unsigned long) _dma_pbase, (unsigned long)_dma_mem_size);
+ dma_free_coherent(DMA_DEV(DMA_DEV_INDEX), _dma_mem_size, _dma_vbase, _dma_pbase);
+ }
+ break;
+#endif /* _SIMPLE_MEMORY_ALLOCATION_ */
+
+ case ALLOC_TYPE_CHUNK: {
+ struct list_head *pos, *tmp;
+ int i, ndevices;
+ if (_use_dma_mapping) {
+ ndevices = BDE_NUM_DEVICES(BDE_SWITCH_DEVICES);
+ for (i = 0; i < ndevices && DMA_DEV(i); i ++) {
+ dma_unmap_single(DMA_DEV(i), (dma_addr_t)_dma_pbase, _dma_mem_size, DMA_BIDIRECTIONAL);
+ }
+ _use_dma_mapping = 0;
+ }
+ list_for_each_safe(pos, tmp, &_dma_seg) {
+ dma_segment_t *dseg = list_entry(pos, dma_segment_t, list);
+ list_del(&dseg->list);
+ _dma_segment_free(dseg);
+ }
+ break;
+ }
+
+ default:
+ gprintk("DMA memory allocation method dmaalloc=%d is not supported\n", dmaalloc);
+ }
+}
+
+/*
+ * Function: _alloc_mpool
+ *
+ * Purpose:
+ * Allocate DMA memory pool
+ * Parameters:
+ * size - size of DMA memory pool
+ * Returns:
+ * Nothing.
+ * Notes:
+ * If set up to use high memory, we simply map the memory into
+ * kernel space.
+ * It is assumed there is only one pool.
+ */
+static void
+_alloc_mpool(size_t size)
+{
+ unsigned long pbase = 0;
+#if defined(__arm__) && !defined(CONFIG_HIGHMEM)
+ if (_use_himem) {
+ gprintk("DMA in high memory requires CONFIG_HIGHMEM on ARM CPUs.\n");
+ return;
+ }
+#endif
+
+ if (_use_himem) {
+ /* Use high memory for DMA */
+ if (_himemaddr) {
+ pbase = _himemaddr;
+ } else {
+ pbase = virt_to_bus(high_memory);
+ }
+ if (((pbase + (size - 1)) >> 16) > DMA_BIT_MASK(16)) {
+ gprintk("DMA in high memory at 0x%lx size 0x%lx is beyond the 4GB limit and not supported.\n", pbase, (unsigned long)size);
+ return;
+ }
+ _cpu_pbase = _dma_pbase = pbase;
+ _dma_vbase = IOREMAP(_dma_pbase, size);
+ } else {
+ /* Get DMA memory from kernel */
+ if (dma_debug >= 1) {
+ gprintk("Allocating DMA memory using method dmaalloc=%d\n", dmaalloc);
+ }
+ switch (dmaalloc) {
+#if _SIMPLE_MEMORY_ALLOCATION_
+ case ALLOC_TYPE_API: {
+ size_t alloc_size = size; /* size of memory allocated in current iteration */
+ if (alloc_size > DMA_MAX_ALLOC_SIZE) {
+ alloc_size = DMA_MAX_ALLOC_SIZE;
+ }
+ /* get a memory allocation from the kernel */
+ {
+ dma_addr_t dma_handle;
+ if (!(_dma_vbase = dma_alloc_coherent(DMA_DEV(DMA_DEV_INDEX),
+ alloc_size, &dma_handle, GFP_KERNEL)) || !dma_handle) {
+ gprintk("Failed to allocate coherent memory pool of size 0x%lx\n", (unsigned long)alloc_size);
+ return;
+ }
+ _cpu_pbase = pbase = dma_handle;
+ }
+
+ if (alloc_size != size) {
+ gprintk("allocated 0x%lx bytes instead of 0x%lx bytes.\n",
+ (unsigned long)alloc_size, (unsigned long)size);
+ }
+ size = _dma_mem_size = alloc_size;
+ break;
+ }
+#endif /* _SIMPLE_MEMORY_ALLOCATION_ */
+
+ case ALLOC_TYPE_CHUNK:
+ _dma_vbase = _pgalloc(size);
+ if (!_dma_vbase) {
+ gprintk("Failed to allocate memory pool of size 0x%lx\n", (unsigned long)size);
+ return;
+ }
+ _cpu_pbase = virt_to_bus(_dma_vbase);
+ /* Use dma_map_single to obtain DMA bus address or IOVA if iommu is present. */
+ if (DMA_DEV(DMA_DEV_INDEX)) {
+ pbase = dma_map_single(DMA_DEV(DMA_DEV_INDEX), _dma_vbase, size, DMA_BIDIRECTIONAL);
+ if (DMA_MAPPING_ERROR(DMA_DEV(DMA_DEV_INDEX), pbase)) {
+ gprintk("Failed to map memory at %p\n", _dma_vbase);
+ _pgcleanup();
+ _dma_vbase = NULL;
+ return;
+ }
+ _use_dma_mapping = 1;
+ } else {
+ pbase = _cpu_pbase;
+ }
+ break;
+ default:
+ _dma_vbase = NULL;
+ gprintk("DMA memory allocation method dmaalloc=%d is not supported\n", dmaalloc);
+ return;
+ }
+
+ if (((pbase + (size - 1)) >> 16) > DMA_BIT_MASK(16)) {
+ gprintk("DMA memory allocated at 0x%lx size 0x%lx is beyond the 4GB limit and not supported.\n", pbase, (unsigned long)size);
+ _pgcleanup();
+ _dma_vbase = NULL;
+ _dma_pbase = 0;
+ return;
+ }
+
+ _dma_pbase = pbase;
+#ifdef REMAP_DMA_NONCACHED
+ _dma_vbase = IOREMAP(_dma_pbase, size);
+#endif
+ if (dma_debug >= 1) {
+ gprintk("_use_dma_mapping:%d _dma_vbase:%p _dma_pbase:%lx _cpu_pbase:%lx allocated:%lx dmaalloc:%d\n",
+ _use_dma_mapping, _dma_vbase, (unsigned long)_dma_pbase,
+ (unsigned long)_cpu_pbase, (unsigned long)size, dmaalloc);
+ }
+ }
+}
+
+/*
+ * Function: _dma_cleanup
+ *
+ * Purpose:
+ * DMA cleanup function.
+ * Parameters:
+ * None
+ * Returns:
+ * Always 0
+ */
+int
+_dma_cleanup(void)
+{
+ if (_dma_vbase) {
+ mpool_destroy(_dma_pool);
+ if (_use_himem) {
+ iounmap(_dma_vbase);
+ } else {
+#ifdef REMAP_DMA_NONCACHED
+ iounmap(_dma_vbase);
+#endif
+ _pgcleanup();
+ }
+ _dma_vbase = NULL;
+ _dma_pbase = 0;
+ _cpu_pbase = 0;
+ }
+ return 0;
+}
+
+void _dma_init(int dev_index)
+{
+ unsigned long pbase;
+
+ if (dev_index > DMA_DEV_INDEX) {
+ if (_use_dma_mapping && DMA_DEV(dev_index) && _dma_vbase) {
+ pbase = dma_map_single(DMA_DEV(dev_index), _dma_vbase, _dma_mem_size, DMA_BIDIRECTIONAL);
+ if (DMA_MAPPING_ERROR(DMA_DEV(dev_index), pbase)) {
+ gprintk("Failed to map memory for device %d at %p\n", dev_index, _dma_vbase);
+ return;
+ }
+ if (pbase != (unsigned long)_dma_pbase) {
+ /* Bus address/IOVA must be identical for all devices. */
+ gprintk("Device %d has different pbase: %lx (should be %lx)\n",
+ dev_index, pbase, (unsigned long)_dma_pbase);
+ }
+ }
+ return;
+ }
+
+ /* DMA Setup */
+ if (dmasize) {
+ if ((dmasize[strlen(dmasize)-1] & ~0x20) == 'M') {
+ _dma_mem_size = simple_strtoul(dmasize, NULL, 0);
+ _dma_mem_size *= ONE_MB;
+ } else {
+ gprintk("DMA memory size must be specified as e.g. dmasize=8M\n");
+ }
+ if (_dma_mem_size & (_dma_mem_size-1)) {
+ gprintk("dmasize must be a power of 2 (1M, 2M, 4M, 8M etc.)\n");
+ _dma_mem_size = 0;
+ }
+ }
+
+ if (himem) {
+ if ((himem[0] & ~0x20) == 'Y' || himem[0] == '1') {
+ _use_himem = 1;
+ } else if ((himem[0] & ~0x20) == 'N' || himem[0] == '0') {
+ _use_himem = 0;
+ }
+ }
+
+ if (himemaddr && strlen(himemaddr) > 0) {
+ char suffix = (himemaddr[strlen(himemaddr)-1] & ~0x20);
+ _himemaddr = simple_strtoul(himemaddr, NULL, 0);
+ if (suffix == 'M') {
+ _himemaddr *= ONE_MB;
+ } else if (suffix == 'G') {
+ _himemaddr *= ONE_GB;
+ } else {
+ gprintk("DMA high memory address must be specified as e.g. himemaddr=8[MG]\n");
+ }
+ }
+
+ if (_dma_mem_size) {
+ _alloc_mpool(_dma_mem_size);
+ if (_dma_vbase == NULL) {
+ gprintk("no DMA memory available\n");
+ } else {
+ mpool_init();
+ _dma_pool = mpool_create(_dma_vbase, _dma_mem_size);
+ }
+ }
+}
+
+/*
+ * Some kernels are configured to prevent mapping of kernel RAM memory
+ * into user space via the /dev/mem device.
+ *
+ * The function below provides a backdoor to mapping the DMA pool to
+ * user space via the BDE device file.
+ */
+int _dma_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ unsigned long phys_addr = vma->vm_pgoff << PAGE_SHIFT;
+ unsigned long size = vma->vm_end - vma->vm_start;
+
+ if (phys_addr < (unsigned long )_cpu_pbase ||
+ (phys_addr + size) > ((unsigned long )_cpu_pbase + _dma_mem_size)) {
+ gprintk("range 0x%lx-0x%lx outside DMA pool 0x%lx-0x%lx\n",
+ phys_addr, phys_addr + size, (unsigned long )_cpu_pbase,
+ (unsigned long )_cpu_pbase + _dma_mem_size);
+ return -EINVAL;
+ }
+
+#ifdef USE_DMA_MMAP_COHERENT
+ if (dmaalloc == ALLOC_TYPE_API) {
+ vma->vm_pgoff = 0;
+ return dma_mmap_coherent(DMA_DEV(DMA_DEV_INDEX), vma, (void *)_dma_vbase, phys_addr, size);
+ }
+#endif
+
+ _PGPROT_NONCACHED(vma->vm_page_prot);
+
+ if (remap_pfn_range(vma,
+ vma->vm_start,
+ vma->vm_pgoff,
+ size,
+ vma->vm_page_prot)) {
+ gprintk("Failed to mmap phys range 0x%lx-0x%lx to 0x%lx-0x%lx\n",
+ phys_addr, phys_addr + size, vma->vm_start,vma->vm_end);
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+/*
+ * Function: _dma_pool_allocated
+ *
+ * Purpose:
+ * Check if DMA pool has been allocated.
+ * Parameters:
+ * None
+ * Returns:
+ * 0 : not allocated
+ * 1 : allocated
+ */
+int
+_dma_pool_allocated(void)
+{
+ return (_dma_vbase) ? 1 : 0;
+}
+
+sal_paddr_t
+_l2p(int d, void *vaddr)
+{
+ if (_dma_mem_size) {
+ /* dma memory is a contiguous block */
+ if (vaddr) {
+ return _dma_pbase + (PTR_TO_UINTPTR(vaddr) - PTR_TO_UINTPTR(_dma_vbase));
+ }
+ return 0;
+ }
+ return ((sal_paddr_t)virt_to_bus(vaddr));
+}
+
+void *
+_p2l(int d, sal_paddr_t paddr)
+{
+ sal_vaddr_t vaddr = (sal_vaddr_t)_dma_vbase;
+
+ if (_dma_mem_size) {
+ /* DMA memory is a contiguous block */
+ if (paddr == 0) {
+ return NULL;
+ }
+ return (void *)(vaddr + (sal_vaddr_t)(paddr - _dma_pbase));
+ }
+ return bus_to_virt(paddr);
+}
+
+/*
+ * Some of the driver malloc's are too large for
+ * kmalloc(), so 'sal_alloc' and 'sal_free' in the
+ * linux kernel sal cannot be implemented with kmalloc().
+ *
+ * Instead, they expect someone to provide an allocator
+ * that can handle the gimongous size of some of the
+ * allocations, and we provide it here, by allocating
+ * this memory out of the boot-time dma pool.
+ *
+ * These are the functions in question:
+ */
+
+void* kmalloc_giant(int sz)
+{
+ return mpool_alloc(_dma_pool, sz);
+}
+
+void kfree_giant(void* ptr)
+{
+ return mpool_free(_dma_pool, ptr);
+}
+
+uint32_t *
+_salloc(int d, int size, const char *name)
+{
+ void *ptr;
+
+ if (_dma_mem_size) {
+ return mpool_alloc(_dma_pool, size);
+ }
+ if ((ptr = kmalloc(size, mem_flags)) == NULL) {
+ ptr = _pgalloc(size);
+ }
+ return ptr;
+}
+
+void
+_sfree(int d, void *ptr)
+{
+ if (_dma_mem_size) {
+ return mpool_free(_dma_pool, ptr);
+ }
+ if (_pgfree(ptr) < 0) {
+ kfree(ptr);
+ }
+}
+
+int
+_sinval(int d, void *ptr, int length)
+{
+#if defined(dma_cache_wback_inv)
+ dma_cache_wback_inv((unsigned long)ptr, length);
+#else
+#if defined(IPROC_CMICD) || defined(BCM958525)
+ /* FIXME: need proper function to replace dma_cache_sync */
+ dma_sync_single_for_cpu(NULL, (unsigned long)ptr, length, DMA_BIDIRECTIONAL);
+#else
+ dma_cache_sync(NULL, ptr, length, DMA_BIDIRECTIONAL);
+#endif
+#endif
+ return 0;
+}
+
+int
+_sflush(int d, void *ptr, int length)
+{
+#if defined(dma_cache_wback_inv)
+ dma_cache_wback_inv((unsigned long)ptr, length);
+#else
+#if defined(IPROC_CMICD) || defined(BCM958525)
+ /* FIXME: need proper function to replace dma_cache_sync */
+ dma_sync_single_for_cpu(NULL, (unsigned long)ptr, length, DMA_BIDIRECTIONAL);
+#else
+ dma_cache_sync(NULL, ptr, length, DMA_BIDIRECTIONAL);
+#endif
+#endif
+
+ return 0;
+}
+
+int
+lkbde_get_dma_info(phys_addr_t* cpu_pbase, phys_addr_t* dma_pbase, ssize_t* size)
+{
+ if (_dma_vbase == NULL) {
+ if (_dma_mem_size == 0) {
+ _dma_mem_size = DMA_MEM_DEFAULT;
+ }
+ _alloc_mpool(_dma_mem_size);
+ }
+ *cpu_pbase = _cpu_pbase;
+ *dma_pbase = _dma_pbase;
+ *size = (_dma_vbase) ? _dma_mem_size : 0;
+ return 0;
+}
+
+void
+_dma_pprint(void)
+{
+ pprintf("DMA Memory (%s): %d bytes, %d used, %d free%s\n",
+ (_use_himem) ? "high" : "kernel",
+ (_dma_vbase) ? _dma_mem_size : 0,
+ (_dma_vbase) ? mpool_usage(_dma_pool) : 0,
+ (_dma_vbase) ? _dma_mem_size - mpool_usage(_dma_pool) : 0,
+ USE_LINUX_BDE_MMAP ? ", local mmap" : "");
+}
+
+/*
+ * Export functions
+ */
+LKM_EXPORT_SYM(kmalloc_giant);
+LKM_EXPORT_SYM(kfree_giant);
+LKM_EXPORT_SYM(lkbde_get_dma_info);
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.c b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2014 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#include <gmodule.h>
+#include <shbde.h>
+#include <shbde_iproc.h>
+#include "linux_shbde.h"
+
+/* Hardware abstractions for shared BDE functions */
+
+static unsigned short
+linux_pcic16_read(void *pci_dev, unsigned int addr)
+{
+ u16 data = 0;
+
+ pci_read_config_word((struct pci_dev *)pci_dev, addr, &data);
+
+ return data;
+}
+
+static void
+linux_pcic16_write(void *pci_dev, unsigned int addr, unsigned short data)
+{
+ pci_write_config_word((struct pci_dev *)pci_dev, addr, (u16)data);
+}
+
+static unsigned int
+linux_pcic32_read(void *pci_dev, unsigned int addr)
+{
+ u32 data = 0;
+
+ pci_read_config_dword((struct pci_dev *)pci_dev, addr, &data);
+
+ return data;
+}
+
+static void
+linux_pcic32_write(void *pci_dev, unsigned int addr, unsigned int data)
+{
+ pci_write_config_dword((struct pci_dev *)pci_dev, addr, (u32)data);
+}
+
+static unsigned int
+linux_io32_read(void *addr)
+{
+ return *((volatile u32 *)addr);
+}
+
+static void
+linux_io32_write(void *addr, unsigned int data)
+{
+ *((volatile u32 *)addr) = data;
+}
+
+static void
+linux_usleep(int usec)
+{
+ udelay(usec);
+}
+
+
+/* To get the PCI parent device under linux, from only the device pointer */
+static void *
+linux_pci_parent_device_get(void *pci_dev)
+{
+ return (void *)(((struct pci_dev *)pci_dev)->bus->self);
+}
+
+
+/*
+ * Function:
+ * linux_shbde_hal_init
+ * Purpose:
+ * Initialize hardware abstraction module for Linux kernel.
+ * Parameters:
+ * shbde - pointer to uninitialized hardware abstraction module
+ * log_func - optional log output function
+ * Returns:
+ * Always 0
+ */
+int
+linux_shbde_hal_init(shbde_hal_t *shbde, shbde_log_func_t log_func)
+{
+ memset(shbde, 0, sizeof(*shbde));
+
+ shbde->log_func = log_func;
+
+ shbde->pcic16_read = linux_pcic16_read;
+ shbde->pcic16_write = linux_pcic16_write;
+ shbde->pcic32_read = linux_pcic32_read;
+ shbde->pcic32_write = linux_pcic32_write;
+
+ shbde->io32_read = linux_io32_read;
+ shbde->io32_write = linux_io32_write;
+
+ shbde->usleep = linux_usleep;
+
+ shbde->pci_parent_device_get = linux_pci_parent_device_get;
+
+ return 0;
+}
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.h b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2014 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#ifndef __LINUX_SHBDE_H__
+#define __LINUX_SHBDE_H__
+
+#include <shbde.h>
+#include <shbde_pci.h>
+#include <shbde_iproc.h>
+
+extern int
+linux_shbde_hal_init(shbde_hal_t *shbde, shbde_log_func_t log_func);
+
+#endif /* __LINUX_SHBDE_H__ */
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/shared/mpool.c b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/shared/mpool.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: mpool.c,v 1.18 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#include <mpool.h>
+
+#ifdef __KERNEL__
+
+/*
+ * Abstractions used when compiling for Linux kernel mode.
+ */
+
+#include <lkm.h>
+
+/*
+ * We cannot use the linux kernel SAL for MALLOC/FREE because
+ * the current implementation of sal_alloc() allocates memory
+ * out of an mpool created by this module...
+ */
+#define MALLOC(x) kmalloc(x, GFP_ATOMIC)
+#define FREE(x) kfree(x)
+
+static spinlock_t _mpool_lock;
+#define MPOOL_LOCK_INIT() spin_lock_init(&_mpool_lock)
+#define MPOOL_LOCK() unsigned long flags; spin_lock_irqsave(&_mpool_lock, flags)
+#define MPOOL_UNLOCK() spin_unlock_irqrestore(&_mpool_lock, flags)
+
+#else /* !__KERNEL__*/
+
+/*
+ * Abstractions used when compiling for Linux user mode.
+ */
+
+#include <stdlib.h>
+#include <sal/core/sync.h>
+
+#define MALLOC(x) malloc(x)
+#define FREE(x) free(x)
+
+static sal_sem_t _mpool_lock;
+#define MPOOL_LOCK_INIT() _mpool_lock = sal_sem_create("mpool_lock", 1, 1)
+#define MPOOL_LOCK() sal_sem_take(_mpool_lock, sal_sem_FOREVER)
+#define MPOOL_UNLOCK() sal_sem_give(_mpool_lock)
+
+#endif /* __KERNEL__ */
+
+/* Allow external override for system cache line size */
+#ifndef BCM_CACHE_LINE_BYTES
+#ifdef L1_CACHE_BYTES
+#define BCM_CACHE_LINE_BYTES L1_CACHE_BYTES
+#else
+#define BCM_CACHE_LINE_BYTES 128 /* Should be fine on most platforms */
+#endif
+#endif
+
+#define MPOOL_BUF_SIZE 1024
+#define MPOOL_BUF_ALLOC_COUNT_MAX 16
+
+typedef struct mpool_mem_s {
+ unsigned char *address;
+ int size;
+ struct mpool_mem_s *prev;
+ struct mpool_mem_s *next;
+} mpool_mem_t;
+
+static int _buf_alloc_count;
+static mpool_mem_t *mpool_buf[MPOOL_BUF_ALLOC_COUNT_MAX];
+static mpool_mem_t *free_list;
+
+#define ALLOC_INIT_MPOOL_BUF(ptr) \
+ ptr = MALLOC((sizeof(mpool_mem_t) * MPOOL_BUF_SIZE)); \
+ if (ptr) { \
+ int i; \
+ for (i = 0; i < MPOOL_BUF_SIZE - 1; i++) { \
+ ptr[i].next = &ptr[i+1]; \
+ } \
+ ptr[MPOOL_BUF_SIZE - 1].next = NULL; \
+ free_list = &ptr[0]; \
+ }
+
+/*
+ * Function: mpool_init
+ *
+ * Purpose:
+ * Initialize mpool lock.
+ * Parameters:
+ * None
+ * Returns:
+ * Always 0
+ */
+int
+mpool_init(void)
+{
+ MPOOL_LOCK_INIT();
+ return 0;
+}
+
+#ifdef TRACK_DMA_USAGE
+static int _dma_mem_used = 0;
+#endif
+
+/*
+ * Function: mpool_alloc
+ *
+ * Purpose:
+ * Allocate memory block from mpool.
+ * Parameters:
+ * pool - mpool handle (from mpool_create)
+ * size - size of memory block to allocate
+ * Returns:
+ * Pointer to allocated memory block or NULL if allocation fails.
+ */
+void *
+mpool_alloc(mpool_handle_t pool, int size)
+{
+ mpool_mem_t *ptr = pool, *newptr = NULL;
+ int mod;
+
+ MPOOL_LOCK();
+
+ if (size < BCM_CACHE_LINE_BYTES) {
+ size = BCM_CACHE_LINE_BYTES;
+ }
+
+ mod = size & (BCM_CACHE_LINE_BYTES - 1);
+ if (mod != 0 ) {
+ size += (BCM_CACHE_LINE_BYTES - mod);
+ }
+ while (ptr && ptr->next) {
+ if (ptr->next->address - (ptr->address + ptr->size) >= size) {
+ break;
+ }
+ ptr = ptr->next;
+ }
+
+ if (!(ptr && ptr->next)) {
+ MPOOL_UNLOCK();
+ return NULL;
+ }
+
+ if (!free_list) {
+ if (_buf_alloc_count == MPOOL_BUF_ALLOC_COUNT_MAX) {
+ MPOOL_UNLOCK();
+ return NULL;
+ }
+
+ ALLOC_INIT_MPOOL_BUF(mpool_buf[_buf_alloc_count]);
+
+ if (mpool_buf[_buf_alloc_count] == NULL) {
+ MPOOL_UNLOCK();
+ return NULL;
+ }
+
+ _buf_alloc_count++;
+ }
+
+ newptr = free_list;
+ free_list = free_list->next;
+
+ newptr->address = ptr->address + ptr->size;
+ newptr->size = size;
+ newptr->next = ptr->next;
+ newptr->prev = ptr;
+ ptr->next->prev = newptr;
+ ptr->next = newptr;
+#ifdef TRACK_DMA_USAGE
+ _dma_mem_used += size;
+#endif
+
+ MPOOL_UNLOCK();
+ return newptr->address;
+}
+
+
+/*
+ * Function: mpool_free
+ *
+ * Purpose:
+ * Free memory block allocated from mpool..
+ * Parameters:
+ * pool - mpool handle (from mpool_create)
+ * addr - address of memory block to free
+ * Returns:
+ * Nothing
+ */
+void
+mpool_free(mpool_handle_t pool, void *addr)
+{
+ unsigned char *address = (unsigned char *)addr;
+ mpool_mem_t *head = pool, *ptr = NULL;
+
+ MPOOL_LOCK();
+
+ if (!(head && head->prev)) {
+ MPOOL_UNLOCK();
+ return;
+ }
+
+ ptr = head->prev->prev;
+
+ while (ptr && (ptr != head)) {
+ if (ptr->address == address) {
+#ifdef TRACK_DMA_USAGE
+ _dma_mem_used -= ptr->size;
+#endif
+ ptr->prev->next = ptr->next;
+ ptr->next->prev = ptr->prev;
+ ptr->next = free_list;
+ free_list = ptr;
+ break;
+ }
+ ptr = ptr->prev;
+ }
+
+ MPOOL_UNLOCK();
+}
+
+/*
+ * Function: mpool_create
+ *
+ * Purpose:
+ * Create and initialize mpool control structures.
+ * Parameters:
+ * base_ptr - pointer to mpool memory block
+ * size - total size of mpool memory block
+ * Returns:
+ * mpool handle
+ * Notes
+ * The mpool handle returned must be used for subsequent
+ * memory allocations from the mpool.
+ */
+mpool_handle_t
+mpool_create(void *base_ptr, int size)
+{
+ mpool_mem_t *head, *tail;
+ int mod = (int)(((unsigned long)base_ptr) & (BCM_CACHE_LINE_BYTES - 1));
+ int i;
+
+ MPOOL_LOCK();
+
+ for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) {
+ mpool_buf[i] = NULL;
+ }
+
+ _buf_alloc_count = 0;
+
+ ALLOC_INIT_MPOOL_BUF(mpool_buf[_buf_alloc_count]);
+
+ if (mpool_buf[_buf_alloc_count] == NULL) {
+ MPOOL_UNLOCK();
+ return NULL;
+ }
+
+ _buf_alloc_count++;
+
+ if (mod) {
+ base_ptr = (char*)base_ptr + (BCM_CACHE_LINE_BYTES - mod);
+ size -= (BCM_CACHE_LINE_BYTES - mod);
+ }
+ size &= ~(BCM_CACHE_LINE_BYTES - 1);
+
+ head = free_list;
+ free_list = free_list->next;
+ tail = free_list;
+ free_list = free_list->next;
+
+ head->size = tail->size = 0;
+ head->address = base_ptr;
+ tail->address = head->address + size;
+ head->prev = tail;
+ head->next = tail;
+ tail->prev = head;
+ tail->next = NULL;
+
+ MPOOL_UNLOCK();
+ return head;
+}
+
+/*
+ * Function: mpool_destroy
+ *
+ * Purpose:
+ * Free mpool control structures.
+ * Parameters:
+ * pool - mpool handle (from mpool_create)
+ * Returns:
+ * Always 0
+ */
+int
+mpool_destroy(mpool_handle_t pool)
+{
+ int i;
+
+ MPOOL_LOCK();
+
+ if ((mpool_mem_t *)pool != mpool_buf[0]) {
+ MPOOL_UNLOCK();
+ return 0;
+ }
+
+ for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) {
+ if (mpool_buf[i]) {
+ FREE(mpool_buf[i]);
+ mpool_buf[i] = NULL;
+ }
+ }
+
+ MPOOL_UNLOCK();
+
+ return 0;
+}
+
+/*
+ * Function: mpool_usage
+ *
+ * Purpose:
+ * Report total sum of allocated mpool memory.
+ * Parameters:
+ * pool - mpool handle (from mpool_create)
+ * Returns:
+ * Number of bytes currently allocated using mpool_alloc.
+ */
+int
+mpool_usage(mpool_handle_t pool)
+{
+ int usage = 0;
+ mpool_mem_t *ptr;
+
+ MPOOL_LOCK();
+
+ for (ptr = pool; ptr; ptr = ptr->next) {
+ usage += ptr->size;
+ }
+
+ MPOOL_UNLOCK();
+
+ return usage;
+}
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/user/kernel/Makefile b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/user/kernel/Makefile
@@ -0,0 +1,70 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.1 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+LOCALDIR = systems/bde/linux/user/kernel
+
+# Make sure we build for the kernel if this is a user-mode build
+ifneq ($(platform), )
+override-target=linux-$(platform)
+endif
+
+include $(SDK)/make/Make.config
+
+LIBS = $(LIBDIR)/libkern.a
+
+ifneq ($(kernel_version),2_4)
+KERNEL_MODULE_DIR = kernel_module
+
+THIS_MOD_NAME := linux-user-bde
+MODULE = $(LIBDIR)/$(THIS_MOD_NAME).o
+KMODULE = $(LIBDIR)/$(THIS_MOD_NAME).ko
+
+build: kernel_libs $(MODULE) $(KMODULE)
+else
+MODULE = $(LIBDIR)/linux-user-bde.o
+
+build: kernel_libs $(MODULE)
+endif
+
+KBUILD_EXTRA_SYMBOLS := ${BLDDIR}/../../kernel/kernel_module/Module.symvers
+
+$(MODULE): $(BLDDIR)/.tree $(BOBJS) $(LIBS)
+ $(LD) $(MODULE_LDFLAGS) -r -d $(BOBJS) $(LIBS) -o $@
+ifneq ($(kernel_version),2_4)
+$(KMODULE): $(MODULE)
+ rm -fr $(BLDDIR)/$(KERNEL_MODULE_DIR)
+ mkdir $(BLDDIR)/$(KERNEL_MODULE_DIR)
+ cp ${SDK}/make/Makefile.linux-kmodule $(BLDDIR)/$(KERNEL_MODULE_DIR)/Makefile
+ cat ${KBUILD_EXTRA_SYMBOLS} > $(BLDDIR)/$(KERNEL_MODULE_DIR)/Module.symvers
+ MOD_NAME=$(THIS_MOD_NAME) $(MAKE) -C $(BLDDIR)/$(KERNEL_MODULE_DIR) $(THIS_MOD_NAME).ko
+endif
+
+kernel_libs:
+ $(MAKE) -C $(SDK)/systems/linux/kernel/modules/shared
+
+include $(SDK)/make/Make.depend
+
+# Make.depend is before clean:: so that Make.depend's clean:: runs first.
+
+clean::
+ $(MAKE) -C $(SDK)/systems/linux/kernel/modules/shared $@
+ $(RM) $(BOBJS) $(MODULE)
+
+.PHONY: build kernel_libs
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.c b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.c
@@ -0,0 +1,1456 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: linux-user-bde.c,v 1.80 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ * Linux User BDE Helper Module
+ */
+#include <gmodule.h>
+#include <mpool.h>
+#include <linux-bde.h>
+
+#include <sal/core/thread.h>
+#include <sal/core/sync.h>
+#include <soc/devids.h>
+#include <soc/drv.h>
+
+#include "linux-user-bde.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0)
+#include <linux/uaccess.h>
+#endif
+
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("User BDE Helper Module");
+MODULE_LICENSE("GPL");
+
+/* CMIC/CMICe defines */
+#define CMIC_IRQ_STAT 0x00000144
+#define CMIC_IRQ_MASK 0x00000148
+#define CMIC_IRQ_MASK_1 0x0000006C
+#define CMIC_IRQ_MASK_2 0x00000070
+
+/* CMICm defines */
+#define CMIC_CMCx_IRQ_STAT0_OFFSET(x) (0x31400 + (0x1000 * x))
+#define CMIC_CMCx_IRQ_STAT1_OFFSET(x) (0x31404 + (0x1000 * x))
+#define CMIC_CMCx_IRQ_STAT2_OFFSET(x) (0x31408 + (0x1000 * x))
+#define CMIC_CMCx_IRQ_STAT3_OFFSET(x) (0x3140c + (0x1000 * x))
+#define CMIC_CMCx_IRQ_STAT4_OFFSET(x) (0x31410 + (0x1000 * x))
+
+#define CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(x) (0x31414 + (0x1000 * x))
+#define CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(x) (0x31418 + (0x1000 * x))
+#define CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(x) (0x3141c + (0x1000 * x))
+#define CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(x) (0x31420 + (0x1000 * x))
+#define CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(x) (0x31424 + (0x1000 * x))
+
+/* CMICd defines */
+#define CMIC_CMCx_IRQ_STAT5_OFFSET(x) (0x314b0 + (0x1000 * x))
+#define CMIC_CMCx_IRQ_STAT6_OFFSET(x) (0x314b4 + (0x1000 * x))
+#define CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(x) (0x314b8 + (0x1000 * x))
+#define CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(x) (0x314bc + (0x1000 * x))
+#define CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(x) (0x314c0 + (0x1000 * x))
+#define CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(x) (0x314c4 + (0x1000 * x))
+
+#define CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(x) (0x31428 + (0x1000 * x))
+#define CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(x) (0x3142c + (0x1000 * x))
+#define CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(x) (0x31430 + (0x1000 * x))
+#define CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(x) (0x31434 + (0x1000 * x))
+#define CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(x) (0x31438 + (0x1000 * x))
+
+/* CMICX defines */
+#define INTC_INTR_REG_NUM (8)
+
+/*
+TODO:HX5
+The INTR base address values are changed for HX5,
+hence making new #defines so runtime decisions can
+be made.
+*/
+
+#define INTC_INTR_ENABLE_REG0 (0x180130f0)
+#define INTC_INTR_STATUS_REG0 (0x18013190)
+#define INTC_INTR_RAW_STATUS_REG0 (0x18013140)
+
+#define INTC_INTR_ENABLE_BASE (INTC_INTR_ENABLE_REG0)
+#define INTC_INTR_STATUS_BASE (INTC_INTR_STATUS_REG0)
+#define INTC_INTR_RAW_STATUS_BASE (INTC_INTR_RAW_STATUS_REG0)
+
+#define HX5_INTC_INTR_ENABLE_REG0 (0x102310f0)
+#define HX5_INTC_INTR_STATUS_REG0 (0x10231190)
+#define HX5_INTC_INTR_RAW_STATUS_REG0 (0x10231140)
+
+#define HX5_INTC_INTR_ENABLE_BASE (HX5_INTC_INTR_ENABLE_REG0)
+#define HX5_INTC_INTR_STATUS_BASE (HX5_INTC_INTR_STATUS_REG0)
+#define HX5_INTC_INTR_RAW_STATUS_BASE (HX5_INTC_INTR_RAW_STATUS_REG0)
+
+#define IOREMAP(addr, size) ioremap_nocache(addr, size)
+
+#define HX5_IHOST_GICD_ISENABLERN_0 (0x10781100)
+#define HX5_IHOST_GICD_ISENABLERN_1 (0x10781104)
+#define HX5_IHOST_GICD_ICENABLERN_1 (0x10781184)
+#define HX5_IHOST_GICD_ICENABLERN_8 (0x107811a0)
+/* Offset between ISENABLERN_1 and ICENABLERN_1 in 4-bytes */
+#define HX5_IHOST_IRQ_MASK_OFFSET 0x20
+#define HX5_IHOST_INTR_MAP_NUM (HX5_IHOST_GICD_ICENABLERN_8 - HX5_IHOST_GICD_ISENABLERN_0)
+#define HX5_IHOST_INTR_STATUS_MAP_NUM (INTC_INTR_REG_NUM * (sizeof(uint32)))
+#define IRQ_BIT(intr) (intr % (sizeof(uint32)*8))
+#define IRQ_MASK_INDEX(intr) (intr / (sizeof(uint32)*8))
+#define HX5_CHIP_INTR_LOW_PRIORITY 119
+#define INTR_LOW_PRIORITY_BITPOS (1 << IRQ_BIT(HX5_CHIP_INTR_LOW_PRIORITY))
+#define INTC_LOW_PRIORITY_INTR_REG_IND IRQ_MASK_INDEX(HX5_CHIP_INTR_LOW_PRIORITY)
+#define INTC_PDMA_INTR_REG_IND 4
+
+#define READ_INTC_INTR(d, reg, v) \
+ (v = user_bde->iproc_read(d, reg))
+#define WRITE_INTC_INTR(d, reg, v) \
+ (user_bde->iproc_write(d, reg, v))
+
+#define IHOST_READ_INTR(d, reg, v) \
+ (v = readl((reg)))
+#define IHOST_WRITE_INTR(d, reg, v) \
+ (writel((v), (reg)))
+
+/* Allow override of default CMICm CMC */
+#ifndef BDE_CMICM_PCIE_CMC
+#define BDE_CMICM_PCIE_CMC 0
+#endif
+
+/* Allow override of default CMICm CMC */
+#ifndef BDE_CMICD_PCIE_CMC
+#define BDE_CMICD_PCIE_CMC 0
+#endif
+
+/* Defines used to distinguish CMICe from CMICm */
+#define CMICE_DEV_REV_ID (0x178 / sizeof(uint32))
+
+static uint32 *ihost_intr_status_base = NULL;
+static uint32 *ihost_intr_enable_base = NULL;
+
+static ibde_t *user_bde = NULL;
+
+typedef void (*isr_f)(void *);
+
+typedef struct bde_ctrl_s {
+ uint32 dev_type;
+ int irq;
+ int enabled;
+ int devid;
+ isr_f isr;
+ uint32 *ba;
+ int inst; /* associate to _bde_inst_resource[] */
+} bde_ctrl_t;
+
+#define VALID_DEVICE(_n) (_n < LINUX_BDE_MAX_DEVICES)
+
+static bde_ctrl_t _devices[LINUX_BDE_MAX_DEVICES];
+
+static wait_queue_head_t _ether_interrupt_wq;
+static atomic_t _ether_interrupt_has_taken_place = ATOMIC_INIT(0);
+
+/*
+ * Multiple instance resource data structure.
+ * To keep the DMA resource per instance.
+ * And track the DMA pool usage.
+ */
+static int _bde_multi_inst = 0;
+
+typedef struct {
+ unsigned int inst_id;
+ unsigned int dma_offset;
+ unsigned int dma_size;
+ wait_queue_head_t intr_wq;
+ atomic_t intr;
+} bde_inst_resource_t;
+
+static bde_inst_resource_t _bde_inst_resource[LINUX_BDE_MAX_DEVICES];
+
+typedef struct {
+ phys_addr_t cpu_pbase; /* CPU physical base address of the DMA pool */
+ phys_addr_t dma_pbase; /* Bus base address of the DMA pool */
+ uint32 total_size; /* Total size of the pool in MB */
+ uint32 offset; /* Current offset of the pool in MB */
+}_dma_pool_t;
+
+static _dma_pool_t _dma_pool;
+
+#define ONE_MB (1024 * 1024)
+
+#ifdef KEYSTONE
+/*
+ * Enforce PCIE transaction ordering. Commit the write transaction.
+ */
+
+#define SSOC_WRITEL(val, addr) \
+ do { \
+ writel((val), (addr)); \
+ __asm__ __volatile__("sync"); \
+ } while(0)
+
+#else
+
+#define SSOC_WRITEL(val, addr) \
+ writel((val), (addr))
+
+#endif
+/*
+ * Function: _interrupt
+ *
+ * Purpose:
+ * Interrupt Handler.
+ * Mask all interrupts on device and wake up interrupt
+ * thread. It is assumed that the interrupt thread unmasks
+ * interrupts again when interrupt handling is complete.
+ * Parameters:
+ * ctrl - BDE control structure for this device.
+ * Returns:
+ * Nothing
+ */
+static void
+_cmic_interrupt(bde_ctrl_t *ctrl)
+{
+ int d;
+ uint32_t mask = 0, stat, imask = 0, fmask = 0;
+ bde_inst_resource_t *res;
+
+ d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
+ res = &_bde_inst_resource[ctrl->inst];
+
+ /* Check for secondary interrupt handler */
+ if (lkbde_irq_mask_get(d, &mask, &fmask) < 0) {
+ fmask = 0;
+ }
+
+ if (fmask != 0) {
+ imask = mask & ~fmask;
+ /* Check for pending user mode interrupts */
+ stat = user_bde->read(d, CMIC_IRQ_STAT);
+ if ((stat & imask) == 0) {
+ /* All handled in kernel mode */
+ lkbde_irq_mask_set(d, CMIC_IRQ_MASK, imask, 0);
+ return;
+ }
+ }
+
+ lkbde_irq_mask_set(d, CMIC_IRQ_MASK, 0, 0);
+
+ atomic_set(&res->intr, 1);
+
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wake_up(&res->intr_wq);
+#else
+ wake_up_interruptible(&res->intr_wq);
+#endif
+}
+
+static void
+_cmicx_interrupt(bde_ctrl_t *ctrl)
+{
+ int d, ind;
+ uint32 stat, iena, mask, fmask;
+ bde_inst_resource_t *res;
+ uint32 intc_intr_status_base = 0, intc_intr_enable_base = 0;
+
+ d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
+ res = &_bde_inst_resource[ctrl->inst];
+
+ lkbde_irq_mask_get(d, &mask, &fmask);
+
+ if ((ctrl->dev_type & BDE_SWITCH_DEV_TYPE) &&
+ ((user_bde->get_dev(d)->device == BCM56370_DEVICE_ID) ||
+ (user_bde->get_dev(d)->device == BCM56371_DEVICE_ID) ||
+ (user_bde->get_dev(d)->device == BCM56372_DEVICE_ID) ||
+ (user_bde->get_dev(d)->device == BCM56374_DEVICE_ID) ||
+ (user_bde->get_dev(d)->device == BCM56375_DEVICE_ID) ||
+ (user_bde->get_dev(d)->device == BCM56376_DEVICE_ID) ||
+ (user_bde->get_dev(d)->device == BCM56377_DEVICE_ID) ||
+ (user_bde->get_dev(d)->device == BCM56577_DEVICE_ID) ||
+ (user_bde->get_dev(d)->device == BCM56578_DEVICE_ID) ||
+ (user_bde->get_dev(d)->device == BCM56579_DEVICE_ID))) {
+ intc_intr_status_base = HX5_INTC_INTR_STATUS_BASE;
+ intc_intr_enable_base = HX5_INTC_INTR_ENABLE_BASE;
+ } else {
+ intc_intr_status_base = INTC_INTR_STATUS_BASE;
+ intc_intr_enable_base = INTC_INTR_ENABLE_BASE;
+ }
+ if (fmask) {
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ IHOST_READ_INTR(d, ihost_intr_status_base + INTC_PDMA_INTR_REG_IND, stat);
+ IHOST_READ_INTR(d, ihost_intr_enable_base + INTC_PDMA_INTR_REG_IND, iena);
+ } else {
+ READ_INTC_INTR(d, intc_intr_status_base + 4 * INTC_PDMA_INTR_REG_IND, stat);
+ READ_INTC_INTR(d, intc_intr_enable_base + 4 * INTC_PDMA_INTR_REG_IND, iena);
+ }
+ if (stat & iena) {
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ IHOST_WRITE_INTR(d, ihost_intr_enable_base + INTC_PDMA_INTR_REG_IND +
+ HX5_IHOST_IRQ_MASK_OFFSET, ~0);
+ } else {
+ WRITE_INTC_INTR(d, intc_intr_enable_base + 4 * INTC_PDMA_INTR_REG_IND, 0);
+ }
+
+ for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) {
+ if (ind == INTC_PDMA_INTR_REG_IND) {
+ continue;
+ }
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ if (ind < INTC_LOW_PRIORITY_INTR_REG_IND) {
+ continue;
+ }
+ IHOST_READ_INTR(d, ihost_intr_status_base + ind, stat);
+ IHOST_READ_INTR(d, ihost_intr_enable_base + ind, iena);
+ if (ind == INTC_LOW_PRIORITY_INTR_REG_IND) {
+ stat &= INTR_LOW_PRIORITY_BITPOS;
+ }
+ } else {
+ READ_INTC_INTR(d, intc_intr_status_base + 4 * ind, stat);
+ READ_INTC_INTR(d, intc_intr_enable_base + 4 * ind, iena);
+ }
+ if (stat & iena) {
+ break;
+ }
+ }
+
+ if (ind >= INTC_INTR_REG_NUM) {
+ return;
+ }
+ }
+ }
+
+ /* Disable all interrupts.. Re-enable unserviced interrupts later
+ * So as to avoid getting new interrupts until the user level driver
+ * enumerates the interrupts to be serviced
+ */
+ for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) {
+ if (fmask && ind == INTC_PDMA_INTR_REG_IND) {
+ continue;
+ }
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ if (ind < INTC_LOW_PRIORITY_INTR_REG_IND) {
+ continue;
+ }
+ if (ind == INTC_LOW_PRIORITY_INTR_REG_IND) {
+ IHOST_WRITE_INTR(d, ihost_intr_enable_base + INTC_LOW_PRIORITY_INTR_REG_IND +
+ HX5_IHOST_IRQ_MASK_OFFSET, INTR_LOW_PRIORITY_BITPOS);
+ } else {
+ IHOST_WRITE_INTR(d, ihost_intr_enable_base + ind +
+ HX5_IHOST_IRQ_MASK_OFFSET, ~0);
+ }
+ } else {
+ WRITE_INTC_INTR(d, intc_intr_enable_base + 4*ind, 0);
+ }
+ }
+
+ /* Notify */
+ atomic_set(&res->intr, 1);
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wake_up(&res->intr_wq);
+#else
+ wake_up_interruptible(&res->intr_wq);
+#endif
+}
+
+static void
+_cmicm_interrupt(bde_ctrl_t *ctrl)
+{
+ int d;
+ int cmc = BDE_CMICM_PCIE_CMC;
+ uint32 stat, mask = 0, fmask = 0, imask = 0;
+ bde_inst_resource_t *res;
+
+ d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
+ res = &_bde_inst_resource[ctrl->inst];
+
+ lkbde_irq_mask_get(d, &mask, &fmask);
+
+ while (fmask) {
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT0_OFFSET(cmc));
+ imask = mask & ~fmask;
+ if (stat & imask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT1_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT2_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT3_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT4_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ return;
+ }
+
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ lkbde_irq_mask_set(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(cmc), 0, 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(1), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(2), 0);
+ }
+ else {
+ lkbde_irq_mask_set(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(cmc), 0, 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(1), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(2), 0);
+ }
+ atomic_set(&res->intr, 1);
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wake_up(&res->intr_wq);
+#else
+ wake_up_interruptible(&res->intr_wq);
+#endif
+}
+
+/* some device has cmc0 only */
+static void
+_cmicd_cmc0_interrupt(bde_ctrl_t *ctrl)
+{
+ int d;
+ int cmc = 0;
+ uint32 stat, mask = 0, fmask = 0, imask = 0;
+ bde_inst_resource_t *res;
+
+ d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
+ res = &_bde_inst_resource[ctrl->inst];
+ lkbde_irq_mask_get(d, &mask, &fmask);
+
+ while (fmask) {
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT0_OFFSET(cmc));
+ imask = mask & ~fmask;
+ if (stat & imask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT1_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT2_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT3_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT4_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT5_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT6_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ return;
+ }
+
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ lkbde_irq_mask_set(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(cmc), 0, 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc), 0);
+ } else {
+ lkbde_irq_mask_set(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(cmc), 0, 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(cmc), 0);
+ }
+ atomic_set(&res->intr, 1);
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wake_up(&res->intr_wq);
+#else
+ wake_up_interruptible(&res->intr_wq);
+#endif
+}
+
+static void
+_cmicd_interrupt(bde_ctrl_t *ctrl)
+{
+ int d;
+ int cmc = BDE_CMICD_PCIE_CMC;
+ uint32 stat, mask = 0, fmask = 0, imask = 0;
+ bde_inst_resource_t *res;
+
+ d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
+ res = &_bde_inst_resource[ctrl->inst];
+ lkbde_irq_mask_get(d, &mask, &fmask);
+
+ while (fmask) {
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT0_OFFSET(cmc));
+ imask = mask & ~fmask;
+ if (stat & imask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT1_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT2_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT3_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT4_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT5_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT6_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ return;
+ }
+
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ lkbde_irq_mask_set(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(cmc), 0, 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(1), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(2), 0);
+ } else {
+ lkbde_irq_mask_set(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(cmc), 0, 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(1), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(2), 0);
+ }
+ atomic_set(&res->intr, 1);
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wake_up(&res->intr_wq);
+#else
+ wake_up_interruptible(&res->intr_wq);
+#endif
+}
+
+static void
+_bcm88750_interrupt(bde_ctrl_t *ctrl)
+{
+ int d;
+ bde_inst_resource_t *res;
+
+ d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
+ res = &_bde_inst_resource[ctrl->inst];
+ lkbde_irq_mask_set(d, CMIC_IRQ_MASK, 0, 0);
+
+ lkbde_irq_mask_set(d, CMIC_IRQ_MASK_1, 0, 0);
+ lkbde_irq_mask_set(d, CMIC_IRQ_MASK_2, 0, 0);
+ atomic_set(&res->intr, 1);
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wake_up(&res->intr_wq);
+#else
+ wake_up_interruptible(&res->intr_wq);
+#endif
+}
+
+/* The actual interrupt handler of ethernet devices */
+static void
+_ether_interrupt(bde_ctrl_t *ctrl)
+{
+ SSOC_WRITEL(0, ctrl->ba + 0x024/4);
+
+ atomic_set(&_ether_interrupt_has_taken_place, 1);
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wake_up(&_ether_interrupt_wq);
+#else
+ wake_up_interruptible(&_ether_interrupt_wq);
+#endif
+}
+
+
+static struct _intr_mode_s {
+ isr_f isr;
+ const char *name;
+} _intr_mode[] = {
+ { (isr_f)_cmic_interrupt, "CMIC/CMICe" },
+ { (isr_f)_cmicm_interrupt, "CMICm" },
+ { (isr_f)_cmicd_interrupt, "CMICd" },
+ { (isr_f)_cmicd_cmc0_interrupt, "CMICd CMC0" },
+ { (isr_f)_bcm88750_interrupt, "BCM88750" },
+ { (isr_f)_cmicx_interrupt, "CMICx" },
+ { NULL, NULL }
+};
+
+static const char *
+_intr_mode_str(void *isr)
+{
+ int imx;
+
+ imx = 0;
+ while (_intr_mode[imx].isr != NULL) {
+ if (isr == _intr_mode[imx].isr) {
+ return _intr_mode[imx].name;
+ }
+ imx++;
+ }
+ return NULL;
+}
+
+static void
+_devices_init(int d)
+{
+ bde_ctrl_t *ctrl;
+ uint32 ver;
+ uint16 device_id_mask = 0xFFF0;
+ uint16 device_id;
+ uint32 state = 0;
+
+ (void)lkbde_dev_state_get(d, &state);
+ if (state == BDE_DEV_STATE_REMOVED) {
+ return;
+ }
+
+ ctrl = &_devices[d];
+ /* Initialize our control info */
+ ctrl->dev_type = user_bde->get_dev_type(d);
+ ctrl->devid = user_bde->get_dev(d)->device;
+ ctrl->inst = 0;
+
+ if (BDE_DEV_MEM_MAPPED(ctrl->dev_type)) {
+ ctrl->enabled = 0;
+ ctrl->ba = lkbde_get_dev_virt(d);
+ }
+ if (ctrl->dev_type & BDE_SWITCH_DEV_TYPE) {
+ switch (user_bde->get_dev(d)->device) {
+ case BCM88750_DEVICE_ID:
+ case BCM88753_DEVICE_ID:
+ case BCM88754_DEVICE_ID:
+ case BCM88755_DEVICE_ID:
+ case BCM88752_DEVICE_ID:
+ ctrl->isr = (isr_f)_bcm88750_interrupt;
+ break;
+ case BCM53540_DEVICE_ID:
+ case BCM53547_DEVICE_ID:
+ case BCM53548_DEVICE_ID:
+ case BCM53549_DEVICE_ID:
+ case BCM88670_DEVICE_ID:
+ case BCM88671_DEVICE_ID:
+ case BCM88671M_DEVICE_ID:
+ case BCM88672_DEVICE_ID:
+ case BCM88673_DEVICE_ID:
+ case BCM88674_DEVICE_ID:
+ case BCM88675_DEVICE_ID:
+ case BCM88675M_DEVICE_ID:
+ case BCM88676_DEVICE_ID:
+ case BCM88676M_DEVICE_ID:
+ case BCM88677_DEVICE_ID:
+ case BCM88678_DEVICE_ID:
+ case BCM88679_DEVICE_ID:
+ case BCM88370_DEVICE_ID:
+ case BCM88371_DEVICE_ID:
+ case BCM88371M_DEVICE_ID:
+ case BCM88375_DEVICE_ID:
+ case BCM88376_DEVICE_ID:
+ case BCM88376M_DEVICE_ID:
+ case BCM88377_DEVICE_ID:
+ case BCM88378_DEVICE_ID:
+ case BCM88379_DEVICE_ID:
+ case BCM88681_DEVICE_ID:
+ case BCM88682_DEVICE_ID:
+ case BCM88683_DEVICE_ID:
+ case BCM88684_DEVICE_ID:
+ case BCM88685_DEVICE_ID:
+ case BCM88380_DEVICE_ID:
+ case BCM88381_DEVICE_ID:
+ case BCM88680_DEVICE_ID:
+ case BCM88800_DEVICE_ID:
+ case BCM88770_DEVICE_ID:
+ case BCM88773_DEVICE_ID:
+ case BCM88774_DEVICE_ID:
+ case BCM88775_DEVICE_ID:
+ case BCM88776_DEVICE_ID:
+ case BCM88777_DEVICE_ID:
+ case BCM88470_DEVICE_ID:
+ case BCM88470P_DEVICE_ID:
+ case BCM88471_DEVICE_ID:
+ case BCM88473_DEVICE_ID:
+ case BCM88474_DEVICE_ID:
+ case BCM88474H_DEVICE_ID:
+ case BCM88476_DEVICE_ID:
+ case BCM88477_DEVICE_ID:
+ case BCM88270_DEVICE_ID:
+ case BCM88272_DEVICE_ID:
+ case BCM88273_DEVICE_ID:
+ case BCM88274_DEVICE_ID:
+ case BCM88278_DEVICE_ID:
+ case BCM88279_DEVICE_ID:
+ case BCM8206_DEVICE_ID:
+ case BCM88950_DEVICE_ID:
+ case BCM88953_DEVICE_ID:
+ case BCM88954_DEVICE_ID:
+ case BCM88955_DEVICE_ID:
+ case BCM88956_DEVICE_ID:
+ case BCM88772_DEVICE_ID:
+ case BCM88952_DEVICE_ID:
+ ctrl->isr = (isr_f)_cmicd_cmc0_interrupt;
+ break;
+ case BCM88790_DEVICE_ID:
+ ctrl->isr = (isr_f)_cmicx_interrupt;
+ break;
+ case BCM56370_DEVICE_ID:
+ case BCM56371_DEVICE_ID:
+ case BCM56372_DEVICE_ID:
+ case BCM56374_DEVICE_ID:
+ case BCM56375_DEVICE_ID:
+ case BCM56376_DEVICE_ID:
+ case BCM56377_DEVICE_ID:
+ case BCM56577_DEVICE_ID:
+ case BCM56578_DEVICE_ID:
+ case BCM56579_DEVICE_ID:
+ ctrl->isr = (isr_f)_cmicx_interrupt;
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ if (!ihost_intr_enable_base) {
+ ihost_intr_enable_base = (uint32_t *)IOREMAP(HX5_IHOST_GICD_ISENABLERN_1,
+ HX5_IHOST_INTR_MAP_NUM);
+ }
+ if (!ihost_intr_status_base) {
+ ihost_intr_status_base = (uint32_t *)IOREMAP(HX5_INTC_INTR_RAW_STATUS_REG0,
+ HX5_IHOST_INTR_STATUS_MAP_NUM);
+ }
+ }
+ break;
+ default:
+ /* Get CMIC version */
+ if (user_bde->get_cmic_ver(d, &ver) != 0) {
+ ver = -1;
+ }
+ device_id = ctrl->devid & device_id_mask;
+ /* TH/TH+/TH2 should use cmicd interrupt handler */
+ if (BCM56960_DEVICE_ID == device_id ||
+ BCM56930_DEVICE_ID == device_id ||
+ BCM56970_DEVICE_ID == device_id) {
+ ctrl->isr = (isr_f)_cmicd_interrupt;
+ }
+ /* check if version is CMICX */
+ else if (ver == 0x04) {
+ ctrl->isr = (isr_f)_cmicx_interrupt;
+ } else {
+ ctrl->isr = (isr_f)_cmic_interrupt;
+ if ((ctrl->dev_type & BDE_256K_REG_SPACE) &&
+#ifdef BCM_PETRA_SUPPORT /* FIXME remove code when hardware design is fixed */
+ ctrl->devid != 0x1234 &&
+#endif
+ readl(ctrl->ba + CMICE_DEV_REV_ID) == 0) {
+ ctrl->isr = (isr_f)_cmicm_interrupt;
+ }
+ }
+ break;
+ }
+
+#ifdef BCM_DNX_SUPPORT
+ /*All Jericho 2 devices from 0x8690 to 0x869F*/
+ if (SOC_IS_JERICHO_2_TYPE(user_bde->get_dev(d)->device)) {
+ ctrl->isr = (isr_f)_cmicx_interrupt;
+ }
+#endif
+
+ /*All Ramon devices from 0x8790 to 0x879F*/
+ if ((user_bde->get_dev(d)->device & BCM88790_DEVICE_ID) == BCM88790_DEVICE_ID) {
+ ctrl->isr = (isr_f)_cmicx_interrupt;
+ }
+ if (_intr_mode_str(ctrl->isr) == NULL) {
+ gprintk("Warning: Unknown interrupt mode\n");
+ }
+ }
+}
+/*
+ * Function: _init
+ *
+ * Purpose:
+ * Module initialization.
+ * Attaches to kernel BDE.
+ * Parameters:
+ * None
+ * Returns:
+ * Always 0
+ */
+static int
+_init(void)
+{
+ int i;
+ phys_addr_t cpu_pbase, dma_pbase;
+ ssize_t dmasize;
+ bde_inst_resource_t *res;
+
+ /* Connect to the kernel bde */
+ if ((linux_bde_create(NULL, &user_bde) < 0) || user_bde == NULL) {
+ return -ENODEV;
+ }
+
+ init_waitqueue_head(&_ether_interrupt_wq);
+
+ lkbde_get_dma_info(&cpu_pbase, &dma_pbase, &dmasize);
+
+ memset(&_dma_pool, 0, sizeof(_dma_pool));
+ _dma_pool.cpu_pbase = cpu_pbase;
+ _dma_pool.dma_pbase = dma_pbase;
+ _dma_pool.total_size = dmasize / ONE_MB;
+
+ memset(_devices, 0, sizeof(_devices));
+
+ /* Use _bde_inst_resource[0] as the default resource */
+ memset(_bde_inst_resource, 0, sizeof(_bde_inst_resource));
+ res = &_bde_inst_resource[0];
+ res->dma_offset = 0;
+ res->dma_size = _dma_pool.total_size;
+ init_waitqueue_head(&res->intr_wq);
+ atomic_set(&res->intr, 0);
+
+ ihost_intr_enable_base = NULL;
+ ihost_intr_status_base = NULL;
+
+ for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ res->inst_id |= (1 << i);
+ _devices_init(i);
+ }
+
+ return 0;
+}
+
+/*
+ * Function: _cleanup
+ *
+ * Purpose:
+ * Module cleanup function.
+ * Parameters:
+ * None
+ * Returns:
+ * Always 0
+ */
+static int
+_cleanup(void)
+{
+ int i;
+
+ if (user_bde) {
+ for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ if (_devices[i].enabled &&
+ BDE_DEV_MEM_MAPPED(_devices[i].dev_type)) {
+ user_bde->interrupt_disconnect(i);
+ }
+ lkbde_dev_instid_set(i, 0);
+ }
+ linux_bde_destroy(user_bde);
+ user_bde = NULL;
+ }
+
+ if (ihost_intr_enable_base) {
+ iounmap(ihost_intr_enable_base);
+ ihost_intr_enable_base = NULL;
+ }
+ if (ihost_intr_status_base) {
+ iounmap(ihost_intr_status_base);
+ ihost_intr_status_base = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * Function: _pprint
+ *
+ * Purpose:
+ * Print proc filesystem information.
+ * Parameters:
+ * None
+ * Returns:
+ * Always 0
+ */
+static int
+_pprint(void)
+{
+ int idx;
+ const char *name;
+ bde_inst_resource_t *res;
+ uint32 state, instid;
+
+ pprintf("Broadcom Device Enumerator (%s)\n", LINUX_USER_BDE_NAME);
+ for (idx = 0; idx < user_bde->num_devices(BDE_ALL_DEVICES); idx++) {
+ name = _intr_mode_str(_devices[idx].isr);
+ if (name == NULL) {
+ name = "unknown";
+ }
+ pprintf("\t%d: Interrupt mode %s ",idx, name);
+ (void)lkbde_dev_state_get(idx, &state);
+ if (state == BDE_DEV_STATE_REMOVED) {
+ pprintf(" Device REMOVED ! \n");
+ } else {
+ (void)lkbde_dev_instid_get(idx, &instid);
+ if (instid) {
+ pprintf("Inst id 0x%x\n",instid);
+ } else {
+ pprintf("\n");
+ }
+ }
+ }
+ pprintf("Instance resource \n");
+
+ for (idx = 0; idx < user_bde->num_devices(BDE_ALL_DEVICES); idx++) {
+ res = &_bde_inst_resource[idx];
+ if (res->inst_id) {
+ pprintf("\tDev mask 0x%x : "
+ "DMA offset %d size %d MB\n",
+ res->inst_id,
+ res->dma_offset,
+ res->dma_size);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Allocate the DMA resource from DMA pool
+ * Parameter :
+ * dma_size (IN): allocate dma_size in MB
+ * dma_offset (OUT): dma offset in MB
+ */
+static int
+_dma_resource_alloc(unsigned int dma_size, unsigned int *dma_offset)
+{
+ uint32 left;
+
+ left = _dma_pool.total_size - _dma_pool.offset;
+ if (dma_size > left) {
+ gprintk("ERROR: Run out the dma resource!\n");
+ return -1;
+ }
+ *dma_offset = _dma_pool.offset;
+ _dma_pool.offset += dma_size;
+ return 0;
+}
+
+static int
+_dma_resource_get(int inst_id, phys_addr_t *cpu_pbase, phys_addr_t *dma_pbase, ssize_t* size)
+{
+ int i;
+ unsigned int dma_size = 0, dma_offset = 0;
+ bde_inst_resource_t *res;
+
+ for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ res = &_bde_inst_resource[i];
+ if (res->inst_id == inst_id) {
+ dma_size = res->dma_size;
+ dma_offset = res->dma_offset;
+ break;
+ }
+ }
+
+ *cpu_pbase = _dma_pool.cpu_pbase + dma_offset * ONE_MB;
+ *dma_pbase = _dma_pool.dma_pbase + dma_offset * ONE_MB;
+ *size = dma_size * ONE_MB;
+
+ return 0;
+}
+
+static int
+_instance_validate(unsigned int inst_id, unsigned int dmasize)
+{
+ int i;
+ bde_inst_resource_t *res;
+
+ for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ res = &_bde_inst_resource[i];
+ if (res->inst_id == inst_id) {
+ if (res->dma_size != dmasize) {
+ if(_devices[i].inst == 0){
+ /* Skip _instance_validate (not init yet) */
+ return LUBDE_SUCCESS;
+ }
+ gprintk("ERROR: dma_size mismatch\n");
+ return LUBDE_FAIL;
+ }
+ return (1);
+ }
+ }
+ return LUBDE_SUCCESS;
+}
+
+static int
+_device_reprobe(void)
+{
+ int i;
+
+ for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ if (_devices[i].devid == 0) {
+ _devices_init(i);
+ }
+ }
+ return 0;
+}
+
+static int
+_instance_attach(unsigned int inst_id, unsigned int dma_size)
+{
+ unsigned int dma_offset;
+ int i, exist;
+ bde_inst_resource_t *res;
+ int inst_idx = -1;
+ uint32 instid;
+
+ /* Reprobe the system for hot-plugged device */
+ _device_reprobe();
+
+ /* Validate the resource with inst_id */
+ exist = _instance_validate(inst_id, dma_size);
+ if (exist < 0) {
+ return LUBDE_FAIL;
+ }
+ if (exist > 0) {
+ return LUBDE_SUCCESS;
+ }
+ if (_dma_resource_alloc(dma_size, &dma_offset) < 0) {
+ return LUBDE_FAIL;
+ }
+ for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ res = &_bde_inst_resource[i];
+ if ((_bde_multi_inst == 0) || (res->inst_id == 0)) {
+ res->inst_id = inst_id;
+ res->dma_offset = dma_offset;
+ res->dma_size = dma_size;
+ _bde_multi_inst++;
+ inst_idx = i;
+ init_waitqueue_head(&res->intr_wq);
+ atomic_set(&res->intr, 0);
+ break;
+ }
+ }
+
+ for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ if (inst_id & (1 << i)) {
+ _devices[i].inst = inst_idx;
+ /* Pass the instid to the kernel BDE */
+ if (lkbde_dev_instid_get(i, &instid) == 0) {
+ if (!instid) {
+ lkbde_dev_instid_set(i, inst_id);
+ }
+ }
+ }
+ }
+
+ return LUBDE_SUCCESS;
+}
+
+/*
+ * Function: _ioctl
+ *
+ * Purpose:
+ * Handle IOCTL commands from user mode.
+ * Parameters:
+ * cmd - IOCTL cmd
+ * arg - IOCTL parameters
+ * Returns:
+ * 0 on success, <0 on error
+ */
+static int
+_ioctl(unsigned int cmd, unsigned long arg)
+{
+ lubde_ioctl_t io;
+ phys_addr_t cpu_pbase, dma_pbase;
+ ssize_t size;
+ const ibde_dev_t *bde_dev;
+ int inst_id;
+ bde_inst_resource_t *res;
+ uint32_t *mapaddr;
+
+ if (copy_from_user(&io, (void *)arg, sizeof(io))) {
+ return -EFAULT;
+ }
+
+ io.rc = LUBDE_SUCCESS;
+
+ switch(cmd) {
+ case LUBDE_VERSION:
+ io.d0 = KBDE_VERSION;
+ break;
+ case LUBDE_GET_NUM_DEVICES:
+ io.d0 = user_bde->num_devices(io.dev);
+ break;
+ case LUBDE_GET_DEVICE:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ bde_dev = user_bde->get_dev(io.dev);
+ if (bde_dev) {
+ io.d0 = bde_dev->device;
+ io.d1 = bde_dev->rev;
+ if (BDE_DEV_MEM_MAPPED(_devices[io.dev].dev_type)) {
+ /* Get physical address to map */
+ io.d2 = lkbde_get_dev_phys(io.dev);
+ io.d3 = lkbde_get_dev_phys_hi(io.dev);
+ }
+ } else {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ case LUBDE_GET_DEVICE_TYPE:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ io.d0 = _devices[io.dev].dev_type;
+ break;
+ case LUBDE_GET_BUS_FEATURES:
+ user_bde->pci_bus_features(io.dev, (int *) &io.d0, (int *) &io.d1,
+ (int *) &io.d2);
+ break;
+ case LUBDE_PCI_CONFIG_PUT32:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ if (_devices[io.dev].dev_type & BDE_PCI_DEV_TYPE) {
+ user_bde->pci_conf_write(io.dev, io.d0, io.d1);
+ } else {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ case LUBDE_PCI_CONFIG_GET32:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ if (_devices[io.dev].dev_type & BDE_PCI_DEV_TYPE) {
+ io.d0 = user_bde->pci_conf_read(io.dev, io.d0);
+ } else {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ case LUBDE_GET_DMA_INFO:
+ inst_id = io.dev;
+ if (_bde_multi_inst){
+ _dma_resource_get(inst_id, &cpu_pbase, &dma_pbase, &size);
+ } else {
+ lkbde_get_dma_info(&cpu_pbase, &dma_pbase, &size);
+ }
+ io.d0 = dma_pbase;
+ io.d1 = size;
+ /* Optionally enable DMA mmap via /dev/linux-kernel-bde */
+ io.d2 = USE_LINUX_BDE_MMAP;
+ /* Get physical address for mmap */
+ io.dx.dw[0] = cpu_pbase;
+#ifdef PHYS_ADDRS_ARE_64BITS
+ io.dx.dw[1] = cpu_pbase >> 32;
+#else
+ io.dx.dw[1] = 0;
+#endif
+ break;
+ case LUBDE_ENABLE_INTERRUPTS:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ if (_devices[io.dev].dev_type & BDE_SWITCH_DEV_TYPE) {
+ if (_devices[io.dev].isr && !_devices[io.dev].enabled) {
+ user_bde->interrupt_connect(io.dev,
+ _devices[io.dev].isr,
+ _devices+io.dev);
+ _devices[io.dev].enabled = 1;
+ }
+ } else {
+ /* Process ethernet device interrupt */
+ /* FIXME: for multiple chips */
+ if (!_devices[io.dev].enabled) {
+ user_bde->interrupt_connect(io.dev,
+ (void(*)(void *))_ether_interrupt,
+ _devices+io.dev);
+ _devices[io.dev].enabled = 1;
+ }
+ }
+ break;
+ case LUBDE_DISABLE_INTERRUPTS:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ if (_devices[io.dev].enabled) {
+ user_bde->interrupt_disconnect(io.dev);
+ _devices[io.dev].enabled = 0;
+ }
+ break;
+ case LUBDE_WAIT_FOR_INTERRUPT:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ if (_devices[io.dev].dev_type & BDE_SWITCH_DEV_TYPE) {
+ res = &_bde_inst_resource[_devices[io.dev].inst];
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wait_event_timeout(res->intr_wq,
+ atomic_read(&res->intr) != 0, 100);
+
+#else
+ wait_event_interruptible(res->intr_wq,
+ atomic_read(&res->intr) != 0);
+#endif
+ /*
+ * Even if we get multiple interrupts, we
+ * only run the interrupt handler once.
+ */
+ atomic_set(&res->intr, 0);
+ } else {
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wait_event_timeout(_ether_interrupt_wq,
+ atomic_read(&_ether_interrupt_has_taken_place) != 0, 100);
+#else
+ wait_event_interruptible(_ether_interrupt_wq,
+ atomic_read(&_ether_interrupt_has_taken_place) != 0);
+#endif
+ /*
+ * Even if we get multiple interrupts, we
+ * only run the interrupt handler once.
+ */
+ atomic_set(&_ether_interrupt_has_taken_place, 0);
+ }
+ break;
+ case LUBDE_USLEEP:
+ case LUBDE_UDELAY:
+ case LUBDE_SEM_OP:
+ return -EINVAL;
+ case LUBDE_WRITE_IRQ_MASK:
+ io.rc = lkbde_irq_mask_set(io.dev, io.d0, io.d1, 0);
+ break;
+ case LUBDE_SPI_READ_REG:
+ if (user_bde->spi_read(io.dev, io.d0, io.dx.buf, io.d1) == -1) {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ case LUBDE_SPI_WRITE_REG:
+ if (user_bde->spi_write(io.dev, io.d0, io.dx.buf, io.d1) == -1) {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ case LUBDE_READ_REG_16BIT_BUS:
+ io.d1 = user_bde->read(io.dev, io.d0);
+ break;
+ case LUBDE_WRITE_REG_16BIT_BUS:
+ io.rc = user_bde->write(io.dev, io.d0, io.d1);
+ break;
+#ifdef BCM_SAND_SUPPORT
+ case LUBDE_CPU_WRITE_REG:
+ {
+ if (lkbde_cpu_write(io.dev, io.d0, (uint32*)io.dx.buf) == -1) {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ }
+ case LUBDE_CPU_READ_REG:
+ {
+ if (lkbde_cpu_read(io.dev, io.d0, (uint32*)io.dx.buf) == -1) {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ }
+ case LUBDE_CPU_PCI_REGISTER:
+ {
+ if (lkbde_cpu_pci_register(io.dev) == -1) {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ }
+#endif
+ case LUBDE_DEV_RESOURCE:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ bde_dev = user_bde->get_dev(io.dev);
+ if (bde_dev) {
+ if (BDE_DEV_MEM_MAPPED(_devices[io.dev].dev_type)) {
+ /* Get physical address to map */
+ io.rc = lkbde_get_dev_resource(io.dev, io.d0,
+ &io.d1, &io.d2, &io.d3);
+ }
+ } else {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ case LUBDE_IPROC_READ_REG:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ if (_devices[io.dev].dev_type & BDE_AXI_DEV_TYPE) {
+ mapaddr = IOREMAP(io.d0, sizeof(uint32_t));
+ if (mapaddr == NULL) {
+ io.rc = LUBDE_FAIL;
+ return -1;
+ }
+ io.d1 = readl(mapaddr);
+ iounmap(mapaddr);
+ } else {
+ io.d1 = user_bde->iproc_read(io.dev, io.d0);
+ if (io.d1 == -1) {
+ io.rc = LUBDE_FAIL;
+ }
+ }
+ break;
+ case LUBDE_IPROC_WRITE_REG:
+ if (user_bde->iproc_write(io.dev, io.d0, io.d1) == -1) {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ case LUBDE_ATTACH_INSTANCE:
+ io.rc = _instance_attach(io.d0, io.d1);
+ break;
+ case LUBDE_GET_DEVICE_STATE:
+ io.rc = lkbde_dev_state_get(io.dev, &io.d0);
+ break;
+ case LUBDE_REPROBE:
+ io.rc = _device_reprobe();
+ break;
+ default:
+ gprintk("Error: Invalid ioctl (%08x)\n", cmd);
+ io.rc = LUBDE_FAIL;
+ break;
+ }
+
+ if (copy_to_user((void *)arg, &io, sizeof(io))) {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/* Workaround for broken Busybox/PPC insmod */
+static char _modname[] = LINUX_USER_BDE_NAME;
+
+static gmodule_t _gmodule =
+{
+ name: LINUX_USER_BDE_NAME,
+ major: LINUX_USER_BDE_MAJOR,
+ init: _init,
+ cleanup: _cleanup,
+ pprint: _pprint,
+ ioctl: _ioctl,
+};
+
+gmodule_t*
+gmodule_get(void)
+{
+ _gmodule.name = _modname;
+ return &_gmodule;
+}
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.h b/sdk-6.5.16/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: linux-user-bde.h,v 1.23 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#ifndef __LINUX_USER_BDE_H__
+#define __LINUX_USER_BDE_H__
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux-bde.h>
+#ifndef __KERNEL__
+#include <stdint.h>
+#endif
+
+#if defined(SAL_BDE_32BIT_USER_64BIT_KERNEL) || defined(PTRS_ARE_64BITS)
+typedef uint64_t bde_kernel_addr_t;
+#else
+typedef uint32_t bde_kernel_addr_t;
+#endif
+
+/* Ioctl control structure */
+typedef struct {
+ unsigned int dev; /* Device ID */
+ unsigned int rc; /* Operation Return Code */
+ unsigned int d0; /* Operation specific data */
+ unsigned int d1;
+ unsigned int d2;
+ unsigned int d3;
+ bde_kernel_addr_t p0;
+ union {
+ unsigned int dw[2];
+ unsigned char buf[64];
+ } dx;
+} lubde_ioctl_t;
+
+
+/* LUBDE ioctls */
+#define LUBDE_MAGIC 'L'
+
+#define LUBDE_VERSION _IO(LUBDE_MAGIC, 0)
+#define LUBDE_GET_NUM_DEVICES _IO(LUBDE_MAGIC, 1)
+#define LUBDE_GET_DEVICE _IO(LUBDE_MAGIC, 2)
+#define LUBDE_PCI_CONFIG_PUT32 _IO(LUBDE_MAGIC, 3)
+#define LUBDE_PCI_CONFIG_GET32 _IO(LUBDE_MAGIC, 4)
+#define LUBDE_GET_DMA_INFO _IO(LUBDE_MAGIC, 5)
+#define LUBDE_ENABLE_INTERRUPTS _IO(LUBDE_MAGIC, 6)
+#define LUBDE_DISABLE_INTERRUPTS _IO(LUBDE_MAGIC, 7)
+#define LUBDE_USLEEP _IO(LUBDE_MAGIC, 8)
+#define LUBDE_WAIT_FOR_INTERRUPT _IO(LUBDE_MAGIC, 9)
+#define LUBDE_SEM_OP _IO(LUBDE_MAGIC, 10)
+#define LUBDE_UDELAY _IO(LUBDE_MAGIC, 11)
+#define LUBDE_GET_DEVICE_TYPE _IO(LUBDE_MAGIC, 12)
+#define LUBDE_SPI_READ_REG _IO(LUBDE_MAGIC, 13)
+#define LUBDE_SPI_WRITE_REG _IO(LUBDE_MAGIC, 14)
+#define LUBDE_READ_REG_16BIT_BUS _IO(LUBDE_MAGIC, 19)
+#define LUBDE_WRITE_REG_16BIT_BUS _IO(LUBDE_MAGIC, 20)
+#define LUBDE_GET_BUS_FEATURES _IO(LUBDE_MAGIC, 21)
+#define LUBDE_WRITE_IRQ_MASK _IO(LUBDE_MAGIC, 22)
+#define LUBDE_CPU_WRITE_REG _IO(LUBDE_MAGIC, 23)
+#define LUBDE_CPU_READ_REG _IO(LUBDE_MAGIC, 24)
+#define LUBDE_CPU_PCI_REGISTER _IO(LUBDE_MAGIC, 25)
+#define LUBDE_DEV_RESOURCE _IO(LUBDE_MAGIC, 26)
+#define LUBDE_IPROC_READ_REG _IO(LUBDE_MAGIC, 27)
+#define LUBDE_IPROC_WRITE_REG _IO(LUBDE_MAGIC, 28)
+#define LUBDE_ATTACH_INSTANCE _IO(LUBDE_MAGIC, 29)
+#define LUBDE_GET_DEVICE_STATE _IO(LUBDE_MAGIC, 30)
+#define LUBDE_REPROBE _IO(LUBDE_MAGIC, 31)
+
+#define LUBDE_SEM_OP_CREATE 1
+#define LUBDE_SEM_OP_DESTROY 2
+#define LUBDE_SEM_OP_TAKE 3
+#define LUBDE_SEM_OP_GIVE 4
+
+#define LUBDE_SUCCESS 0
+#define LUBDE_FAIL ((unsigned int)-1)
+
+
+/*
+ * Version history
+ * 1: add LUBDE_GET_DEVICE_STATE to support PCI hot plug
+ * 2: add LUBDE_REPROBE to support reprobe available devices
+ */
+#define KBDE_VERSION 2
+
+
+/* This is the signal that will be used
+ * when an interrupt occurs
+ */
+
+#ifndef __KERNEL__
+#include <signal.h>
+#endif
+
+#define LUBDE_INTERRUPT_SIGNAL SIGUSR1
+#define LUBDE_ETHER_INTERRUPT_SIGNAL SIGUSR2
+
+#endif /* __LUBDE_H__ */
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde.h b/sdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2014 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#ifndef __SHBDE_H__
+#define __SHBDE_H__
+
+typedef void (*shbde_log_func_t)(int level, const char *str, int param);
+
+#define SHBDE_ERR 0
+#define SHBDE_WARN 1
+#define SHBDE_DBG 2
+
+/* iProc configuration (primarily used for PCI-AXI bridge) */
+typedef struct shbde_iproc_config_s {
+ unsigned int dev_id;
+ unsigned int dev_rev;
+ unsigned int use_msi;
+ unsigned int iproc_ver;
+ unsigned int cmic_ver;
+ unsigned int cmic_rev;
+ unsigned int dma_hi_bits;
+ unsigned int mdio_base_addr;
+ unsigned int pcie_phy_addr;
+ unsigned int adjust_pcie_preemphasis;
+} shbde_iproc_config_t;
+
+/* Hardware abstraction functions */
+typedef struct shbde_hal_s {
+
+ /* Optional log output interface */
+ shbde_log_func_t log_func;
+
+ /* PCI configuration access */
+ unsigned char (*pcic8_read)(void *pci_dev, unsigned int reg);
+ void (*pcic8_write)(void *pci_dev, unsigned int reg, unsigned char data);
+ unsigned short (*pcic16_read)(void *pci_dev, unsigned int reg);
+ void (*pcic16_write)(void *pci_dev, unsigned int reg, unsigned short data);
+ unsigned int (*pcic32_read)(void *pci_dev, unsigned int reg);
+ void (*pcic32_write)(void *pci_dev, unsigned int reg, unsigned int data);
+
+ /* iProc register access */
+ unsigned int (*io32_read)(void *addr);
+ void (*io32_write)(void *addr, unsigned int);
+
+ /* usleep function (optional) */
+ void (*usleep)(int usec);
+
+ /* PCI parent device access */
+ void *(*pci_parent_device_get)(void *pci_dev);
+
+ /* iProc configuration */
+ shbde_iproc_config_t icfg;
+
+} shbde_hal_t;
+
+
+#endif /* __SHBDE_H__ */
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde_iproc.h b/sdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde_iproc.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2014 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#ifndef __SHBDE_IPROC_H__
+#define __SHBDE_IPROC_H__
+
+#include <shbde.h>
+
+extern int
+shbde_iproc_config_init(shbde_iproc_config_t *icfg,
+ unsigned int dev_id, unsigned int dev_rev);
+
+extern int
+shbde_iproc_paxb_init(shbde_hal_t *shbde, void *iproc_regs,
+ shbde_iproc_config_t *icfg);
+
+extern unsigned int
+shbde_iproc_pci_read(shbde_hal_t *shbde, void *iproc_regs,
+ unsigned int addr);
+
+extern void
+shbde_iproc_pci_write(shbde_hal_t *shbde, void *iproc_regs,
+ unsigned int addr, unsigned int data);
+
+extern int
+shbde_iproc_pcie_preemphasis_set(shbde_hal_t *shbde, void *iproc_regs,
+ shbde_iproc_config_t *icfg, void *pci_dev);
+
+#endif /* __SHBDE_IPROC_H__ */
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde_mdio.h b/sdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde_mdio.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2015 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#ifndef __SHBDE_MDIO_H__
+#define __SHBDE_MDIO_H__
+
+#include <shbde.h>
+
+typedef struct shbde_mdio_ctrl_s {
+
+ /* Primary HAL*/
+ shbde_hal_t *shbde;
+
+ /* Context for iProc MDIO register access */
+ void *regs;
+
+ /* Base address for MDIO registers */
+ unsigned int base_addr;
+
+ /* iProc MDIO register access */
+ unsigned int (*io32_read)(shbde_hal_t *shbde, void *iproc_regs,
+ unsigned int addr);
+ void (*io32_write)(shbde_hal_t *shbde, void *iproc_regs,
+ unsigned int addr, unsigned int data);
+
+} shbde_mdio_ctrl_t;
+
+
+extern int
+shbde_iproc_mdio_init(shbde_mdio_ctrl_t *smc);
+
+extern int
+shbde_iproc_mdio_read(shbde_mdio_ctrl_t *smc, unsigned int phy_addr,
+ unsigned int reg, unsigned int *val);
+
+extern int
+shbde_iproc_mdio_write(shbde_mdio_ctrl_t *smc, unsigned int phy_addr,
+ unsigned int reg, unsigned int val);
+
+#endif /* __SHBDE_MDIO_H__ */
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde_pci.h b/sdk-6.5.16/src/gpl-modules/systems/bde/shared/include/shbde_pci.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2014 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#ifndef __SHBDE_PCI_H__
+#define __SHBDE_PCI_H__
+
+#include <shbde.h>
+
+extern unsigned int
+shbde_pci_pcie_cap(shbde_hal_t *shbde, void *pci_dev);
+
+extern int
+shbde_pci_is_pcie(shbde_hal_t *shbde, void *pci_dev);
+
+extern int
+shbde_pci_is_iproc(shbde_hal_t *shbde, void *pci_dev, int *cmic_bar);
+
+extern int
+shbde_pci_max_payload_set(shbde_hal_t *shbde, void *pci_dev, int maxpayload);
+
+extern int
+shbde_pci_iproc_version_get(shbde_hal_t *shbde, void *pci_dev,
+ unsigned int *iproc_ver,
+ unsigned int *cmic_ver,
+ unsigned int *cmic_rev);
+
+#endif /* __SHBDE_PCI_H__ */
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/shared/shbde_iproc.c b/sdk-6.5.16/src/gpl-modules/systems/bde/shared/shbde_iproc.c
@@ -0,0 +1,494 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2014 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#include <shbde_iproc.h>
+#include <shbde_mdio.h>
+#include <shbde_pci.h>
+
+/* PAXB register offsets within PCI BAR0 window */
+#define BAR0_PAXB_ENDIANESS 0x2030
+#define BAR0_PAXB_PCIE_EP_AXI_CONFIG 0x2104
+#define BAR0_PAXB_CONFIG_IND_ADDR 0x2120
+#define BAR0_PAXB_CONFIG_IND_DATA 0x2124
+
+#define PAXB_0_CMICD_TO_PCIE_INTR_EN 0x2380
+
+#define BAR0_PAXB_IMAP0_0 (0x2c00)
+#define BAR0_PAXB_IMAP0_1 (0x2c04)
+#define BAR0_PAXB_IMAP0_2 (0x2c08)
+#define BAR0_PAXB_IMAP0_7 (0x2c1c)
+
+#define BAR0_PAXB_OARR_FUNC0_MSI_PAGE 0x2d34
+#define BAR0_PAXB_OARR_2 0x2d60
+#define BAR0_PAXB_OARR_2_UPPER 0x2d64
+#define BAR0_DMU_PCU_PCIE_SLAVE_RESET_MODE 0x7024
+
+#define PAXB_0_FUNC0_IMAP1_3 0x2d88
+
+/* Force byte pointer for offset adjustments */
+#define ROFFS(_ptr, _offset) ((unsigned char*)(_ptr) + (_offset))
+
+#define PAXB_CONFIG_IND_ADDRr_PROTOCOL_LAYERf_SHFT 11
+#define PAXB_CONFIG_IND_ADDRr_PROTOCOL_LAYERf_MASK 0x3
+#define PAXB_CONFIG_IND_ADDRr_ADDRESSf_SHFT 0
+#define PAXB_CONFIG_IND_ADDRr_ADDRESSf_MASK 0x7ff
+#define PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT 20
+
+/* Register value set/get by field */
+#define REG_FIELD_SET(_r, _f, _r_val, _f_val) \
+ _r_val = ((_r_val) & ~(_r##_##_f##_MASK << _r##_##_f##_SHFT)) | \
+ (((_f_val) & _r##_##_f##_MASK) << _r##_##_f##_SHFT)
+#define REG_FIELD_GET(_r, _f, _r_val) \
+ (((_r_val) >> _r##_##_f##_SHFT) & _r##_##_f##_MASK)
+
+/* PCIe capabilities definition */
+#ifndef PCI_EXP_LNKSTA
+#define PCI_EXP_LNKSTA 0x12
+#endif
+/* Current Link Speed 5.0GT/s */
+#ifndef PCI_EXP_LNKSTA_CLS_5_0GB
+#define PCI_EXP_LNKSTA_CLS_5_0GB 2
+#endif
+#ifndef PCI_EXP_LNKSTA2
+#define PCI_EXP_LNKSTA2 0x32
+#endif
+/* Current Deemphasis Level -3.5 dB */
+#ifndef PCI_EXP_LNKSTA2_CDL_3_5DB
+#define PCI_EXP_LNKSTA2_CDL_3_5DB 0x1
+#endif
+
+static unsigned int
+iproc32_read(shbde_hal_t *shbde, void *addr)
+{
+ if (!shbde || !shbde->io32_read) {
+ return 0;
+ }
+ return shbde->io32_read(addr);
+}
+
+static void
+iproc32_write(shbde_hal_t *shbde, void *addr, unsigned int data)
+{
+ if (!shbde || !shbde->io32_write) {
+ return;
+ }
+ shbde->io32_write(addr, data);
+}
+
+static void
+wait_usec(shbde_hal_t *shbde, int usec)
+{
+ if (shbde && shbde->usleep) {
+ shbde->usleep(usec);
+ } else {
+ int idx;
+ volatile int count;
+ for (idx = 0; idx < usec; idx++) {
+ for (count = 0; count < 100; count++);
+ }
+ }
+}
+
+/*
+ * Function:
+ * shbde_iproc_config_init
+ * Purpose:
+ * Initialize iProc configuration parameters
+ * Parameters:
+ * icfg - pointer to empty iProc configuration structure
+ * Returns:
+ * -1 if error, otherwise 0
+ */
+int
+shbde_iproc_config_init(shbde_iproc_config_t *icfg,
+ unsigned int dev_id, unsigned int dev_rev)
+{
+ if (!icfg) {
+ return -1;
+ }
+
+ /* Save device ID and revision */
+ icfg->dev_id = dev_id;
+ icfg->dev_rev = dev_rev;
+
+ /* Check device families first */
+ switch (icfg->dev_id & 0xfff0) {
+ case 0x8400: /* Greyhound Lite */
+ case 0x8410: /* Greyhound */
+ case 0x8420: /* Bloodhound */
+ case 0x8450: /* Elkhound */
+ case 0xb060: /* Ranger2(Greyhound) */
+ case 0x8360: /* Greyhound 53365 & 53369 */
+ case 0xb260: /* saber2 */
+ case 0xb460: /* saber2+ */
+ case 0xb170: /* Hurricane3-MG */
+ case 0x8570: /* Greyhound2 */
+ case 0xb070: /* Greyhound2(emulation) */
+ case 0x8580: /* Greyhound2(emulation) */
+ case 0xb230: /* Dagger2 */
+ icfg->iproc_ver = 7;
+ icfg->dma_hi_bits = 0x2;
+ break;
+ case 0xb560: /* Apache */
+ case 0xb670: /* MO */
+ case 0xb760: /* Maverick */
+ icfg->iproc_ver = 0xB;
+ break;
+ case 0xb160: /* Hurricane3 */
+ case 0x8440: /* Buckhound2 */
+ case 0x8430: /* Foxhound2 */
+ case 0x8540: /* Wolfhound2 */
+ icfg->iproc_ver = 10;
+ icfg->dma_hi_bits = 0x2;
+ break;
+ default:
+ break;
+ }
+
+ /* Check for exceptions */
+ switch (icfg->dev_id) {
+ case 0xb069:
+ case 0xb068:
+ icfg->iproc_ver = 0xB; /*Ranger2+ Apache Family */
+ icfg->dma_hi_bits = 0;
+ break;
+ case 0xb168: /* Ranger3+ */
+ case 0xb169:
+ icfg->iproc_ver = 0;
+ icfg->dma_hi_bits = 0;
+ break;
+ default:
+ break;
+ }
+ /* Check for PCIe PHY address that needs PCIe preemphasis and
+ * assign the MDIO base address
+ */
+ switch (icfg->dev_id & 0xfff0) {
+ case 0xb150: /* Hurricane2 */
+ case 0x8340: /* Wolfhound */
+ case 0x8330: /* Foxhound */
+ case 0x8390: /* Dearhound */
+ icfg->mdio_base_addr = 0x18032000;
+ icfg->pcie_phy_addr = 0x2;
+ break;
+ case 0xb340: /* Helilx4 */
+ case 0xb540: /* FireScout */
+ case 0xb040: /* Spiral, Ranger */
+ icfg->mdio_base_addr = 0x18032000;
+ icfg->pcie_phy_addr = 0x5;
+ icfg->adjust_pcie_preemphasis = 1;
+ break;
+ case 0xa450: /* Katana2 */
+ case 0xb240:
+ case 0xb450:
+ icfg->mdio_base_addr = 0x18032000;
+ icfg->pcie_phy_addr = 0x5;
+ icfg->adjust_pcie_preemphasis = 1;
+ break;
+ default:
+ break;
+ }
+
+ /* Check for exceptions */
+ switch (icfg->dev_id) {
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Function:
+ * shbde_iproc_paxb_init
+ * Purpose:
+ * Initialize iProc PCI-AXI bridge for CMIC access
+ * Parameters:
+ * shbde - pointer to initialized hardware abstraction module
+ * iproc_regs - memory mapped iProc registers in PCI BAR
+ * icfg - iProc configuration parameters
+ * Returns:
+ * -1 if error, otherwise 0
+ */
+int
+shbde_iproc_paxb_init(shbde_hal_t *shbde, void *iproc_regs,
+ shbde_iproc_config_t *icfg)
+{
+ void *reg;
+ unsigned int data;
+ int pci_num;
+
+ if (!iproc_regs || !icfg) {
+ return -1;
+ }
+
+ /*
+ * The following code attempts to auto-detect the correct
+ * iProc PCI endianess configuration by reading a well-known
+ * register (the endianess configuration register itself).
+ * Note that the PCI endianess may be different for different
+ * big endian host processors.
+ */
+ reg = ROFFS(iproc_regs, BAR0_PAXB_ENDIANESS);
+ /* Select big endian */
+ iproc32_write(shbde, reg, 0x01010101);
+ /* Check if endianess register itself is correct endian */
+ if (iproc32_read(shbde, reg) != 1) {
+ /* If not, then assume little endian */
+ iproc32_write(shbde, reg, 0x0);
+ }
+
+ /* Select which PCI core to use */
+ pci_num = 0;
+ reg = ROFFS(iproc_regs, BAR0_PAXB_IMAP0_2);
+ data = iproc32_read(shbde, reg);
+ if (data & 0x1000) {
+ /* PAXB_1 is mapped to sub-window 2 */
+ pci_num = 1;
+ }
+
+ /* Default DMA mapping if uninitialized */
+ if (icfg->dma_hi_bits == 0) {
+ icfg->dma_hi_bits = 0x1;
+ if (pci_num == 1) {
+ icfg->dma_hi_bits = 0x2;
+ }
+ }
+
+ /* Enable iProc DMA to external host memory */
+ reg = ROFFS(iproc_regs, BAR0_PAXB_PCIE_EP_AXI_CONFIG);
+ iproc32_write(shbde, reg, 0x0);
+ if(icfg->cmic_ver < 4) { /* Non-CMICX */
+ reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_2);
+ iproc32_write(shbde, reg, 0x1);
+ reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_2_UPPER);
+ iproc32_write(shbde, reg, icfg->dma_hi_bits);
+ /* Configure MSI interrupt page */
+ if (icfg->use_msi) {
+ reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_FUNC0_MSI_PAGE);
+ data = iproc32_read(shbde, reg);
+ iproc32_write(shbde, reg, data | 0x1);
+ }
+ }
+
+ /* Configure MSIX interrupt page, only need for iproc ver == 0x10 */
+ if ((icfg->use_msi == 2) && (icfg->iproc_ver == 0x10)) {
+ unsigned int mask = (0x1 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT) - 1;
+ reg = ROFFS(iproc_regs, PAXB_0_FUNC0_IMAP1_3);
+ data = iproc32_read(shbde, reg);
+ data &= mask;
+ data |= 0x410 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT;
+ iproc32_write(shbde, reg, data);
+ }
+
+ /* Disable INTx interrupt if MSI/MSIX is selected */
+ reg = ROFFS(iproc_regs, PAXB_0_CMICD_TO_PCIE_INTR_EN);
+ data = iproc32_read(shbde, reg);
+ if (icfg->use_msi) {
+ data &= ~0x1;
+ } else {
+ data |= 0x1;
+ }
+ iproc32_write(shbde, reg, data);
+
+ return pci_num;
+}
+
+/*
+ * Function:
+ * shbde_iproc_pci_read
+ * Purpose:
+ * Read iProc register through PCI BAR 0
+ * Parameters:
+ * shbde - pointer to initialized hardware abstraction module
+ * iproc_regs - memory mapped iProc registers in PCI BAR
+ * addr - iProc register address in AXI memory space
+ * Returns:
+ * Register value
+ */
+unsigned int
+shbde_iproc_pci_read(shbde_hal_t *shbde, void *iproc_regs,
+ unsigned int addr)
+{
+ unsigned int subwin_base;
+ void *reg;
+ shbde_iproc_config_t *icfg = &shbde->icfg;
+
+ if (!iproc_regs) {
+ return -1;
+ }
+
+ /* Sub-window size is 0x1000 (4K) */
+ subwin_base = (addr & ~0xfff);
+
+ if((icfg->cmic_ver >= 4) &&
+ ((subwin_base == 0x10231000) || (subwin_base == 0x18013000))) {
+ /* Route the INTC block access through IMAP0_6 */
+ reg = ROFFS(iproc_regs, 0x6000 + (addr & 0xfff));
+ } else {
+ /* Update base address for sub-window 7 */
+ subwin_base |= 1; /* Valid bit */
+ reg = ROFFS(iproc_regs, BAR0_PAXB_IMAP0_7);
+ iproc32_write(shbde, reg, subwin_base);
+ /* Read it to make sure the write actually goes through */
+ subwin_base = iproc32_read(shbde, reg);
+
+ /* Read register through sub-window 7 */
+ reg = ROFFS(iproc_regs, 0x7000 + (addr & 0xfff));
+ }
+
+ return iproc32_read(shbde, reg);
+}
+
+/*
+ * Function:
+ * shbde_iproc_pci_write
+ * Purpose:
+ * Write iProc register through PCI BAR 0
+ * Parameters:
+ * shbde - pointer to initialized hardware abstraction module
+ * iproc_regs - memory mapped iProc registers in PCI BAR
+ * addr - iProc register address in AXI memory space
+ * data - data to write to iProc register
+ * Returns:
+ * Register value
+ */
+void
+shbde_iproc_pci_write(shbde_hal_t *shbde, void *iproc_regs,
+ unsigned int addr, unsigned int data)
+{
+ unsigned int subwin_base;
+ void *reg;
+ shbde_iproc_config_t *icfg = &shbde->icfg;
+
+ if (!iproc_regs) {
+ return;
+ }
+
+ /* Sub-window size is 0x1000 (4K) */
+ subwin_base = (addr & ~0xfff);
+
+ if((icfg->cmic_ver >= 4) &&
+ ((subwin_base == 0x10231000) || (subwin_base == 0x18013000))) {
+ /* Route the INTC block access through IMAP0_6 */
+ reg = ROFFS(iproc_regs, 0x6000 + (addr & 0xfff));
+ } else {
+ /* Update base address for sub-window 7 */
+ subwin_base |= 1; /* Valid bit */
+ reg = ROFFS(iproc_regs, BAR0_PAXB_IMAP0_7);
+ iproc32_write(shbde, reg, subwin_base);
+ /* Read it to make sure the write actually goes through */
+ subwin_base = iproc32_read(shbde, reg);
+
+ /* Read register through sub-window 7 */
+ reg = ROFFS(iproc_regs, 0x7000 + (addr & 0xfff));
+ }
+
+ iproc32_write(shbde, reg, data);
+}
+
+int
+shbde_iproc_pcie_preemphasis_set(shbde_hal_t *shbde, void *iproc_regs,
+ shbde_iproc_config_t *icfg, void *pci_dev)
+{
+ shbde_mdio_ctrl_t mdio_ctrl, *smc = &mdio_ctrl;
+ unsigned int phy_addr, data;
+ void *reg;
+ unsigned int pcie_cap_base;
+ unsigned short link_stat, link_stat2;
+
+ if (!icfg) {
+ return -1;
+ }
+
+ /* PHY address for PCIe link */
+ phy_addr = icfg->pcie_phy_addr;
+ if (phy_addr == 0 || icfg->mdio_base_addr == 0) {
+ return 0;
+ }
+
+ /* Initialize MDIO control */
+ smc->shbde = shbde;
+ smc->regs = iproc_regs;
+ smc->base_addr = icfg->mdio_base_addr;
+ smc->io32_read = shbde_iproc_pci_read;
+ smc->io32_write = shbde_iproc_pci_write;
+ shbde_iproc_mdio_init(smc);
+
+ /* PCIe SerDes Gen1/Gen2 CDR Track Bandwidth Adjustment
+ * for Better Jitter Tolerance
+ */
+ shbde_iproc_mdio_write(smc, phy_addr, 0x1f, 0x8630);
+ shbde_iproc_mdio_write(smc, phy_addr, 0x13, 0x190);
+ shbde_iproc_mdio_write(smc, phy_addr, 0x19, 0x191);
+
+ if (!icfg->adjust_pcie_preemphasis) {
+ return 0;
+ }
+
+ /* Check to see if the PCIe SerDes deemphasis needs to be changed
+ * based on the advertisement from the root complex
+ */
+ /* Find PCIe capability base */
+ if (!shbde || !shbde->pcic16_read || !pci_dev) {
+ return -1;
+ }
+ pcie_cap_base = shbde_pci_pcie_cap(shbde, pci_dev);
+ if (pcie_cap_base) {
+ link_stat = shbde->pcic16_read(pci_dev,
+ pcie_cap_base + PCI_EXP_LNKSTA);
+ link_stat2 = shbde->pcic16_read(pci_dev,
+ pcie_cap_base + PCI_EXP_LNKSTA2);
+ if (((link_stat & 0xf) == PCI_EXP_LNKSTA_CLS_5_0GB) &&
+ (link_stat2 & PCI_EXP_LNKSTA2_CDL_3_5DB)) {
+ /* Device is operating at Gen2 speeds and RC requested -3.5dB */
+ /* Change the transmitter setting */
+ shbde_iproc_mdio_write(smc, phy_addr, 0x1f, 0x8610);
+ shbde_iproc_mdio_read(smc, phy_addr, 0x17, &data);
+ data &= ~0xf00;
+ data |= 0x700;
+ shbde_iproc_mdio_write(smc, phy_addr, 0x17, data);
+
+ /* Force the PCIe link to retrain */
+ data = 0;
+ REG_FIELD_SET(PAXB_CONFIG_IND_ADDRr, PROTOCOL_LAYERf, data, 0x2);
+ REG_FIELD_SET(PAXB_CONFIG_IND_ADDRr, ADDRESSf, data, 0x4);
+ reg = ROFFS(iproc_regs, BAR0_PAXB_CONFIG_IND_ADDR);
+ iproc32_write(shbde, reg, data);
+
+ reg = ROFFS(iproc_regs, BAR0_PAXB_CONFIG_IND_DATA);
+ data = iproc32_read(shbde, reg);
+ data &= ~0x4000;
+ iproc32_write(shbde, reg, data);
+ data |= 0x4000;
+ iproc32_write(shbde, reg, data);
+ data &= ~0x4000;
+ iproc32_write(shbde, reg, data);
+
+ /* Wait a short while for the retraining to complete */
+ wait_usec(shbde, 1000);
+ }
+ }
+
+ return 0;
+}
+
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/shared/shbde_mdio.c b/sdk-6.5.16/src/gpl-modules/systems/bde/shared/shbde_mdio.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2015 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#include <shbde_mdio.h>
+
+/* iProc MDIO register offset */
+#define MII_MGMT_CTRL 0x0
+#define MII_MGMT_CMD_DATA 0x4
+
+/* iProc MII register with fields definition */
+#define MII_MGMT_CTRLr_MDCDIVf_SHFT 0
+#define MII_MGMT_CTRLr_MDCDIVf_MASK 0x7f
+#define MII_MGMT_CTRLr_BSYf_SHFT 8
+#define MII_MGMT_CTRLr_BSYf_MASK 0x1
+
+#define MII_MGMT_CMD_DATAr_DATAf_SHFT 0
+#define MII_MGMT_CMD_DATAr_DATAf_MASK 0xffff
+#define MII_MGMT_CMD_DATAr_TAf_SHFT 16
+#define MII_MGMT_CMD_DATAr_TAf_MASK 0x3
+#define MII_MGMT_CMD_DATAr_RAf_SHFT 18
+#define MII_MGMT_CMD_DATAr_RAf_MASK 0x1f
+#define MII_MGMT_CMD_DATAr_PAf_SHFT 23
+#define MII_MGMT_CMD_DATAr_PAf_MASK 0x1f
+#define MII_MGMT_CMD_DATAr_OPf_SHFT 28
+#define MII_MGMT_CMD_DATAr_OPf_MASK 0x3
+#define MII_MGMT_CMD_DATAr_SBf_SHFT 30
+#define MII_MGMT_CMD_DATAr_SBf_MASK 0x3
+
+/* Register field value set/get */
+#define REG_FIELD_SET(_r, _f, _r_val, _f_val) \
+ _r_val = ((_r_val) & ~(_r##_##_f##_MASK << _r##_##_f##_SHFT)) | \
+ (((_f_val) & _r##_##_f##_MASK) << _r##_##_f##_SHFT)
+#define REG_FIELD_GET(_r, _f, _r_val) \
+ (((_r_val) >> _r##_##_f##_SHFT) & _r##_##_f##_MASK)
+
+#define LOG_OUT(_shbde, _lvl, _str, _prm) \
+ if ((_shbde)->log_func) { \
+ (_shbde)->log_func(_lvl, _str, _prm); \
+ }
+#define LOG_ERR(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_ERR, _str, _prm)
+#define LOG_WARN(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_WARN, _str, _prm)
+#define LOG_DBG(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_DBG, _str, _prm)
+
+static unsigned int
+mdio32_read(shbde_mdio_ctrl_t *smc, unsigned int offset)
+{
+ if (!smc || !smc->io32_read) {
+ return 0;
+ }
+ return smc->io32_read(smc->shbde, smc->regs, smc->base_addr + offset);
+}
+
+static void
+mdio32_write(shbde_mdio_ctrl_t *smc, unsigned int offset, unsigned int data)
+{
+ if (!smc || !smc->io32_read) {
+ return;
+ }
+ smc->io32_write(smc->shbde, smc->regs, smc->base_addr + offset, data);
+}
+
+static void
+wait_usec(shbde_mdio_ctrl_t *smc, int usec)
+{
+ shbde_hal_t *shbde = smc->shbde;
+
+ if (shbde && shbde->usleep) {
+ shbde->usleep(usec);
+ } else {
+ int idx;
+ volatile int count;
+ for (idx = 0; idx < usec; idx++) {
+ for (count = 0; count < 100; count++);
+ }
+ }
+}
+
+static int
+iproc_mdio_wait_for_busy(shbde_mdio_ctrl_t *smc)
+{
+ int mii_busy;
+ unsigned int reg_val;
+ int count = 1000;
+
+ /* Wait until MII is not busy */
+ do {
+ reg_val = mdio32_read(smc, MII_MGMT_CTRL);
+ mii_busy = REG_FIELD_GET(MII_MGMT_CTRLr, BSYf, reg_val);
+ if (!mii_busy) {
+ break;
+ }
+ wait_usec(smc, 10);
+ count --;
+ } while (count > 0);
+
+ return mii_busy;
+}
+
+int
+shbde_iproc_mdio_init(shbde_mdio_ctrl_t *smc)
+{
+ shbde_hal_t *shbde = smc->shbde;
+ unsigned int reg_val = 0;
+
+ /* Enable the iProc internal MDIO interface */
+ REG_FIELD_SET(MII_MGMT_CTRLr, MDCDIVf, reg_val, 0x7f);
+ mdio32_write(smc, MII_MGMT_CTRL, reg_val);
+
+ if (shbde && !shbde->usleep) {
+ LOG_DBG(shbde, "shbde_mdio: no registration of usleep vector", 0);
+ }
+
+ wait_usec(smc, 100);
+
+ return 0;
+}
+
+int
+shbde_iproc_mdio_read(shbde_mdio_ctrl_t *smc, unsigned int phy_addr,
+ unsigned int reg, unsigned int *val)
+{
+ unsigned int reg_val = 0;
+
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, SBf, reg_val, 0x1);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, TAf, reg_val, 0x2);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, OPf, reg_val, 0x2);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, PAf, reg_val, phy_addr);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, RAf, reg_val, reg);
+ mdio32_write(smc, MII_MGMT_CMD_DATA, reg_val);
+
+ if (iproc_mdio_wait_for_busy(smc)) {
+ *val = 0;
+ LOG_DBG(smc->shbde, "shbde_iproc_mdio_read busy", reg);
+ return -1;
+ }
+
+ reg_val = mdio32_read(smc, MII_MGMT_CMD_DATA);
+ *val = REG_FIELD_GET(MII_MGMT_CMD_DATAr, DATAf, reg_val);
+
+ return 0;
+}
+
+int
+shbde_iproc_mdio_write(shbde_mdio_ctrl_t *smc, unsigned int phy_addr,
+ unsigned int reg, unsigned int val)
+{
+ unsigned int reg_val = 0;
+
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, SBf, reg_val, 0x1);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, TAf, reg_val, 0x2);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, OPf, reg_val, 0x1);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, PAf, reg_val, phy_addr);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, RAf, reg_val, reg);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, DATAf, reg_val, val);
+ mdio32_write(smc, MII_MGMT_CMD_DATA, reg_val);
+
+ if (iproc_mdio_wait_for_busy(smc)) {
+ LOG_DBG(smc->shbde, "shbde_iproc_mdio_write busy", reg);
+ return -1;
+ }
+
+ /* Wait for some time for the write to take effect */
+ wait_usec(smc, 100);
+
+ return 0;
+}
+
diff --git a/sdk-6.5.16/src/gpl-modules/systems/bde/shared/shbde_pci.c b/sdk-6.5.16/src/gpl-modules/systems/bde/shared/shbde_pci.c
@@ -0,0 +1,392 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2014 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#include <shbde_pci.h>
+
+/* PCIe capabilities */
+#ifndef PCI_CAPABILITY_LIST
+#define PCI_CAPABILITY_LIST 0x34
+#endif
+#ifndef PCI_CAP_ID_EXP
+#define PCI_CAP_ID_EXP 0x10
+#endif
+#ifndef PCI_EXP_DEVCAP
+#define PCI_EXP_DEVCAP 4
+#endif
+#ifndef PCI_EXP_DEVCTL
+#define PCI_EXP_DEVCTL 8
+#endif
+#ifndef PCI_EXT_CAP_START
+#define PCI_EXT_CAP_START 0x100
+#endif
+#ifndef PCI_EXT_CAP_ID
+#define PCI_EXT_CAP_ID(_hdr) (_hdr & 0x0000ffff)
+#endif
+#ifndef PCI_EXT_CAP_VER
+#define PCI_EXT_CAP_VER(_hdr) ((_hdr >> 16) & 0xf)
+#endif
+#ifndef PCI_EXT_CAP_NEXT
+#define PCI_EXT_CAP_NEXT(_hdr) ((_hdr >> 20) & 0xffc)
+#endif
+#ifndef PCI_EXT_CAP_ID_VNDR
+#define PCI_EXT_CAP_ID_VNDR 0x0b
+#endif
+
+#define LOG_OUT(_shbde, _lvl, _str, _prm) \
+ if ((_shbde)->log_func) { \
+ (_shbde)->log_func(_lvl, _str, _prm); \
+ }
+#define LOG_ERR(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_ERR, _str, _prm)
+#define LOG_WARN(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_WARN, _str, _prm)
+#define LOG_DBG(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_DBG, _str, _prm)
+
+#ifndef NULL
+#define NULL (void *)0
+#endif
+
+/*
+ * Warpper functions with null-pointer checks.
+ */
+static unsigned int
+pcic16_read(shbde_hal_t *shbde, void *pci_dev,
+ unsigned int addr)
+{
+ if (!shbde || !shbde->pcic16_read) {
+ return 0;
+ }
+ return shbde->pcic16_read(pci_dev, addr);
+}
+
+static void
+pcic16_write(shbde_hal_t *shbde, void *pci_dev,
+ unsigned int addr, unsigned int data)
+{
+ if (!shbde || !shbde->pcic16_write) {
+ return;
+ }
+ shbde->pcic16_write(pci_dev, addr, data);
+}
+
+static unsigned int
+pcic32_read(shbde_hal_t *shbde, void *pci_dev,
+ unsigned int addr)
+{
+ if (!shbde || !shbde->pcic32_read) {
+ return 0;
+ }
+ return shbde->pcic32_read(pci_dev, addr);
+}
+
+static void *
+pci_parent_device_get(shbde_hal_t *shbde, void *pci_dev)
+{
+ if (!shbde || !shbde->pci_parent_device_get) {
+ return NULL;
+ }
+ return shbde->pci_parent_device_get(pci_dev);
+}
+
+/*
+ * Function:
+ * shbde_pci_pcie_cap
+ * Purpose:
+ * Return offset of PCIe capabilities in PCI configuration space
+ * Parameters:
+ * shbde - pointer to initialized hardware abstraction module
+ * dev - PCI device handle (passed back to PCI HAL functions)
+ * Returns:
+ * PCI_CAP_ID_EXP offset in PCI configuration space if PCIe, otherwise 0
+ */
+unsigned int
+shbde_pci_pcie_cap(shbde_hal_t *shbde, void *pci_dev)
+{
+ unsigned int cap_base, rval;
+
+ cap_base = pcic16_read(shbde, pci_dev, PCI_CAPABILITY_LIST);
+ while (cap_base) {
+ rval = pcic16_read(shbde, pci_dev, cap_base);
+ if ((rval & 0xff) == PCI_CAP_ID_EXP) {
+ break;
+ }
+ cap_base = (rval >> 8) & 0xff;
+ }
+
+ return cap_base;
+}
+
+/*
+ * Function:
+ * shbde_pci_is_pcie
+ * Purpose:
+ * Check if PCI device is PCIe device
+ * Parameters:
+ * shbde - pointer to initialized hardware abstraction module
+ * dev - PCI device handle (passed back to PCI HAL functions)
+ * Returns:
+ * 1 if PCIe, otherwise 0
+ */
+int
+shbde_pci_is_pcie(shbde_hal_t *shbde, void *pci_dev)
+{
+ return shbde_pci_pcie_cap(shbde, pci_dev) ? 1 : 0;
+}
+
+/*
+ * Function:
+ * shbde_pci_is_iproc
+ * Purpose:
+ * Check if PCI device is iProc-based
+ * Parameters:
+ * shbde - pointer to initialized hardware abstraction module
+ * dev - PCI device handle (passed back to PCI HAL functions)
+ * cmic_bar - (OUT) PCI BAR which contains switch CMIC registers
+ * Returns:
+ * 1 if iProc-based, otherwise 0
+ */
+int
+shbde_pci_is_iproc(shbde_hal_t *shbde, void *pci_dev, int *cmic_bar)
+{
+ unsigned int cap_base, rval;
+
+ if (!shbde_pci_is_pcie(shbde, pci_dev)) {
+ return 0;
+ }
+
+ /* Look for PCIe vendor-specific extended capability (VSEC) */
+ cap_base = PCI_EXT_CAP_START;
+ while (cap_base) {
+ rval = pcic32_read(shbde, pci_dev, cap_base);
+ if (rval == 0xffffffff) {
+ /* Assume PCI HW read error */
+ return 0;
+ }
+
+ if (PCI_EXT_CAP_ID(rval) == PCI_EXT_CAP_ID_VNDR) {
+ break;
+ }
+ cap_base = PCI_EXT_CAP_NEXT(rval);
+ }
+ if (cap_base) {
+ /*
+ * VSEC layout:
+ *
+ * 0x00: PCI Express Extended Capability Header
+ * 0x04: Vendor-Specific Header
+ * 0x08: Vendor-Specific Register 1
+ * 0x0c: Vendor-Specific Register 2
+ * ...
+ * 0x24: Vendor-Specific Register 8
+ */
+ /* 32'b // 31:12=0 Reserved; 11:08=CMIC BAR; 07:00=iProc Configuration ID */
+ rval = pcic32_read(shbde, pci_dev, cap_base + 8);
+ LOG_DBG(shbde, "Found VSEC", rval);
+
+ /* Determine PCI BAR of CMIC */
+ *cmic_bar = 0;
+ if ((rval & 0x100) == 0x100) {
+ *cmic_bar = 2;
+ }
+ /* Assume iProc device */
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Function:
+ * shbde_pci_iproc_version_get
+ * Purpose:
+ * Get iproc, cmic versions and revisions
+ * Parameters:
+ * shbde - pointer to initialized hardware abstraction module
+ * dev - PCI device handle (passed back to PCI HAL functions)
+ * iproc_ver - (OUT) iProc version
+ * cmic_ver - (OUT) CMIC version
+ * cmic_rev - (OUT) CMIC revision
+ * Returns:
+ * 1 for no error, otherwise 0
+ */
+int
+shbde_pci_iproc_version_get(shbde_hal_t *shbde, void *pci_dev,
+ unsigned int *iproc_ver,
+ unsigned int *cmic_ver,
+ unsigned int *cmic_rev)
+{
+ unsigned int cap_base, rval;
+
+ if (!shbde_pci_is_pcie(shbde, pci_dev)) {
+ return 0;
+ }
+
+ /* Look for PCIe vendor-specific extended capability (VSEC) */
+ cap_base = PCI_EXT_CAP_START;
+ while (cap_base) {
+ rval = pcic32_read(shbde, pci_dev, cap_base);
+ if (rval == 0xffffffff) {
+ /* Assume PCI HW read error */
+ return 0;
+ }
+
+ if (PCI_EXT_CAP_ID(rval) == PCI_EXT_CAP_ID_VNDR) {
+ break;
+ }
+ cap_base = PCI_EXT_CAP_NEXT(rval);
+ }
+ if (cap_base) {
+ /*
+ * VSEC layout:
+ *
+ * 0x00: PCI Express Extended Capability Header
+ * 0x04: Vendor-Specific Header
+ * 0x08: Vendor-Specific Register 1
+ * 0x0c: Vendor-Specific Register 2
+ * ...
+ * 0x24: Vendor-Specific Register 8
+ */
+
+ /* Read PCIe Vendor Specific Register 1 */
+ /* VENODR REG FORMAT
+ * [7:0] iProc Rev = 8'h0E (for P14)
+ * [11:8] CMIC BAR = 4'h1 (BAR64-1)
+ * [15:12] CMIC Version = 4'h4
+ * [19:16] CMIC Rev = 4'h1
+ * [22:20] SBUS Version = 4'h4
+ */
+
+ rval = pcic32_read(shbde, pci_dev, cap_base + 8);
+ LOG_DBG(shbde, "Found VSEC", rval);
+
+ /* Determine PCI BAR of CMIC */
+ *iproc_ver = rval & 0xff;
+ *cmic_ver = (rval >> 12) & 0xf;
+ *cmic_rev = (rval >> 16) & 0xf;
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Function:
+ * shbde_pci_max_payload_set
+ * Purpose:
+ * Set PCIe maximum payload
+ * Parameters:
+ * shbde - pointer to initialized hardware abstraction module
+ * dev - PCI device handle (passed back to PCI HAL functions)
+ * maxpayload - maximum payload (in byte)
+ * Returns:
+ * -1 if error, otherwise 0
+ * Notes:
+ * If not PCIe device, set the PCI retry count to infinte instead.
+ */
+int
+shbde_pci_max_payload_set(shbde_hal_t *shbde, void *pci_dev, int maxpayload)
+{
+ unsigned int cap_base, parent_cap_base;
+ unsigned int devcap, devctl, parent_devctl;
+ int max_val, max_cap, parent_max_val;
+ void *parent_pci_dev;
+
+ cap_base = shbde_pci_pcie_cap(shbde, pci_dev);
+
+ if (cap_base == 0) {
+ /* Not PCIe */
+ return 0;
+ }
+
+ /* Get current device control settings */
+ devctl = pcic16_read(shbde, pci_dev, cap_base + PCI_EXP_DEVCTL);
+
+ /* Get current max payload setting */
+ max_val = (devctl >> 5) & 0x7;
+
+ if (maxpayload) {
+ /* Get encoding from byte value */
+ max_val = 0;
+ while ((1 << (max_val + 7)) < maxpayload) {
+ max_val++;
+ }
+ LOG_DBG(shbde, "Set max payload size", maxpayload);
+ LOG_DBG(shbde, "Set max payload val", max_val);
+
+ /* Get max supported payload size */
+ devcap = pcic16_read(shbde, pci_dev, cap_base + PCI_EXP_DEVCAP);
+ max_cap = (devcap & 0x7);
+
+ /* Do not exceed device capabilities */
+ if (max_val > max_cap) {
+ max_val = max_cap;
+ LOG_DBG(shbde,
+ "Payload size exceeds device capability",
+ maxpayload);
+ }
+
+ /* Get currently set max payload size for the parent device
+ * in the PCI tree (if it exists).
+ */
+ parent_pci_dev = pci_parent_device_get(shbde, pci_dev);
+ if (parent_pci_dev != NULL) {
+ parent_cap_base = shbde_pci_pcie_cap(shbde, parent_pci_dev);
+ parent_devctl = pcic16_read(shbde,
+ parent_pci_dev,
+ parent_cap_base + PCI_EXP_DEVCTL);
+ parent_max_val = (parent_devctl >> 5) & 0x7;
+
+ /* Do not exceed current parent max payload setting (our device
+ * should have an MPS setting <= current parent MPS setting in
+ * the tree of PCIe devices).
+ */
+ if (max_val > parent_max_val) {
+ max_val = parent_max_val;
+ LOG_DBG(shbde,
+ "Payload size exceeds current parent device setting",
+ maxpayload);
+ }
+ }
+
+ /* Update max payload size */
+ devctl &= ~(0x7 << 5);
+ devctl |= (max_val) << 5;
+
+ /* Update max request size */
+ devctl &= ~(0x7 << 12);
+ devctl |= (max_val << 12);
+ }
+
+ /* Always disable relaxed ordering */
+ devctl &= ~(1 << 4);
+
+ /* Update device control settings */
+ pcic16_write(shbde, pci_dev, cap_base + PCI_EXP_DEVCTL, devctl);
+
+ /* Warn if non-default setting is used */
+ if (max_val > 0) {
+ LOG_WARN(shbde,
+ "Selected payload size may not be supported by all "
+ "PCIe bridges by default.",
+ (1 << (max_val + 7)));
+ }
+
+ return 0;
+}
diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/Makefile b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/Makefile
@@ -0,0 +1,31 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.10 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+# Makefile for SOC SAL support
+#
+LOCALDIR = systems/linux/kernel/modules
+
+include ${SDK}/make/Make.config
+
+subdirs=shared uk-proxy bcm-diag-full bcm-core bcm-net bcm-diag
+
+include ${SDK}/make/Make.subdirs
+
+include ${SDK}/make/Make.depend
diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/Makefile b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/Makefile
@@ -0,0 +1,67 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.3 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+LOCALDIR = systems/linux/kernel/modules/bcm-knet
+
+include ${SDK}/make/Make.config
+
+LIBS = $(LIBDIR)/libkern.a
+
+ifeq ($(kernel_version),2_4)
+MODULE = $(LIBDIR)/linux-bcm-knet.o
+else
+KERNEL_MODULE_DIR = kernel_module
+
+THIS_MOD_NAME := linux-bcm-knet
+MODULE = $(LIBDIR)/$(THIS_MOD_NAME).o
+KMODULE = $(LIBDIR)/$(THIS_MOD_NAME).ko
+
+build: $(MODULE) $(KMODULE)
+endif
+
+KBUILD_EXTRA_SYMBOLS := ${BLDDIR}/../../../../bde/linux/kernel/kernel_module/Module.symvers
+ifeq (,$(findstring -DPROXY_SUPPORT=0,$(CFLAGS)))
+KBUILD_EXTRA_SYMBOLS += ${BLDDIR}/../uk-proxy/kernel_module/Module.symvers
+endif
+
+# BCM Network Device
+
+$(MODULE): $(BLDDIR)/.tree $(BOBJS) $(LIBS)
+ $(LD) $(MODULE_LDFLAGS) -r -d $(BOBJS) $(LIBS) -o $@
+ifneq ($(kernel_version),2_4)
+$(KMODULE): $(MODULE)
+ rm -fr $(BLDDIR)/$(KERNEL_MODULE_DIR)
+ mkdir $(BLDDIR)/$(KERNEL_MODULE_DIR)
+ cp ${SDK}/make/Makefile.linux-kmodule $(BLDDIR)/$(KERNEL_MODULE_DIR)/Makefile
+ cat ${KBUILD_EXTRA_SYMBOLS} > $(BLDDIR)/$(KERNEL_MODULE_DIR)/Module.symvers
+ MOD_NAME=$(THIS_MOD_NAME) $(MAKE) -C $(BLDDIR)/$(KERNEL_MODULE_DIR) $(THIS_MOD_NAME).ko
+endif
+
+# Make.depend is before clean:: so that Make.depend's clean:: runs first.
+
+include ${SDK}/make/Make.depend
+
+clean::
+ $(RM) $(BLDDIR)/version.c $(BLDDIR)/version.o
+ $(RM) $(BOBJS) $(MODULE)
+
+ifneq ($(kernel_version),2_4)
+.PHONY: build
+endif
diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c
@@ -0,0 +1,8947 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: bcm-knet.c,v 1.90 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+/*
+ * This module implements a Linux network driver for Broadcom
+ * XGS switch devices. The driver simultaneously serves a
+ * number of vitual Linux network devices and a Tx/Rx API
+ * implemented in user space.
+ *
+ * Packets received from the switch device are sent to either
+ * a virtual Linux network device or the user mode Rx API
+ * based on a set of packet filters.susp
+ *
+ * Packets from the virtual Linux network devices and the user
+ * mode Tx API are multiplexed with priority given to the Tx API.
+ *
+ * A message-based IOCTL interface is used for managing packet
+ * filters and virtual Linux network interfaces.
+ *
+ * A virtual network interface can be configured to work in RCPU
+ * mode, which means that packets from the switch device will
+ * be encasulated with a RCPU header and a block of meta data
+ * that basically contains the core DCB information. Likewise,
+ * packets received from the Linux network stack are assumed to
+ * be RCPU encapsulated when going out on an interface in RCPU
+ * mode.
+ *
+ * The module implements basic Rx DMA rate control. The rate is
+ * specified in packets per second, and different Rx DMA channels
+ * can be configured to use different maximum packet rates.
+ * The packet rate can be configure as a module parameter, and
+ * it can also be changed dynamically through the proc file
+ * system (syntax is described in function header comment).
+ *
+ * To support multiple instance, each instance has its event queue.
+ *
+ * To support pci hot-plug in this module, the resource update
+ * should be handled when the PCI device is re-plugged.
+ * NOTE: the KNET detach should be invoked befere removing the
+ * device.
+ *
+ * For a list of supported module parameters, please see below.
+ */
+
+#include <gmodule.h> /* Must be included first */
+#include <linux-bde.h>
+#include <kcom.h>
+#include <bcm-knet.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/random.h>
+#include <linux/seq_file.h>
+#include <linux/if_vlan.h>
+
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Network Device Driver for Broadcom BCM TxRx API");
+MODULE_LICENSE("GPL");
+
+static int debug;
+LKM_MOD_PARAM(debug, "i", int, 0);
+MODULE_PARM_DESC(debug,
+"Debug level (default 0)");
+
+static char *mac_addr = NULL;
+LKM_MOD_PARAM(mac_addr, "s", charp, 0);
+MODULE_PARM_DESC(mac_addr,
+"Ethernet MAC address (default 02:10:18:xx:xx:xx)");
+
+static int rx_buffer_size = 9216;
+LKM_MOD_PARAM(rx_buffer_size, "i", int, 0);
+MODULE_PARM_DESC(rx_buffer_size,
+"Size of RX packet buffers (default 9216)");
+
+static int default_mtu = 1500;
+LKM_MOD_PARAM(default_mtu, "i", int, 0);
+MODULE_PARM_DESC(default_mtu,
+"Default MTU for KNET network interfaces (default 1500)");
+
+static int rx_sync_retry = 1000;
+LKM_MOD_PARAM(rx_sync_retry, "i", int, 0);
+MODULE_PARM_DESC(rx_sync_retry,
+"Retries if chain is incomplete on interrupt (default 10)");
+
+static char *base_dev_name = NULL;
+LKM_MOD_PARAM(base_dev_name, "s", charp, 0);
+MODULE_PARM_DESC(base_dev_name,
+"Base device name (default bcm0, bcm1, etc.)");
+
+static int rcpu_mode = 0;
+LKM_MOD_PARAM(rcpu_mode, "i", int, 0);
+MODULE_PARM_DESC(rcpu_mode,
+"Enable RCPU encapsulation (default 0)");
+
+static char *rcpu_dmac = NULL;
+LKM_MOD_PARAM(rcpu_dmac, "s", charp, 0);
+MODULE_PARM_DESC(rcpu_dmac,
+"RCPU destination MAC address (by default use L2 destination MAC address)");
+
+static char *rcpu_smac = NULL;
+LKM_MOD_PARAM(rcpu_smac, "s", charp, 0);
+MODULE_PARM_DESC(rcpu_smac,
+"RCPU source MAC address (by default use L2 source MAC address)");
+
+static int rcpu_ethertype = 0xde08;
+LKM_MOD_PARAM(rcpu_ethertype, "i", int, 0);
+MODULE_PARM_DESC(rcpu_ethertype,
+"RCPU EtherType (default DE08h)");
+
+static int rcpu_signature = 0;
+LKM_MOD_PARAM(rcpu_signature, "i", int, 0);
+MODULE_PARM_DESC(rcpu_signature,
+"RCPU Signature (default is PCI device ID)");
+
+static int rcpu_vlan = 1;
+LKM_MOD_PARAM(rcpu_vlan, "i", int, 0);
+MODULE_PARM_DESC(rcpu_vlan,
+"RCPU VLAN ID (default 1)");
+
+static int use_rx_skb = 0;
+LKM_MOD_PARAM(use_rx_skb, "i", int, 0);
+MODULE_PARM_DESC(use_rx_skb,
+"Use socket buffers for receive operation (default 0)");
+
+static int num_rx_prio = 1;
+LKM_MOD_PARAM(num_rx_prio, "i", int, 0);
+MODULE_PARM_DESC(num_rx_prio,
+"Number of filter priorities per Rx DMA channel");
+
+static int rx_rate[8] = { 100000, 100000, 100000, 100000, 100000, 100000, 100000, 0 };
+LKM_MOD_PARAM_ARRAY(rx_rate, "1-4i", int, NULL, 0);
+MODULE_PARM_DESC(rx_rate,
+"Rx rate in packets per second (default 100000)");
+
+static int rx_burst[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+LKM_MOD_PARAM_ARRAY(rx_burst, "1-4i", int, NULL, 0);
+MODULE_PARM_DESC(rx_burst,
+"Rx rate burst maximum in packets (default rx_rate/10)");
+
+static int check_rcpu_signature = 0;
+LKM_MOD_PARAM(check_rcpu_signature, "i", int, 0);
+MODULE_PARM_DESC(check_rcpu_signature,
+"Check RCPU Signature for Tx packets from RCPU interfaces");
+
+static int basedev_suspend = 0;
+LKM_MOD_PARAM(basedev_suspend, "i", int, 0);
+MODULE_PARM_DESC(basedev_suspend,
+"Pause traffic till base device is up (enabled by default in NAPI mode)");
+
+/* Debug levels */
+#define DBG_LVL_VERB 0x1
+#define DBG_LVL_DCB 0x2
+#define DBG_LVL_PKT 0x4
+#define DBG_LVL_SKB 0x8
+#define DBG_LVL_CMD 0x10
+#define DBG_LVL_EVT 0x20
+#define DBG_LVL_IRQ 0x40
+#define DBG_LVL_NAPI 0x80
+#define DBG_LVL_PDMP 0x100
+#define DBG_LVL_FLTR 0x200
+#define DBG_LVL_KCOM 0x400
+#define DBG_LVL_RCPU 0x800
+#define DBG_LVL_WARN 0x1000
+#define DBG_LVL_NDEV 0x2000
+#define DBG_LVL_INST 0x4000
+/* Level to output Dune internal headers Parsing */
+#define DBG_LVL_DUNE 0x8000
+#define DBG_LVL_DCB_TX 0x10000
+#define DBG_LVL_DCB_RX 0x20000
+#define DBG_LVL_PDMP_TX 0x40000
+#define DBG_LVL_PDMP_RX 0x80000
+
+#define DBG_VERB(_s) do { if (debug & DBG_LVL_VERB) gprintk _s; } while (0)
+#define DBG_PKT(_s) do { if (debug & DBG_LVL_PKT) gprintk _s; } while (0)
+#define DBG_SKB(_s) do { if (debug & DBG_LVL_SKB) gprintk _s; } while (0)
+#define DBG_CMD(_s) do { if (debug & DBG_LVL_CMD) gprintk _s; } while (0)
+#define DBG_EVT(_s) do { if (debug & DBG_LVL_EVT) gprintk _s; } while (0)
+#define DBG_IRQ(_s) do { if (debug & DBG_LVL_IRQ) gprintk _s; } while (0)
+#define DBG_NAPI(_s) do { if (debug & DBG_LVL_NAPI) gprintk _s; } while (0)
+#define DBG_PDMP(_s) do { if (debug & DBG_LVL_PDMP) gprintk _s; } while (0)
+#define DBG_FLTR(_s) do { if (debug & DBG_LVL_FLTR) gprintk _s; } while (0)
+#define DBG_KCOM(_s) do { if (debug & DBG_LVL_KCOM) gprintk _s; } while (0)
+#define DBG_RCPU(_s) do { if (debug & DBG_LVL_RCPU) gprintk _s; } while (0)
+#define DBG_WARN(_s) do { if (debug & DBG_LVL_WARN) gprintk _s; } while (0)
+#define DBG_NDEV(_s) do { if (debug & DBG_LVL_NDEV) gprintk _s; } while (0)
+#define DBG_INST(_s) do { if (debug & DBG_LVL_INST) gprintk _s; } while (0)
+#define DBG_DUNE(_s) do { if (debug & DBG_LVL_DUNE) gprintk _s; } while (0)
+#define DBG_DCB_TX(_s) do { if (debug & (DBG_LVL_DCB|DBG_LVL_DCB_TX)) \
+ gprintk _s; } while (0)
+#define DBG_DCB_RX(_s) do { if (debug & (DBG_LVL_DCB|DBG_LVL_DCB_RX)) \
+ gprintk _s; } while (0)
+#define DBG_DCB(_s) do { if (debug & (DBG_LVL_DCB|DBG_LVL_DCB_TX| \
+ DBG_LVL_DCB_RX)) \
+ gprintk _s; } while (0)
+
+
+/* This flag is used to indicate if debugging packet function is open or closed */
+static int dbg_pkt_enable = 0;
+
+/* Module Information */
+#define MODULE_MAJOR 122
+#define MODULE_NAME "linux-bcm-knet"
+
+#ifndef NAPI_SUPPORT
+#define NAPI_SUPPORT 1
+#endif
+
+#if NAPI_SUPPORT
+
+static int use_napi = 0;
+LKM_MOD_PARAM(use_napi, "i", int, 0);
+MODULE_PARM_DESC(use_napi,
+"Use NAPI interface (default 0)");
+
+static int napi_weight = 64;
+LKM_MOD_PARAM(napi_weight, "i", int, 0);
+MODULE_PARM_DESC(napi_weight,
+"Weight of NAPI interfaces (default 64)");
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+#define bkn_napi_enable(_dev, _napi) netif_poll_enable(_dev)
+#define bkn_napi_disable(_dev, _napi) netif_poll_disable(_dev)
+#define bkn_napi_schedule(_dev, _napi) netif_rx_schedule(_dev)
+#define bkn_napi_schedule_prep(_dev, _napi) netif_rx_schedule_prep(_dev)
+#define __bkn_napi_schedule(_dev, _napi) __netif_rx_schedule(_dev)
+#define bkn_napi_complete(_dev, _napi) netif_rx_complete(_dev)
+#else
+#define bkn_napi_enable(_dev, _napi) napi_enable(_napi)
+#define bkn_napi_disable(_dev, _napi) napi_disable(_napi)
+#define bkn_napi_schedule(_dev, _napi) napi_schedule(_napi)
+#define bkn_napi_schedule_prep(_dev, _napi) napi_schedule_prep(_napi)
+#define __bkn_napi_schedule(_dev, _napi) __napi_schedule(_napi)
+#define bkn_napi_complete(_dev, _napi) napi_complete(_napi)
+#endif
+
+#else
+
+static int use_napi = 0;
+static int napi_weight = 0;
+
+#define bkn_napi_enable(_dev, _napi)
+#define bkn_napi_disable(_dev, _napi)
+#define bkn_napi_schedule(_dev, _napi)
+#define bkn_napi_schedule_prep(_dev, _napi) (0)
+#define __bkn_napi_schedule(_dev, _napi)
+#define bkn_napi_complete(_dev, _napi)
+
+#endif
+
+/*
+ * If proxy support is compiled in the module will attempt to use
+ * the user/kernel message service provided by the linux-uk-proxy
+ * kernel module, otherwise device IOCTL will be used.
+ */
+#ifndef PROXY_SUPPORT
+#define PROXY_SUPPORT 0
+#endif
+
+#if PROXY_SUPPORT
+
+#include <linux-uk-proxy.h>
+
+static int use_proxy = 1;
+LKM_MOD_PARAM(use_proxy, "i", int, 0);
+MODULE_PARM_DESC(use_proxy,
+"Use Linux User/Kernel proxy (default 1)");
+
+#define PROXY_SERVICE_CREATE(_s,_q,_f) linux_uk_proxy_service_create(_s,_q,_f)
+#define PROXY_SERVICE_DESTROY(_s) linux_uk_proxy_service_destroy(_s);
+#define PROXY_SEND(_s,_m,_l) linux_uk_proxy_send(_s,_m,_l)
+#define PROXY_RECV(_s,_m,_l) linux_uk_proxy_recv(_s,_m,_l)
+
+#else
+
+static int use_proxy = 0;
+
+#define PROXY_SERVICE_CREATE(_s,_q,_f)
+#define PROXY_SERVICE_DESTROY(_s)
+#define PROXY_SEND(_s,_m,_l)
+#define PROXY_RECV(_s,_m,_l) (-1)
+
+#endif
+
+/* Compatibility */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0))
+#define NETDEV_UPDATE_TRANS_START_TIME(dev) dev->trans_start = jiffies
+#else
+#define NETDEV_UPDATE_TRANS_START_TIME(dev) netif_trans_update(dev)
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
+#define skb_copy_to_linear_data(_skb, _pkt, _len) \
+ eth_copy_and_sum(_skb, _pkt, _len, 0)
+struct napi_struct { int not_used; };
+#define netif_napi_add(_dev, _napi, _poll, _weight) do { \
+ (_dev)->poll = _poll; \
+ (_dev)->weight = _weight; \
+} while(0)
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
+#define SKB_PADTO(_skb,_len) (((_skb = skb_padto(_skb,_len)) == NULL) ? -1 : 0)
+#else
+#define SKB_PADTO(_skb,_len) skb_padto(_skb,_len)
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12))
+#define skb_header_cloned(_skb) \
+ skb_cloned(_skb)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27)
+static inline void *netdev_priv(struct net_device *dev)
+{
+ return dev->priv;
+}
+#endif /* KERNEL_VERSION(2,4,27) */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23)
+/* Special check for MontaVista 2.4.20 MIPS */
+#if !(defined(MAX_USER_RT_PRIO) && defined(CONFIG_MIPS))
+static inline void free_netdev(struct net_device *dev)
+{
+ kfree(dev);
+}
+#endif
+static inline void netif_poll_disable(struct net_device *dev)
+{
+ while (test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state)) {
+ /* No hurry. */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+}
+static inline void netif_poll_enable(struct net_device *dev)
+{
+ clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
+}
+#endif /* KERNEL_VERSION(2,4,23) */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21)
+static struct sk_buff *skb_pad(struct sk_buff *skb, int pad)
+{
+ struct sk_buff *nskb;
+
+ /* If the skbuff is non linear tailroom is always zero.. */
+ if(skb_tailroom(skb) >= pad)
+ {
+ memset(skb->data+skb->len, 0, pad);
+ return skb;
+ }
+
+ nskb = skb_copy_expand(skb, skb_headroom(skb), skb_tailroom(skb) + pad, GFP_ATOMIC);
+ kfree_skb(skb);
+ if(nskb)
+ memset(nskb->data+nskb->len, 0, pad);
+ return nskb;
+}
+static inline struct sk_buff *skb_padto(struct sk_buff *skb, unsigned int len)
+{
+ unsigned int size = skb->len;
+ if(likely(size >= len))
+ return skb;
+ return skb_pad(skb, len-size);
+}
+#endif /* KERNEL_VERSION(2,4,21) */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
+#define bkn_vlan_hwaccel_put_tag(_skb, _proto, _tci) \
+ __vlan_hwaccel_put_tag(_skb, _tci)
+#else
+#define bkn_vlan_hwaccel_put_tag(_skb, _proto, _tci) \
+ __vlan_hwaccel_put_tag(_skb, htons(_proto), _tci)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
+#define bkn_dma_mapping_error(d, a) \
+ dma_mapping_error(a)
+#define bkn_pci_dma_mapping_error(d, a) \
+ pci_dma_mapping_error(a)
+#else
+#define bkn_dma_mapping_error(d, a) \
+ dma_mapping_error(d, a)
+#define bkn_pci_dma_mapping_error(d, a) \
+ pci_dma_mapping_error(d, a)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+enum {
+ SKBTX_HW_TSTAMP = 1 << 0,
+ SKBTX_SW_TSTAMP = 1 << 1,
+ SKBTX_IN_PROGRESS = 1 << 2,
+};
+struct skb_shared_hwtstamps {
+ ktime_t hwtstamp;
+ ktime_t syststamp;
+};
+struct bkn_skb_shared_info {
+ uint8_t tx_flags;
+ struct skb_shared_hwtstamps hwtstamps;
+};
+#define bkn_skb_shinfo(_skb) ((struct bkn_skb_shared_info *)(unsigned char *)_skb->end)
+#define bkn_skb_tx_flags(_skb) bkn_skb_shinfo(_skb)->tx_flags
+static inline struct skb_shared_hwtstamps *skb_hwtstamps(struct sk_buff *skb)
+{
+ return &bkn_skb_shinfo(skb)->hwtstamps;
+}
+void skb_tstamp_tx(struct sk_buff *orig_skb, struct skb_shared_hwtstamps *hwtstamps)
+{
+}
+static inline void bkn_skb_tx_timestamp(struct sk_buff *skb)
+{
+}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+static inline ktime_t ns_to_ktime(u64 ns)
+{
+ static const ktime_t ktime;
+ return ktime;
+}
+#endif
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+#include <linux/net_tstamp.h>
+enum {
+ SKBTX_HW_TSTAMP = 1 << 0,
+ SKBTX_SW_TSTAMP = 1 << 1,
+ SKBTX_IN_PROGRESS = 1 << 2,
+};
+#define bkn_skb_tx_flags(_skb) skb_shinfo(_skb)->tx_flags.flags
+static inline void bkn_skb_tx_timestamp(struct sk_buff *skb)
+{
+}
+#else
+#include <linux/net_tstamp.h>
+#define bkn_skb_tx_flags(_skb) skb_shinfo(_skb)->tx_flags
+static inline void bkn_skb_tx_timestamp(struct sk_buff *skb)
+{
+ return skb_tx_timestamp(skb);
+}
+#endif
+
+#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT
+#define DMA_DEV device
+#define DMA_FROMDEV DMA_FROM_DEVICE
+#define DMA_TODEV DMA_TO_DEVICE
+#define DMA_MAP_SINGLE(d,p,s,r) dma_map_single(d,p,s,r)
+#define DMA_UNMAP_SINGLE(d,a,s,r) dma_unmap_single(d,a,s,r)
+#define DMA_ALLOC_COHERENT(d,s,h) dma_alloc_coherent(d,s,h,GFP_ATOMIC|GFP_DMA32)
+#define DMA_FREE_COHERENT(d,s,a,h) dma_free_coherent(d,s,a,h)
+#define DMA_MAPPING_ERROR(d,a) bkn_dma_mapping_error(d,a)
+#else
+#define DMA_DEV pci_dev
+#define DMA_FROMDEV PCI_DMA_FROMDEVICE
+#define DMA_TODEV PCI_DMA_TODEVICE
+#define DMA_MAP_SINGLE(d,p,s,r) pci_map_single(d,p,s,r)
+#define DMA_UNMAP_SINGLE(d,a,s,r) pci_unmap_single(d,a,s,r)
+#define DMA_ALLOC_COHERENT(d,s,h) pci_alloc_consistent(d,s,h)
+#define DMA_FREE_COHERENT(d,s,a,h) pci_free_consistent(d,s,a,h)
+#define DMA_MAPPING_ERROR(d,a) bkn_pci_dma_mapping_error(d,a)
+#endif
+
+/* RCPU operations */
+#define RCPU_OPCODE_RX 0x10
+#define RCPU_OPCODE_TX 0x20
+
+/* RCPU flags */
+#define RCPU_F_MODHDR 0x4
+
+/* RCPU encapsulation */
+#define RCPU_HDR_SIZE 32
+#define RCPU_TX_META_SIZE 32
+#define RCPU_TX_ENCAP_SIZE (RCPU_HDR_SIZE + RCPU_TX_META_SIZE)
+#define RCPU_RX_META_SIZE 64
+#define RCPU_RX_ENCAP_SIZE (RCPU_HDR_SIZE + RCPU_RX_META_SIZE)
+
+#define PKT_TX_HDR_SIZE 16
+
+static volatile int module_initialized;
+
+static ibde_t *kernel_bde = NULL;
+
+/* Descriptor info */
+typedef struct bkn_desc_info_s {
+ uint32_t *dcb_mem;
+ uint64_t dcb_dma;
+ struct sk_buff *skb;
+ uint64_t skb_dma;
+ uint32_t dma_size;
+} bkn_desc_info_t;
+
+/* DCB chain info */
+typedef struct bkn_dcb_chain_s {
+ struct list_head list;
+ int dcb_cnt;
+ int dcb_cur;
+ uint32_t *dcb_mem;
+ uint64_t dcb_dma;
+} bkn_dcb_chain_t;
+
+#define MAX_TX_DCBS 64
+#define MAX_RX_DCBS 64
+
+#define NUM_DMA_CHAN 8
+#define NUM_RX_CHAN 7
+#define NUM_CMICX_RX_CHAN 7
+#define NUM_CMICM_RX_CHAN 3
+
+#define FCS_SZ 4
+#define TAG_SZ 4
+
+/* Device control info */
+typedef struct bkn_switch_info_s {
+ struct list_head list;
+ struct list_head ndev_list; /* Associated virtual Ethernet interfaces */
+ struct net_device **ndevs; /* Indexed array of ndev_list */
+ int ndev_max; /* Size of indexed array */
+ struct list_head rxpf_list; /* Associated Rx packet filters */
+ volatile void *base_addr; /* Base address for PCI register access */
+ struct DMA_DEV *dma_dev; /* Required for DMA memory control */
+ struct pci_dev *pdev; /* Required for DMA memory control */
+ struct net_device *dev; /* Base network device */
+ struct napi_struct napi; /* New NAPI */
+ struct timer_list timer; /* Retry/resource timer */
+ int timer_queued; /* Flag indicating queued timer function */
+ uint32_t timer_runs; /* Timer function runs (debug only) */
+ struct timer_list rxtick; /* Rx rate control timer */
+ uint32_t rxticks_per_sec; /* Rx rate control update frequency */
+ uint32_t rxtick_jiffies; /* Time between updates (in jiffies) */
+ uint32_t rxticks; /* Rx rate control debug counter */
+ uint32_t interrupts; /* Total number of interrupts */
+ spinlock_t lock; /* Main lock for device */
+ int dev_no; /* Device number (from BDE) */
+ int cpu_no; /* Cpu number. 1 for iHost(AXI),0 for others */
+ int dcb_type; /* DCB type */
+ int dcb_wsize; /* DCB size (in 32-bit words) */
+ int pkt_hdr_size; /* Packet header size */
+ uint32_t ftmh_lb_key_ext_size; /* FTMH LB-Key Extension existence/size */
+ uint32_t ftmh_stacking_ext_size; /* FTMH Stacking extension existence/size */
+ uint32_t pph_base_size; /* Size of PPH base */
+ uint32_t pph_lif_ext_size[8]; /* Size of PPH Lif extension header */
+ uint8_t udh_enable; /* Indicates UDH existence */
+ uint32_t udh_length_type[4]; /* Size of UDH header per type */
+ int rx_chans; /* Number of Rx channels */
+ uint32_t dma_hi; /* DMA higher address */
+ uint32_t cmic_type; /* CMIC type (CMICe or CMICm) */
+ uint32_t irq_mask; /* Active IRQs for DMA control */
+ uint32_t napi_poll_mode; /* NAPI is in polling mode */
+ uint32_t napi_not_done; /* NAPI poll did not process all packets */
+ uint32_t napi_poll_again; /* Used if DCB chain is restarted */
+ uint32_t tx_yield; /* Tx schedule for Continuous DMA and Non-NAPI mode */
+ void *dcb_mem; /* Logical pointer to DCB memory */
+ uint64_t dcb_dma; /* Physical bus address for DCB memory */
+ int dcb_mem_size; /* Total size of allocated DCB memory */
+ uint32_t dma_events; /* DMA events pending for BCM API */
+ uint32_t rcpu_sig; /* RCPU signature */
+ uint64_t halt_addr[NUM_DMA_CHAN]; /* DMA halt address */
+ uint32_t cdma_channels; /* Active channels for Continuous DMA mode */
+ uint32_t poll_channels; /* Channels for polling */
+ uint32_t inst_id; /* Instance id of this device */
+ int evt_idx; /* Event queue index for this device*/
+ int basedev_suspended; /* Base device suspended */
+ int tx_hwts; /* HW timestamp for Tx */
+ int rx_hwts; /* HW timestamp for Rx */
+ struct sk_buff_head tx_ptp_queue; /* Tx PTP skb queue */
+ struct work_struct tx_ptp_work; /* Tx PTP work */
+ struct {
+ bkn_desc_info_t desc[MAX_TX_DCBS+1];
+ int free; /* Number of free Tx DCBs */
+ int cur; /* Index of current Tx DCB */
+ int dirty; /* Index of next Tx DCB to complete */
+ int api_active; /* BCM Tx API is in progress */
+ int suspends; /* Calls to netif_stop_queue (debug only) */
+ struct list_head api_dcb_list; /* Tx DCB chains from BCM Tx API */
+ bkn_dcb_chain_t *api_dcb_chain; /* Current Tx DCB chain */
+ bkn_dcb_chain_t *api_dcb_chain_end; /* Tx DCB chain end */
+ uint32_t pkts; /* Tx packet counter */
+ uint32_t pkts_d_no_skb; /* Tx drop - skb allocation failed */
+ uint32_t pkts_d_rcpu_encap; /* Tx drop - bad RCPU encapsulation */
+ uint32_t pkts_d_rcpu_sig; /* Tx drop - bad RCPU signature */
+ uint32_t pkts_d_rcpu_meta; /* Tx drop - bad RCPU meta data */
+ uint32_t pkts_d_pad_fail; /* Tx drop - pad to minimum size failed */
+ uint32_t pkts_d_dma_resrc; /* Tx drop - no DMA resources */
+ uint32_t pkts_d_callback; /* Tx drop - consumed by call-back */
+ uint32_t pkts_d_no_link; /* Tx drop - software link down */
+ uint32_t pkts_d_over_limit; /* Tx drop - length is out of range */
+ } tx;
+ struct {
+ bkn_desc_info_t desc[MAX_RX_DCBS+1];
+ int free; /* Number of free Rx DCBs */
+ int cur; /* Index of current Rx DCB */
+ int dirty; /* Index of next Rx DCB to complete */
+ int running; /* Rx DMA is active */
+ int api_active; /* BCM Rx API is active */
+ int chain_complete; /* All DCBs in chain processed */
+ int sync_err; /* Chain done with incomplete DCBs (debug) */
+ int sync_retry; /* Total retry times for sync error (debug) */
+ int sync_maxloop; /* Max loop times once in recovering sync (debug) */
+ int use_rx_skb; /* Use SKBs for DMA */
+ uint32_t rate_max; /* Rx rate in packets/sec */
+ uint32_t burst_max; /* Rx burst size in number of packets */
+ uint32_t tokens; /* Tokens for Rx rate control */
+ uint32_t rate; /* Current packet rate */
+ unsigned long tok_jif; /* Jiffies at last token update */
+ unsigned long rate_jif; /* Jiffies at last rate update */
+ struct list_head api_dcb_list; /* Rx DCB chains from BCM Rx API */
+ bkn_dcb_chain_t *api_dcb_chain; /* Current Rx DCB chain */
+ bkn_dcb_chain_t *api_dcb_chain_end; /* Rx DCB chain end */
+ uint32_t pkts; /* Rx packet counter */
+ uint32_t pkts_ref; /* Rx packet count for rate calculation */
+ uint32_t pkts_f_api; /* Rx packets filtered to API */
+ uint32_t pkts_f_netif; /* Rx packets filtered to net interface */
+ uint32_t pkts_m_api; /* Rx packets mirrored to API */
+ uint32_t pkts_m_netif; /* Rx packets mirrored to net interface */
+ uint32_t pkts_d_no_skb; /* Rx drop - skb allocation failed */
+ uint32_t pkts_d_no_match; /* Rx drop - no matching filters */
+ uint32_t pkts_d_unkn_netif; /* Rx drop - unknown net interface ID */
+ uint32_t pkts_d_unkn_dest; /* Rx drop - unknown destination type */
+ uint32_t pkts_d_callback; /* Rx drop - consumed by call-back */
+ uint32_t pkts_d_no_link; /* Rx drop - software link down */
+ uint32_t pkts_d_no_api_buf; /* Rx drop - no API buffers */
+ } rx[NUM_RX_CHAN];
+} bkn_switch_info_t;
+
+/* PTCH_2 */
+#define BKN_DNX_PTCH_2_SIZE 2
+/* ITMH */
+#define BKN_DNX_ITMH_SIZE 5
+/* Modlue Header */
+#define BKN_DNX_MODULE_HEADER_SIZE 20
+/* FTMH */
+#define BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_MSB 17
+#define BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_NOF_BITS 16
+#define BKN_DNX_FTMH_PP_DSP_MSB 33
+#define BKN_DNX_FTMH_PP_DSP_NOF_BITS 8
+#define BKN_DNX_FTMH_ACTION_TYPE_MSB 43
+#define BKN_DNX_FTMH_ACTION_TYPE_NOF_BITS 2
+#define BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_MSB 73
+#define BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_NOF_BITS 1
+#define BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_MSB 74
+#define BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_NOF_BITS 1
+#define BKN_DNX_FTMH_TM_DST_EXT_PRESENT_MSB 75
+#define BKN_DNX_FTMH_TM_DST_EXT_PRESENT_NOF_BITS 1
+#define BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_MSB 76
+#define BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_NOF_BITS 1
+#define BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_MSB 77
+#define BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_NOF_BITS 1
+#define BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_MSB 78
+#define BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_NOF_BITS 1
+/* Fix Length for FTMH and Extension headers */
+#define BKN_DNX_FTMH_BASE_SIZE 10
+#define BKN_DNX_FTMH_BIER_BFR_EXT_SIZE 2
+#define BKN_DNX_FTMH_TM_DST_EXT_SIZE 3
+#define BKN_DNX_FTMH_FLOW_ID_EXT_SIZE 3
+#define BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE 6
+/* TSH */
+#define BKN_DNX_TSH_SIZE 4
+/* PPH */
+#define BKN_DNX_PPH_BASE_TYPE_9 9
+#define BKN_DNX_PPH_BASE_TYPE_10 10
+#define BKN_DNX_PPH_BASE_TYPE_12 12
+#define BKN_DNX_PPH_9_FORWARD_DOMAIN_MSB 5
+#define BKN_DNX_PPH_9_FORWARD_DOMAIN_NOF_BITS 16
+#define BKN_DNX_PPH_9_LEARN_EXT_PRESENT_MSB 53
+#define BKN_DNX_PPH_9_LEARN_EXT_PRESENT_NOF_BITS 1
+#define BKN_DNX_PPH_9_FHEI_SIZE_MSB 54
+#define BKN_DNX_PPH_9_FHEI_SIZE_NOF_BITS 2
+#define BKN_DNX_PPH_9_LIF_EXT_TYPE_MSB 56
+#define BKN_DNX_PPH_9_LIF_EXT_TYPE_NOF_BITS 3
+#define BKN_DNX_PPH_10_FORWARD_DOMAIN_MSB 9
+#define BKN_DNX_PPH_10_FORWARD_DOMAIN_NOF_BITS 16
+#define BKN_DNX_PPH_10_LEARN_EXT_PRESENT_MSB 61
+#define BKN_DNX_PPH_10_LEARN_EXT_PRESENT_NOF_BITS 1
+#define BKN_DNX_PPH_10_FHEI_SIZE_MSB 62
+#define BKN_DNX_PPH_10_FHEI_SIZE_NOF_BITS 2
+#define BKN_DNX_PPH_10_LIF_EXT_TYPE_MSB 64
+#define BKN_DNX_PPH_10_LIF_EXT_TYPE_NOF_BITS 3
+#define BKN_DNX_PPH_12_FORWARD_DOMAIN_MSB 21
+#define BKN_DNX_PPH_12_FORWARD_DOMAIN_NOF_BITS 18
+#define BKN_DNX_PPH_12_LEARN_EXT_PRESENT_MSB 77
+#define BKN_DNX_PPH_12_LEARN_EXT_PRESENT_NOF_BITS 1
+#define BKN_DNX_PPH_12_FHEI_SIZE_MSB 78
+#define BKN_DNX_PPH_12_FHEI_SIZE_NOF_BITS 2
+#define BKN_DNX_PPH_12_LIF_EXT_TYPE_MSB 80
+#define BKN_DNX_PPH_12_LIF_EXT_TYPE_NOF_BITS 3
+/* PPH.FHEI_TYPE */
+#define BKN_DNX_PPH_FHEI_TYPE_SZ0 1
+#define BKN_DNX_PPH_FHEI_TYPE_SZ1 2
+#define BKN_DNX_PPH_FHEI_TYPE_SZ2 3
+/* FHEI */
+#define BKN_DNX_PPH_FHEI_SZ0_SIZE 3
+#define BKN_DNX_PPH_FHEI_SZ1_SIZE 5
+#define BKN_DNX_PPH_FHEI_SZ2_SIZE 8
+#define BKN_DNX_PPH_FHEI_TRAP_5B_QUALIFIER_MSB 0
+#define BKN_DNX_PPH_FHEI_TRAP_5B_QUALIFIER_NOF_BITS 27
+#define BKN_DNX_PPH_FHEI_TRAP_5B_CODE_MSB 27
+#define BKN_DNX_PPH_FHEI_TRAP_5B_CODE_NOF_BITS 9
+#define BKN_DNX_PPH_FHEI_TRAP_5B_TYPE_MSB 36
+#define BKN_DNX_PPH_FHEI_TRAP_5B_TYPE_NOF_BITS 4
+/* PPH Extension */
+#define BKN_DNX_PPH_LEARN_EXT_SIZE 19
+/* UDH */
+#define BKN_DNX_UDH_DATA_TYPE_0_MSB 0
+#define BKN_DNX_UDH_DATA_TYPE_0_NOF_BITS 2
+#define BKN_DNX_UDH_DATA_TYPE_1_MSB 2
+#define BKN_DNX_UDH_DATA_TYPE_1_NOF_BITS 2
+#define BKN_DNX_UDH_DATA_TYPE_2_MSB 4
+#define BKN_DNX_UDH_DATA_TYPE_2_NOF_BITS 2
+#define BKN_DNX_UDH_DATA_TYPE_3_MSB 6
+#define BKN_DNX_UDH_DATA_TYPE_3_NOF_BITS 2
+#define BKN_DNX_UDH_BASE_SIZE 1
+
+#define BKN_DPP_HDR_MAX_SIZE 40
+/* PTCH_2 */
+#define BKN_DPP_PTCH_2_SIZE 2
+/* ITMH */
+#define BKN_DPP_ITMH_SIZE 4
+/* FTMH */
+#define BKN_DPP_FTMH_LB_EXT_EN 0x1
+#define BKN_DPP_FTMH_STACKING_EXT_EN 0x2
+#define BKN_DPP_FTMH_SIZE_BYTE 9
+#define BKN_DPP_FTMH_LB_EXT_SIZE_BYTE 1
+#define BKN_DPP_FTMH_STACKING_SIZE_BYTE 2
+#define BKN_DPP_FTMH_DEST_EXT_SIZE_BYTE 2
+#define BKN_DPP_FTMH_LB_EXT_SIZE_BYTE 1
+#define BKN_DPP_FTMH_PKT_SIZE_MSB 0
+#define BKN_DPP_FTMH_PKT_SIZE_NOF_BITS 14
+#define BKN_DPP_FTMH_TC_MSB 14
+#define BKN_DPP_FTMH_TC_NOF_BITS 3
+#define BKN_DPP_FTMH_SRC_SYS_PORT_MSB 17
+#define BKN_DPP_FTMH_SRC_SYS_PORT_NOF_BITS 16
+#define BKN_DPP_FTMH_EXT_DSP_EXIST_MSB 68
+#define BKN_DPP_FTMH_EXT_DSP_EXIST_NOF_BITS 1
+#define BKN_DPP_FTMH_EXT_MSB 45
+#define BKN_DPP_FTMH_EXT_NOF_BITS 2
+#define BKN_DPP_FTMH_FIRST_EXT_MSB 72
+#define BKN_DPP_FTMH_ACTION_TYPE_MSB 43
+#define BKN_DPP_FTMH_ACTION_TYPE_NOF_BITS 2
+#define BKN_DPP_FTMH_PPH_TYPE_MSB 45
+#define BKN_DPP_FTMH_PPH_TYPE_NOF_BITS 2
+
+/* PPH */
+#define BKN_DPP_PPH_SIZE_BYTE 7
+#define BKN_DPP_PPH_EEI_EXTENSION_PRESENT_MSB 0
+#define BKN_DPP_PPH_EEI_EXTENSION_PRESENT_NOF_BITS 1
+#define BKN_DPP_PPH_LEARN_EXENSION_PRESENT_MSB 1
+#define BKN_DPP_PPH_LEARN_EXENSION_PRESENT_NOF_BITS 1
+#define BKN_DPP_PPH_FHEI_SIZE_MSB 2
+#define BKN_DPP_PPH_FHEI_SIZE_NOF_BITS 2
+#define BKN_DPP_PPH_FORWARD_CODE_MSB 4
+#define BKN_DPP_PPH_FORWARD_CODE_NOF_BITS 4
+#define BKN_DPP_PPH_VSI_MSB 22
+#define BKN_DPP_PPH_VSI_NOF_BITS 16
+/* FHEI TRAP/SNOOP 3B */
+#define BKN_DPP_PPH_FHEI_3B_SIZE_BYTE 3
+#define BKN_DPP_PPH_FHEI_5B_SIZE_BYTE 5
+#define BKN_DPP_PPH_FHEI_8B_SIZE_BYTE 8
+#define BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_MSB 0
+#define BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_NOF_BITS 16
+#define BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_MSB 16
+#define BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_NOF_BITS 8
+/* PPH extension */
+#define BKN_DPP_PPH_EXPLICIT_EDITING_INFOMATION_EXTENSION_SIZE_BYTE 3
+#define BKN_DPP_PPH_LEARN_EXTENSION_SIZE_BYTE 5
+
+/* ftmh action type. */
+typedef enum bkn_dpp_ftmh_action_type_e {
+ BKN_DPP_FTMH_ACTION_TYPE_FORWARD = 0, /* TM action is forward */
+ BKN_DPP_FTMH_ACTION_TYPE_SNOOP = 1, /* TM action is snoop */
+ BKN_DPP_FTMH_ACTION_TYPE_INBOUND_MIRROR = 2, /* TM action is inbound mirror. */
+ BKN_DPP_FTMH_ACTION_TYPE_OUTBOUND_MIRROR = 3 /* TM action is outbound mirror. */
+}bkn_dpp_ftmh_action_type_t;
+
+/* ftmh dest extension. */
+typedef struct bkn_dpp_ftmh_dest_extension_s {
+ uint8 valid; /* Set if the extension is present */
+ uint32_t dst_sys_port; /* Destination System Port */
+} bkn_dpp_ftmh_dest_extension_t;
+
+/* dnx packet */
+typedef struct bkn_dune_system_header_info_s {
+ uint32_t ntwrk_header_ptr;
+ struct {
+ uint32_t packet_size; /* Packet size in bytes */
+ uint32_t action_type; /* Indicates if the copy is one of the Forward Snoop or Mirror packet copies */
+ uint32_t pph_type;
+ uint32_t prio; /* Traffic class */
+ uint32_t src_sys_port; /* Source System port*/
+ } ftmh;
+ struct {
+ uint32_t vsi;
+ uint32_t trap_qualifier; /* RAW Data */
+ uint32_t trap_id; /* RAW Data */
+ } internal;
+ uint32_t system_header_size;
+ uint32_t ftmh_spa; /* FTMH: Source-System-Port-Aggregate*/
+ uint32_t pph_forward_domain; /* PPH: Forward-Domain*/
+ uint32_t fhei_qualifier; /* FHEI: Qualifier */
+ uint32_t fhei_code; /* FHEI: Code */
+ uint32_t fhei_type; /* FHEI: Type */
+} bkn_dune_system_header_info_t;
+
+#define PREV_IDX(_cur, _max) (((_cur) == 0) ? (_max) - 1 : (_cur) - 1)
+
+#if defined(CMIC_SOFT_BYTE_SWAP)
+
+#define CMIC_SWAP32(_x) ((((_x) & 0xff000000) >> 24) \
+ | (((_x) & 0x00ff0000) >> 8) \
+ | (((_x) & 0x0000ff00) << 8) \
+ | (((_x) & 0x000000ff) << 24))
+
+#define DEV_READ32(_d, _a, _p) \
+ do { \
+ uint32_t _data; \
+ _data = (((volatile uint32_t *)(_d)->base_addr)[(_a)/4]); \
+ *(_p) = CMIC_SWAP32(_data); \
+ } while(0)
+
+#define DEV_WRITE32(_d, _a, _v) \
+ do { \
+ uint32_t _data = CMIC_SWAP32(_v); \
+ ((volatile uint32_t *)(_d)->base_addr)[(_a)/4] = (_data); \
+ } while(0)
+
+#else
+
+#define DEV_READ32(_d, _a, _p) \
+ do { \
+ *(_p) = (((volatile uint32_t *)(_d)->base_addr)[(_a)/4]); \
+ } while(0)
+
+#define DEV_WRITE32(_d, _a, _v) \
+ do { \
+ ((volatile uint32_t *)(_d)->base_addr)[(_a)/4] = (_v); \
+ } while(0)
+
+#endif /* defined(CMIC_SOFT_BYTE_SWAP) */
+
+#define MEMORY_BARRIER smp_mb()
+
+/* Default random MAC address has Broadcom OUI with local admin bit set */
+static u8 bkn_dev_mac[6] = { 0x02, 0x10, 0x18, 0x00, 0x00, 0x00 };
+
+static u8 bkn_rcpu_dmac[6];
+static u8 bkn_rcpu_smac[6];
+
+/* Driver Proc Entry root */
+static struct proc_dir_entry *bkn_proc_root = NULL;
+
+typedef struct bkn_priv_s {
+ struct list_head list;
+ struct net_device_stats stats;
+ struct net_device *dev;
+ bkn_switch_info_t *sinfo;
+ int id;
+ int type;
+ int port;
+ uint8_t itmh[4];
+ int qnum;
+ uint32_t vlan;
+ uint32_t flags;
+ uint32_t cb_user_data;
+ uint8_t system_headers[27];
+ uint32_t system_headers_size;
+} bkn_priv_t;
+
+typedef struct bkn_filter_s {
+ struct list_head list;
+ int dev_no;
+ unsigned long hits;
+ kcom_filter_t kf;
+} bkn_filter_t;
+
+
+/*
+ * Multiple instance support in KNET
+ */
+static int _bkn_multi_inst = 0;
+typedef struct {
+ wait_queue_head_t evt_wq;
+ int evt_wq_put;
+ int evt_wq_get;
+ uint32_t inst_id;
+} bkn_evt_resource_t;
+
+static bkn_evt_resource_t _bkn_evt[LINUX_BDE_MAX_DEVICES];
+
+static int bkn_knet_dev_init(int d);
+static int bkn_knet_dev_reinit(int d);
+
+/* IOCTL debug counters */
+static int ioctl_cmd;
+static int ioctl_evt;
+
+/* Switch devices */
+LIST_HEAD(_sinfo_list);
+
+/* Reallocation chunk size for netif array */
+#define NDEVS_CHUNK 64
+
+/* User call-backs */
+static knet_skb_cb_f knet_rx_cb = NULL;
+static knet_skb_cb_f knet_tx_cb = NULL;
+static knet_filter_cb_f knet_filter_cb = NULL;
+static knet_hw_tstamp_enable_cb_f knet_hw_tstamp_enable_cb = NULL;
+static knet_hw_tstamp_enable_cb_f knet_hw_tstamp_disable_cb = NULL;
+static knet_hw_tstamp_tx_time_get_cb_f knet_hw_tstamp_tx_time_get_cb = NULL;
+static knet_hw_tstamp_tx_meta_get_cb_f knet_hw_tstamp_tx_meta_get_cb = NULL;
+static knet_hw_tstamp_ptp_clock_index_cb_f knet_hw_tstamp_ptp_clock_index_cb = NULL;
+static knet_hw_tstamp_rx_time_upscale_cb_f knet_hw_tstamp_rx_time_upscale_cb = NULL;
+
+/*
+ * Thread management
+ */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10))
+/*
+ * Old style using kernel_thread()
+ */
+typedef struct {
+ const char * name;
+ volatile int pid;
+ volatile int run;
+ struct completion completion;
+ int state;
+} bkn_thread_ctrl_t;
+
+static int
+bkn_thread_start(bkn_thread_ctrl_t *tc, const char *name,
+ int (*threadfn)(void *))
+{
+ if (name == NULL) {
+ return -1;
+ }
+ tc->name = name;
+ tc->pid = kernel_thread(threadfn, tc, 0);
+ if (tc->pid < 0) {
+ tc->pid = 0;
+ return -1;
+ }
+ tc->run = 1;
+ init_completion(&tc->completion);
+ return 0;
+}
+
+static int
+bkn_thread_stop(bkn_thread_ctrl_t *tc)
+{
+ if (tc->pid == 0) {
+ return 0;
+ }
+ tc->run = 0;
+ kill_proc(tc->pid, SIGTERM, 1);
+ wait_for_completion(&tc->completion);
+ return 0;
+}
+
+static int
+bkn_thread_should_stop(bkn_thread_ctrl_t *tc)
+{
+ if (tc->run) {
+ return 0;
+ }
+ tc->pid = 0;
+ return 1;
+}
+
+static void
+bkn_thread_boot(bkn_thread_ctrl_t *tc)
+{
+ siginitsetinv(¤t->blocked, sigmask(SIGTERM) | sigmask(SIGKILL));
+}
+
+static void
+bkn_thread_exit(bkn_thread_ctrl_t *tc)
+{
+ complete_and_exit(&tc->completion, 0);
+}
+
+static void
+bkn_sleep(int clicks)
+{
+ wait_queue_head_t wq;
+
+ init_waitqueue_head(&wq);
+ sleep_on_timeout(&wq, clicks);
+}
+#else
+/*
+ * New style using kthread API
+ */
+#include <linux/kthread.h>
+typedef struct {
+ const char * name;
+ struct task_struct *task;
+ int state;
+} bkn_thread_ctrl_t;
+
+static int
+bkn_thread_start(bkn_thread_ctrl_t *tc, const char *name,
+ int (*threadfn)(void *))
+{
+ if (name == NULL) {
+ return -1;
+ }
+ tc->name = name;
+ tc->task = kthread_run(threadfn, tc, name);
+ if (IS_ERR(tc->task)) {
+ tc->task = NULL;
+ return -1;
+ }
+ return 0;
+}
+
+static int
+bkn_thread_stop(bkn_thread_ctrl_t *tc)
+{
+ if (tc->task == NULL) {
+ return 0;
+ }
+ send_sig(SIGTERM, tc->task, 0);
+ return kthread_stop(tc->task);
+}
+
+static int
+bkn_thread_should_stop(bkn_thread_ctrl_t *tc)
+{
+ return kthread_should_stop();
+}
+
+static void
+bkn_thread_boot(bkn_thread_ctrl_t *tc)
+{
+ allow_signal(SIGTERM);
+ allow_signal(SIGKILL);
+}
+
+static void
+bkn_thread_exit(bkn_thread_ctrl_t *tc)
+{
+}
+
+static void
+bkn_sleep(int clicks)
+{
+ wait_queue_head_t wq;
+
+ init_waitqueue_head(&wq);
+ wait_event_timeout(wq, 0, clicks);
+}
+#endif
+
+static bkn_thread_ctrl_t bkn_cmd_ctrl;
+static bkn_thread_ctrl_t bkn_evt_ctrl;
+
+/*
+ * On XGS devices bit 15 fo the Transferred Bytes field in
+ * the DCBs is used to indicate that kernel processing is
+ * complete. Using this bit reduces the theoretically maximum
+ * supported packet size from 64K to 32K, but this is still
+ * adequate for 16K jumbo packets.
+ */
+#define SOC_DCB_KNET_DONE 0x8000
+#define SOC_DCB_KNET_COUNT_MASK 0x7fff
+#define SOC_DCB_META_OFFSET 2
+
+/* Default channel configuration */
+#define XGS_DMA_TX_CHAN 0
+#define XGS_DMA_RX_CHAN 1
+
+/* CMIC registers */
+#define CMIC_DMA_CTRLr 0x00000100
+#define CMIC_DMA_STATr 0x00000104
+#define CMIC_DMA_DESC0r 0x00000110
+#define CMIC_IRQ_STATr 0x00000144
+#define CMIC_IRQ_MASKr 0x00000148
+#define CMIC_DEV_REV_IDr 0x00000178
+
+/* CMIC interrupts reserved for kernel handler */
+#define CMIC_TXRX_IRQ_MASK 0x7f80
+
+/* CMICm registers */
+#define CMICM_CMC_BASE 0x00031000
+#define CMICM_DMA_CTRLr (CMICM_CMC_BASE + 0x00000140)
+#define CMICM_DMA_STATr (CMICM_CMC_BASE + 0x00000150)
+#define CMICM_DMA_STAT_CLRr (CMICM_CMC_BASE + 0x000001a4)
+#define CMICM_DMA_DESC0r (CMICM_CMC_BASE + 0x00000158)
+#define CMICM_DMA_HALT_ADDRr (CMICM_CMC_BASE + 0x00000120)
+#define CMICM_IRQ_STATr (CMICM_CMC_BASE + 0x00000400)
+#define CMICM_IRQ_PCI_MASKr (CMICM_CMC_BASE + 0x00000414)
+#define CMICM_IRQ_UC0_MASKr (CMICM_CMC_BASE + 0x00000428)
+#define CMICM_DEV_REV_IDr 0x00010224
+
+/* CMICm interrupts reserved for kernel handler */
+#define CMICM_TXRX_IRQ_MASK 0xff00
+
+/* CMICd increased interrupts reserved for kernel handler */
+#define CMICD_CTRLD_IRQ_MASK 0x78000000
+
+/* CMICx registers */
+#define CMICX_CMC_BASE 0x00000000
+#define CMICX_DMA_CTRLr (CMICX_CMC_BASE + 0x00002100)
+#define CMICX_DMA_STATr (CMICX_CMC_BASE + 0x00002114)
+#define CMICX_DMA_DESC_HIr (CMICX_CMC_BASE + 0x00002108)
+#define CMICX_DMA_DESC_LOr (CMICX_CMC_BASE + 0x00002104)
+#define CMICX_DMA_HALT_HIr (CMICX_CMC_BASE + 0x00002110)
+#define CMICX_DMA_HALT_LOr (CMICX_CMC_BASE + 0x0000210c)
+#define CMICX_IRQ_STATr (CMICX_CMC_BASE + 0x0000106c)
+#define CMICX_IRQ_STAT_CLRr (CMICX_CMC_BASE + 0x00001074)
+#define CMICX_IRQ_ENABr 0x18013100
+#define IHOST_GIC_GIC400_GICD_ISENABLERN_5r 0x10781114
+#define IHOST_GIC_GIC400_GICD_ICENABLERN_5r 0x10781194
+
+/* CMICx interrupts reserved for kernel handler */
+#define CMICX_TXRX_IRQ_MASK 0xffffffff
+
+#define DEV_IS_CMICX(_sinfo) ((_sinfo)->cmic_type == 'x')
+#define DEV_IS_CMICM(_sinfo) ((_sinfo)->cmic_type == 'm')
+#define CDMA_CH(_d, _ch) ((_d)->cdma_channels & (1 << (_ch)))
+
+/*
+ * DMA_STAT: control bits
+ *
+ * xxx_SET and xxx_CLR can be WRITTEN to CMIC_DMA_STAT
+ * xxx_TST can be masked against values read from CMIC_DMA_STAT.
+ * Argument required: 0 <= ch <= 3
+ */
+#define DS_DMA_ACTIVE(ch) (0x00040000 << (ch))
+#define DS_DMA_EN_SET(ch) (0x80|(ch))
+#define DS_DMA_EN_CLR(ch) (0x00|(ch))
+#define DS_DMA_EN_TST(ch) (0x00000001 << (ch))
+
+#define DS_CHAIN_DONE_SET(ch) (0x80|(4+(ch)))
+#define DS_CHAIN_DONE_CLR(ch) (0x00|(4+(ch)))
+#define DS_CHAIN_DONE_TST(ch) (0x00000010 << (ch))
+
+#define DS_DESC_DONE_SET(ch) (0x80|(8+(ch)))
+#define DS_DESC_DONE_CLR(ch) (0x00|(8+(ch)))
+#define DS_DESC_DONE_TST(ch) (0x00000100 << (ch))
+
+#define DC_ABORT_DMA(ch) (0x04 << (8 * (ch)))
+
+#define DS_CMC_DESCRD_CMPLT_CLR(ch) (0x00000001 << (ch))
+#define DS_CMC_CTRLD_INT_CLR(ch) (0x00000100 << (ch))
+#define DS_CMC_DMA_ACTIVE(ch) (0x00000100 << (ch))
+
+#define CMICX_DS_CMC_DESC_DONE(ch) (0x00000001 << ((ch) * 4))
+#define CMICX_DS_CMC_CHAIN_DONE(ch) (0x00000002 << ((ch) * 4))
+#define CMICX_DS_CMC_CTRLD_INT(ch) (0x00000008 << ((ch) * 4))
+#define CMICX_DS_CMC_DMA_CHAIN_DONE (0x00000001)
+#define CMICX_DS_CMC_DMA_ACTIVE (0x00000002)
+
+#define DMA_TO_BUS_HI(dma) ((dma) | sinfo->dma_hi)
+#define BUS_TO_DMA_HI(bus) ((bus) & ~sinfo->dma_hi)
+
+/*
+ * DMA_CTRL: control bits
+ */
+#define DC_CMC_DIRECTION (0x00000001)
+#define DC_CMC_ENABLE (0x00000002)
+#define DC_CMC_ABORT (0x00000004)
+#define DC_CMC_CTRLD_INT (0x00000100)
+#define DC_CMC_CONTINUOUS (0x00000200)
+
+#define CMICX_DC_CMC_DIRECTION (0x00000001)
+#define CMICX_DC_CMC_ENABLE (0x00000002)
+#define CMICX_DC_CMC_ABORT (0x00000004)
+#define CMICX_DC_CMC_CTRLD_INT (0x00000080)
+#define CMICX_DC_CMC_CONTINUOUS (0x00000100)
+
+/*
+ * Per-channel operations.
+ * These are the basis for the TX/RX functions
+ */
+
+static inline void
+xgs_dma_chain_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ DBG_IRQ(("Clear chain on device %d chan %d\n",
+ sinfo->dev_no, chan));
+ DEV_WRITE32(sinfo, CMIC_DMA_STATr, DS_DMA_EN_CLR(chan));
+ DEV_WRITE32(sinfo, CMIC_DMA_STATr, DS_CHAIN_DONE_CLR(chan));
+
+ MEMORY_BARRIER;
+}
+
+static inline void
+xgs_dma_desc_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ uint32_t val;
+
+ DBG_IRQ(("Clear desc on device %d chan %d\n",
+ sinfo->dev_no, chan));
+ DEV_WRITE32(sinfo, CMIC_DMA_STATr, DS_DESC_DONE_CLR(chan));
+
+ MEMORY_BARRIER;
+
+ /* Flush write buffer */
+ DEV_READ32(sinfo, CMIC_DMA_STATr, &val);
+
+ MEMORY_BARRIER;
+}
+
+static int
+xgs_dma_chan_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ xgs_dma_chain_clear(sinfo, chan);
+ xgs_dma_desc_clear(sinfo, chan);
+
+ return 0;
+}
+
+static int
+xgs_dma_chan_init(bkn_switch_info_t *sinfo, int chan, int dir)
+{
+ uint32_t cdc;
+
+ DEV_READ32(sinfo, CMIC_DMA_CTRLr, &cdc);
+
+ cdc &= ~(0x9 << (8 * chan));
+ if (dir) {
+ cdc |= 0x1 << (8 * chan);
+ } else {
+ cdc |= 0x8 << (8 * chan);
+ }
+
+ DEV_WRITE32(sinfo, CMIC_DMA_CTRLr, cdc);
+
+ return 0;
+}
+
+static int
+xgs_dma_chan_start(bkn_switch_info_t *sinfo, int chan, uint64_t dcb)
+{
+ /* Write the DCB address to the DESC address for this channel */
+ DEV_WRITE32(sinfo, CMIC_DMA_DESC0r + 4 * chan, dcb);
+
+ MEMORY_BARRIER;
+
+ /* Kick it off */
+ DEV_WRITE32(sinfo, CMIC_DMA_STATr, DS_DMA_EN_SET(chan));
+
+ MEMORY_BARRIER;
+
+ return 0;
+}
+
+static int
+xgs_dma_chan_abort(bkn_switch_info_t *sinfo, int chan, int polls)
+{
+ uint32_t ctrl, dma_stat;
+ int p;
+
+ /* Clear enable */
+ DEV_WRITE32(sinfo, CMIC_DMA_STATr, DS_DMA_EN_CLR(chan));
+
+ MEMORY_BARRIER;
+
+ /* Abort the channel */
+ DEV_READ32(sinfo, CMIC_DMA_CTRLr, &ctrl);
+ DEV_WRITE32(sinfo, CMIC_DMA_CTRLr, ctrl | DC_ABORT_DMA(chan));
+
+ MEMORY_BARRIER;
+
+ /* Poll for abort completion */
+ for (p = 0; p < polls; p++) {
+ DEV_READ32(sinfo, CMIC_DMA_STATr, &dma_stat);
+ if (!(dma_stat & DS_DMA_ACTIVE(chan))) {
+ /* Restore previous control value */
+ DEV_WRITE32(sinfo, CMIC_DMA_CTRLr, ctrl);
+
+ MEMORY_BARRIER;
+
+ /* Clear up channel */
+ xgs_dma_chan_clear(sinfo, chan);
+
+ return polls;
+ }
+ }
+ DBG_WARN(("DMA channel %d abort failed\n", chan));
+
+ return -1;
+}
+
+static inline void
+xgs_irq_mask_set(bkn_switch_info_t *sinfo, uint32_t mask)
+{
+ if (sinfo->napi_poll_mode) {
+ mask = 0;
+ }
+ lkbde_irq_mask_set(sinfo->dev_no | LKBDE_ISR2_DEV, CMIC_IRQ_MASKr,
+ mask, CMIC_TXRX_IRQ_MASK);
+}
+
+static inline void
+xgs_irq_mask_enable(bkn_switch_info_t *sinfo, int chan, int update_hw)
+{
+ uint32_t mask;
+
+ if (chan == XGS_DMA_TX_CHAN) {
+ mask = 0x100;
+ } else {
+ mask = 0x180 << (2 * chan);
+ }
+
+ sinfo->irq_mask |= mask;
+
+ if (update_hw) {
+ xgs_irq_mask_set(sinfo, sinfo->irq_mask);
+ }
+}
+
+static inline void
+xgs_irq_mask_disable(bkn_switch_info_t *sinfo, int chan, int update_hw)
+{
+ uint32_t mask;
+
+ if (chan == XGS_DMA_TX_CHAN) {
+ mask = 0x100;
+ } else {
+ mask = 0x180 << (2 * chan);
+ }
+
+ sinfo->irq_mask &= ~mask;
+
+ if (update_hw) {
+ xgs_irq_mask_set(sinfo, sinfo->irq_mask);
+ }
+}
+
+static inline void
+xgsm_dma_chain_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ uint32_t cdc;
+
+ /* Disabing DMA clears chain done */
+ DEV_READ32(sinfo, CMICM_DMA_CTRLr + 4 * chan, &cdc);
+ cdc &= ~(DC_CMC_ENABLE | DC_CMC_ABORT);
+ DEV_WRITE32(sinfo, CMICM_DMA_CTRLr + 4 * chan, cdc);
+
+ MEMORY_BARRIER;
+}
+
+static inline void
+xgsm_dma_desc_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ uint32_t val;
+
+ val = DS_CMC_DESCRD_CMPLT_CLR(chan);
+ if (CDMA_CH(sinfo, chan)) {
+ val |= DS_CMC_CTRLD_INT_CLR(chan);
+ }
+ DEV_WRITE32(sinfo, CMICM_DMA_STAT_CLRr, val);
+
+ MEMORY_BARRIER;
+
+ /* Flush write buffer */
+ DEV_READ32(sinfo, CMICM_DMA_STAT_CLRr, &val);
+
+ MEMORY_BARRIER;
+}
+
+static int
+xgsm_dma_chan_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ xgsm_dma_chain_clear(sinfo, chan);
+ xgsm_dma_desc_clear(sinfo, chan);
+
+ return 0;
+}
+
+static inline void
+xgsm_cdma_halt_set(bkn_switch_info_t *sinfo, int chan)
+{
+ DEV_WRITE32(sinfo, CMICM_DMA_HALT_ADDRr + 4 * chan,
+ sinfo->halt_addr[chan]);
+
+ MEMORY_BARRIER;
+}
+
+static int
+xgsm_dma_chan_init(bkn_switch_info_t *sinfo, int chan, int dir)
+{
+ uint32_t cdc;
+
+ DEV_READ32(sinfo, CMICM_DMA_CTRLr + 4 * chan, &cdc);
+ cdc &= ~DC_CMC_DIRECTION;
+ if (dir) {
+ cdc |= DC_CMC_DIRECTION;
+ }
+ if (CDMA_CH(sinfo, chan)) {
+ cdc |= DC_CMC_CONTINUOUS | DC_CMC_CTRLD_INT;
+ xgsm_cdma_halt_set(sinfo, chan);
+ }
+ DEV_WRITE32(sinfo, CMICM_DMA_CTRLr + 4 * chan, cdc);
+
+ return 0;
+}
+
+static int
+xgsm_dma_chan_start(bkn_switch_info_t *sinfo, int chan, uint64_t dcb)
+{
+ uint32_t cdc;
+
+ /* Write the DCB address to the DESC address for this channel */
+ DEV_WRITE32(sinfo, CMICM_DMA_DESC0r + 4 * chan, dcb);
+
+ MEMORY_BARRIER;
+
+ /* Kick it off */
+ DEV_READ32(sinfo, CMICM_DMA_CTRLr + 4 * chan, &cdc);
+ cdc |= DC_CMC_ENABLE;
+ DEV_WRITE32(sinfo, CMICM_DMA_CTRLr + 4 * chan, cdc);
+
+ MEMORY_BARRIER;
+
+ return 0;
+}
+
+static int
+xgsm_dma_chan_abort(bkn_switch_info_t *sinfo, int chan, int polls)
+{
+ uint32_t ctrl, dma_stat;
+ int p;
+
+ /* Skip abort sequence if channel is not active */
+ DEV_READ32(sinfo, CMICM_DMA_STATr, &dma_stat);
+ if (!(dma_stat & DS_CMC_DMA_ACTIVE(chan))) {
+ return 0;
+ }
+
+ /* Abort the channel */
+ DEV_READ32(sinfo, CMICM_DMA_CTRLr + 4 * chan, &ctrl);
+ ctrl |= (DC_CMC_ENABLE | DC_CMC_ABORT);
+ DEV_WRITE32(sinfo, CMICM_DMA_CTRLr + 4 * chan, ctrl);
+
+ MEMORY_BARRIER;
+
+ /* Poll for abort completion */
+ for (p = 0; p < polls; p++) {
+ DEV_READ32(sinfo, CMICM_DMA_STATr, &dma_stat);
+ if (!(dma_stat & DS_CMC_DMA_ACTIVE(chan))) {
+ /* Clear up channel */
+ xgsm_dma_chan_clear(sinfo, chan);
+ return polls;
+ }
+ }
+ DBG_WARN(("DMA channel %d abort failed\n", chan));
+
+ return -1;
+}
+
+static inline void
+xgsm_irq_mask_set(bkn_switch_info_t *sinfo, uint32_t mask)
+{
+ uint32_t irq_mask_reg = CMICM_IRQ_PCI_MASKr;
+ uint32_t ctrld_mask = 0;
+
+ if (sinfo->napi_poll_mode) {
+ mask = 0;
+ }
+ if (sinfo->cpu_no == 1) {
+ irq_mask_reg = CMICM_IRQ_UC0_MASKr;
+ }
+
+ /* Get the Controlled Interrupts mask for Continuous DMA mode */
+ ctrld_mask |= (sinfo->cdma_channels << 27) & CMICD_CTRLD_IRQ_MASK;
+
+ lkbde_irq_mask_set(sinfo->dev_no | LKBDE_ISR2_DEV, irq_mask_reg,
+ mask, CMICM_TXRX_IRQ_MASK | ctrld_mask);
+}
+
+static inline void
+xgsm_irq_mask_enable(bkn_switch_info_t *sinfo, int chan, int update_hw)
+{
+ uint32_t mask;
+
+ if (CDMA_CH(sinfo, chan)) {
+ mask = 0x08000000 << chan;
+ } else {
+ if (chan == XGS_DMA_TX_CHAN) {
+ mask = 0x8000;
+ } else {
+ mask = 0xc000 >> (2 * chan);
+ }
+ }
+
+ sinfo->irq_mask |= mask;
+
+ if (update_hw) {
+ xgsm_irq_mask_set(sinfo, sinfo->irq_mask);
+ }
+}
+
+static inline void
+xgsm_irq_mask_disable(bkn_switch_info_t *sinfo, int chan, int update_hw)
+{
+ uint32_t mask;
+
+ if (CDMA_CH(sinfo, chan)) {
+ mask = 0x08000000 << chan;
+ } else {
+ if (chan == XGS_DMA_TX_CHAN) {
+ mask = 0x8000;
+ } else {
+ mask = 0xc000 >> (2 * chan);
+ }
+ }
+
+ sinfo->irq_mask &= ~mask;
+
+ if (update_hw) {
+ xgsm_irq_mask_set(sinfo, sinfo->irq_mask);
+ }
+}
+
+static inline void
+xgsx_dma_chain_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ uint32_t ctrl, stat;
+
+ /* Disabing DMA clears chain done */
+ DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl);
+ ctrl &= ~(CMICX_DC_CMC_ENABLE | CMICX_DC_CMC_ABORT);
+ DEV_WRITE32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, ctrl);
+
+ stat = CMICX_DS_CMC_CHAIN_DONE(chan);
+ DEV_WRITE32(sinfo, CMICX_IRQ_STAT_CLRr, stat);
+
+ MEMORY_BARRIER;
+
+ /* Flush write buffer */
+ DEV_READ32(sinfo, CMICX_IRQ_STAT_CLRr, &stat);
+
+ MEMORY_BARRIER;
+}
+
+static inline void
+xgsx_dma_desc_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ uint32_t stat;
+
+ if (CDMA_CH(sinfo, chan)) {
+ stat = CMICX_DS_CMC_CTRLD_INT(chan);
+ } else {
+ stat = CMICX_DS_CMC_DESC_DONE(chan);
+ }
+ DEV_WRITE32(sinfo, CMICX_IRQ_STAT_CLRr, stat);
+
+ MEMORY_BARRIER;
+
+ /* Flush write buffer */
+ DEV_READ32(sinfo, CMICX_IRQ_STAT_CLRr, &stat);
+
+ MEMORY_BARRIER;
+}
+
+static int
+xgsx_dma_chan_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ xgsx_dma_chain_clear(sinfo, chan);
+ xgsx_dma_desc_clear(sinfo, chan);
+
+ return 0;
+}
+
+static inline void
+xgsx_cdma_halt_set(bkn_switch_info_t *sinfo, int chan)
+{
+ DEV_WRITE32(sinfo, CMICX_DMA_HALT_LOr + 0x80 * chan,
+ sinfo->halt_addr[chan]);
+ DEV_WRITE32(sinfo, CMICX_DMA_HALT_HIr + 0x80 * chan,
+ DMA_TO_BUS_HI(sinfo->halt_addr[chan] >> 32));
+
+ MEMORY_BARRIER;
+}
+
+static int
+xgsx_dma_chan_init(bkn_switch_info_t *sinfo, int chan, int dir)
+{
+ uint32_t ctrl;
+
+ DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl);
+ ctrl &= ~CMICX_DC_CMC_DIRECTION;
+ if (dir) {
+ ctrl |= CMICX_DC_CMC_DIRECTION;
+ }
+ if (CDMA_CH(sinfo, chan)) {
+ ctrl |= CMICX_DC_CMC_CONTINUOUS | CMICX_DC_CMC_CTRLD_INT;
+ xgsx_cdma_halt_set(sinfo, chan);
+ }
+ DEV_WRITE32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, ctrl);
+
+ MEMORY_BARRIER;
+
+ return 0;
+}
+
+static int
+xgsx_dma_chan_start(bkn_switch_info_t *sinfo, int chan, uint64_t dcb)
+{
+ uint32_t ctrl;
+
+ /* Write the DCB address to the DESC address for this channel */
+ DEV_WRITE32(sinfo, CMICX_DMA_DESC_LOr + 0x80 * chan, dcb);
+ DEV_WRITE32(sinfo, CMICX_DMA_DESC_HIr + 0x80 * chan, DMA_TO_BUS_HI(dcb >> 32));
+
+ MEMORY_BARRIER;
+
+ /* Kick it off */
+ DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl);
+ ctrl |= CMICX_DC_CMC_ENABLE;
+ DEV_WRITE32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, ctrl);
+
+ MEMORY_BARRIER;
+
+ return 0;
+}
+
+static int
+xgsx_dma_chan_abort(bkn_switch_info_t *sinfo, int chan, int polls)
+{
+ uint32_t ctrl, stat;
+ int p;
+
+ /* Skip abort sequence if channel is not active */
+ DEV_READ32(sinfo, CMICX_DMA_STATr + 0x80 * chan, &stat);
+ if (!(stat & CMICX_DS_CMC_DMA_ACTIVE)) {
+ return 0;
+ }
+
+ /* Abort the channel */
+ DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl);
+ ctrl |= CMICX_DC_CMC_ENABLE | CMICX_DC_CMC_ABORT;
+ DEV_WRITE32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, ctrl);
+
+ MEMORY_BARRIER;
+
+ /* Poll for abort completion */
+ for (p = 0; p < polls; p++) {
+ DEV_READ32(sinfo, CMICX_DMA_STATr + 0x80 * chan, &stat);
+ if (!(stat & CMICX_DS_CMC_DMA_ACTIVE)) {
+ /* Clear up channel */
+ xgsx_dma_chan_clear(sinfo, chan);
+ return polls;
+ }
+ }
+
+ DBG_WARN(("DMA channel %d abort failed\n", chan));
+
+ return -1;
+}
+
+static inline void
+xgsx_irq_mask_set(bkn_switch_info_t *sinfo, uint32_t mask)
+{
+ uint32_t irq_mask_reg = CMICX_IRQ_ENABr;
+ uint32_t irq_mask, irq_fmask, disable_mask;
+
+ if (sinfo->napi_poll_mode) {
+ mask = 0;
+ }
+
+ if (sinfo->cpu_no == 1) {
+ lkbde_irq_mask_get(sinfo->dev_no, &irq_mask, &irq_fmask);
+ disable_mask = ~mask & (irq_mask & irq_fmask);
+ if (disable_mask) {
+ lkbde_irq_mask_set(sinfo->dev_no | LKBDE_ISR2_DEV | LKBDE_IPROC_REG,
+ IHOST_GIC_GIC400_GICD_ICENABLERN_5r, disable_mask, CMICX_TXRX_IRQ_MASK);
+ }
+ irq_mask_reg = IHOST_GIC_GIC400_GICD_ISENABLERN_5r;
+ }
+
+ lkbde_irq_mask_set(sinfo->dev_no | LKBDE_ISR2_DEV | LKBDE_IPROC_REG,
+ irq_mask_reg, mask, CMICX_TXRX_IRQ_MASK);
+}
+
+static inline void
+xgsx_irq_mask_enable(bkn_switch_info_t *sinfo, int chan, int update_hw)
+{
+ uint32_t mask;
+
+ if (CDMA_CH(sinfo, chan)) {
+ mask = CMICX_DS_CMC_CTRLD_INT(chan);
+ } else {
+ if (chan == XGS_DMA_TX_CHAN) {
+ mask = CMICX_DS_CMC_CHAIN_DONE(chan);
+ } else {
+ mask = CMICX_DS_CMC_DESC_DONE(chan) |
+ CMICX_DS_CMC_CHAIN_DONE(chan);
+ }
+ }
+
+ sinfo->irq_mask |= mask;
+
+ if (update_hw) {
+ xgsx_irq_mask_set(sinfo, sinfo->irq_mask);
+ }
+}
+
+static inline void
+xgsx_irq_mask_disable(bkn_switch_info_t *sinfo, int chan, int update_hw)
+{
+ uint32_t mask;
+
+ if (CDMA_CH(sinfo, chan)) {
+ mask = CMICX_DS_CMC_CTRLD_INT(chan);
+ } else {
+ if (chan == XGS_DMA_TX_CHAN) {
+ mask = CMICX_DS_CMC_CHAIN_DONE(chan);
+ } else {
+ mask = CMICX_DS_CMC_DESC_DONE(chan) |
+ CMICX_DS_CMC_CHAIN_DONE(chan);
+ }
+ }
+
+ sinfo->irq_mask &= ~mask;
+
+ if (update_hw) {
+ xgsx_irq_mask_set(sinfo, sinfo->irq_mask);
+ }
+}
+
+static inline void
+dev_dma_chain_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ xgsx_dma_chain_clear(sinfo, chan);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ xgsm_dma_chain_clear(sinfo, chan);
+ } else {
+ xgs_dma_chain_clear(sinfo, chan);
+ }
+}
+
+static inline void
+dev_dma_desc_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ xgsx_dma_desc_clear(sinfo, chan);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ xgsm_dma_desc_clear(sinfo, chan);
+ } else {
+ xgs_dma_desc_clear(sinfo, chan);
+ }
+}
+
+static int
+dev_dma_chan_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ return xgsx_dma_chan_clear(sinfo, chan);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ return xgsm_dma_chan_clear(sinfo, chan);
+ } else {
+ return xgs_dma_chan_clear(sinfo, chan);
+ }
+}
+
+static void
+dev_cdma_halt_set(bkn_switch_info_t *sinfo, int chan)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ xgsx_cdma_halt_set(sinfo, chan);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ xgsm_cdma_halt_set(sinfo, chan);
+ }
+}
+
+static int
+dev_dma_chan_init(bkn_switch_info_t *sinfo, int chan, int dir)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ return xgsx_dma_chan_init(sinfo, chan, dir);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ return xgsm_dma_chan_init(sinfo, chan, dir);
+ } else {
+ return xgs_dma_chan_init(sinfo, chan, dir);
+ }
+}
+
+static int
+dev_dma_chan_start(bkn_switch_info_t *sinfo, int chan, uint64_t dcb)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ return xgsx_dma_chan_start(sinfo, chan, dcb);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ return xgsm_dma_chan_start(sinfo, chan, dcb);
+ } else {
+ return xgs_dma_chan_start(sinfo, chan, dcb);
+ }
+}
+
+static int
+dev_dma_chan_abort(bkn_switch_info_t *sinfo, int chan, int polls)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ return xgsx_dma_chan_abort(sinfo, chan, polls);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ return xgsm_dma_chan_abort(sinfo, chan, polls);
+ } else {
+ return xgs_dma_chan_abort(sinfo, chan, polls);
+ }
+}
+
+static inline void
+dev_irq_mask_set(bkn_switch_info_t *sinfo, uint32_t mask)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ xgsx_irq_mask_set(sinfo, mask);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ xgsm_irq_mask_set(sinfo, mask);
+ } else {
+ xgs_irq_mask_set(sinfo, mask);
+ }
+}
+
+static inline void
+dev_irq_mask_enable(bkn_switch_info_t *sinfo, int chan, int update_hw)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ xgsx_irq_mask_enable(sinfo, chan, update_hw);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ xgsm_irq_mask_enable(sinfo, chan, update_hw);
+ } else {
+ xgs_irq_mask_enable(sinfo, chan, update_hw);
+ }
+}
+
+static void
+dev_irq_mask_disable(bkn_switch_info_t *sinfo, int chan, int update_hw)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ xgsx_irq_mask_disable(sinfo, chan, update_hw);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ xgsm_irq_mask_disable(sinfo, chan, update_hw);
+ } else {
+ xgs_irq_mask_disable(sinfo, chan, update_hw);
+ }
+}
+
+static int
+bkn_alloc_dcbs(bkn_switch_info_t *sinfo)
+{
+ int dcb_size;
+ int tx_ring_size, rx_ring_size;
+ dma_addr_t dcb_dma = 0;
+
+ dcb_size = sinfo->dcb_wsize * sizeof(uint32_t);
+ tx_ring_size = dcb_size * (MAX_TX_DCBS + 1);
+ rx_ring_size = dcb_size * (MAX_RX_DCBS + 1);
+ sinfo->dcb_mem_size = tx_ring_size + rx_ring_size * sinfo->rx_chans;
+
+ sinfo->dcb_mem = DMA_ALLOC_COHERENT(sinfo->dma_dev,
+ sinfo->dcb_mem_size,
+ &dcb_dma);
+ if (sinfo->dcb_mem == NULL) {
+ gprintk("DCB memory allocation (%d bytes) failed.\n",
+ sinfo->dcb_mem_size);
+ return -ENOMEM;
+ }
+ sinfo->dcb_dma = (uint64_t)dcb_dma;
+
+ return 0;
+}
+
+static void
+bkn_free_dcbs(bkn_switch_info_t *sinfo)
+{
+ if (sinfo->dcb_mem != NULL) {
+ DMA_FREE_COHERENT(sinfo->dma_dev, sinfo->dcb_mem_size,
+ sinfo->dcb_mem, (dma_addr_t)sinfo->dcb_dma);
+ sinfo->dcb_mem = NULL;
+ }
+}
+
+static void
+bkn_clean_tx_dcbs(bkn_switch_info_t *sinfo)
+{
+ bkn_desc_info_t *desc;
+
+ DBG_DCB_TX(("Cleaning Tx DCBs (%d %d).\n",
+ sinfo->tx.cur, sinfo->tx.dirty));
+ while (sinfo->tx.free < MAX_TX_DCBS) {
+ desc = &sinfo->tx.desc[sinfo->tx.dirty];
+ if (desc->skb != NULL) {
+ DBG_SKB(("Cleaning Tx SKB from DCB %d.\n",
+ sinfo->tx.dirty));
+ DMA_UNMAP_SINGLE(sinfo->dma_dev,
+ desc->skb_dma, desc->dma_size,
+ DMA_TODEV);
+ desc->skb_dma = 0;
+ dev_kfree_skb_any(desc->skb);
+ desc->skb = NULL;
+ }
+ if (++sinfo->tx.dirty >= MAX_TX_DCBS) {
+ sinfo->tx.dirty = 0;
+ }
+ sinfo->tx.free++;
+ }
+ sinfo->tx.api_active = 0;
+ DBG_DCB_TX(("Cleaned Tx DCBs (%d %d).\n",
+ sinfo->tx.cur, sinfo->tx.dirty));
+}
+
+static void
+bkn_clean_rx_dcbs(bkn_switch_info_t *sinfo, int chan)
+{
+ bkn_desc_info_t *desc;
+
+ DBG_DCB_RX(("Cleaning Rx%d DCBs (%d %d).\n",
+ chan, sinfo->rx[chan].cur, sinfo->rx[chan].dirty));
+ while (sinfo->rx[chan].free) {
+ desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty];
+ if (desc->skb != NULL) {
+ DBG_SKB(("Cleaning Rx%d SKB from DCB %d.\n",
+ chan, sinfo->rx[chan].dirty));
+ DMA_UNMAP_SINGLE(sinfo->dma_dev,
+ desc->skb_dma, desc->dma_size,
+ DMA_FROMDEV);
+ desc->skb_dma = 0;
+ dev_kfree_skb_any(desc->skb);
+ desc->skb = NULL;
+ }
+ if (++sinfo->rx[chan].dirty >= MAX_RX_DCBS) {
+ sinfo->rx[chan].dirty = 0;
+ }
+ sinfo->rx[chan].free--;
+ }
+ sinfo->rx[chan].running = 0;
+ sinfo->rx[chan].api_active = 0;
+ DBG_DCB_RX(("Cleaned Rx%d DCBs (%d %d).\n",
+ chan, sinfo->rx[chan].cur, sinfo->rx[chan].dirty));
+}
+
+static void
+bkn_clean_dcbs(bkn_switch_info_t *sinfo)
+{
+ int chan;
+
+ bkn_clean_tx_dcbs(sinfo);
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ bkn_clean_rx_dcbs(sinfo, chan);
+ }
+}
+
+static void
+bkn_init_dcbs(bkn_switch_info_t *sinfo)
+{
+ int dcb_size;
+ uint32_t *dcb_mem;
+ uint64_t dcb_dma;
+ bkn_desc_info_t *desc;
+ int idx;
+ int chan;
+
+ memset(sinfo->dcb_mem, 0, sinfo->dcb_mem_size);
+
+ dcb_size = sinfo->dcb_wsize * sizeof(uint32_t);
+ dcb_mem = sinfo->dcb_mem;
+ dcb_dma = sinfo->dcb_dma;
+
+ for (idx = 0; idx < (MAX_TX_DCBS + 1); idx++) {
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ if (sinfo->cmic_type == 'x') {
+ dcb_mem[2] |= 1 << 24 | 1 << 16;
+ } else {
+ dcb_mem[1] |= 1 << 24 | 1 << 16;
+ }
+ if (idx == MAX_TX_DCBS) {
+ if (sinfo->cmic_type == 'x') {
+ dcb_mem[0] = sinfo->tx.desc[0].dcb_dma;
+ dcb_mem[1] = DMA_TO_BUS_HI(sinfo->tx.desc[0].dcb_dma >> 32);
+ dcb_mem[2] |= 1 << 18;
+ } else {
+ dcb_mem[0] = sinfo->tx.desc[0].dcb_dma;
+ dcb_mem[1] |= 1 << 18;
+ }
+ }
+ }
+ desc = &sinfo->tx.desc[idx];
+ desc->dcb_mem = dcb_mem;
+ desc->dcb_dma = dcb_dma;
+ dcb_mem += sinfo->dcb_wsize;
+ dcb_dma += dcb_size;
+ }
+ sinfo->halt_addr[XGS_DMA_TX_CHAN] = sinfo->tx.desc[0].dcb_dma;
+ sinfo->tx.free = MAX_TX_DCBS;
+ sinfo->tx.cur = 0;
+ sinfo->tx.dirty = 0;
+
+ DBG_DCB_TX(("Tx DCBs @ 0x%08x.\n",
+ (uint32_t)sinfo->tx.desc[0].dcb_dma));
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ for (idx = 0; idx < (MAX_RX_DCBS + 1); idx++) {
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ if (sinfo->cmic_type == 'x') {
+ dcb_mem[2] |= 1 << 24 | 1 << 16;
+ } else {
+ dcb_mem[1] |= 1 << 24 | 1 << 16;
+ }
+ if (idx == MAX_RX_DCBS) {
+ if (sinfo->cmic_type == 'x') {
+ dcb_mem[0] = sinfo->rx[chan].desc[0].dcb_dma;
+ dcb_mem[1] = DMA_TO_BUS_HI(sinfo->rx[chan].desc[0].dcb_dma >> 32);
+ dcb_mem[2] |= 1 << 18;
+ } else {
+ dcb_mem[0] = sinfo->rx[chan].desc[0].dcb_dma;
+ dcb_mem[1] |= 1 << 18;
+ }
+ }
+ }
+ desc = &sinfo->rx[chan].desc[idx];
+ desc->dcb_mem = dcb_mem;
+ desc->dcb_dma = dcb_dma;
+ dcb_mem += sinfo->dcb_wsize;
+ dcb_dma += dcb_size;
+ }
+ sinfo->halt_addr[XGS_DMA_RX_CHAN + chan] = sinfo->rx[chan].desc[MAX_RX_DCBS].dcb_dma;
+ sinfo->rx[chan].free = 0;
+ sinfo->rx[chan].cur = 0;
+ sinfo->rx[chan].dirty = 0;
+
+ DBG_DCB_RX(("Rx%d DCBs @ 0x%08x.\n",
+ chan, (uint32_t)sinfo->rx[chan].desc[0].dcb_dma));
+ }
+}
+
+static void
+bkn_dump_dcb(char *prefix, uint32_t *dcb, int wsize, int txrx)
+{
+ if (XGS_DMA_TX_CHAN == txrx) {
+ if (wsize > 4) {
+ DBG_DCB_TX(("%s: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x ... 0x%08x\n",
+ prefix, dcb[0], dcb[1], dcb[2], dcb[3], dcb[4], dcb[5],
+ dcb[wsize - 1]));
+ } else {
+ DBG_DCB_TX(("%s: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ prefix, dcb[0], dcb[1], dcb[2], dcb[3]));
+ }
+ } else {
+ if (wsize > 4) {
+ DBG_DCB_RX(("%s: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x ... 0x%08x\n",
+ prefix, dcb[0], dcb[1], dcb[2], dcb[3], dcb[4], dcb[5],
+ dcb[wsize - 1]));
+ } else {
+ DBG_DCB_RX(("%s: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ prefix, dcb[0], dcb[1], dcb[2], dcb[3]));
+ }
+ }
+}
+
+static void
+bkn_dump_pkt(uint8_t *data, int size, int txrx)
+{
+ int idx;
+ char str[128];
+
+ if (!(debug & DBG_LVL_PDMP) &&
+ !(txrx == XGS_DMA_TX_CHAN && debug & DBG_LVL_PDMP_TX) &&
+ !(txrx == XGS_DMA_RX_CHAN && debug & DBG_LVL_PDMP_RX)) {
+ return;
+ }
+
+ for (idx = 0; idx < size; idx++) {
+ if ((idx & 0xf) == 0) {
+ sprintf(str, "%04x: ", idx);
+ }
+ if ((idx & 0xf) == 8) {
+ sprintf(&str[strlen(str)], "- ");
+ }
+ sprintf(&str[strlen(str)], "%02x ", data[idx]);
+ if ((idx & 0xf) == 0xf) {
+ sprintf(&str[strlen(str)], "\n");
+ gprintk(str);
+ }
+ }
+ if ((idx & 0xf) != 0) {
+ sprintf(&str[strlen(str)], "\n");
+ gprintk(str);
+ }
+}
+
+static bkn_switch_info_t *
+bkn_sinfo_from_unit(int unit)
+{
+ struct list_head *list;
+ bkn_switch_info_t *sinfo;
+
+ list_for_each(list, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)list;
+ if (sinfo->dev_no == unit || unit == -1) {
+ return sinfo;
+ }
+ }
+ return NULL;
+}
+
+static void
+bkn_cdma_goto(bkn_switch_info_t *sinfo, int chan, uint64_t dcb)
+{
+ if (sinfo->basedev_suspended) {
+ return;
+ }
+
+ /* Set the new halt location */
+ sinfo->halt_addr[chan] = dcb;
+ dev_cdma_halt_set(sinfo, chan);
+}
+
+static void
+bkn_api_rx_restart(bkn_switch_info_t *sinfo, int chan)
+{
+ bkn_dcb_chain_t *dcb_chain;
+ int start_dma;
+
+ if (sinfo->basedev_suspended) {
+ return;
+ }
+
+ /* If resume from basedev suspended, there could be a suspended chain */
+ if (sinfo->rx[chan].api_dcb_chain) {
+ return;
+ }
+
+ /* Assume that driver lock is held */
+ if (!list_empty(&sinfo->rx[chan].api_dcb_list)) {
+ dcb_chain = list_entry(sinfo->rx[chan].api_dcb_list.next,
+ bkn_dcb_chain_t, list);
+ start_dma = 0;
+ if (sinfo->rx[chan].use_rx_skb == 0) {
+ sinfo->rx[chan].chain_complete = 0;
+ start_dma = 1;
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) &&
+ sinfo->rx[chan].api_active) {
+ /* HW is running already, so we just move to the next chain */
+ start_dma = 0;
+ }
+ }
+ sinfo->rx[chan].api_dcb_chain = dcb_chain;
+ sinfo->rx[chan].api_active = 1;
+ if (start_dma) {
+ DBG_DCB_RX(("Start API Rx DMA, first DCB @ 0x%08x (%d DCBs).\n",
+ (uint32_t)dcb_chain->dcb_dma, dcb_chain->dcb_cnt));
+ dev_dma_chan_clear(sinfo, XGS_DMA_RX_CHAN + chan);
+ dev_irq_mask_enable(sinfo, XGS_DMA_RX_CHAN + chan, 1);
+ dev_dma_chan_start(sinfo, XGS_DMA_RX_CHAN + chan, dcb_chain->dcb_dma);
+ }
+
+ list_del(&dcb_chain->list);
+ }
+}
+
+static void
+bkn_api_rx_chain_done(bkn_switch_info_t *sinfo, int chan)
+{
+ DBG_DCB_RX(("API Rx DMA chain done\n"));
+
+ if (!CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ sinfo->rx[chan].api_active = 0;
+ }
+ if (sinfo->rx[chan].api_dcb_chain) {
+ kfree(sinfo->rx[chan].api_dcb_chain);
+ sinfo->rx[chan].api_dcb_chain = NULL;
+ }
+ bkn_api_rx_restart(sinfo, chan);
+}
+
+static int
+bkn_api_rx_copy_from_skb(bkn_switch_info_t *sinfo,
+ int chan, bkn_desc_info_t *desc)
+{
+ bkn_dcb_chain_t *dcb_chain;
+ uint32_t *dcb;
+ uint32_t dcb_stat;
+ uint8_t *pkt;
+ uint64_t pkt_dma;
+ int pktlen;
+ int i;
+ bkn_evt_resource_t *evt;
+
+ dcb_stat = desc->dcb_mem[sinfo->dcb_wsize-1];
+ pktlen = dcb_stat & SOC_DCB_KNET_COUNT_MASK;
+
+ dcb_chain = sinfo->rx[chan].api_dcb_chain;
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) && dcb_chain == NULL) {
+ /* Last chain done, try to get a new one */
+ bkn_api_rx_chain_done(sinfo, chan);
+ dcb_chain = sinfo->rx[chan].api_dcb_chain;
+ }
+ if (dcb_chain == NULL) {
+ DBG_WARN(("No Rx API buffers\n"));
+ sinfo->rx[chan].pkts_d_no_api_buf++;
+ return -1;
+ }
+ dcb = &dcb_chain->dcb_mem[dcb_chain->dcb_cur * sinfo->dcb_wsize];
+ if ((sinfo->cmic_type == 'x' && (dcb[2] & 0xffff) < pktlen) ||
+ (sinfo->cmic_type != 'x' && (dcb[1] & 0xffff) < pktlen)) {
+ DBG_WARN(("Rx API buffer too small\n"));
+ return -1;
+ }
+ if (sinfo->cmic_type == 'x') {
+ pkt_dma = BUS_TO_DMA_HI(dcb[1]);
+ pkt_dma = pkt_dma << 32 | dcb[0];
+ } else {
+ pkt_dma = dcb[0];
+ }
+ pkt = (uint8_t *)kernel_bde->p2l(sinfo->dev_no, (sal_paddr_t)pkt_dma);
+ if (pkt == NULL) {
+ DBG_WARN(("Invalid Rx API buffer\n"));
+ return -1;
+ }
+
+ /* Copy packet data */
+ memcpy(pkt, desc->skb->data, pktlen);
+
+ /* Copy packet metadata and mark as done */
+ if (sinfo->cmic_type != 'x') {
+ for (i = SOC_DCB_META_OFFSET; i < sinfo->dcb_wsize; i++) {
+ dcb[i] = desc->dcb_mem[i];
+ }
+ }
+ dcb[sinfo->dcb_wsize-1] = dcb_stat | SOC_DCB_KNET_DONE;
+ MEMORY_BARRIER;
+
+ dcb_chain->dcb_cur++;
+
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ dcb = &dcb_chain->dcb_mem[dcb_chain->dcb_cur * sinfo->dcb_wsize];
+ if ((sinfo->cmic_type == 'x' && dcb[2] & (1 << 18)) ||
+ (sinfo->cmic_type != 'x' && dcb[1] & (1 << 18))) {
+ /* Get the next chain if reload done */
+ dcb[sinfo->dcb_wsize-1] |= 1 << 31 | SOC_DCB_KNET_DONE;
+ MEMORY_BARRIER;
+ bkn_api_rx_chain_done(sinfo, chan);
+ dcb_chain = sinfo->rx[chan].api_dcb_chain;
+ if (dcb_chain == NULL) {
+ sinfo->rx[chan].api_dcb_chain_end = NULL;
+ }
+ }
+ } else {
+ if ((sinfo->cmic_type == 'x' && (dcb[2] & (1 << 16)) == 0) ||
+ (sinfo->cmic_type != 'x' && (dcb[1] & (1 << 16)) == 0)) {
+ bkn_api_rx_chain_done(sinfo, chan);
+ }
+ }
+
+ sinfo->dma_events |= KCOM_DMA_INFO_F_RX_DONE;
+
+ evt = &_bkn_evt[sinfo->evt_idx];
+ evt->evt_wq_put++;
+ wake_up_interruptible(&evt->evt_wq);
+
+ return 0;
+}
+
+static void
+bkn_rx_refill(bkn_switch_info_t *sinfo, int chan)
+{
+ struct sk_buff *skb;
+ bkn_desc_info_t *desc;
+ uint32_t *dcb;
+ uint32_t resv_size = sinfo->cmic_type == 'x' ? RCPU_HDR_SIZE : RCPU_RX_ENCAP_SIZE;
+ uint32_t meta_size = sinfo->cmic_type == 'x' ? RCPU_RX_META_SIZE : 0;
+ int prev;
+
+ if (sinfo->rx[chan].use_rx_skb == 0) {
+ /* Rx buffers are provided by BCM Rx API */
+ return;
+ }
+
+ if (!CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) &&
+ sinfo->rx[chan].tokens < MAX_RX_DCBS) {
+ /* Pause DMA for now */
+ return;
+ }
+
+ while (sinfo->rx[chan].free < MAX_RX_DCBS) {
+ desc = &sinfo->rx[chan].desc[sinfo->rx[chan].cur];
+ if (desc->skb == NULL) {
+ skb = dev_alloc_skb(rx_buffer_size + RCPU_RX_ENCAP_SIZE);
+ if (skb == NULL) {
+ break;
+ }
+ skb_reserve(skb, resv_size);
+ desc->skb = skb;
+ } else {
+ DBG_DCB_RX(("Refill Rx%d SKB in DCB %d recycled.\n",
+ chan, sinfo->rx[chan].cur));
+ }
+ skb = desc->skb;
+ desc->dma_size = rx_buffer_size + meta_size;
+#ifdef KNET_NO_AXI_DMA_INVAL
+ /*
+ * FIXME: Need to retain this code until iProc customers have been
+ * migrated to updated u-boot. Old u-boot versions are unable to load
+ * the kernel into non-ACP memory.
+ */
+ /*
+ * Cache invalidate may corrupt DMA memory on some iProc-based devices
+ * if the kernel is mapped to ACP memory.
+ */
+ if (sinfo->pdev == NULL) {
+ desc->dma_size = 0;
+ }
+#endif
+ desc->skb_dma = DMA_MAP_SINGLE(sinfo->dma_dev,
+ skb->data, desc->dma_size,
+ DMA_FROMDEV);
+ if (DMA_MAPPING_ERROR(sinfo->dma_dev, desc->skb_dma)) {
+ dev_kfree_skb_any(skb);
+ desc->skb = NULL;
+ break;
+ }
+ DBG_DCB_RX(("Refill Rx%d DCB %d (0x%08x).\n",
+ chan, sinfo->rx[chan].cur, (uint32_t)desc->skb_dma));
+ dcb = desc->dcb_mem;
+ dcb[0] = desc->skb_dma;
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ if (sinfo->cmic_type == 'x') {
+ dcb[2] |= 1 << 24 | 1 << 16;
+ } else {
+ dcb[1] |= 1 << 24 | 1 << 16;
+ }
+ } else {
+ prev = PREV_IDX(sinfo->rx[chan].cur, MAX_RX_DCBS);
+ if (prev < (MAX_RX_DCBS - 1)) {
+ if (sinfo->cmic_type == 'x') {
+ sinfo->rx[chan].desc[prev].dcb_mem[2] |= 1 << 16;
+ } else {
+ sinfo->rx[chan].desc[prev].dcb_mem[1] |= 1 << 16;
+ }
+ }
+ }
+ if (sinfo->cmic_type == 'x') {
+ dcb[1] = DMA_TO_BUS_HI(desc->skb_dma >> 32);
+ dcb[2] |= rx_buffer_size + meta_size;
+ } else {
+ dcb[1] |= rx_buffer_size;
+ }
+
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) &&
+ sinfo->rx[chan].tokens > MAX_RX_DCBS) {
+ /* DMA run to the new halt location */
+ bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, desc->dcb_dma);
+ }
+
+ if (++sinfo->rx[chan].cur >= MAX_RX_DCBS) {
+ sinfo->rx[chan].cur = 0;
+ }
+ sinfo->rx[chan].free++;
+ sinfo->rx[chan].tokens--;
+ }
+}
+
+static int
+bkn_rx_restart(bkn_switch_info_t *sinfo, int chan)
+{
+ bkn_desc_info_t *desc;
+
+ if (sinfo->basedev_suspended) {
+ return 0;
+ }
+
+ if (sinfo->rx[chan].running) {
+ return 0;
+ }
+
+ if (sinfo->rx[chan].free < MAX_RX_DCBS) {
+ return 1;
+ }
+
+ desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty];
+ sinfo->rx[chan].chain_complete = 0;
+ DBG_DCB_RX(("Restart Rx%d DMA, DCB @ 0x%08x (%d).\n",
+ chan, (uint32_t)desc->dcb_dma, sinfo->rx[chan].dirty));
+ dev_dma_chan_clear(sinfo, XGS_DMA_RX_CHAN + chan);
+ dev_irq_mask_enable(sinfo, XGS_DMA_RX_CHAN + chan, 1);
+ dev_dma_chan_start(sinfo, XGS_DMA_RX_CHAN + chan, desc->dcb_dma);
+ sinfo->rx[chan].running = 1;
+
+ /* Request one extra poll if chain was restarted during poll */
+ if (sinfo->napi_poll_mode) {
+ sinfo->napi_poll_again = 1;
+ }
+
+ return 0;
+}
+
+static int
+bkn_tx_dma_start(bkn_switch_info_t *sinfo)
+{
+ bkn_desc_info_t *desc;
+
+ desc = &sinfo->tx.desc[sinfo->tx.cur];
+ if (sinfo->tx.free == MAX_TX_DCBS) {
+ if (!sinfo->tx.api_active) {
+ DBG_DCB_TX(("Start Tx DMA, DCB @ 0x%08x (%d).\n",
+ (uint32_t)desc->dcb_dma, sinfo->tx.cur));
+ dev_dma_chan_clear(sinfo, XGS_DMA_TX_CHAN);
+ dev_irq_mask_enable(sinfo, XGS_DMA_TX_CHAN, 1);
+ dev_dma_chan_start(sinfo, XGS_DMA_TX_CHAN, desc->dcb_dma);
+ }
+ }
+
+ return 0;
+}
+
+static int
+bkn_dma_init(bkn_switch_info_t *sinfo)
+{
+ int chan;
+
+ dev_dma_chan_init(sinfo, XGS_DMA_TX_CHAN, 1);
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ bkn_tx_dma_start(sinfo);
+ }
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ dev_dma_chan_init(sinfo, XGS_DMA_RX_CHAN + chan, 0);
+ bkn_rx_refill(sinfo, chan);
+ bkn_rx_restart(sinfo, chan);
+ }
+
+ return 0;
+}
+
+static int
+bkn_dma_abort_tx(bkn_switch_info_t *sinfo)
+{
+ bkn_dcb_chain_t *dcb_chain;
+
+ DBG_VERB(("Aborting Tx DMA.\n"));
+
+ dev_irq_mask_disable(sinfo, XGS_DMA_TX_CHAN, 1);
+
+ dev_dma_chan_abort(sinfo, XGS_DMA_TX_CHAN, 10000);
+
+ if (sinfo->tx.api_dcb_chain) {
+ DBG_DCB_TX(("Freeing active Tx DCB chain.\n"));
+ kfree(sinfo->tx.api_dcb_chain);
+ sinfo->tx.api_dcb_chain = NULL;
+ }
+ while (!list_empty(&sinfo->tx.api_dcb_list)) {
+ dcb_chain = list_entry(sinfo->tx.api_dcb_list.next,
+ bkn_dcb_chain_t, list);
+ list_del(&dcb_chain->list);
+ DBG_DCB_TX(("Freeing Tx DCB chain.\n"));
+ kfree(dcb_chain);
+ }
+ sinfo->tx.api_dcb_chain_end = NULL;
+
+ return 0;
+}
+
+static int
+bkn_dma_abort_rx(bkn_switch_info_t *sinfo, int chan)
+{
+ bkn_dcb_chain_t *dcb_chain;
+
+ DBG_VERB(("Aborting Rx%d DMA.\n", chan));
+
+ dev_irq_mask_disable(sinfo, XGS_DMA_RX_CHAN + chan, 1);
+
+ dev_dma_chan_abort(sinfo, XGS_DMA_RX_CHAN + chan, 10000);
+
+ if (sinfo->rx[chan].api_dcb_chain) {
+ DBG_DCB_RX(("Freeing active Rx%d DCB chain.\n", chan));
+ kfree(sinfo->rx[chan].api_dcb_chain);
+ sinfo->rx[chan].api_dcb_chain = NULL;
+ }
+ while (!list_empty(&sinfo->rx[chan].api_dcb_list)) {
+ dcb_chain = list_entry(sinfo->rx[chan].api_dcb_list.next,
+ bkn_dcb_chain_t, list);
+ list_del(&dcb_chain->list);
+ DBG_DCB_RX(("Freeing Rx%d DCB chain.\n", chan));
+ kfree(dcb_chain);
+ }
+ sinfo->rx[chan].api_dcb_chain_end = NULL;
+
+ return 0;
+}
+
+static int
+bkn_dma_abort(bkn_switch_info_t *sinfo)
+{
+ int chan;
+
+ bkn_dma_abort_tx(sinfo);
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ bkn_dma_abort_rx(sinfo, chan);
+ }
+
+ return 0;
+}
+
+static int
+device_is_dpp(bkn_switch_info_t *sinfo)
+{
+ int is_dpp = 0;
+
+ is_dpp = (sinfo->dcb_type == 28) ? 1 : 0;
+ return is_dpp;
+}
+
+static int
+device_is_dnx(bkn_switch_info_t *sinfo)
+{
+ int is_dnx = 0;
+
+ /* No EP_TO_CPU header for DNX(JR2) */
+ is_dnx = ((sinfo->cmic_type == 'x') && (sinfo->pkt_hdr_size ==0)) ? 1 : 0;
+ return is_dnx;
+}
+
+/* is DPP or is DNX*/
+static int
+device_is_sand(bkn_switch_info_t *sinfo)
+{
+ int is_sand = 0;
+
+ if (device_is_dpp(sinfo) || device_is_dnx(sinfo)) {
+ is_sand = 1;
+ }
+ return is_sand;
+}
+
+static bkn_filter_t *
+bkn_match_rx_pkt(bkn_switch_info_t *sinfo, uint8_t *pkt, int pktlen,
+ void *meta, int chan, bkn_filter_t *cbf)
+{
+ struct list_head *list;
+ bkn_filter_t *filter;
+ kcom_filter_t scratch, *kf;
+ uint8_t *oob = (uint8_t *)meta;
+ int size, wsize;
+ int idx, match;
+
+ list_for_each(list, &sinfo->rxpf_list) {
+ filter = (bkn_filter_t *)list;
+ kf = &filter->kf;
+ memcpy(&scratch.data.b[0],
+ &oob[kf->oob_data_offset], kf->oob_data_size);
+ memcpy(&scratch.data.b[kf->oob_data_size],
+ &pkt[kf->pkt_data_offset], kf->pkt_data_size);
+ size = kf->oob_data_size + kf->pkt_data_size;
+ wsize = BYTES2WORDS(size);
+ DBG_VERB(("Filter: size = %d (%d), data = 0x%08x, mask = 0x%08x\n",
+ size, wsize, kf->data.w[0], kf->mask.w[0]));
+
+ if (device_is_dnx(sinfo)) {
+ DBG_DUNE(("Filter: size = %d (wsize %d)\n", size, wsize));
+ for (idx = 0; idx < wsize; idx++)
+ {
+ DBG_DUNE(("OOB[%d]: 0x%08x [0x%08x]\n", idx, kf->data.w[idx], kf->mask.w[idx]));
+ }
+ DBG_DUNE(("Meta Data [+ Selected Raw packet data]\n"));
+ for (idx = 0; idx < wsize; idx++)
+ {
+ DBG_DUNE(("Scratch[%d]: 0x%08x\n", idx, scratch.data.w[idx]));
+ }
+ }
+
+ match = 1;
+ if (match) {
+ if (device_is_sand(sinfo))
+ {
+ /** priority 0 means no priority check */
+ if (kf->priority && (kf->priority < (num_rx_prio * sinfo->rx_chans))) {
+ if (kf->priority < (num_rx_prio * chan) ||
+ kf->priority >= (num_rx_prio * (chan + 1))) {
+ match = 0;
+ }
+ }
+ }
+ else {
+ if (kf->priority < (num_rx_prio * sinfo->rx_chans)) {
+ if (kf->priority < (num_rx_prio * chan) ||
+ kf->priority >= (num_rx_prio * (chan + 1))) {
+ match = 0;
+ }
+ }
+ }
+ }
+ if (match) {
+ for (idx = 0; idx < wsize; idx++) {
+ scratch.data.w[idx] &= kf->mask.w[idx];
+ if (scratch.data.w[idx] != kf->data.w[idx]) {
+ match = 0;
+ break;
+ }
+ }
+ }
+ if (match) {
+ if (kf->dest_type == KCOM_DEST_T_CB) {
+ /* Check for custom filters */
+ if (knet_filter_cb != NULL && cbf != NULL) {
+ memset(cbf, 0, sizeof(*cbf));
+ memcpy(&cbf->kf, kf, sizeof(cbf->kf));
+ if (knet_filter_cb(pkt, pktlen, sinfo->dev_no,
+ meta, chan, &cbf->kf)) {
+ filter->hits++;
+ return cbf;
+ }
+ } else {
+ DBG_FLTR(("Match, but not filter callback\n"));
+ }
+ } else {
+ filter->hits++;
+ return filter;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static bkn_priv_t *
+bkn_netif_lookup(bkn_switch_info_t *sinfo, int id)
+{
+ struct list_head *list;
+ bkn_priv_t *priv;
+ int found;
+
+ /* Fast path */
+ if (id < sinfo->ndev_max) {
+ if (sinfo->ndevs[id] != NULL) {
+ DBG_NDEV(("Look up netif ID %d successful\n", id));
+ return netdev_priv(sinfo->ndevs[id]);
+ }
+ }
+
+ /* Slow path - should normally not get here */
+ found = 0;
+ priv = NULL;
+ list_for_each(list, &sinfo->ndev_list) {
+ priv = (bkn_priv_t *)list;
+ if (priv->id == id) {
+ found = 1;
+ break;
+ }
+ }
+ if (found && priv != NULL) {
+ return priv;
+ }
+ return NULL;
+}
+
+static int
+bkn_hw_tstamp_rx_set(bkn_switch_info_t *sinfo, struct sk_buff *skb, uint32 *meta)
+{
+ struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
+ uint32_t *md = meta;
+ uint64_t ts = 0;
+
+ switch (sinfo->dcb_type) {
+ case 26:
+ case 32:
+ case 33:
+ ts = md[14];
+ ts = ts << 32 | md[12];
+ break;
+ case 36:
+ ts = md[10];
+ break;
+ case 38:
+ ts = md[4] & 0xffff;
+ ts = ts << 32 | md[5];
+ break;
+ default:
+ return -1;
+ }
+
+ if (knet_hw_tstamp_rx_time_upscale_cb) {
+ if (knet_hw_tstamp_rx_time_upscale_cb(sinfo->dev_no, &ts) < 0) {
+ return -1;
+ }
+ }
+
+ memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+ shhwtstamps->hwtstamp = ns_to_ktime(be64_to_cpu(ts));
+
+ return 0;
+}
+
+static int
+bkn_add_rcpu_encap(bkn_switch_info_t *sinfo, struct sk_buff *skb, void *meta)
+{
+ int pktlen = skb->len;
+ uint32_t *dmeta, *smeta, wsize, psize;
+ int idx;
+
+ /* Add and clear RCPU encapsulation */
+ if (sinfo->cmic_type == 'x') {
+ psize = RCPU_HDR_SIZE + sinfo->pkt_hdr_size;
+ skb_push(skb, psize);
+ memset(skb->data, 0, RCPU_HDR_SIZE);
+ } else {
+ psize = RCPU_RX_ENCAP_SIZE;
+ skb_push(skb, psize);
+ memset(skb->data, 0, RCPU_RX_ENCAP_SIZE);
+ }
+
+ /* RCPU Header */
+ memcpy(skb->data, &skb->data[psize], 12);
+ if (rcpu_dmac != NULL) {
+ memcpy(skb->data, bkn_rcpu_dmac, 6);
+ }
+ if (rcpu_smac != NULL) {
+ memcpy(&skb->data[6], bkn_rcpu_smac, 6);
+ }
+ skb->data[12] = 0x81;
+ skb->data[14] = rcpu_vlan >> 8;
+ skb->data[15] = rcpu_vlan & 0xff;
+ skb->data[16] = rcpu_ethertype >> 8;
+ skb->data[17] = rcpu_ethertype & 0xff;
+ skb->data[18] = sinfo->rcpu_sig >> 8;
+ skb->data[19] = sinfo->rcpu_sig & 0xff;
+ skb->data[20] = RCPU_OPCODE_RX;
+ skb->data[21] = RCPU_F_MODHDR;
+ skb->data[24] = pktlen >> 8;
+ skb->data[25] = pktlen & 0xff;
+
+ /* Meta data */
+ dmeta = (uint32_t *)&skb->data[RCPU_HDR_SIZE];
+ smeta = sinfo->cmic_type == 'x' ? (uint32_t *)meta : (uint32_t *)meta + 2;
+ wsize = sinfo->cmic_type == 'x' ? sinfo->pkt_hdr_size / 4 : sinfo->dcb_wsize - 3;
+ for (idx = 0; idx < wsize; idx++) {
+ dmeta[idx] = htonl(smeta[idx]);
+ }
+
+ return 0;
+}
+
+static void
+bkn_eth_type_update(struct sk_buff *skb, int ethertype)
+{
+#if defined(PM_ETH_TYPE) && defined(PM_FC_TYPE)
+ /* Optionally override standard protocol */
+ skb->protocol = PM_ETH_TYPE;
+ if (ethertype == ETH_P_FCOE) {
+ skb->protocol = PM_FC_TYPE;
+ }
+#endif
+}
+
+#define BKN_DNX_BIT(x) (1<<(x))
+#define BKN_DNX_RBIT(x) (~(1<<(x)))
+#ifdef __LITTLE_ENDIAN
+#define BKN_DNX_BYTE_SWAP(x) (x)
+#else
+#define BKN_DNX_BYTE_SWAP(x) ((((x) << 24)) | (((x) & 0xff00) << 8) | (((x) & 0xff0000) >> 8) | (((x) >> 24)))
+#endif
+
+static int
+packet_is_untagged(uint16_t tpid)
+{
+ int is_untagged = 0;
+
+ /* Fixme SDK-111398 */
+ /* 0x8100 is used in 802.1Q */
+ /* 0x8848 is used in 802.11ad, the dtag tpid can be set to anything besides 0x8848, 0x9100 is a typical value, but couldn't cover all scenarios. */
+ is_untagged = ((tpid != 0x8100) && (tpid != 0x8848) && (tpid != 0x9100));
+ return is_untagged;
+}
+
+static void
+bkn_bitstream_set_field(uint32_t *input_buffer, uint32_t start_bit, uint32_t nof_bits, uint32_t field)
+{
+ uint32_t place;
+ uint32_t field_bit_i;
+ uint32_t bit_indicator;
+
+ if( nof_bits > 32)
+ {
+ return;
+ }
+
+ for( place=start_bit, field_bit_i = 0; field_bit_i< nof_bits; ++place, ++field_bit_i)
+ {
+ bit_indicator = field & BKN_DNX_BIT(nof_bits-field_bit_i-1);
+ if(bit_indicator)
+ {
+ input_buffer[place>>5] |= (0x80000000 >> (place & 0x0000001F));
+ }
+ else
+ {
+ input_buffer[place>>5] &= ~(0x80000000 >> (place & 0x0000001F));
+ }
+ }
+ return;
+}
+
+static void
+bkn_bitstream_get_field(uint8_t *input_buffer, uint32_t start_bit, uint32_t nof_bits, uint32_t *output_value)
+{
+ uint32_t idx;
+ uint32_t buf_sizes=0;
+ uint32_t tmp_output_value[2]={0};
+ uint32_t first_byte_ndx;
+ uint32_t last_byte_ndx;
+ uint32_t place;
+ uint32_t field_bit_i;
+ uint8_t *tmp_output_value_u8_ptr = (uint8_t*)&tmp_output_value;
+ uint32_t bit_indicator;
+
+ if (nof_bits > 32)
+ {
+ return;
+ }
+
+ first_byte_ndx = start_bit / 8;
+ last_byte_ndx = ((start_bit + nof_bits - 1) / 8);
+ *output_value=0;
+
+ /* get 32 bit value, MSB */
+ for (idx = first_byte_ndx; idx <= last_byte_ndx; ++idx)
+ {
+ tmp_output_value_u8_ptr[last_byte_ndx - idx] = input_buffer[idx];
+ buf_sizes += 8;
+ }
+ tmp_output_value[0] = BKN_DNX_BYTE_SWAP(tmp_output_value[0]);
+ if (last_byte_ndx > 4)
+ {
+ tmp_output_value[1] = BKN_DNX_BYTE_SWAP(tmp_output_value[1]);
+ }
+
+ place = buf_sizes - (start_bit % 8 + nof_bits);
+ for (field_bit_i = 0; field_bit_i< nof_bits; ++place, ++field_bit_i)
+ {
+ uint32_t result;
+ result = tmp_output_value[place>>5] & BKN_DNX_BIT(place & 0x0000001F);
+ if (result)
+ {
+ bit_indicator = 1;
+ } else {
+ bit_indicator = 0;
+ }
+ *output_value |= bit_indicator << field_bit_i;
+ }
+ return;
+}
+
+static void
+bkn_dpp_packet_parse_ftmh(bkn_switch_info_t *sinfo, uint8_t hdr_buff[], bkn_dune_system_header_info_t *packet_info)
+{
+ uint32_t header_ptr = 0;
+ uint32_t dsp_ext_exist=0;
+ uint32_t fld_val;
+
+ header_ptr = packet_info->ntwrk_header_ptr;
+
+ /* Packet-size */
+ bkn_bitstream_get_field(
+ &hdr_buff[header_ptr],
+ BKN_DPP_FTMH_PKT_SIZE_MSB,
+ BKN_DPP_FTMH_PKT_SIZE_NOF_BITS,
+ &fld_val);
+ packet_info->ftmh.packet_size = fld_val;
+ /* Traffic-class */
+ bkn_bitstream_get_field(
+ &hdr_buff[header_ptr],
+ BKN_DPP_FTMH_TC_MSB,
+ BKN_DPP_FTMH_TC_NOF_BITS,
+ &fld_val);
+ packet_info->ftmh.prio = fld_val;
+ /* Source-system-port-aggregate */
+ bkn_bitstream_get_field(
+ &hdr_buff[header_ptr],
+ BKN_DPP_FTMH_SRC_SYS_PORT_MSB,
+ BKN_DPP_FTMH_SRC_SYS_PORT_NOF_BITS,
+ &fld_val);
+ packet_info->ftmh.src_sys_port = fld_val;
+ /* TM-action-type */
+ bkn_bitstream_get_field(
+ &hdr_buff[header_ptr],
+ BKN_DPP_FTMH_ACTION_TYPE_MSB,
+ BKN_DPP_FTMH_ACTION_TYPE_NOF_BITS,
+ &fld_val);
+ packet_info->ftmh.action_type = fld_val;
+ /* PPH-type */
+ bkn_bitstream_get_field(
+ &hdr_buff[header_ptr],
+ BKN_DPP_FTMH_PPH_TYPE_MSB,
+ BKN_DPP_FTMH_PPH_TYPE_NOF_BITS,
+ &fld_val);
+ packet_info->ftmh.pph_type = fld_val;
+
+ packet_info->ntwrk_header_ptr += BKN_DPP_FTMH_SIZE_BYTE;
+ DBG_DUNE(("FTMH(%d) Packet-size %d Action-type %d PPH-type %d Source-system-port 0x%x Traffic-class %d\n",
+ packet_info->ntwrk_header_ptr, packet_info->ftmh.packet_size, packet_info->ftmh.action_type,
+ packet_info->ftmh.pph_type, packet_info->ftmh.src_sys_port, packet_info->ftmh.prio));
+
+ /* LB-Key ext */
+ if ((sinfo->pkt_hdr_size & BKN_DPP_FTMH_LB_EXT_EN) == BKN_DPP_FTMH_LB_EXT_EN)
+ {
+ packet_info->ntwrk_header_ptr += BKN_DPP_FTMH_LB_EXT_SIZE_BYTE;
+ DBG_DUNE(("FTMH(%d) FTMH LB-Key Extension is present\n", packet_info->ntwrk_header_ptr));
+ }
+ /* DSP ext*/
+ fld_val = 0;
+ bkn_bitstream_get_field(
+ &hdr_buff[header_ptr],
+ BKN_DPP_FTMH_EXT_DSP_EXIST_MSB,
+ BKN_DPP_FTMH_EXT_DSP_EXIST_NOF_BITS,
+ &dsp_ext_exist);
+ if (dsp_ext_exist)
+ {
+ packet_info->ntwrk_header_ptr += BKN_DPP_FTMH_DEST_EXT_SIZE_BYTE;
+ DBG_DUNE(("FTMH(%d) DSP-extension-present 1\n", packet_info->ntwrk_header_ptr));
+ }
+
+ /* stacking ext */
+ if ((sinfo->pkt_hdr_size & BKN_DPP_FTMH_STACKING_EXT_EN) == BKN_DPP_FTMH_STACKING_EXT_EN)
+ {
+ packet_info->ntwrk_header_ptr += BKN_DPP_FTMH_STACKING_SIZE_BYTE;
+ DBG_DUNE(("FTMH(%d) FTMH Stacking Extension is present\n", packet_info->ntwrk_header_ptr));
+ }
+ return;
+}
+
+static void
+bkn_dpp_packet_parse_internal(bkn_switch_info_t *sinfo, uint8_t hdr_buff[], bkn_dune_system_header_info_t *packet_info)
+{
+ uint32_t header_ptr = 0;
+ uint32_t fld_val;
+ uint32_t eei_extension_present = 0;
+ uint32_t learn_extension_present = 0;
+ uint32_t fhei_size = 0;
+ uint32_t forward_code;
+ uint8_t is_trapped = 0;
+
+ header_ptr = packet_info->ntwrk_header_ptr;
+
+ bkn_bitstream_get_field(
+ &hdr_buff[header_ptr],
+ BKN_DPP_PPH_EEI_EXTENSION_PRESENT_MSB,
+ BKN_DPP_PPH_EEI_EXTENSION_PRESENT_NOF_BITS,
+ &eei_extension_present);
+ bkn_bitstream_get_field(
+ &hdr_buff[header_ptr],
+ BKN_DPP_PPH_LEARN_EXENSION_PRESENT_MSB,
+ BKN_DPP_PPH_LEARN_EXENSION_PRESENT_NOF_BITS,
+ &learn_extension_present);
+ bkn_bitstream_get_field(
+ &hdr_buff[header_ptr],
+ BKN_DPP_PPH_FHEI_SIZE_MSB,
+ BKN_DPP_PPH_FHEI_SIZE_NOF_BITS,
+ &fhei_size);
+ bkn_bitstream_get_field(
+ &hdr_buff[header_ptr],
+ BKN_DPP_PPH_FORWARD_CODE_MSB,
+ BKN_DPP_PPH_FORWARD_CODE_NOF_BITS,
+ &forward_code);
+ /* 7: CPU-Trap */
+ is_trapped = (uint8_t)(forward_code == 7);
+
+ bkn_bitstream_get_field(
+ &hdr_buff[header_ptr],
+ BKN_DPP_PPH_VSI_MSB,
+ BKN_DPP_PPH_VSI_NOF_BITS,
+ &fld_val);
+ packet_info->internal.vsi = fld_val;
+
+ /* size of PPH base is 7 */
+ packet_info->ntwrk_header_ptr += BKN_DPP_PPH_SIZE_BYTE;
+ header_ptr = packet_info->ntwrk_header_ptr;
+
+ DBG_DUNE(("PPH(%d) Forward-Code %d EEI-Extension %d Learn-Extension %d VSI %d FHEI-size %d\n", packet_info->ntwrk_header_ptr,
+ forward_code, eei_extension_present, learn_extension_present, packet_info->internal.vsi, fhei_size));
+
+ /* PPH extension */
+ if (is_trapped && (fhei_size == 1))
+ {
+ /* CPU trap code qualifier */
+ bkn_bitstream_get_field(
+ &hdr_buff[header_ptr],
+ BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_MSB,
+ BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_NOF_BITS,
+ &fld_val);
+ packet_info->internal.trap_qualifier = fld_val;
+ /* CPU trap code */
+ bkn_bitstream_get_field(
+ &hdr_buff[header_ptr],
+ BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_MSB,
+ BKN_DPP_PPH_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_NOF_BITS,
+ &fld_val);
+ packet_info->internal.trap_id = fld_val;
+ }
+ switch(fhei_size) {
+ case 1:
+ packet_info->ntwrk_header_ptr += BKN_DPP_PPH_FHEI_3B_SIZE_BYTE;
+ break;
+ case 2:
+ packet_info->ntwrk_header_ptr += BKN_DPP_PPH_FHEI_5B_SIZE_BYTE;
+ break;
+ case 3:
+ packet_info->ntwrk_header_ptr += BKN_DPP_PPH_FHEI_8B_SIZE_BYTE;
+ break;
+ default:
+ break;
+ }
+ if (eei_extension_present) {
+ packet_info->ntwrk_header_ptr += BKN_DPP_PPH_EXPLICIT_EDITING_INFOMATION_EXTENSION_SIZE_BYTE;
+ }
+ if (learn_extension_present) {
+ packet_info->ntwrk_header_ptr += BKN_DPP_PPH_LEARN_EXTENSION_SIZE_BYTE;
+ }
+
+ DBG_DUNE(("FHEI(%d) trap_qualifier 0x%x trap_id 0x%x\n", packet_info->ntwrk_header_ptr, packet_info->internal.trap_qualifier, packet_info->internal.trap_id));
+ return;
+}
+
+static int
+bkn_dpp_packet_header_parse(bkn_switch_info_t *sinfo, uint8 *buff, uint32_t buff_len, bkn_dune_system_header_info_t *packet_info)
+{
+ uint8_t hdr_buff[BKN_DPP_HDR_MAX_SIZE];
+ uint32_t hdr_size;
+ uint8_t has_internal = 0;
+
+ if ((buff == NULL) || (packet_info == NULL)) {
+ return -1;
+ }
+ hdr_size = buff_len < BKN_DPP_HDR_MAX_SIZE ? buff_len: BKN_DPP_HDR_MAX_SIZE;
+ memcpy(hdr_buff, buff, hdr_size);
+
+ /* FTMH */
+ bkn_dpp_packet_parse_ftmh(sinfo, hdr_buff, packet_info);
+ if (packet_info->ftmh.packet_size != (buff_len + 2)) {
+ DBG_DUNE(("FTMH packet size verfication failed, %d-%d\n", packet_info->ftmh.packet_size, buff_len));
+ memset(packet_info, 0, sizeof(bkn_dune_system_header_info_t));
+ return -1;
+ }
+ switch (packet_info->ftmh.pph_type) {
+ case 0:
+ has_internal = 0;
+ break;
+ case 1:
+ has_internal = 1;
+ break;
+ case 2: /* PPH OAM-TS only */
+ case 3: /* PPH Base + OAM-TS */
+ /* OTSH immediately follows the FTMH when present */
+ packet_info->ntwrk_header_ptr += 6;
+ DBG_DUNE(("FTMH + OAM-TS(%d)\n", packet_info->ntwrk_header_ptr));
+ has_internal = 1;
+ break;
+ default:
+ break;
+ }
+
+ if (has_internal) {
+ bkn_dpp_packet_parse_internal(sinfo, &hdr_buff[0], packet_info);
+ }
+
+ /* FIXME: */
+ /* ignore packets with a double set of FTMH,internals */
+ /* ignore the user header size */
+ return 0;
+}
+
+static int
+bkn_dnx_packet_header_parse(bkn_switch_info_t *sinfo, uint8 *buf, uint32_t buf_len, bkn_dune_system_header_info_t *packet_info)
+{
+ uint32_t fld_val;
+ uint32_t hdr_size = 0;
+ uint32_t pkt_offset_ingress_untrapped =0;
+ uint8_t tm_dst_ext_present = 0;
+ uint8_t app_specific_ext_size = 0;
+ uint8_t flow_id_ext_size = 0;
+ uint8_t bier_bfr_ext_size = 0;
+ uint8_t is_pph_en = 0;
+ uint8_t is_tsh_en = 0;
+
+ if ((buf == NULL) || (packet_info == NULL)) {
+ return -1;
+ }
+
+ /* FTMH: Source-System-Port-Aggregate */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_MSB,
+ BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_NOF_BITS,
+ &fld_val);
+ packet_info->ftmh_spa = fld_val;
+ /* FTMH: PPH-Type TSH */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_MSB,
+ BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_NOF_BITS,
+ &fld_val);
+ is_tsh_en = fld_val;
+ /* FTMH: PPH-Type PPH base */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_MSB,
+ BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_NOF_BITS,
+ &fld_val);
+ is_pph_en = fld_val;
+ /* FTMH: TM-Destination-Extension-Present */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_FTMH_TM_DST_EXT_PRESENT_MSB,
+ BKN_DNX_FTMH_TM_DST_EXT_PRESENT_NOF_BITS,
+ &fld_val);
+ tm_dst_ext_present = fld_val;
+ /* FTMH: Application-Specific-Extension-Size */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_MSB,
+ BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_NOF_BITS,
+ &fld_val);
+ app_specific_ext_size = fld_val;
+ /* FTMH: Flow-ID-Extension-Size */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_MSB,
+ BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_NOF_BITS,
+ &fld_val);
+ flow_id_ext_size = fld_val;
+ /* FTMH: BIER-BFR-Extension-Size */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_MSB,
+ BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_NOF_BITS,
+ &fld_val);
+ bier_bfr_ext_size = fld_val;
+
+ hdr_size = BKN_DNX_FTMH_BASE_SIZE;
+ pkt_offset_ingress_untrapped = BKN_DNX_FTMH_BASE_SIZE;
+
+ DBG_DUNE(("FTMH(%d) source-system-port 0x%x is_tsh_en %d is_pph_en %d\n",
+ hdr_size, packet_info->ftmh_spa, is_tsh_en, is_pph_en));
+
+ /* FTMH LB-Key Extension */
+ if (sinfo->ftmh_lb_key_ext_size > 0)
+ {
+ hdr_size += sinfo->ftmh_lb_key_ext_size;
+ DBG_DUNE(("FTMH LB-Key Extension(%d) is present\n", sinfo->ftmh_lb_key_ext_size));
+ }
+ /* FTMH Stacking Extension */
+ if (sinfo->ftmh_stacking_ext_size > 0)
+ {
+ hdr_size += sinfo->ftmh_stacking_ext_size;
+ DBG_DUNE(("FTMH Stacking Extension(%d) is present\n", sinfo->ftmh_stacking_ext_size));
+ }
+ /* FTMH BIER BFR Extension */
+ if (bier_bfr_ext_size > 0)
+ {
+ hdr_size += BKN_DNX_FTMH_BIER_BFR_EXT_SIZE;
+ DBG_DUNE(("FTMH BIER BFR Extension(2) is present\n"));
+ }
+ /* FTMH TM Destination Extension */
+ if (tm_dst_ext_present > 0)
+ {
+ hdr_size += BKN_DNX_FTMH_TM_DST_EXT_SIZE;
+ DBG_DUNE(("FTMH TM Destination Extension(3) is present\n"));
+ }
+ /* FTMH Application Specific Extension */
+ if (app_specific_ext_size > 0)
+ {
+ hdr_size += BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE;
+ DBG_DUNE(("FTMH Application Specific Extension(6) is present\n"));
+ }
+ /* FTMH Flow-ID Extension */
+ if (flow_id_ext_size > 0)
+ {
+ hdr_size += BKN_DNX_FTMH_FLOW_ID_EXT_SIZE;
+ DBG_DUNE(("FTMH Flow-ID Extension(3) is present\n"));
+ }
+
+ /* Given the packet is trapped to CPU */
+
+ /* Time-Stamp Header */
+ if (is_tsh_en == TRUE)
+ {
+ hdr_size += BKN_DNX_TSH_SIZE;
+ DBG_DUNE(("Time-Stamp Header(4) is present\n"));
+ }
+
+ /* Packet Processing Header */
+ if (is_pph_en)
+ {
+ uint8_t learn_ext_present;
+ uint8_t fhei_size;
+ uint8_t lif_ext_type;
+
+ switch (sinfo->pph_base_size)
+ {
+ case BKN_DNX_PPH_BASE_TYPE_9:
+ /* FTMH: Forward-Domain */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_PPH_9_FORWARD_DOMAIN_MSB,
+ BKN_DNX_PPH_9_FORWARD_DOMAIN_NOF_BITS,
+ &fld_val);
+ packet_info->pph_forward_domain = fld_val;
+ /* FTMH: Learn-Extension-Present */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_PPH_9_LEARN_EXT_PRESENT_MSB,
+ BKN_DNX_PPH_9_LEARN_EXT_PRESENT_NOF_BITS,
+ &fld_val);
+ learn_ext_present = fld_val;
+ /* FTMH: FHEI-Size */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_PPH_9_FHEI_SIZE_MSB,
+ BKN_DNX_PPH_9_FHEI_SIZE_NOF_BITS,
+ &fld_val);
+ fhei_size = fld_val;
+ /* FTMH: LIF-Extension-Type */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_PPH_9_LIF_EXT_TYPE_MSB,
+ BKN_DNX_PPH_9_LIF_EXT_TYPE_NOF_BITS,
+ &fld_val);
+ lif_ext_type = fld_val;
+
+ hdr_size += BKN_DNX_PPH_BASE_TYPE_9;
+ DBG_DUNE(("PPH(10) FWD_DOMAIN %d, LEARN_EXT %d, FHEI_SIZE %d, LIF_EXT %d \n",
+ packet_info->pph_forward_domain, learn_ext_present, fhei_size, lif_ext_type));
+ break;
+ case BKN_DNX_PPH_BASE_TYPE_10:
+ /* FTMH: Forward-Domain */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_PPH_10_FORWARD_DOMAIN_MSB,
+ BKN_DNX_PPH_10_FORWARD_DOMAIN_NOF_BITS,
+ &fld_val);
+ packet_info->pph_forward_domain = fld_val;
+ /* FTMH: Learn-Extension-Present */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_PPH_10_LEARN_EXT_PRESENT_MSB,
+ BKN_DNX_PPH_10_LEARN_EXT_PRESENT_NOF_BITS,
+ &fld_val);
+ learn_ext_present = fld_val;
+ /* FTMH: FHEI-Size */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_PPH_10_FHEI_SIZE_MSB,
+ BKN_DNX_PPH_10_FHEI_SIZE_NOF_BITS,
+ &fld_val);
+ fhei_size = fld_val;
+ /* FTMH: LIF-Extension-Type */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_PPH_10_LIF_EXT_TYPE_MSB,
+ BKN_DNX_PPH_10_LIF_EXT_TYPE_NOF_BITS,
+ &fld_val);
+ lif_ext_type = fld_val;
+
+ hdr_size += BKN_DNX_PPH_BASE_TYPE_10;
+ DBG_DUNE(("PPH(10) FWD_DOMAIN %d, LEARN_EXT %d, FHEI_SIZE %d, LIF_EXT %d \n",
+ packet_info->pph_forward_domain, learn_ext_present, fhei_size, lif_ext_type));
+ break;
+ case BKN_DNX_PPH_BASE_TYPE_12:
+ /* FTMH: Forward-Domain */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_PPH_12_FORWARD_DOMAIN_MSB,
+ BKN_DNX_PPH_12_FORWARD_DOMAIN_NOF_BITS,
+ &fld_val);
+ packet_info->pph_forward_domain = fld_val;
+ /* FTMH: Learn-Extension-Present */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_PPH_12_LEARN_EXT_PRESENT_MSB,
+ BKN_DNX_PPH_12_LEARN_EXT_PRESENT_NOF_BITS,
+ &fld_val);
+ learn_ext_present = fld_val;
+ /* FTMH: FHEI-Size */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_PPH_12_FHEI_SIZE_MSB,
+ BKN_DNX_PPH_12_FHEI_SIZE_NOF_BITS,
+ &fld_val);
+ fhei_size = fld_val;
+ /* FTMH: LIF-Extension-Type */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_PPH_12_LIF_EXT_TYPE_MSB,
+ BKN_DNX_PPH_12_LIF_EXT_TYPE_NOF_BITS,
+ &fld_val);
+ lif_ext_type = fld_val;
+
+ hdr_size += BKN_DNX_PPH_BASE_TYPE_12;
+ DBG_DUNE(("PPH(12) FWD_DOMAIN %d, LEARN_EXT %d, FHEI_SIZE %d, LIF_EXT %d \n",
+ packet_info->pph_forward_domain, learn_ext_present, fhei_size, lif_ext_type));
+ break;
+ default:
+ fhei_size = 0;
+ lif_ext_type = 0;
+ learn_ext_present = 0;
+ break;
+ }
+ if (fhei_size)
+ {
+ switch (fhei_size)
+ {
+ case BKN_DNX_PPH_FHEI_TYPE_SZ0:
+ hdr_size += BKN_DNX_PPH_FHEI_SZ0_SIZE;
+ DBG_DUNE(("FHEI(3) is present\n"));
+ break;
+ case BKN_DNX_PPH_FHEI_TYPE_SZ1:
+ /* FHEI: Code */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_PPH_FHEI_TRAP_5B_TYPE_MSB,
+ BKN_DNX_PPH_FHEI_TRAP_5B_TYPE_NOF_BITS,
+ &fld_val);
+ packet_info->fhei_type = fld_val;
+ /* FHEI-Size == 5B, FHEI-Type == Trap/Sniff */
+ if (packet_info->fhei_type == 0x5)
+ {
+ /* FHEI: Qualifier */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_PPH_FHEI_TRAP_5B_QUALIFIER_MSB,
+ BKN_DNX_PPH_FHEI_TRAP_5B_QUALIFIER_NOF_BITS,
+ &fld_val);
+ packet_info->fhei_qualifier = fld_val;
+ /* FHEI: Code */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_PPH_FHEI_TRAP_5B_CODE_MSB,
+ BKN_DNX_PPH_FHEI_TRAP_5B_CODE_NOF_BITS,
+ &fld_val);
+ packet_info->fhei_code = fld_val;
+ }
+ hdr_size += BKN_DNX_PPH_FHEI_SZ1_SIZE;
+ DBG_DUNE(("FHEI(5) is present code 0x%x qualifier 0x%x\n", packet_info->fhei_code, packet_info->fhei_qualifier));
+ break;
+ case BKN_DNX_PPH_FHEI_TYPE_SZ2:
+ hdr_size += BKN_DNX_PPH_FHEI_SZ1_SIZE;
+ DBG_DUNE(("FHEI(8) is present\n"));
+ break;
+ }
+ }
+
+ /* PPH LIF Extension */
+ if (lif_ext_type)
+ {
+ hdr_size += sinfo->pph_lif_ext_size[lif_ext_type];
+ DBG_DUNE(("PPH LIF Extension(%d) is present\n", sinfo->pph_lif_ext_size[lif_ext_type]));
+ }
+
+ /* PPH Learn Extension */
+ if (learn_ext_present)
+ {
+ hdr_size += BKN_DNX_PPH_LEARN_EXT_SIZE;
+ DBG_DUNE(("PPH Learn Extension(19) is present\n"));
+ }
+ }
+
+ /* UDH Header */
+ if (sinfo->udh_enable)
+ {
+ uint8 data_type_0;
+ uint8 data_type_1;
+ uint8 data_type_2;
+ uint8 data_type_3;
+
+ DBG_DUNE(("UDH base(1) is present\n"));
+
+ /* UDH: UDH-Data-Type[0] */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_UDH_DATA_TYPE_0_MSB,
+ BKN_DNX_UDH_DATA_TYPE_0_NOF_BITS,
+ &fld_val);
+ data_type_0 = fld_val;
+ hdr_size += sinfo->udh_length_type[data_type_0];
+ /* UDH: UDH-Data-Type[1] */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_UDH_DATA_TYPE_1_MSB,
+ BKN_DNX_UDH_DATA_TYPE_1_NOF_BITS,
+ &fld_val);
+ data_type_1 = fld_val;
+ hdr_size += sinfo->udh_length_type[data_type_1];
+ /* UDH: UDH-Data-Type[2] */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_UDH_DATA_TYPE_2_MSB,
+ BKN_DNX_UDH_DATA_TYPE_2_NOF_BITS,
+ &fld_val);
+ data_type_2 = fld_val;
+ hdr_size += sinfo->udh_length_type[data_type_2];
+ /* UDH: UDH-Data-Type[3] */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_UDH_DATA_TYPE_3_MSB,
+ BKN_DNX_UDH_DATA_TYPE_3_NOF_BITS,
+ &fld_val);
+ data_type_3 = fld_val;
+ hdr_size += sinfo->udh_length_type[data_type_3];
+ hdr_size += BKN_DNX_UDH_BASE_SIZE;
+ }
+
+ /*
+ * Check if fhei_type if of type trap
+ * There is a RISK that raw packet data is parsed and fhei_type is 0x5 by chance
+ */
+ if (packet_info->fhei_type == 0x5)
+ {
+ /* Done for ingress trapped packets */
+ packet_info->system_header_size = hdr_size;
+ DBG_DUNE(("Total Size of Headers is %d\n", packet_info->system_header_size));
+ return 0;
+ }
+ else
+ {
+ /* New generated header will be FTMH(80b), TSH(32b), PPH(96b), FHEI(40b) */
+
+ /* Revert packet_info except info from FTHM base header */
+ packet_info->fhei_qualifier = 0;
+ packet_info->fhei_code = 0;
+ packet_info->fhei_type = 0;
+ hdr_size = pkt_offset_ingress_untrapped;
+
+ /* Time-Stamp Header */
+ hdr_size += BKN_DNX_TSH_SIZE;
+ DBG_DUNE(("Time-Stamp Header(4) is present\n"));
+
+ /** Packet Processing Header */
+ bkn_bitstream_get_field(
+ &buf[hdr_size],
+ BKN_DNX_PPH_12_FORWARD_DOMAIN_MSB,
+ BKN_DNX_PPH_12_FORWARD_DOMAIN_NOF_BITS,
+ &fld_val);
+ packet_info->pph_forward_domain = fld_val;
+ hdr_size += BKN_DNX_PPH_BASE_TYPE_12;
+ DBG_DUNE(("PPH(12) is present\n"));
+
+ /*
+ * FHEI(Trap,40)
+ * 5B-FHEI format for sys_hdr_generation_profile:J2-OAM
+ * 8b' 0
+ * 19b'oam_id
+ * 9b' cpu_trap_code: INGRESS_TRAP_ID is always 0 here
+ * 4b' type(0x5): J2-Configuration FHEI Type for CPU trap
+ */
+ hdr_size += BKN_DNX_PPH_FHEI_SZ1_SIZE;
+ DBG_DUNE(("FHEI(5) is present\n"));
+ }
+ packet_info->system_header_size = hdr_size;
+ DBG_DUNE(("Total Size of Headers is %d\n", packet_info->system_header_size));
+ return 0;
+}
+
+
+static int
+bkn_do_api_rx(bkn_switch_info_t *sinfo, int chan, int budget)
+{
+ bkn_priv_t *priv;
+ bkn_dcb_chain_t *dcb_chain;
+ struct sk_buff *skb;
+ bkn_filter_t cbf;
+ bkn_filter_t *filter;
+ uint32_t err_woff;
+ uint32_t *dcb, *meta;
+ uint8_t *pkt;
+ uint64_t pkt_dma;
+ int drop_api;
+ int ethertype;
+ int pktlen;
+ int idx;
+ int dcbs_done = 0;
+ bkn_dune_system_header_info_t packet_info = {0};
+ uint32_t dnx_meta_data[3] = {0};
+
+ dcb_chain = sinfo->rx[chan].api_dcb_chain;
+ if (dcb_chain == NULL) {
+ /* No active chains */
+ return 0;
+ }
+
+ while (dcb_chain->dcb_cur < dcb_chain->dcb_cnt) {
+ dcb = &dcb_chain->dcb_mem[dcb_chain->dcb_cur * sinfo->dcb_wsize];
+ DBG_VERB(("DCB %2d: 0x%08x\n",
+ dcb_chain->dcb_cur, dcb[sinfo->dcb_wsize-1]));
+ if ((dcb[sinfo->dcb_wsize-1] & (1 << 31)) == 0) {
+ break;
+ }
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ /* Handle for Continuous DMA mode */
+ if (dcbs_done >= budget) {
+ break;
+ }
+ if ((sinfo->cmic_type == 'x' && dcb[2] & (1 << 18)) ||
+ (sinfo->cmic_type != 'x' && dcb[1] & (1 << 18))) {
+ dcb[sinfo->dcb_wsize-1] |= SOC_DCB_KNET_DONE;
+ bkn_api_rx_chain_done(sinfo, chan);
+ dcb_chain = sinfo->rx[chan].api_dcb_chain;
+ if (dcb_chain == NULL) {
+ break;
+ }
+ continue;
+ }
+ }
+ if ((sinfo->cmic_type == 'x' && (dcb[2] & (1 << 16)) == 0) ||
+ (sinfo->cmic_type != 'x' && (dcb[1] & (1 << 16)) == 0)) {
+ sinfo->rx[chan].chain_complete = 1;
+ }
+ sinfo->rx[chan].pkts++;
+ if (sinfo->cmic_type == 'x') {
+ pkt_dma = BUS_TO_DMA_HI(dcb[1]);
+ pkt_dma = pkt_dma << 32 | dcb[0];
+ } else {
+ pkt_dma = dcb[0];
+ }
+ pkt = (uint8_t *)kernel_bde->p2l(sinfo->dev_no, (sal_paddr_t)pkt_dma);
+ if (sinfo->cmic_type == 'x') {
+ if (device_is_dnx(sinfo)){
+ meta = &dnx_meta_data[0];
+ /* get error bit from last DCB words */
+ err_woff = 2;
+ meta[err_woff] = dcb[sinfo->dcb_wsize-1];
+ } else {
+ meta = (uint32_t *)pkt;
+ err_woff = sinfo->pkt_hdr_size / sizeof(uint32_t) - 1;
+ meta[err_woff] = dcb[sinfo->dcb_wsize-1];
+ }
+ } else {
+ meta = dcb;
+ err_woff = sinfo->dcb_wsize - 1;
+ }
+ pktlen = dcb[sinfo->dcb_wsize-1] & SOC_DCB_KNET_COUNT_MASK;
+ bkn_dump_pkt(pkt, pktlen, XGS_DMA_RX_CHAN);
+
+ if (device_is_dpp(sinfo)) {
+ uint16_t tpid = 0;
+ uint16_t vid = 0;
+ int res = -1;
+
+ memset(&packet_info, 0, sizeof(bkn_dune_system_header_info_t));
+ res = bkn_dpp_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info);
+ if (res == 0) {
+ if (packet_info.ftmh.action_type == 0x2) {
+ bkn_bitstream_set_field((uint32_t *)dcb, 192, 32, 0x8);
+ } else if (packet_info.ftmh.action_type == 0x1) {
+ bkn_bitstream_set_field((uint32_t *)dcb, 231, 25, 0x20);
+ }
+ bkn_bitstream_set_field((uint32_t *)dcb, 112, 16, packet_info.ftmh.src_sys_port);
+ bkn_bitstream_set_field((uint32_t *)dcb, 296, 12, packet_info.internal.vsi);
+ bkn_bitstream_set_field((uint32_t *)dcb, 64, 32, (packet_info.internal.trap_id << 16 | packet_info.internal.trap_qualifier));
+ pkt += packet_info.ntwrk_header_ptr;
+ pktlen -= packet_info.ntwrk_header_ptr;
+ bkn_dump_pkt(pkt, 32, XGS_DMA_RX_CHAN);
+ /* check if vlan tag exists */
+ tpid = (uint16_t)((pkt[12] << 8) | pkt[13]);
+ vid = (uint16_t)(packet_info.internal.vsi & 0xfff);
+ if (packet_is_untagged(tpid)) {
+ if ((pktlen + 4) < rx_buffer_size) {
+ DBG_DUNE(("add vlan tag (%d) to untagged packets\n", vid));
+ for (idx = (pktlen-1); idx >= 12; idx--) {
+ pkt[idx+4] = pkt[idx];
+ }
+ pkt[12] = 0x81;
+ pkt[13] = 0x00;
+ pkt[14] = (vid >> 8);
+ pkt[15] = (vid & 0xff);
+ /* reset packet length in DCB */
+ pktlen += 4;
+ dcb[sinfo->dcb_wsize-1] &= ~SOC_DCB_KNET_COUNT_MASK;
+ dcb[sinfo->dcb_wsize-1] |= ((pktlen + packet_info.ntwrk_header_ptr) & SOC_DCB_KNET_COUNT_MASK);
+ bkn_dump_pkt(pkt, 32, XGS_DMA_RX_CHAN);
+ }
+ }
+ }
+ }
+ else if (device_is_dnx(sinfo)) {
+ int res = -1;
+ res = bkn_dnx_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info);
+ if (res == 0) {
+ bkn_bitstream_set_field(meta, 0, 16, packet_info.fhei_code);
+ bkn_bitstream_set_field(meta, 16, 16, packet_info.fhei_qualifier);
+ bkn_bitstream_set_field(meta, 32, 16, packet_info.ftmh_spa);
+ bkn_bitstream_set_field(meta, 48, 16, (packet_info.pph_forward_domain & 0xffff));
+
+ pkt += packet_info.system_header_size;
+ pktlen -= packet_info.system_header_size;
+ bkn_dump_pkt(pkt, 32, XGS_DMA_RX_CHAN);
+ }
+ }
+
+ if (device_is_dpp(sinfo)) {
+ filter = bkn_match_rx_pkt(sinfo, pkt, pktlen, dcb, chan, &cbf);
+ } else if (device_is_dnx(sinfo)) {
+ filter = bkn_match_rx_pkt(sinfo, pkt, pktlen, meta, chan, &cbf);
+ } else {
+ filter = bkn_match_rx_pkt(sinfo, pkt + sinfo->pkt_hdr_size,
+ pktlen - sinfo->pkt_hdr_size, meta, chan, &cbf);
+ }
+ if ((dcb[sinfo->dcb_wsize-1] & 0xf0000) != 0x30000) {
+ /* Fragment or error */
+ if (filter && filter->kf.mask.w[err_woff] == 0) {
+ /* Drop unless DCB status is part of filter */
+ filter = NULL;
+ }
+ }
+ drop_api = 1;
+ if (filter) {
+ DBG_FLTR(("Match filter ID %d\n", filter->kf.id));
+ switch (filter->kf.dest_type) {
+ case KCOM_DEST_T_API:
+ DBG_FLTR(("Send to Rx API\n"));
+ sinfo->rx[chan].pkts_f_api++;
+ drop_api = 0;
+ break;
+ case KCOM_DEST_T_NETIF:
+ priv = bkn_netif_lookup(sinfo, filter->kf.dest_id);
+ if (priv) {
+ /* Check that software link is up */
+ if (!netif_carrier_ok(priv->dev)) {
+ sinfo->rx[chan].pkts_d_no_link++;
+ break;
+ }
+
+ if (sinfo->cmic_type == 'x') {
+ pkt += sinfo->pkt_hdr_size;
+ pktlen -= sinfo->pkt_hdr_size;
+ }
+
+ /* Add 2 bytes for IP header alignment (see below) */
+ skb = dev_alloc_skb(pktlen + RCPU_RX_ENCAP_SIZE + 2);
+ if (skb == NULL) {
+ sinfo->rx[chan].pkts_d_no_skb++;
+ break;
+ }
+ skb_reserve(skb, RCPU_RX_ENCAP_SIZE);
+
+ DBG_FLTR(("Send to netif %d (%s)\n",
+ priv->id, priv->dev->name));
+ sinfo->rx[chan].pkts_f_netif++;
+ skb->dev = priv->dev;
+ skb_reserve(skb, 2); /* 16 byte align the IP fields. */
+
+ /* Save for RCPU before stripping tag */
+ ethertype = (pkt[16] << 8) | pkt[17];
+ if ((priv->flags & KCOM_NETIF_F_KEEP_RX_TAG) == 0) {
+ if (filter->kf.flags & KCOM_FILTER_F_STRIP_TAG) {
+ /* Strip the VLAN tag */
+ uint16_t vlan_proto = (uint16_t)((pkt[12] << 8) | pkt[13]);
+ if (vlan_proto == 0x8100 || vlan_proto == 0x88a8) {
+ DBG_FLTR(("Strip VLAN tag\n"));
+ for (idx = 11; idx >= 0; idx--) {
+ pkt[idx+4] = pkt[idx];
+ }
+ pktlen -= 4;
+ pkt += 4;
+ }
+ } else {
+ /*
+ * Mark packet as VLAN-tagged, otherwise newer
+ * kernels will strip the tag.
+ */
+ uint16_t tci = (pkt[14] << 8) | pkt[15];
+ if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) {
+ bkn_vlan_hwaccel_put_tag(skb, ETH_P_8021Q, tci);
+ } else {
+ bkn_vlan_hwaccel_put_tag(skb,
+ ((skb->data[12] << 8) | skb->data[13]), tci);
+ }
+ }
+ }
+
+ skb_copy_to_linear_data(skb, pkt, pktlen);
+ if (device_is_sand(sinfo)) {
+ /* CRC has been stripped */
+ skb_put(skb, pktlen);
+ } else {
+ skb_put(skb, pktlen - 4); /* Strip CRC */
+ }
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += skb->len;
+
+ /* Optional SKB updates */
+ if (knet_rx_cb != NULL) {
+ KNET_SKB_CB(skb)->netif_user_data = priv->cb_user_data;
+ KNET_SKB_CB(skb)->filter_user_data = filter->kf.cb_user_data;
+ KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF;
+ skb = knet_rx_cb(skb, sinfo->dev_no, meta);
+ if (skb == NULL) {
+ /* Consumed by call-back */
+ sinfo->rx[chan].pkts_d_callback++;
+ break;
+ }
+ }
+
+ /* Do Rx timestamping */
+ if (sinfo->rx_hwts) {
+ bkn_hw_tstamp_rx_set(sinfo, skb, meta);
+ }
+
+ if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) {
+ bkn_add_rcpu_encap(sinfo, skb, meta);
+ DBG_PDMP(("After add RCPU ENCAP\n"));
+ bkn_dump_pkt(skb->data, pktlen + RCPU_RX_ENCAP_SIZE, XGS_DMA_RX_CHAN);
+ }
+ skb->protocol = eth_type_trans(skb, skb->dev);
+ if (filter->kf.dest_proto) {
+ skb->protocol = filter->kf.dest_proto;
+ }
+ if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) {
+ bkn_eth_type_update(skb, ethertype);
+ }
+ DBG_DUNE(("skb protocol 0x%04x\n",skb->protocol));
+
+ /* Unlock while calling up network stack */
+ spin_unlock(&sinfo->lock);
+ if (use_napi) {
+ netif_receive_skb(skb);
+ } else {
+ netif_rx(skb);
+ }
+ spin_lock(&sinfo->lock);
+
+ if (filter->kf.mirror_type == KCOM_DEST_T_API ||
+ dbg_pkt_enable) {
+ DBG_FLTR(("Mirror to Rx API\n"));
+ sinfo->rx[chan].pkts_m_api++;
+ drop_api = 0;
+ }
+ } else {
+ DBG_FLTR(("Unknown netif %d\n",
+ filter->kf.dest_id));
+ sinfo->rx[chan].pkts_d_unkn_netif++;
+ }
+ break;
+ default:
+ /* Drop packet */
+ DBG_FLTR(("Unknown dest type %d\n",
+ filter->kf.dest_type));
+ sinfo->rx[chan].pkts_d_unkn_dest++;
+ break;
+ }
+ } else {
+ DBG_PKT(("Rx packet dropped.\n"));
+ sinfo->rx[chan].pkts_d_no_match++;
+ }
+ if (drop_api) {
+ /* If count is zero, the DCB will just be recycled */
+ dcb[sinfo->dcb_wsize-1] &= ~SOC_DCB_KNET_COUNT_MASK;
+ }
+ dcb[sinfo->dcb_wsize-1] |= SOC_DCB_KNET_DONE;
+ dcb_chain->dcb_cur++;
+ dcbs_done++;
+ }
+
+ return dcbs_done;
+}
+
+static int
+bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget)
+{
+ bkn_priv_t *priv;
+ bkn_desc_info_t *desc;
+ struct sk_buff *skb;
+ bkn_filter_t cbf;
+ bkn_filter_t *filter;
+ uint32_t err_woff;
+ uint32_t *dcb, *meta;
+ int ethertype;
+ int pktlen;
+ int idx;
+ int dcbs_done = 0;
+ bkn_dune_system_header_info_t packet_info = {0};
+ uint32_t dnx_meta_data[3] = {0};
+
+ if (!sinfo->rx[chan].running) {
+ /* Rx not ready */
+ return 0;
+ }
+
+ while (dcbs_done < budget) {
+ char str[32];
+ sprintf(str, "Rx DCB (%d)", sinfo->rx[chan].dirty);
+ desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty];
+ dcb = desc->dcb_mem;
+ bkn_dump_dcb(str, dcb, sinfo->dcb_wsize, XGS_DMA_RX_CHAN);
+ if ((dcb[sinfo->dcb_wsize-1] & (1 << 31)) == 0) {
+ break;
+ }
+ if ((sinfo->cmic_type == 'x' && (dcb[2] & (1 << 16)) == 0) ||
+ (sinfo->cmic_type != 'x' && (dcb[1] & (1 << 16)) == 0)) {
+ sinfo->rx[chan].chain_complete = 1;
+ /* Request one extra poll to check for chain done interrupt */
+ if (sinfo->napi_poll_mode) {
+ sinfo->napi_poll_again = 1;
+ }
+ }
+ sinfo->rx[chan].pkts++;
+ skb = desc->skb;
+ if (sinfo->cmic_type == 'x') {
+ if (device_is_dnx(sinfo)){
+ meta = &dnx_meta_data[0];
+ /* get error bit from last DCB words */
+ err_woff = 2;
+ meta[err_woff] = dcb[sinfo->dcb_wsize-1];
+ } else {
+ meta = (uint32_t *)skb->data;
+ err_woff = sinfo->pkt_hdr_size / sizeof(uint32_t) - 1;
+ meta[err_woff] = dcb[sinfo->dcb_wsize-1];
+ }
+ } else {
+ meta = dcb;
+ err_woff = sinfo->dcb_wsize - 1;
+ }
+ pktlen = dcb[sinfo->dcb_wsize-1] & 0xffff;
+ priv = netdev_priv(sinfo->dev);
+ DBG_DCB_RX(("Rx%d SKB DMA done (%d).\n", chan, sinfo->rx[chan].dirty));
+ DMA_UNMAP_SINGLE(sinfo->dma_dev,
+ desc->skb_dma, desc->dma_size,
+ DMA_FROMDEV);
+ desc->skb_dma = 0;
+ bkn_dump_pkt(skb->data, pktlen, XGS_DMA_RX_CHAN);
+
+ if (device_is_dpp(sinfo)) {
+ uint16_t tpid = 0;
+ uint16_t vid = 0;
+ uint8_t *pkt = skb->data;
+ int res = 0;
+
+ memset(&packet_info, 0, sizeof(bkn_dune_system_header_info_t));
+ res = bkn_dpp_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info);
+ if (res == 0) {
+ if (packet_info.ftmh.action_type == 0x2) {
+ bkn_bitstream_set_field((uint32_t *)dcb, 192, 32, 0x8);
+ } else if (packet_info.ftmh.action_type == 0x1) {
+ bkn_bitstream_set_field((uint32_t *)dcb, 231, 25, 0x20);
+ }
+ bkn_bitstream_set_field((uint32_t *)dcb, 112, 16, packet_info.ftmh.src_sys_port);
+ bkn_bitstream_set_field((uint32_t *)dcb, 296, 12, packet_info.internal.vsi);
+ bkn_bitstream_set_field((uint32_t *)dcb, 64, 32, (packet_info.internal.trap_id << 16 | packet_info.internal.trap_qualifier));
+ pkt = skb->data + packet_info.ntwrk_header_ptr;
+ /* check if vlan tag exists */
+ tpid = (uint16_t)((pkt[12] << 8) | pkt[13]);
+ vid = (uint16_t)(packet_info.internal.vsi & 0xfff);
+ if (packet_is_untagged(tpid)) {
+ if ((pktlen + 4) < rx_buffer_size) {
+ DBG_DUNE(("add vlan tag to untagged packets\n"));
+ for (idx = (pktlen-packet_info.ntwrk_header_ptr-1); idx >= 12; idx--) {
+ pkt[idx+4] = pkt[idx];
+ }
+ pkt[12] = 0x81;
+ pkt[13] = 0x00;
+ pkt[14] = (vid >> 8);
+ pkt[15] = (vid & 0xff);
+ pktlen += 4;
+ /* reset packet length in DCB */
+ dcb[sinfo->dcb_wsize-1] &= ~SOC_DCB_KNET_COUNT_MASK;
+ dcb[sinfo->dcb_wsize-1] |= (pktlen & SOC_DCB_KNET_COUNT_MASK);
+ bkn_dump_pkt(pkt, 32, XGS_DMA_RX_CHAN);
+ }
+ }
+ }
+ }
+ else if (device_is_dnx(sinfo)) {
+ uint8_t *pkt = skb->data;
+ int res = -1;
+
+ res = bkn_dnx_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info);
+ if (res == 0) {
+ bkn_bitstream_set_field(meta, 0, 16, packet_info.fhei_code);
+ bkn_bitstream_set_field(meta, 16, 16, packet_info.fhei_qualifier);
+ bkn_bitstream_set_field(meta, 32, 16, packet_info.ftmh_spa);
+ bkn_bitstream_set_field(meta, 48, 16, (packet_info.pph_forward_domain & 0xffff));
+
+ pkt += packet_info.system_header_size;
+ pktlen -= packet_info.ntwrk_header_ptr;
+ bkn_dump_pkt(pkt, 32, XGS_DMA_RX_CHAN);
+ }
+ }
+
+ if (device_is_dpp(sinfo)) {
+ filter = bkn_match_rx_pkt(sinfo, skb->data + packet_info.ntwrk_header_ptr,
+ pktlen, dcb, chan, &cbf);
+ } else if (device_is_dnx(sinfo)) {
+ filter = bkn_match_rx_pkt(sinfo, skb->data + packet_info.system_header_size,
+ pktlen, meta, chan, &cbf);
+ } else {
+ filter = bkn_match_rx_pkt(sinfo, skb->data + sinfo->pkt_hdr_size,
+ pktlen - sinfo->pkt_hdr_size, meta, chan, &cbf);
+ }
+ if ((dcb[sinfo->dcb_wsize-1] & 0xf0000) != 0x30000) {
+ /* Fragment or error */
+ priv->stats.rx_errors++;
+ if (filter && filter->kf.mask.w[err_woff] == 0) {
+ /* Drop unless DCB status is part of filter */
+ filter = NULL;
+ }
+ }
+ DBG_PKT(("Rx packet (%d bytes).\n", pktlen));
+ if (filter) {
+ DBG_FLTR(("Match filter ID %d\n", filter->kf.id));
+ switch (filter->kf.dest_type) {
+ case KCOM_DEST_T_API:
+ DBG_FLTR(("Send to Rx API\n"));
+ sinfo->rx[chan].pkts_f_api++;
+ bkn_api_rx_copy_from_skb(sinfo, chan, desc);
+ break;
+ case KCOM_DEST_T_NETIF:
+ priv = bkn_netif_lookup(sinfo, filter->kf.dest_id);
+ if (priv) {
+ /* Check that software link is up */
+ if (!netif_carrier_ok(priv->dev)) {
+ sinfo->rx[chan].pkts_d_no_link++;
+ break;
+ }
+ DBG_FLTR(("Send to netif %d (%s)\n",
+ priv->id, priv->dev->name));
+ sinfo->rx[chan].pkts_f_netif++;
+
+ if (((filter->kf.mirror_type == KCOM_DEST_T_API) &&
+ (!device_is_sand(sinfo))) || dbg_pkt_enable) {
+ sinfo->rx[chan].pkts_m_api++;
+ bkn_api_rx_copy_from_skb(sinfo, chan, desc);
+ }
+
+ if (device_is_dpp(sinfo)) {
+ if (filter->kf.mirror_type == KCOM_DEST_T_API) {
+ sinfo->rx[chan].pkts_m_api++;
+ bkn_api_rx_copy_from_skb(sinfo, chan, desc);
+ }
+ /* Strip Dune headers */
+ skb->data += packet_info.ntwrk_header_ptr;
+ pktlen -= packet_info.ntwrk_header_ptr;
+ bkn_dump_pkt(skb->data, 32, XGS_DMA_RX_CHAN);
+ /* CRC has been stripped on Dune*/
+ skb_put(skb, pktlen);
+ } else if (device_is_dnx(sinfo)) {
+ if (filter->kf.mirror_type == KCOM_DEST_T_API) {
+ sinfo->rx[chan].pkts_m_api++;
+ bkn_api_rx_copy_from_skb(sinfo, chan, desc);
+ }
+ /* Strip Dune headers */
+ skb->data += packet_info.system_header_size;
+ pktlen -= packet_info.system_header_size;
+ bkn_dump_pkt(skb->data, 32, XGS_DMA_RX_CHAN);
+ /* CRC has been stripped on Dune*/
+ skb_put(skb, pktlen);
+ } else {
+ skb_put(skb, pktlen - 4); /* Strip CRC */
+ }
+
+ if (sinfo->cmic_type == 'x' && !device_is_dnx(sinfo)) {
+ skb_pull(skb, sinfo->pkt_hdr_size);
+ }
+
+ /* Save for RCPU before stripping tag */
+ ethertype = (skb->data[16] << 8) | skb->data[17];
+ if ((priv->flags & KCOM_NETIF_F_KEEP_RX_TAG) == 0) {
+ if (filter->kf.flags & KCOM_FILTER_F_STRIP_TAG) {
+ /* Strip VLAN tag */
+ uint16_t vlan_proto = (uint16_t)((skb->data[12] << 8) | skb->data[13]);
+ if (vlan_proto == 0x8100 || vlan_proto == 0x88a8) {
+ DBG_FLTR(("Strip VLAN tag\n"));
+ ((u32*)skb->data)[3] = ((u32*)skb->data)[2];
+ ((u32*)skb->data)[2] = ((u32*)skb->data)[1];
+ ((u32*)skb->data)[1] = ((u32*)skb->data)[0];
+ skb_pull(skb, 4);
+ if (sinfo->cmic_type == 'x' && !device_is_dnx(sinfo)) {
+ for (idx = sinfo->pkt_hdr_size / sizeof(uint32_t); idx; idx--) {
+ meta[idx] = meta[idx - 1];
+ }
+ meta++;
+ }
+ }
+ } else {
+ /*
+ * Mark packet as VLAN-tagged, otherwise newer
+ * kernels will strip the tag.
+ */
+ uint16_t tci = (skb->data[14] << 8) | skb->data[15];
+ if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) {
+ bkn_vlan_hwaccel_put_tag(skb, ETH_P_8021Q, tci);
+ } else {
+ bkn_vlan_hwaccel_put_tag(skb,
+ ((skb->data[12] << 8) | skb->data[13]), tci);
+ }
+ }
+ }
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += skb->len;
+ skb->dev = priv->dev;
+
+ /* Optional SKB updates */
+ if (knet_rx_cb != NULL) {
+ KNET_SKB_CB(skb)->netif_user_data = priv->cb_user_data;
+ KNET_SKB_CB(skb)->filter_user_data = filter->kf.cb_user_data;
+ KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF;
+ skb = knet_rx_cb(skb, sinfo->dev_no, meta);
+ if (skb == NULL) {
+ /* Consumed by call-back */
+ sinfo->rx[chan].pkts_d_callback++;
+ priv->stats.rx_dropped++;
+ desc->skb = NULL;
+ break;
+ }
+ }
+
+ /* Do Rx timestamping */
+ if (sinfo->rx_hwts) {
+ bkn_hw_tstamp_rx_set(sinfo, skb, meta);
+ }
+
+ if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) {
+ bkn_add_rcpu_encap(sinfo, skb, meta);
+ DBG_PDMP(("After add RCPU ENCAP\n"));
+ bkn_dump_pkt(skb->data, pktlen + RCPU_RX_ENCAP_SIZE, XGS_DMA_RX_CHAN);
+ }
+ skb->protocol = eth_type_trans(skb, skb->dev);
+ if (filter->kf.dest_proto) {
+ skb->protocol = filter->kf.dest_proto;
+ }
+ if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) {
+ bkn_eth_type_update(skb, ethertype);
+ }
+ DBG_DUNE(("skb protocol 0x%04x\n",skb->protocol));
+
+ if (filter->kf.mirror_type == KCOM_DEST_T_NETIF) {
+ bkn_priv_t *mpriv;
+ struct sk_buff *mskb;
+ mpriv = bkn_netif_lookup(sinfo, filter->kf.mirror_id);
+ if (mpriv && netif_carrier_ok(mpriv->dev)) {
+ mskb = skb_clone(skb, GFP_ATOMIC);
+ if (mskb == NULL) {
+ sinfo->rx[chan].pkts_d_no_skb++;
+ } else {
+ sinfo->rx[chan].pkts_m_netif++;
+ mpriv->stats.rx_packets++;
+ mpriv->stats.rx_bytes += mskb->len;
+ skb->dev = mpriv->dev;
+ if (filter->kf.mirror_proto) {
+ skb->protocol = filter->kf.mirror_proto;
+ }
+ /* Unlock while calling up network stack */
+ spin_unlock(&sinfo->lock);
+ if (use_napi) {
+ netif_receive_skb(mskb);
+ } else {
+ netif_rx(mskb);
+ }
+ spin_lock(&sinfo->lock);
+ }
+ }
+ }
+
+ /* Unlock while calling up network stack */
+ spin_unlock(&sinfo->lock);
+ if (use_napi) {
+ netif_receive_skb(skb);
+ } else {
+ netif_rx(skb);
+ }
+ spin_lock(&sinfo->lock);
+
+ /* Ensure that we reallocate SKB for this DCB */
+ desc->skb = NULL;
+ } else {
+ DBG_FLTR(("Unknown netif %d\n",
+ filter->kf.dest_id));
+ sinfo->rx[chan].pkts_d_unkn_netif++;
+ }
+ break;
+ default:
+ /* Drop packet */
+ DBG_FLTR(("Unknown dest type %d\n",
+ filter->kf.dest_type));
+ sinfo->rx[chan].pkts_d_unkn_dest++;
+ break;
+ }
+ } else {
+ DBG_PKT(("Rx packet dropped.\n"));
+ sinfo->rx[chan].pkts_d_no_match++;
+ priv->stats.rx_dropped++;
+ }
+ dcb[sinfo->dcb_wsize-1] &= ~(1 << 31);
+ if (++sinfo->rx[chan].dirty >= MAX_RX_DCBS) {
+ sinfo->rx[chan].dirty = 0;
+ }
+ sinfo->rx[chan].free--;
+ dcbs_done++;
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ /* Right now refill for Continuous DMA mode */
+ bkn_rx_refill(sinfo, chan);
+ }
+ }
+
+ return dcbs_done;
+}
+
+static int
+bkn_do_rx(bkn_switch_info_t *sinfo, int chan, int budget)
+{
+ if (sinfo->rx[chan].use_rx_skb == 0) {
+ /* Rx buffers are provided by BCM Rx API */
+ return bkn_do_api_rx(sinfo, chan, budget);
+ } else {
+ /* Rx buffers are provided by Linux kernel */
+ return bkn_do_skb_rx(sinfo, chan, budget);
+ }
+}
+
+static void
+bkn_rx_desc_done(bkn_switch_info_t *sinfo, int chan)
+{
+ bkn_evt_resource_t *evt;
+ evt = &_bkn_evt[sinfo->evt_idx];
+ DBG_IRQ(("Rx%d desc done\n", chan));
+
+ if (sinfo->rx[chan].use_rx_skb == 0) {
+ sinfo->dma_events |= KCOM_DMA_INFO_F_RX_DONE;
+ evt->evt_wq_put++;
+ wake_up_interruptible(&evt->evt_wq);
+ }
+}
+
+static void
+bkn_rx_chain_done(bkn_switch_info_t *sinfo, int chan)
+{
+ DBG_IRQ(("Rx%d chain done\n", chan));
+
+ if (sinfo->rx[chan].chain_complete == 0) {
+ /*
+ * In certain environments the DCB memory is updated after
+ * the corresponding interrupt has been received.
+ * The following code will ensure that this situation is
+ * handled properly.
+ */
+ int maxloop = 0;
+ while (sinfo->rx[chan].chain_complete == 0) {
+ sinfo->rx[chan].sync_retry++;
+ if (maxloop == 0) {
+ sinfo->rx[chan].sync_err++;
+ }
+ if (maxloop > sinfo->rx[chan].sync_maxloop) {
+ sinfo->rx[chan].sync_maxloop = maxloop;
+ }
+ if (bkn_do_rx(sinfo, chan, MAX_RX_DCBS) > 0) {
+ bkn_rx_desc_done(sinfo, chan);
+ }
+ if (++maxloop > rx_sync_retry) {
+ gprintk("Fatal error: Incomplete chain\n");
+ sinfo->rx[chan].chain_complete = 1;
+ break;
+ }
+ }
+ }
+
+ sinfo->rx[chan].running = 0;
+
+ if (sinfo->rx[chan].use_rx_skb == 0) {
+ bkn_api_rx_chain_done(sinfo, chan);
+ } else {
+ bkn_rx_refill(sinfo, chan);
+
+ if (bkn_rx_restart(sinfo, chan) != 0) {
+ /* Presumably out of resources */
+ sinfo->timer.expires = jiffies + 1;
+ if (!sinfo->timer_queued) {
+ sinfo->timer_queued = 1;
+ add_timer(&sinfo->timer);
+ }
+ }
+ }
+}
+
+static void
+bkn_suspend_tx(bkn_switch_info_t *sinfo)
+{
+ struct list_head *list;
+ bkn_priv_t *priv = netdev_priv(sinfo->dev);
+
+ /* Stop main device */
+ netif_stop_queue(priv->dev);
+ sinfo->tx.suspends++;
+ /* Stop associated virtual devices */
+ list_for_each(list, &sinfo->ndev_list) {
+ priv = (bkn_priv_t *)list;
+ netif_stop_queue(priv->dev);
+ }
+}
+
+static void
+bkn_resume_tx(bkn_switch_info_t *sinfo)
+{
+ struct list_head *list;
+ bkn_priv_t *priv = netdev_priv(sinfo->dev);
+
+ /* Check main device */
+ if (netif_queue_stopped(priv->dev) && sinfo->tx.free > 1) {
+ netif_wake_queue(priv->dev);
+ }
+ /* Check associated virtual devices */
+ list_for_each(list, &sinfo->ndev_list) {
+ priv = (bkn_priv_t *)list;
+ if (netif_queue_stopped(priv->dev) && sinfo->tx.free > 1) {
+ netif_wake_queue(priv->dev);
+ }
+ }
+}
+
+static int
+bkn_hw_tstamp_tx_set(bkn_switch_info_t *sinfo, struct sk_buff *skb)
+{
+ struct skb_shared_hwtstamps shhwtstamps;
+ uint64_t ts = 0;
+ uint32_t hdrlen = sinfo->cmic_type == 'x' ? PKT_TX_HDR_SIZE : 0;
+ int port;
+
+ if (!knet_hw_tstamp_tx_time_get_cb) {
+ return -1;
+ }
+
+ port = KNET_SKB_CB(skb)->port;
+ if (knet_hw_tstamp_tx_time_get_cb(sinfo->dev_no, port, skb->data + hdrlen, &ts) < 0) {
+ return -1;
+ }
+
+ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+ shhwtstamps.hwtstamp = ns_to_ktime(be64_to_cpu(ts));
+ skb_tstamp_tx(skb, &shhwtstamps);
+
+ return 0;
+}
+
+static void
+bkn_hw_tstamp_tx_work(struct work_struct *work)
+{
+ bkn_switch_info_t *sinfo = container_of(work, bkn_switch_info_t, tx_ptp_work);
+ struct sk_buff *skb;
+
+ while (skb_queue_len(&sinfo->tx_ptp_queue)) {
+ skb = skb_dequeue(&sinfo->tx_ptp_queue);
+ if (bkn_hw_tstamp_tx_set(sinfo, skb) < 0) {
+ gprintk("Timestamp has not been taken for the current skb.\n");
+ }
+ dev_kfree_skb_any(skb);
+ }
+}
+
+static int
+bkn_do_tx(bkn_switch_info_t *sinfo)
+{
+ bkn_desc_info_t *desc;
+ int dcbs_done = 0;
+
+ if (!CDMA_CH(sinfo, XGS_DMA_TX_CHAN) && sinfo->tx.api_active) {
+ return dcbs_done;
+ }
+
+ while (dcbs_done < MAX_TX_DCBS) {
+ char str[32];
+ if (sinfo->tx.free == MAX_TX_DCBS) {
+ break;
+ }
+ sprintf(str, "Tx DCB (%d)", sinfo->tx.dirty);
+ desc = &sinfo->tx.desc[sinfo->tx.dirty];
+ bkn_dump_dcb(str, desc->dcb_mem, sinfo->dcb_wsize, XGS_DMA_TX_CHAN);
+ if ((desc->dcb_mem[sinfo->dcb_wsize-1] & (1 << 31)) == 0) {
+ break;
+ }
+ if (desc->skb) {
+ DBG_DCB_TX(("Tx SKB DMA done (%d).\n", sinfo->tx.dirty));
+ DMA_UNMAP_SINGLE(sinfo->dma_dev,
+ desc->skb_dma, desc->dma_size,
+ DMA_TODEV);
+ if (bkn_skb_tx_flags(desc->skb) & SKBTX_IN_PROGRESS) {
+ skb_queue_tail(&sinfo->tx_ptp_queue, desc->skb);
+ schedule_work(&sinfo->tx_ptp_work);
+ } else {
+ dev_kfree_skb_any(desc->skb);
+ }
+ desc->skb = NULL;
+ desc->skb_dma = 0;
+ }
+ desc->dcb_mem[sinfo->dcb_wsize-1] &= ~(1 << 31);
+ if (++sinfo->tx.dirty >= MAX_TX_DCBS) {
+ sinfo->tx.dirty = 0;
+ }
+ if (++sinfo->tx.free > MAX_TX_DCBS) {
+ gprintk("Too many free Tx DCBs(%d).\n", sinfo->tx.free);
+ }
+ dcbs_done++;
+ }
+
+ return dcbs_done;
+}
+
+static void
+bkn_tx_cdma_chain_switch(bkn_switch_info_t *sinfo)
+{
+ bkn_dcb_chain_t *dcb_chain = sinfo->tx.api_dcb_chain;
+ uint32_t *dcb_mem;
+ uint64_t dcb_dma;
+ int woffset;
+
+ /* Switch between SKB Tx and API Tx for Continuous DMA mode */
+ if (!sinfo->tx.api_active) {
+ /*
+ * Set the current SKB DCB as reload DCB and the last DCB of
+ * the pending API chain as the new halt location.
+ */
+ sinfo->tx.api_active = 1;
+ dcb_mem = sinfo->tx.desc[sinfo->tx.cur].dcb_mem;
+ memset(dcb_mem, 0, sinfo->dcb_wsize * sizeof(uint32_t));
+ dcb_mem[0] = dcb_chain->dcb_dma;
+ if (sinfo->cmic_type == 'x') {
+ dcb_mem[1] = DMA_TO_BUS_HI(dcb_chain->dcb_dma >> 32);
+ dcb_mem[2] |= 1 << 24 | 1 << 18 | 1 << 16;
+ } else {
+ dcb_mem[1] |= 1 << 24 | 1 << 18 | 1 << 16;
+ }
+ if (++sinfo->tx.cur >= MAX_TX_DCBS) {
+ sinfo->tx.cur = 0;
+ }
+ sinfo->tx.free--;
+ woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize;
+ dcb_dma = dcb_chain->dcb_dma + woffset * sizeof(uint32_t);
+ /* DMA run to the new halt location */
+ bkn_cdma_goto(sinfo, XGS_DMA_TX_CHAN, dcb_dma);
+ } else {
+ /* Only need to set the current SKB DCB as the new halt location */
+ sinfo->tx.api_active = 0;
+ woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize;
+ dcb_mem = &dcb_chain->dcb_mem[woffset];
+ dcb_mem[0] = sinfo->tx.desc[sinfo->tx.dirty].dcb_dma;
+ if (sinfo->cmic_type == 'x') {
+ dcb_mem[1] = DMA_TO_BUS_HI(sinfo->tx.desc[sinfo->tx.dirty].dcb_dma >> 32);
+ }
+ dcb_dma = sinfo->tx.desc[sinfo->tx.cur].dcb_dma;
+ /* DMA run to the new halt location */
+ bkn_cdma_goto(sinfo, XGS_DMA_TX_CHAN, dcb_dma);
+ }
+}
+
+static void
+bkn_skb_tx(bkn_switch_info_t *sinfo)
+{
+ if (sinfo->tx.api_active) {
+ /* Switch from API Tx to SKB Tx */
+ bkn_tx_cdma_chain_switch(sinfo);
+ }
+}
+
+static void
+bkn_api_tx(bkn_switch_info_t *sinfo)
+{
+ bkn_dcb_chain_t *dcb_chain;
+ uint64_t pkt_dma;
+ unsigned char *pktdata;
+ int pktlen;
+ int i;
+
+ /* Assume that driver lock is held */
+ if (list_empty(&sinfo->tx.api_dcb_list)) {
+ sinfo->tx.api_active = 0;
+ } else {
+ sinfo->tx.pkts++;
+ dcb_chain = list_entry(sinfo->tx.api_dcb_list.next,
+ bkn_dcb_chain_t, list);
+ DBG_DCB_TX(("Start API Tx DMA, first DCB @ 0x%08x (%d DCBs).\n",
+ (uint32_t)dcb_chain->dcb_dma, dcb_chain->dcb_cnt));
+ for (i = 0; i < dcb_chain->dcb_cnt && debug & DBG_LVL_PDMP; i++) {
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN) && i == dcb_chain->dcb_cnt - 1) {
+ break;
+ }
+ if (sinfo->cmic_type == 'x') {
+ pkt_dma = BUS_TO_DMA_HI(dcb_chain->dcb_mem[sinfo->dcb_wsize * i + 1]);
+ pkt_dma = pkt_dma << 32 | dcb_chain->dcb_mem[sinfo->dcb_wsize * i];
+ } else {
+ pkt_dma = dcb_chain->dcb_mem[sinfo->dcb_wsize * i];
+ }
+ pktdata = kernel_bde->p2l(sinfo->dev_no, pkt_dma);
+ if (sinfo->cmic_type == 'x') {
+ pktlen = dcb_chain->dcb_mem[sinfo->dcb_wsize * i + 2] & 0xffff;
+ } else {
+ pktlen = dcb_chain->dcb_mem[sinfo->dcb_wsize * i + 1] & 0xffff;
+ }
+ bkn_dump_pkt(pktdata, pktlen, XGS_DMA_TX_CHAN);
+ }
+
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ sinfo->tx.api_dcb_chain = dcb_chain;
+ if (!sinfo->tx.api_active) {
+ /* Switch from SKB Tx to API Tx */
+ bkn_tx_cdma_chain_switch(sinfo);
+ }
+ list_del(&dcb_chain->list);
+ } else {
+ sinfo->tx.api_active = 1;
+ dev_dma_chan_clear(sinfo, XGS_DMA_TX_CHAN);
+ dev_irq_mask_enable(sinfo, XGS_DMA_TX_CHAN, 1);
+ dev_dma_chan_start(sinfo, XGS_DMA_TX_CHAN, dcb_chain->dcb_dma);
+ list_del(&dcb_chain->list);
+ kfree(dcb_chain);
+ }
+ }
+}
+
+static void
+bkn_tx_cdma_chain_done(bkn_switch_info_t *sinfo, int done)
+{
+ int woffset;
+ int dcbs_done = 0;
+ bkn_evt_resource_t *evt;
+
+ DBG_IRQ(("Tx CDMA chain done \n"));
+
+ evt = &_bkn_evt[sinfo->evt_idx];
+
+ if (sinfo->tx.api_active) {
+ /* Drain API Tx chains */
+ while (sinfo->tx.api_dcb_chain != sinfo->tx.api_dcb_chain_end) {
+ woffset = sinfo->tx.api_dcb_chain->dcb_cnt * sinfo->dcb_wsize - 1;
+ if (!(sinfo->tx.api_dcb_chain->dcb_mem[woffset] & (1 << 31))) {
+ return;
+ }
+ sinfo->tx.api_dcb_chain->dcb_mem[woffset - sinfo->dcb_wsize] |= SOC_DCB_KNET_DONE;
+ sinfo->dma_events |= KCOM_DMA_INFO_F_TX_DONE;
+ evt->evt_wq_put++;
+ wake_up_interruptible(&evt->evt_wq);
+ kfree(sinfo->tx.api_dcb_chain);
+ sinfo->tx.api_dcb_chain = NULL;
+ bkn_api_tx(sinfo);
+ if ((++dcbs_done + done) >= MAX_TX_DCBS) {
+ if (sinfo->napi_poll_mode) {
+ /* Request one extra poll to reschedule Tx */
+ sinfo->napi_poll_again = 1;
+ } else {
+ /* Request to yield for Continuous DMA mode */
+ sinfo->tx_yield = 1;
+ }
+ return;
+ }
+ }
+ woffset = (sinfo->tx.api_dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize - 1;
+ if (!(sinfo->tx.api_dcb_chain->dcb_mem[woffset] & (1 << 31))) {
+ return;
+ }
+ sinfo->tx.api_dcb_chain->dcb_mem[woffset] |= SOC_DCB_KNET_DONE;
+ /* Try and park at SKB Tx if API Tx done */
+ bkn_skb_tx(sinfo);
+ sinfo->dma_events |= KCOM_DMA_INFO_F_TX_DONE;
+ evt->evt_wq_put++;
+ wake_up_interruptible(&evt->evt_wq);
+ kfree(sinfo->tx.api_dcb_chain);
+ sinfo->tx.api_dcb_chain = NULL;
+ sinfo->tx.api_dcb_chain_end = NULL;
+ if (!sinfo->napi_poll_mode) {
+ /* Not need to yield for Continuous DMA mode */
+ sinfo->tx_yield = 0;
+ }
+ } else {
+ if (sinfo->tx.free == MAX_TX_DCBS) {
+ /* Try API Tx if SKB Tx done */
+ bkn_api_tx(sinfo);
+ if (sinfo->tx.api_active) {
+ return;
+ }
+ }
+ }
+
+ /* Resume if netif Tx resources available and API Tx not active */
+ bkn_resume_tx(sinfo);
+}
+
+static void
+bkn_tx_chain_done(bkn_switch_info_t *sinfo, int done)
+{
+ bkn_desc_info_t *desc;
+ int idx, pending;
+ bkn_evt_resource_t *evt;
+
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ return bkn_tx_cdma_chain_done(sinfo, done);
+ }
+
+ DBG_IRQ(("Tx chain done (%d/%d)\n", sinfo->tx.cur, sinfo->tx.dirty));
+
+ dev_irq_mask_disable(sinfo, XGS_DMA_TX_CHAN, 0);
+
+ evt = &_bkn_evt[sinfo->evt_idx];
+
+ if (sinfo->tx.api_active) {
+ sinfo->dma_events |= KCOM_DMA_INFO_F_TX_DONE;
+ evt->evt_wq_put++;
+ wake_up_interruptible(&evt->evt_wq);
+ /* Check if BCM API has more to send */
+ bkn_api_tx(sinfo);
+ if (sinfo->tx.api_active) {
+ return;
+ }
+ }
+
+ if (sinfo->tx.free == MAX_TX_DCBS) {
+ /* If netif Tx is idle then allow BCM API to send */
+ bkn_api_tx(sinfo);
+ if (sinfo->tx.api_active) {
+ return;
+ }
+ } else {
+ /* If two or more DCBs are pending, chain them */
+ pending = MAX_TX_DCBS - sinfo->tx.free;
+ idx = sinfo->tx.dirty;
+ while (--pending && idx < (MAX_TX_DCBS - 1)) {
+ if (sinfo->cmic_type == 'x') {
+ sinfo->tx.desc[idx++].dcb_mem[2] |= 1 << 16;
+ } else {
+ sinfo->tx.desc[idx++].dcb_mem[1] |= 1 << 16;
+ }
+ DBG_DCB_TX(("Chain Tx DCB %d (%d)\n", idx, pending));
+ }
+ /* Restart DMA from where we stopped */
+ desc = &sinfo->tx.desc[sinfo->tx.dirty];
+ DBG_DCB_TX(("Restart Tx DMA, DCB @ 0x%08x (%d).\n",
+ (uint32_t)desc->dcb_dma, sinfo->tx.dirty));
+ dev_dma_chan_clear(sinfo, XGS_DMA_TX_CHAN);
+ dev_irq_mask_enable(sinfo, XGS_DMA_TX_CHAN, 0);
+ dev_dma_chan_start(sinfo, XGS_DMA_TX_CHAN, desc->dcb_dma);
+ }
+
+ /* Resume if netif Tx resources available and API Tx not active */
+ bkn_resume_tx(sinfo);
+}
+
+static void
+bkn_schedule_napi_poll(bkn_switch_info_t *sinfo)
+{
+ /* Schedule NAPI poll */
+ DBG_NAPI(("Schedule NAPI poll on %s.\n", sinfo->dev->name));
+ /* Disable interrupts until poll job is complete */
+ sinfo->napi_poll_mode = 1;
+ /* Unlock while calling up network stack */
+ spin_unlock(&sinfo->lock);
+ if (bkn_napi_schedule_prep(sinfo->dev, &sinfo->napi)) {
+ __bkn_napi_schedule(sinfo->dev, &sinfo->napi);
+ DBG_NAPI(("Schedule prep OK on %s.\n", sinfo->dev->name));
+ } else {
+ /* Most likely the base device is has not been opened */
+ gprintk("Warning: Unable to schedule NAPI - base device not up?\n");
+ }
+ spin_lock(&sinfo->lock);
+}
+
+static void
+bkn_napi_poll_complete(bkn_switch_info_t *sinfo)
+{
+ /* Unlock while calling up network stack */
+ spin_unlock(&sinfo->lock);
+ bkn_napi_complete(sinfo->dev, &sinfo->napi);
+ spin_lock(&sinfo->lock);
+ /* Re-enable interrupts */
+ sinfo->napi_poll_mode = 0;
+ dev_irq_mask_set(sinfo, sinfo->irq_mask);
+}
+
+static int
+xgs_do_dma(bkn_switch_info_t *sinfo, int budget)
+{
+ int rx_dcbs_done = 0, tx_dcbs_done = 0;
+ int chan_done, budget_chans = 0;
+ uint32_t dma_stat;
+ int chan;
+
+ DEV_READ32(sinfo, CMIC_DMA_STATr, &dma_stat);
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (dma_stat & DS_DESC_DONE_TST(XGS_DMA_RX_CHAN + chan)) {
+ xgs_dma_desc_clear(sinfo, XGS_DMA_RX_CHAN + chan);
+ sinfo->poll_channels |= 1 << chan;
+ }
+ }
+ if (!sinfo->poll_channels) {
+ sinfo->poll_channels = (uint32_t)(1 << sinfo->rx_chans) - 1;
+ budget_chans = budget / sinfo->rx_chans;
+ } else {
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (1 << chan & sinfo->poll_channels) {
+ budget_chans++;
+ }
+ }
+ budget_chans = budget / budget_chans;
+ }
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (1 << chan & sinfo->poll_channels) {
+ chan_done = bkn_do_rx(sinfo, chan, budget_chans);
+ rx_dcbs_done += chan_done;
+ if (chan_done < budget_chans) {
+ sinfo->poll_channels &= ~(1 << chan);
+ }
+ bkn_rx_desc_done(sinfo, chan);
+ }
+
+ if (dma_stat & DS_CHAIN_DONE_TST(XGS_DMA_RX_CHAN + chan)) {
+ xgs_dma_chain_clear(sinfo, XGS_DMA_RX_CHAN + chan);
+ bkn_rx_chain_done(sinfo, chan);
+ }
+ }
+
+ if (dma_stat & DS_CHAIN_DONE_TST(XGS_DMA_TX_CHAN)) {
+ xgs_dma_chain_clear(sinfo, XGS_DMA_TX_CHAN);
+ tx_dcbs_done = bkn_do_tx(sinfo);
+ bkn_tx_chain_done(sinfo, tx_dcbs_done);
+ }
+
+ return sinfo->poll_channels ? budget : rx_dcbs_done;
+}
+
+static int
+xgsm_do_dma(bkn_switch_info_t *sinfo, int budget)
+{
+ int rx_dcbs_done = 0, tx_dcbs_done = 0;
+ int chan_done, budget_chans = 0;
+ uint32_t dma_stat, irq_stat = 0;
+ int chan;
+
+ /* Get Controlled interrupt states for Continuous DMA mode */
+ if (sinfo->cdma_channels) {
+ DEV_READ32(sinfo, CMICM_IRQ_STATr, &irq_stat);
+ }
+
+ DEV_READ32(sinfo, CMICM_DMA_STATr, &dma_stat);
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (dma_stat & (0x10 << (XGS_DMA_RX_CHAN + chan)) ||
+ irq_stat & (0x08000000 << (XGS_DMA_RX_CHAN + chan))) {
+ xgsm_dma_desc_clear(sinfo, XGS_DMA_RX_CHAN + chan);
+ sinfo->poll_channels |= 1 << chan;
+ }
+ }
+ if (!sinfo->poll_channels) {
+ sinfo->poll_channels = (uint32_t)(1 << sinfo->rx_chans) - 1;
+ budget_chans = budget / sinfo->rx_chans;
+ } else {
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (1 << chan & sinfo->poll_channels) {
+ budget_chans++;
+ }
+ }
+ budget_chans = budget / budget_chans;
+ }
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (1 << chan & sinfo->poll_channels) {
+ chan_done = bkn_do_rx(sinfo, chan, budget_chans);
+ rx_dcbs_done += chan_done;
+ if (chan_done < budget_chans) {
+ sinfo->poll_channels &= ~(1 << chan);
+ }
+ bkn_rx_desc_done(sinfo, chan);
+ }
+
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ continue;
+ }
+
+ if (dma_stat & (0x1 << (XGS_DMA_RX_CHAN + chan))) {
+ xgsm_dma_chain_clear(sinfo, XGS_DMA_RX_CHAN + chan);
+ bkn_rx_chain_done(sinfo, chan);
+ }
+ }
+
+ if (dma_stat & (0x1 << XGS_DMA_TX_CHAN) ||
+ irq_stat & (0x08000000 << XGS_DMA_TX_CHAN)) {
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ xgsm_dma_desc_clear(sinfo, XGS_DMA_TX_CHAN);
+ } else {
+ xgsm_dma_chain_clear(sinfo, XGS_DMA_TX_CHAN);
+ }
+ tx_dcbs_done = bkn_do_tx(sinfo);
+ bkn_tx_chain_done(sinfo, tx_dcbs_done);
+ }
+
+ return sinfo->poll_channels ? budget : rx_dcbs_done;
+}
+
+static int
+xgsx_do_dma(bkn_switch_info_t *sinfo, int budget)
+{
+ int rx_dcbs_done = 0, tx_dcbs_done = 0;
+ int chan_done, budget_chans = 0;
+ uint32_t irq_stat, tx_dma_stat, rx_dma_stat[NUM_CMICX_RX_CHAN];
+ int chan;
+
+ DEV_READ32(sinfo, CMICX_IRQ_STATr, &irq_stat);
+ DEV_READ32(sinfo, CMICX_DMA_STATr + 0x80 * XGS_DMA_TX_CHAN, &tx_dma_stat);
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ DEV_READ32(sinfo,
+ CMICX_DMA_STATr + 0x80 * (XGS_DMA_RX_CHAN + chan),
+ &rx_dma_stat[chan]);
+ }
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if ((irq_stat & CMICX_DS_CMC_CTRLD_INT(XGS_DMA_RX_CHAN + chan)) ||
+ (irq_stat & CMICX_DS_CMC_DESC_DONE(XGS_DMA_RX_CHAN + chan))) {
+ xgsx_dma_desc_clear(sinfo, XGS_DMA_RX_CHAN + chan);
+ sinfo->poll_channels |= 1 << chan;
+ }
+ }
+ if (!sinfo->poll_channels) {
+ sinfo->poll_channels = (uint32_t)(1 << sinfo->rx_chans) - 1;
+ budget_chans = budget / sinfo->rx_chans;
+ } else {
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (1 << chan & sinfo->poll_channels) {
+ budget_chans++;
+ }
+ }
+ budget_chans = budget / budget_chans;
+ }
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (1 << chan & sinfo->poll_channels) {
+ chan_done = bkn_do_rx(sinfo, chan, budget_chans);
+ rx_dcbs_done += chan_done;
+ if (chan_done < budget_chans) {
+ sinfo->poll_channels &= ~(1 << chan);
+ }
+ bkn_rx_desc_done(sinfo, chan);
+ }
+
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ continue;
+ }
+
+ if (rx_dma_stat[chan] & CMICX_DS_CMC_DMA_CHAIN_DONE) {
+ xgsx_dma_chain_clear(sinfo, XGS_DMA_RX_CHAN + chan);
+ bkn_rx_chain_done(sinfo, chan);
+ }
+ }
+
+ if ((irq_stat & CMICX_DS_CMC_CTRLD_INT(XGS_DMA_TX_CHAN)) ||
+ (tx_dma_stat & CMICX_DS_CMC_DMA_CHAIN_DONE)) {
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ xgsx_dma_desc_clear(sinfo, XGS_DMA_TX_CHAN);
+ } else {
+ xgsx_dma_chain_clear(sinfo, XGS_DMA_TX_CHAN);
+ }
+ tx_dcbs_done = bkn_do_tx(sinfo);
+ bkn_tx_chain_done(sinfo, tx_dcbs_done);
+ }
+
+ return sinfo->poll_channels ? budget : rx_dcbs_done;
+}
+
+static int
+dev_do_dma(bkn_switch_info_t *sinfo, int budget)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ return xgsx_do_dma(sinfo, budget);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ return xgsm_do_dma(sinfo, budget);
+ } else {
+ return xgs_do_dma(sinfo, budget);
+ }
+}
+
+static void
+xgs_isr(bkn_switch_info_t *sinfo)
+{
+ uint32_t irq_stat;
+ int rx_dcbs_done;
+
+ DEV_READ32(sinfo, CMIC_IRQ_STATr, &irq_stat);
+ if ((irq_stat & sinfo->irq_mask) == 0) {
+ /* Not ours */
+ return;
+ }
+ sinfo->interrupts++;
+
+ DBG_IRQ(("Got interrupt on device %d (0x%08x)\n",
+ sinfo->dev_no, irq_stat));
+
+ if (use_napi) {
+ bkn_schedule_napi_poll(sinfo);
+ } else {
+ xgs_irq_mask_set(sinfo, 0);
+ do {
+ rx_dcbs_done = xgs_do_dma(sinfo, MAX_RX_DCBS);
+ } while (rx_dcbs_done);
+ }
+
+ xgs_irq_mask_set(sinfo, sinfo->irq_mask);
+}
+
+static void
+xgsm_isr(bkn_switch_info_t *sinfo)
+{
+ uint32_t irq_stat;
+ int rx_dcbs_done;
+
+ DEV_READ32(sinfo, CMICM_IRQ_STATr, &irq_stat);
+ if ((irq_stat & sinfo->irq_mask) == 0) {
+ /* Not ours */
+ return;
+ }
+ sinfo->interrupts++;
+
+ DBG_IRQ(("Got interrupt on device %d (0x%08x)\n",
+ sinfo->dev_no, irq_stat));
+
+ if (use_napi) {
+ bkn_schedule_napi_poll(sinfo);
+ } else {
+ xgsm_irq_mask_set(sinfo, 0);
+ do {
+ rx_dcbs_done = xgsm_do_dma(sinfo, MAX_RX_DCBS);
+ if (sinfo->cdma_channels) {
+ if (rx_dcbs_done >= MAX_RX_DCBS || sinfo->tx_yield) {
+ /* Continuous DMA mode requires to yield timely */
+ break;
+ }
+ }
+ } while (rx_dcbs_done);
+ }
+
+ xgsm_irq_mask_set(sinfo, sinfo->irq_mask);
+}
+
+static void
+xgsx_isr(bkn_switch_info_t *sinfo)
+{
+ uint32_t irq_stat;
+ int rx_dcbs_done;
+
+ DEV_READ32(sinfo, CMICX_IRQ_STATr, &irq_stat);
+ if ((irq_stat & sinfo->irq_mask) == 0) {
+ /* Not ours */
+ return;
+ }
+ sinfo->interrupts++;
+
+ DBG_IRQ(("Got interrupt on device %d (0x%08x)\n",
+ sinfo->dev_no, irq_stat));
+
+ if (use_napi) {
+ bkn_schedule_napi_poll(sinfo);
+ } else {
+ xgsx_irq_mask_set(sinfo, 0);
+ do {
+ rx_dcbs_done = xgsx_do_dma(sinfo, MAX_RX_DCBS);
+ if (sinfo->cdma_channels) {
+ if (rx_dcbs_done >= MAX_RX_DCBS || sinfo->tx_yield) {
+ /* Continuous DMA mode requires to yield timely */
+ break;
+ }
+ }
+ } while (rx_dcbs_done);
+ }
+
+ xgsx_irq_mask_set(sinfo, sinfo->irq_mask);
+}
+
+static void
+bkn_isr(void *isr_data)
+{
+ bkn_switch_info_t *sinfo = isr_data;
+
+ /* Safe exit on SMP systems */
+ if (!module_initialized) {
+ return;
+ }
+
+ /* Ensure that we do not touch registers during device reset */
+ if (sinfo->irq_mask == 0) {
+ /* Not ours */
+ return;
+ }
+
+ spin_lock(&sinfo->lock);
+
+ if (sinfo->napi_poll_mode) {
+ /* Not ours */
+ spin_unlock(&sinfo->lock);
+ return;
+ }
+
+ if (DEV_IS_CMICX(sinfo)) {
+ xgsx_isr(sinfo);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ xgsm_isr(sinfo);
+ } else {
+ xgs_isr(sinfo);
+ }
+
+ spin_unlock(&sinfo->lock);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void
+bkn_poll_controller(struct net_device *dev)
+{
+ bkn_priv_t *priv = netdev_priv(dev);
+
+ disable_irq(dev->irq);
+ bkn_isr(priv->sinfo);
+ enable_irq(dev->irq);
+}
+#endif
+
+static void
+bkn_resume_rx(bkn_switch_info_t *sinfo)
+{
+ bkn_desc_info_t *desc;
+ bkn_dcb_chain_t *dcb_chain;
+ uint64_t cur_halt, last_dcb, dcb_dma;
+ int woffset, chan, cdma_running;
+
+ /* Resume Rx DMA on all channels */
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (sinfo->rx[chan].use_rx_skb) {
+ cdma_running = 0;
+ bkn_api_rx_restart(sinfo, chan);
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ cur_halt = sinfo->halt_addr[XGS_DMA_RX_CHAN + chan];
+ last_dcb = sinfo->rx[chan].desc[MAX_RX_DCBS].dcb_dma;
+ if (cur_halt != last_dcb) {
+ desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty + 1];
+ bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, desc->dcb_dma);
+ cdma_running = 1;
+ }
+ }
+ if (!cdma_running) {
+ bkn_rx_restart(sinfo, chan);
+ }
+ } else {
+ cdma_running = 0;
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ if (sinfo->rx[chan].api_active) {
+ dcb_chain = sinfo->rx[chan].api_dcb_chain_end;
+ woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize;
+ dcb_dma = dcb_chain->dcb_dma + woffset * sizeof(uint32_t);
+ bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, dcb_dma);
+ cdma_running = 1;
+ }
+ }
+ if (!cdma_running) {
+ bkn_api_rx_restart(sinfo, chan);
+ }
+ }
+ }
+}
+
+static int
+bkn_open(struct net_device *dev)
+{
+ bkn_priv_t *priv = netdev_priv(dev);
+ bkn_switch_info_t *sinfo = priv->sinfo;
+ unsigned long flags;
+
+ /* Check if base device */
+ if (priv->id <= 0) {
+ /* NAPI used only on base device */
+ if (use_napi) {
+ bkn_napi_enable(dev, &sinfo->napi);
+ }
+
+ /* Start DMA when base device is started */
+ if (sinfo->basedev_suspended) {
+ spin_lock_irqsave(&sinfo->lock, flags);
+ dev_do_dma(sinfo, MAX_RX_DCBS);
+ sinfo->basedev_suspended = 0;
+ bkn_api_tx(sinfo);
+ if (!sinfo->tx.api_active) {
+ bkn_resume_tx(sinfo);
+ }
+ bkn_resume_rx(sinfo);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ }
+ }
+
+ if (!sinfo->basedev_suspended) {
+ netif_start_queue(dev);
+ }
+
+ return 0;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
+static int
+bkn_set_mac_address(struct net_device *dev, void *addr)
+{
+ if (!is_valid_ether_addr(((struct sockaddr *)addr)->sa_data)) {
+ return -EINVAL;
+ }
+ memcpy(dev->dev_addr, ((struct sockaddr *)addr)->sa_data, dev->addr_len);
+ return 0;
+}
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
+static int
+bkn_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ bkn_priv_t *priv = netdev_priv(dev);
+ bkn_switch_info_t *sinfo = priv->sinfo;
+ struct hwtstamp_config config;
+
+ if (cmd == SIOCSHWTSTAMP) {
+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) {
+ return -EFAULT;
+ }
+
+ if (!knet_hw_tstamp_enable_cb || !knet_hw_tstamp_disable_cb ||
+ priv->type != KCOM_NETIF_T_PORT) {
+ return -ERANGE;
+ }
+
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ knet_hw_tstamp_disable_cb(sinfo->dev_no, priv->port);
+ sinfo->tx_hwts = 0;
+ break;
+ case HWTSTAMP_TX_ON:
+ knet_hw_tstamp_enable_cb(sinfo->dev_no, priv->port);
+ sinfo->tx_hwts = 1;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ if (sinfo->rx_hwts) {
+ knet_hw_tstamp_disable_cb(sinfo->dev_no, priv->port);
+ sinfo->rx_hwts = 0;
+ }
+ break;
+ default:
+ if (!sinfo->rx_hwts) {
+ knet_hw_tstamp_enable_cb(sinfo->dev_no, priv->port);
+ sinfo->rx_hwts = 1;
+ }
+ config.rx_filter = HWTSTAMP_FILTER_ALL;
+ break;
+ }
+
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0;
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
+ if (cmd == SIOCGHWTSTAMP) {
+ config.flags = 0;
+ config.tx_type = sinfo->tx_hwts ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
+ config.rx_filter = sinfo->rx_hwts ? HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE;
+
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0;
+ }
+#endif
+
+ return -EINVAL;
+}
+#endif
+
+static int
+bkn_change_mtu(struct net_device *dev, int new_mtu)
+{
+ int max_size = new_mtu + ETH_HLEN + VLAN_HLEN + 4;
+
+ if (new_mtu < 68 || max_size > rx_buffer_size) {
+ return -EINVAL;
+ }
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+static int
+bkn_poll(struct net_device *dev, int *budget)
+{
+ bkn_priv_t *priv = netdev_priv(dev);
+ bkn_switch_info_t *sinfo = priv->sinfo;
+ int cur_budget = *budget;
+ int poll_again = 0;
+ int rx_dcbs_done;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ DBG_NAPI(("NAPI poll on %s.\n", dev->name));
+
+ sinfo->napi_poll_again = 0;
+
+ if (cur_budget > dev->quota) {
+ cur_budget = dev->quota;
+ }
+
+ rx_dcbs_done = dev_do_dma(sinfo, cur_budget);
+
+ *budget -= rx_dcbs_done;
+ cur_budget -= rx_dcbs_done;
+ dev->quota -= rx_dcbs_done;
+
+ if (sinfo->napi_poll_again || cur_budget <= 0) {
+ poll_again = 1;
+ sinfo->napi_not_done++;
+ } else {
+ bkn_napi_poll_complete(sinfo);
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return poll_again;
+}
+#else
+static int
+bkn_poll(struct napi_struct *napi, int budget)
+{
+ bkn_switch_info_t *sinfo = container_of(napi, bkn_switch_info_t, napi);
+ int rx_dcbs_done;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ DBG_NAPI(("NAPI poll on %s.\n", sinfo->dev->name));
+
+ sinfo->napi_poll_again = 0;
+
+ rx_dcbs_done = dev_do_dma(sinfo, budget);
+
+ if (sinfo->napi_poll_again || rx_dcbs_done >= budget) {
+ /* Force poll again */
+ rx_dcbs_done = budget;
+ sinfo->napi_not_done++;
+ } else {
+ bkn_napi_poll_complete(sinfo);
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return rx_dcbs_done;
+}
+#endif
+
+static int
+bkn_stop(struct net_device *dev)
+{
+ bkn_priv_t *priv = netdev_priv(dev);
+ bkn_switch_info_t *sinfo = priv->sinfo;
+ unsigned long flags;
+
+ netif_stop_queue(dev);
+
+ /* Check if base device */
+ if (priv->id <= 0) {
+ /* NAPI used only on base device */
+ if (use_napi) {
+ bkn_napi_disable(dev, &sinfo->napi);
+ }
+ /* Suspend all devices if base device is stopped */
+ if (basedev_suspend) {
+ spin_lock_irqsave(&sinfo->lock, flags);
+ bkn_suspend_tx(sinfo);
+ sinfo->basedev_suspended = 1;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Network Device Statistics.
+ * Cleared at init time.
+ */
+static struct net_device_stats *
+bkn_get_stats(struct net_device *dev)
+{
+ bkn_priv_t *priv = netdev_priv(dev);
+
+ return &priv->stats;
+}
+
+/* Fake multicast ability */
+static void
+bkn_set_multicast_list(struct net_device *dev)
+{
+}
+
+static int
+bkn_hw_tstamp_tx_config(bkn_switch_info_t *sinfo, struct sk_buff *skb, uint32_t *meta)
+{
+ uint32_t *md = NULL;
+
+ if (!knet_hw_tstamp_tx_meta_get_cb) {
+ return -1;
+ }
+
+ KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF;
+ knet_hw_tstamp_tx_meta_get_cb(sinfo->dev_no, skb, &md);
+ if (!md) {
+ return -1;
+ }
+
+ switch (sinfo->dcb_type) {
+ case 26:
+ case 32:
+ case 33:
+ meta[2] |= md[0];
+ meta[3] |= md[1];
+ meta[4] |= md[2];
+ meta[5] |= md[3];
+ break;
+ case 36:
+ case 38:
+ meta[0] |= md[0];
+ meta[1] |= md[1];
+ meta[2] |= md[2];
+ meta[3] |= md[3];
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+bkn_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ bkn_priv_t *priv = netdev_priv(dev);
+ bkn_switch_info_t *sinfo = priv->sinfo;
+ struct sk_buff *new_skb = NULL;
+ unsigned char *pktdata;
+ int pktlen, hdrlen, taglen, rcpulen, metalen;
+ int sop, idx;
+ uint16_t tpid;
+ uint32_t *metadata;
+ unsigned long flags;
+
+ DBG_VERB(("Netif Tx: Len=%d\n", skb->len));
+
+ if (priv->id <= 0) {
+ /* Do not transmit on base device */
+ priv->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+
+ if (!netif_carrier_ok(dev)) {
+ DBG_WARN(("Tx drop: Invalid RCPU encapsulation\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_no_link++;
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ if (sinfo->tx.free > 1) {
+ bkn_desc_info_t *desc = &sinfo->tx.desc[sinfo->tx.cur];
+ uint32_t *dcb, *meta;
+
+ pktdata = skb->data;
+ pktlen = skb->len;
+ hdrlen = (sinfo->cmic_type == 'x' ) ? ((device_is_dnx(sinfo)) ? priv->system_headers_size: PKT_TX_HDR_SIZE) : 0;
+ rcpulen = 0;
+ sop = 0;
+
+ if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) {
+ rcpulen = RCPU_HDR_SIZE;
+ if (skb->len < (rcpulen + 14)) {
+ DBG_WARN(("Tx drop: Invalid RCPU encapsulation\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_rcpu_encap++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ if (check_rcpu_signature &&
+ ((skb->data[18] << 8) | skb->data[19]) != sinfo->rcpu_sig) {
+ DBG_WARN(("Tx drop: Invalid RCPU signature\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_rcpu_sig++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ if (skb->data[21] & RCPU_F_MODHDR) {
+ sop = skb->data[RCPU_HDR_SIZE];
+ switch (sop) {
+ case 0xff:
+ case 0x81:
+ case 0xfb:
+ case 0xfc:
+ break;
+ default:
+ DBG_WARN(("Tx drop: Invalid RCPU meta data\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_rcpu_meta++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ if (sinfo->cmic_type != 'x') {
+ rcpulen += RCPU_TX_META_SIZE;
+ }
+ }
+ /* Skip over RCPU encapsulation */
+ pktdata = &skb->data[rcpulen];
+ pktlen -= rcpulen;
+
+ /* CPU packets require tag */
+ if (sop == 0) {
+ hdrlen = 0;
+ tpid = (pktdata[12] << 8) | pktdata[13];
+ if (tpid != 0x8100) {
+ if (skb_header_cloned(skb)) {
+ /* Current SKB cannot be modified */
+ DBG_SKB(("Realloc Tx SKB\n"));
+ new_skb = dev_alloc_skb(pktlen + TAG_SZ + FCS_SZ);
+ if (new_skb == NULL) {
+ DBG_WARN(("Tx drop: No SKB memory\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_no_skb++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ memcpy(new_skb->data, pktdata, 12);
+ memcpy(&new_skb->data[16], &pktdata[12], pktlen - 12);
+ skb_put(new_skb, pktlen + TAG_SZ);
+ dev_kfree_skb_any(skb);
+ skb = new_skb;
+ pktdata = skb->data;
+ rcpulen = 0;
+ } else {
+ /* Add tag to RCPU header space */
+ DBG_SKB(("Expand into unused RCPU header\n"));
+ rcpulen -= TAG_SZ;
+ pktdata = &skb->data[rcpulen];
+ for (idx = 0; idx < 12; idx++) {
+ pktdata[idx] = pktdata[idx + TAG_SZ];
+ }
+ }
+ pktdata[12] = 0x81;
+ pktdata[13] = 0x00;
+ pktdata[14] = (priv->vlan >> 8) & 0xf;
+ pktdata[15] = priv->vlan & 0xff;
+ pktlen += TAG_SZ;
+ }
+ }
+ } else {
+ if (sinfo->cmic_type == 'x' && priv->port >= 0) {
+ if (skb_header_cloned(skb) || skb_headroom(skb) < hdrlen + 4) {
+ /* Current SKB cannot be modified */
+ DBG_SKB(("Realloc Tx SKB\n"));
+ new_skb = dev_alloc_skb(pktlen + hdrlen + 4 + FCS_SZ);
+ if (new_skb == NULL) {
+ DBG_WARN(("Tx drop: No SKB memory\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_no_skb++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ if (!device_is_dnx(sinfo))
+ {
+ skb_reserve(new_skb, 4);
+ }
+ memcpy(new_skb->data + hdrlen, skb->data, pktlen);
+ skb_put(new_skb, pktlen + hdrlen);
+ dev_kfree_skb_any(skb);
+ skb = new_skb;
+ } else {
+ DBG_SKB(("Expand Tx SKB\n"));
+ skb_push(skb, hdrlen);
+ }
+ memset(skb->data, 0, hdrlen);
+ pktdata = skb->data;
+ pktlen += hdrlen;
+ } else {
+ hdrlen = 0;
+ }
+
+ if (priv->port < 0 || (priv->flags & KCOM_NETIF_F_ADD_TAG)) {
+ DBG_DUNE(("ADD VLAN TAG\n"));
+ /* Need to add VLAN tag if packet is untagged */
+ tpid = (skb->data[hdrlen + 12] << 8) | skb->data[hdrlen + 13];
+ if (tpid != 0x8100) {
+ if (skb_header_cloned(skb) || skb_headroom(skb) < 4) {
+ /* Current SKB cannot be modified */
+ DBG_SKB(("Realloc Tx SKB\n"));
+ new_skb = dev_alloc_skb(pktlen + TAG_SZ + FCS_SZ);
+ if (new_skb == NULL) {
+ DBG_WARN(("Tx drop: No SKB memory\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_no_skb++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ memcpy(new_skb->data, skb->data, hdrlen + 12);
+ memcpy(&new_skb->data[hdrlen + 16], &skb->data[hdrlen + 12],
+ pktlen - hdrlen - 12);
+ skb_put(new_skb, pktlen + TAG_SZ);
+ dev_kfree_skb_any(skb);
+ skb = new_skb;
+ } else {
+ /* Add tag to existing buffer */
+ DBG_SKB(("Expand Tx SKB\n"));
+ skb_push(skb, TAG_SZ);
+ for (idx = 0; idx < hdrlen + 12; idx++) {
+ skb->data[idx] = skb->data[idx + TAG_SZ];
+ }
+ }
+ pktdata = skb->data;
+ pktdata[hdrlen + 12] = 0x81;
+ pktdata[hdrlen + 13] = 0x00;
+ pktdata[hdrlen + 14] = (priv->vlan >> 8) & 0xf;
+ pktdata[hdrlen + 15] = priv->vlan & 0xff;
+ pktlen += TAG_SZ;
+ }
+ }
+ }
+
+ /* Pad packet if needed */
+ taglen = 0;
+ tpid = (pktdata[hdrlen + 12] << 8) | pktdata[hdrlen + 13];
+ if (tpid == 0x8100) {
+ taglen = 4;
+ }
+ if (pktlen < (60 + taglen + hdrlen)) {
+ pktlen = (60 + taglen + hdrlen);
+ if (SKB_PADTO(skb, pktlen) != 0) {
+ DBG_WARN(("Tx drop: skb_padto failed\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_pad_fail++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ /* skb_padto may update the skb->data pointer */
+ pktdata = &skb->data[rcpulen];
+ }
+
+ if ((pktlen + FCS_SZ) > SOC_DCB_KNET_COUNT_MASK) {
+ DBG_WARN(("Tx drop: size of pkt (%d) is out of range(%d)\n",
+ (pktlen + FCS_SZ), SOC_DCB_KNET_COUNT_MASK));
+ sinfo->tx.pkts_d_over_limit++;
+ priv->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+
+ dcb = desc->dcb_mem;
+ meta = (sinfo->cmic_type == 'x') ? (uint32_t *)pktdata : dcb;
+ memset(dcb, 0, sinfo->dcb_wsize * sizeof(uint32_t));
+ if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) {
+ /* If module header SOP is non-zero, use RCPU meta data */
+ if (sop != 0) {
+ if (sinfo->cmic_type == 'x') {
+ dcb[2] |= 1 << 19;
+ } else {
+ metalen = (sinfo->dcb_wsize - 3) * sizeof(uint32_t);
+ if (metalen > RCPU_TX_META_SIZE) {
+ metalen = RCPU_TX_META_SIZE;
+ }
+ metadata = (uint32_t *)&skb->data[RCPU_HDR_SIZE];
+ for (idx = 0; idx < BYTES2WORDS(metalen); idx++) {
+ dcb[idx + 2] = ntohl(metadata[idx]);
+ }
+ dcb[1] |= 1 << 19;
+ }
+ }
+ } else if (priv->port >= 0) {
+ /* Send to physical port */
+ if (sinfo->cmic_type == 'x') {
+ dcb[2] |= 1 << 19;
+ } else {
+ dcb[1] |= 1 << 19;
+ }
+ switch (sinfo->dcb_type) {
+ case 23:
+ case 26:
+ case 30:
+ case 31:
+ case 34:
+ case 37:
+ dcb[2] = 0x81000000;
+ dcb[3] = priv->port;
+ dcb[3] |= (priv->qnum & 0xc00) << 20;
+ dcb[4] = 0x00040000;
+ dcb[4] |= (priv->qnum & 0x3ff) << 8;
+ break;
+ case 24:
+ dcb[2] = 0xff000000;
+ dcb[3] = 0x00000100;
+ dcb[4] = priv->port;
+ dcb[4] |= (priv->qnum & 0xfff) << 14;
+ break;
+ case 28:
+ {
+ if (priv->type == KCOM_NETIF_T_PORT) {
+ /* add PTCH ITMH header */
+ if (skb_header_cloned(skb) || skb_headroom(skb) < 4) {
+ /* Current SKB cannot be modified */
+ DBG_SKB(("Realloc Tx SKB for DNX ITMH header\n"));
+ new_skb = dev_alloc_skb(pktlen + 4 + 2 + FCS_SZ);
+ if (new_skb == NULL) {
+ DBG_WARN(("Tx drop: No SKB memory for DNX ITMH header\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_no_skb++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ memcpy(&new_skb->data[6], skb->data, pktlen);
+ skb_put(new_skb, pktlen + 6);
+ dev_kfree_skb_any(skb);
+ skb = new_skb;
+ } else {
+ /* Add tag to existing buffer */
+ DBG_SKB(("Expand Tx SKB for DNX ITMH header\n"));
+ skb_push(skb, 6);
+ }
+ pktdata = skb->data;
+ pktdata[0] = 0x50;
+ pktdata[1] = 0x00;
+ memcpy(&pktdata[2], priv->itmh, 4);
+ pktlen += 6;
+ }
+ else if (priv->type == KCOM_NETIF_T_VLAN) {
+ /* add PTCH header */
+ if (skb_header_cloned(skb) || skb_headroom(skb) < 4) {
+ /* Current SKB cannot be modified */
+ DBG_SKB(("Realloc Tx SKB for DNX header\n"));
+ new_skb = dev_alloc_skb(pktlen + 2 + FCS_SZ);
+ if (new_skb == NULL) {
+ DBG_WARN(("Tx drop: No SKB memory for DNX header\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_no_skb++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ memcpy(&new_skb->data[2], skb->data, pktlen);
+ skb_put(new_skb, pktlen + 2);
+ dev_kfree_skb_any(skb);
+ skb = new_skb;
+ } else {
+ /* Add tag to existing buffer */
+ DBG_SKB(("Expand Tx SKB for DNX header\n"));
+ skb_push(skb, 2);
+ }
+ pktdata = skb->data;
+ pktdata[0] = 0xd0;
+ pktdata[1] = priv->port;
+ pktlen += 2;
+ }
+ dcb[1] = pktlen;
+ break;
+ }
+ case 29:
+ dcb[2] = 0x81000000;
+ dcb[3] = priv->port;
+ dcb[4] = 0x00100000;
+ dcb[4] |= (priv->qnum & 0xfff) << 8;
+ break;
+ case 32:
+ dcb[2] = 0x81000000;
+ dcb[3] = priv->port;
+ dcb[4] = 0x00004000;
+ dcb[4] |= (priv->qnum & 0x3f) << 8;
+ break;
+ case 33:
+ dcb[2] = 0x81000000;
+ dcb[3] = (priv->port) << 2;
+ dcb[4] = 0x00100000;
+ dcb[4] |= (priv->qnum & 0xfff) << 8;
+ break;
+ case 35:
+ dcb[2] = 0x81000000;
+ dcb[3] = (priv->port) << 4;
+ dcb[4] = 0x00400000;
+ dcb[4] |= (priv->qnum & 0x3fff) << 8;
+ break;
+ case 36:
+ if (sinfo->cmic_type == 'x') {
+ meta[0] = htonl(0x81000000);
+ meta[1] = htonl(priv->port);
+ meta[2] = htonl(0x00008000 | (priv->qnum & 0x3f) << 9);
+ } else {
+ dcb[2] = 0x81000000;
+ dcb[3] = priv->port;
+ dcb[4] = 0x00008000;
+ dcb[4] |= (priv->qnum & 0x3f) << 9;
+ }
+ break;
+ case 38:
+ if (sinfo->cmic_type == 'x') {
+ meta[0] = htonl(0x81000000);
+ meta[1] = htonl(priv->port);
+ meta[2] = htonl(0x00004000 | (priv->qnum & 0x3f) << 8);
+ } else {
+ dcb[2] = 0x81000000;
+ dcb[3] = priv->port;
+ dcb[4] = 0x00004000;
+ dcb[4] |= (priv->qnum & 0x3f) << 8;
+ }
+ break;
+ case 39:
+ if (device_is_dnx(sinfo)) {
+ /*
+ * if KCOM_NETIF_T_PORT, add MH+PTCH+ITMH header
+ * if KCOM_NETIF_T_VLAN, add MH+PTCH+header
+ */
+ pktdata = skb->data;
+ memcpy(&pktdata[0], priv->system_headers, priv->system_headers_size);
+ }
+ break;
+ default:
+ dcb[2] = 0xff000000;
+ dcb[3] = 0x00000100;
+ dcb[4] = priv->port;
+ break;
+ }
+ }
+
+ /* Optional SKB updates */
+ if (knet_tx_cb != NULL) {
+ KNET_SKB_CB(skb)->netif_user_data = priv->cb_user_data;
+ KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF;
+ skb = knet_tx_cb(skb, sinfo->dev_no, meta);
+ if (skb == NULL) {
+ /* Consumed by call-back */
+ DBG_WARN(("Tx drop: Consumed by call-back\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_callback++;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ /* Restore (possibly) altered packet variables
+ * bit0 -bit15 of dcb[1] is used to save requested byte count
+ */
+ if ((skb->len + FCS_SZ) <= SOC_DCB_KNET_COUNT_MASK) {
+ pktlen = skb->len;
+ if (pktlen < (60 + taglen + hdrlen)) {
+ pktlen = (60 + taglen + hdrlen);
+ if (SKB_PADTO(skb, pktlen) != 0) {
+ DBG_WARN(("Tx drop: skb_padto failed\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_pad_fail++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ DBG_SKB(("Packet padded to %d bytes after tx callback\n", pktlen));
+ }
+ pktdata = skb->data;
+ if (sinfo->cmic_type == 'x') {
+ meta = (uint32_t *)pktdata;
+ }
+ } else {
+ DBG_WARN(("Tx drop: size of pkt (%d) is out of range(%d)\n",
+ (pktlen + FCS_SZ), SOC_DCB_KNET_COUNT_MASK));
+ sinfo->tx.pkts_d_over_limit++;
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_callback++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ }
+
+ /* Do Tx timestamping */
+ if (priv->port >= 0) {
+ if (bkn_skb_tx_flags(skb) & SKBTX_HW_TSTAMP && sinfo->tx_hwts) {
+ KNET_SKB_CB(skb)->port = priv->port;
+ bkn_hw_tstamp_tx_config(sinfo, skb, meta);
+ bkn_skb_tx_flags(skb) |= SKBTX_IN_PROGRESS;
+ }
+ bkn_skb_tx_timestamp(skb);
+ }
+
+ /* Prepare for DMA */
+ desc->skb = skb;
+ /* Add FCS bytes */
+ pktlen = pktlen + FCS_SZ;
+ desc->dma_size = pktlen;
+ desc->skb_dma = DMA_MAP_SINGLE(sinfo->dma_dev,
+ pktdata, desc->dma_size,
+ DMA_TODEV);
+ if (DMA_MAPPING_ERROR(sinfo->dma_dev, desc->skb_dma)) {
+ priv->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ dcb[0] = desc->skb_dma;
+ if (sinfo->cmic_type == 'x') {
+ dcb[1] = DMA_TO_BUS_HI(desc->skb_dma >> 32);
+ dcb[2] &= ~SOC_DCB_KNET_COUNT_MASK;
+ dcb[2] |= pktlen;
+ } else {
+ dcb[1] &= ~SOC_DCB_KNET_COUNT_MASK;
+ dcb[1] |= pktlen;
+ }
+
+ bkn_dump_dcb("Tx RCPU", dcb, sinfo->dcb_wsize, XGS_DMA_TX_CHAN);
+ DBG_DCB_TX(("Add Tx DCB @ 0x%08x (%d) [%d free] (%d bytes).\n",
+ (uint32_t)desc->dcb_dma, sinfo->tx.cur,
+ sinfo->tx.free, pktlen));
+ bkn_dump_pkt(pktdata, pktlen, XGS_DMA_TX_CHAN);
+
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ if (sinfo->cmic_type == 'x') {
+ dcb[2] |= 1 << 24 | 1 << 16;
+ } else {
+ dcb[1] |= 1 << 24 | 1 << 16;
+ }
+ } else {
+ bkn_tx_dma_start(sinfo);
+ }
+ if (++sinfo->tx.cur >= MAX_TX_DCBS) {
+ sinfo->tx.cur = 0;
+ }
+ sinfo->tx.free--;
+
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN) && !sinfo->tx.api_active) {
+ /* DMA run to the new halt location */
+ bkn_cdma_goto(sinfo, XGS_DMA_TX_CHAN,
+ sinfo->tx.desc[sinfo->tx.cur].dcb_dma);
+ }
+
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += pktlen;
+ sinfo->tx.pkts++;
+ } else {
+ DBG_WARN(("Tx drop: No DMA resources\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_dma_resrc++;
+ dev_kfree_skb_any(skb);
+ }
+
+ /* Check our Tx resources */
+ if (sinfo->tx.free <= 1) {
+ bkn_suspend_tx(sinfo);
+ }
+
+ NETDEV_UPDATE_TRANS_START_TIME(dev);
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return 0;
+}
+
+static void
+bkn_timer_func(bkn_switch_info_t *sinfo)
+{
+ unsigned long flags;
+ int chan;
+ int restart_timer;
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ sinfo->timer_runs++;
+
+ restart_timer = 0;
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ /* Restart channel if not running */
+ if (sinfo->rx[chan].running == 0) {
+ bkn_rx_refill(sinfo, chan);
+ if (bkn_rx_restart(sinfo, chan) != 0) {
+ restart_timer = 1;
+ }
+ }
+ }
+
+ if (restart_timer) {
+ /* Presumably still out of memory */
+ sinfo->timer.expires = jiffies + 1;
+ add_timer(&sinfo->timer);
+ } else {
+ sinfo->timer_queued = 0;
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
+static void
+bkn_timer(unsigned long context)
+{
+ bkn_switch_info_t *sinfo = (bkn_switch_info_t *)context;
+ return bkn_timer_func(sinfo);
+}
+#else
+static void
+bkn_timer(struct timer_list *t)
+{
+ bkn_switch_info_t *sinfo = from_timer(sinfo, t, timer);
+ return bkn_timer_func(sinfo);
+}
+#endif
+
+static void
+bkn_rx_add_tokens(bkn_switch_info_t *sinfo, int chan)
+{
+ unsigned long cur_jif, ticks;
+ uint32_t tokens_per_tick;
+ bkn_desc_info_t *desc;
+
+ tokens_per_tick = sinfo->rx[chan].rate_max / HZ;
+ cur_jif = jiffies;
+ ticks = cur_jif - sinfo->rx[chan].tok_jif;
+ sinfo->rx[chan].tokens += ticks * tokens_per_tick;
+ sinfo->rx[chan].tok_jif = cur_jif;
+ if (sinfo->rx[chan].tokens > sinfo->rx[chan].burst_max) {
+ sinfo->rx[chan].tokens = sinfo->rx[chan].burst_max;
+ }
+
+ /* Restart channel if Rx is suppressed */
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ bkn_rx_refill(sinfo, chan);
+ desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty];
+ if (desc->dcb_dma == sinfo->halt_addr[XGS_DMA_RX_CHAN + chan]) {
+ desc = &sinfo->rx[chan].desc[MAX_RX_DCBS];
+ bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, desc->dcb_dma);
+ }
+ } else {
+ if (sinfo->rx[chan].running == 0) {
+ bkn_rx_refill(sinfo, chan);
+ bkn_rx_restart(sinfo, chan);
+ }
+ }
+}
+
+static void
+bkn_rxtick_func(bkn_switch_info_t *sinfo)
+{
+ unsigned long flags;
+ unsigned long cur_jif, ticks;
+ uint32_t pkt_diff;
+ int chan;
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ sinfo->rxtick.expires = jiffies + sinfo->rxtick_jiffies;
+
+ /* For debug purposes we maintain a rough actual packet rate */
+ if (++sinfo->rxticks >= sinfo->rxticks_per_sec) {
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ pkt_diff = sinfo->rx[chan].pkts - sinfo->rx[chan].pkts_ref;
+ cur_jif = jiffies;
+ ticks = cur_jif - sinfo->rx[chan].rate_jif;
+ sinfo->rx[chan].rate = (pkt_diff * HZ) / ticks;
+ sinfo->rx[chan].rate_jif = cur_jif;
+ sinfo->rx[chan].pkts_ref = sinfo->rx[chan].pkts;
+ }
+ sinfo->rxticks = 0;
+ }
+
+ /* Update tokens for Rx rate control */
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (sinfo->rx[chan].tokens < sinfo->rx[chan].burst_max) {
+ bkn_rx_add_tokens(sinfo, chan);
+ }
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ add_timer(&sinfo->rxtick);
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
+static void
+bkn_rxtick(unsigned long context)
+{
+ bkn_switch_info_t *sinfo = (bkn_switch_info_t *)context;
+ return bkn_rxtick_func(sinfo);
+}
+#else
+static void
+bkn_rxtick(struct timer_list *t)
+{
+ bkn_switch_info_t *sinfo = from_timer(sinfo, t, rxtick);
+ return bkn_rxtick_func(sinfo);
+}
+#endif
+
+static void
+bkn_rx_rate_config(bkn_switch_info_t *sinfo)
+{
+ unsigned long flags;
+ int chan;
+ uint32_t rxticks_per_sec, rps;
+ uint32_t jiffies_per_rxtick;
+ uint32_t tokens_per_rxtick;
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ /* Calculate the minimum update frequency across all channels */
+ rxticks_per_sec = 1;
+ for (chan = 0; chan < NUM_RX_CHAN; chan++) {
+ if (sinfo->rx[chan].burst_max == 0) {
+ sinfo->rx[chan].burst_max = sinfo->rx[chan].rate_max / 10;
+ }
+ rps = sinfo->rx[chan].rate_max / sinfo->rx[chan].burst_max;
+ if (rxticks_per_sec < rps) {
+ rxticks_per_sec = rps;
+ }
+ }
+
+ /* Convert update frequency to system ticks */
+ jiffies_per_rxtick = HZ / rxticks_per_sec;
+ if (jiffies_per_rxtick == 0) {
+ jiffies_per_rxtick = 1;
+ }
+ rxticks_per_sec = HZ / jiffies_per_rxtick;
+
+ for (chan = 0; chan < NUM_RX_CHAN; chan++) {
+ /* Ensure that burst size satifies overall rate */
+ tokens_per_rxtick = sinfo->rx[chan].rate_max / rxticks_per_sec;
+ if (sinfo->rx[chan].burst_max < tokens_per_rxtick) {
+ sinfo->rx[chan].burst_max = tokens_per_rxtick;
+ }
+ /* Ensure that rate has a sane value */
+ if (sinfo->rx[chan].rate_max != 0) {
+ if (sinfo->rx[chan].rate_max < rxticks_per_sec) {
+ sinfo->rx[chan].rate_max = rxticks_per_sec;
+ }
+ }
+ sinfo->rx[chan].tokens = sinfo->rx[chan].burst_max;
+ }
+
+ /* Update timer controls */
+ sinfo->rxticks_per_sec = rxticks_per_sec;
+ sinfo->rxtick_jiffies = jiffies_per_rxtick;
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+}
+
+static void
+bkn_destroy_sinfo(bkn_switch_info_t *sinfo)
+{
+ list_del(&sinfo->list);
+ bkn_free_dcbs(sinfo);
+ kfree(sinfo);
+}
+
+static bkn_switch_info_t *
+bkn_create_sinfo(int dev_no)
+{
+ bkn_switch_info_t *sinfo;
+ int chan;
+
+ if ((sinfo = kmalloc(sizeof(*sinfo), GFP_KERNEL)) == NULL) {
+ return NULL;
+ }
+ memset(sinfo, 0, sizeof(*sinfo));
+ INIT_LIST_HEAD(&sinfo->ndev_list);
+ INIT_LIST_HEAD(&sinfo->rxpf_list);
+ sinfo->base_addr = lkbde_get_dev_virt(dev_no);
+ sinfo->dma_dev = lkbde_get_dma_dev(dev_no);
+ sinfo->pdev = lkbde_get_hw_dev(dev_no);
+ sinfo->dev_no = dev_no;
+ sinfo->evt_idx = -1;
+
+ spin_lock_init(&sinfo->lock);
+ skb_queue_head_init(&sinfo->tx_ptp_queue);
+ INIT_WORK(&sinfo->tx_ptp_work, bkn_hw_tstamp_tx_work);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
+ init_timer(&sinfo->timer);
+ sinfo->timer.data = (unsigned long)sinfo;
+ sinfo->timer.function = bkn_timer;
+#else
+ timer_setup(&sinfo->timer, bkn_timer, 0);
+#endif
+ sinfo->timer.expires = jiffies + 1;
+
+ INIT_LIST_HEAD(&sinfo->tx.api_dcb_list);
+
+ for (chan = 0; chan < NUM_RX_CHAN; chan++) {
+ INIT_LIST_HEAD(&sinfo->rx[chan].api_dcb_list);
+ sinfo->rx[chan].use_rx_skb = use_rx_skb;
+ }
+
+ /*
+ * Check for dual DMA mode where Rx DMA channel 0 uses DMA buffers
+ * provided by the BCM API, and the remaining Rx DMA channel(s)
+ * use socket buffers (SKB) provided by the Linux kernel.
+ */
+ if (use_rx_skb == 2) {
+ sinfo->rx[0].use_rx_skb = 0;
+ }
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
+ init_timer(&sinfo->rxtick);
+ sinfo->rxtick.data = (unsigned long)sinfo;
+ sinfo->rxtick.function = bkn_rxtick;
+#else
+ timer_setup(&sinfo->rxtick, bkn_rxtick, 0);
+#endif
+ sinfo->rxtick.expires = jiffies + 1;
+
+ for (chan = 0; chan < NUM_RX_CHAN; chan++) {
+ sinfo->rx[chan].rate_max = rx_rate[chan];
+ sinfo->rx[chan].burst_max = rx_burst[chan];
+ }
+ bkn_rx_rate_config(sinfo);
+
+ add_timer(&sinfo->rxtick);
+
+ list_add_tail(&sinfo->list, &_sinfo_list);
+
+ return sinfo;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
+static const struct net_device_ops bkn_netdev_ops = {
+ .ndo_open = bkn_open,
+ .ndo_stop = bkn_stop,
+ .ndo_start_xmit = bkn_tx,
+ .ndo_get_stats = bkn_get_stats,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_rx_mode = bkn_set_multicast_list,
+ .ndo_set_mac_address = bkn_set_mac_address,
+ .ndo_do_ioctl = bkn_ioctl,
+ .ndo_tx_timeout = NULL,
+ .ndo_change_mtu = bkn_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = bkn_poll_controller,
+#endif
+};
+#endif
+
+static void
+bkn_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
+{
+ strlcpy(drvinfo->driver, "bcm-knet", sizeof(drvinfo->driver));
+ snprintf(drvinfo->version, sizeof(drvinfo->version), "%d", KCOM_VERSION);
+ strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+ strlcpy(drvinfo->bus_info, "N/A", sizeof(drvinfo->bus_info));
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0))
+static int
+bkn_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
+{
+ bkn_priv_t *priv = netdev_priv(dev);
+ bkn_switch_info_t *sinfo = priv->sinfo;
+
+ switch (sinfo->dcb_type) {
+ case 26:
+ case 32:
+ case 33:
+ case 36:
+ case 38:
+ info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+ info->tx_types = 1 << HWTSTAMP_TX_OFF | 1 << HWTSTAMP_TX_ON;
+ info->rx_filters = 1 << HWTSTAMP_FILTER_NONE | 1 << HWTSTAMP_FILTER_ALL;
+ if (knet_hw_tstamp_ptp_clock_index_cb) {
+ info->phc_index = knet_hw_tstamp_ptp_clock_index_cb(sinfo->dev_no);
+ } else {
+ info->phc_index = -1;
+ }
+ break;
+ default:
+ info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE;
+ info->phc_index = -1;
+ break;
+ }
+
+ return 0;
+}
+#endif
+
+static const struct ethtool_ops bkn_ethtool_ops = {
+ .get_drvinfo = bkn_get_drvinfo,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0))
+ .get_ts_info = bkn_get_ts_info,
+#endif
+};
+
+static struct net_device *
+bkn_init_ndev(u8 *mac, char *name)
+{
+ struct net_device *dev;
+
+ /* Create Ethernet device */
+ dev = alloc_etherdev(sizeof(bkn_priv_t));
+
+ if (dev == NULL) {
+ DBG_WARN(("Error allocating Ethernet device.\n"));
+ return NULL;
+ }
+#ifdef SET_MODULE_OWNER
+ SET_MODULE_OWNER(dev);
+#endif
+
+ /* Set the device MAC address */
+ memcpy(dev->dev_addr, mac, 6);
+
+ /* Device information -- not available right now */
+ dev->irq = 0;
+ dev->base_addr = 0;
+
+ /* Default MTU should not exceed MTU of switch front-panel ports */
+ dev->mtu = default_mtu;
+ if (dev->mtu == 0) {
+ dev->mtu = rx_buffer_size;
+ }
+
+ /* Device vectors */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
+ dev->netdev_ops = &bkn_netdev_ops;
+#else
+ dev->open = bkn_open;
+ dev->hard_start_xmit = bkn_tx;
+ dev->stop = bkn_stop;
+ dev->set_multicast_list = bkn_set_multicast_list;
+ dev->do_ioctl = NULL;
+ dev->get_stats = bkn_get_stats;
+ dev->change_mtu = bkn_change_mtu;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = bkn_poll_controller;
+#endif
+#endif
+ dev->ethtool_ops = &bkn_ethtool_ops;
+ if (name && *name) {
+ strncpy(dev->name, name, IFNAMSIZ-1);
+ }
+
+ /* Register the kernel Ethernet device */
+ if (register_netdev(dev)) {
+ DBG_WARN(("Error registering Ethernet device.\n"));
+ free_netdev(dev);
+ return NULL;
+ }
+ DBG_VERB(("Created Ethernet device %s.\n", dev->name));
+
+ return dev;
+}
+
+/*
+ * Device Link Control Proc Read Entry
+ */
+static int
+bkn_proc_link_show(struct seq_file *m, void *v)
+{
+ struct list_head *slist, *dlist;
+ struct net_device *dev;
+ bkn_priv_t *priv;
+ bkn_switch_info_t *sinfo;
+ unsigned long flags;
+
+ seq_printf(m, "Software link status:\n");
+ list_for_each(slist, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)slist;
+ spin_lock_irqsave(&sinfo->lock, flags);
+ list_for_each(dlist, &sinfo->ndev_list) {
+ priv = (bkn_priv_t *)dlist;
+ dev = priv->dev;
+ if (dev) {
+ seq_printf(m, " %-14s %s\n", dev->name,
+ netif_carrier_ok(dev) ? "up" : "down");
+ }
+ }
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ }
+ return 0;
+}
+
+static int
+bkn_proc_link_open(struct inode * inode, struct file * file)
+{
+ return single_open(file, bkn_proc_link_show, NULL);
+}
+
+/*
+ * Device Link Control Proc Write Entry
+ *
+ * Syntax:
+ * <netif>=up|down
+ *
+ * Where <netif> is a virtual network interface name.
+ *
+ * Examples:
+ * eth4=up
+ * eth4=down
+ */
+static ssize_t
+bkn_proc_link_write(struct file *file, const char *buf,
+ size_t count, loff_t *loff)
+{
+ struct list_head *slist, *dlist;
+ struct net_device *dev;
+ bkn_priv_t *priv;
+ bkn_switch_info_t *sinfo;
+ unsigned long flags;
+ char link_str[40];
+ char *ptr;
+ char *newline;
+
+ if (count > sizeof(link_str)) {
+ count = sizeof(link_str) - 1;
+ link_str[count] = '\0';
+ }
+ if (copy_from_user(link_str, buf, count)) {
+ return -EFAULT;
+ }
+ link_str[count] = 0;
+ newline = strchr(link_str, '\n');
+ if (newline) {
+ /* Chop off the trailing newline */
+ *newline = '\0';
+ }
+
+ if ((ptr = strchr(link_str, '=')) == NULL &&
+ (ptr = strchr(link_str, ':')) == NULL) {
+ gprintk("Error: link syntax not recognized: '%s'\n", link_str);
+ return count;
+ }
+ *ptr++ = 0;
+
+ dev = NULL;
+ list_for_each(slist, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)slist;
+ spin_lock_irqsave(&sinfo->lock, flags);
+ list_for_each(dlist, &sinfo->ndev_list) {
+ priv = (bkn_priv_t *)dlist;
+ if (priv->dev) {
+ if (strcmp(priv->dev->name, link_str) == 0) {
+ dev = priv->dev;
+ break;
+ }
+ }
+ }
+ if (dev) {
+ if (strcmp(ptr, "up") == 0) {
+ netif_carrier_on(dev);
+ } else if (strcmp(ptr, "down") == 0) {
+ netif_carrier_off(dev);
+ } else {
+ gprintk("Warning: unknown link state setting: '%s'\n", ptr);
+ }
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return count;
+ }
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ }
+
+ gprintk("Warning: unknown network interface: '%s'\n", link_str);
+
+ return count;
+}
+
+struct file_operations bkn_proc_link_file_ops = {
+ owner: THIS_MODULE,
+ open: bkn_proc_link_open,
+ read: seq_read,
+ llseek: seq_lseek,
+ write: bkn_proc_link_write,
+ release: single_release,
+};
+
+/*
+ * Device Rate Control Proc Read Entry
+ */
+static int
+bkn_proc_rate_show(struct seq_file *m, void *v)
+{
+ int unit = 0;
+ struct list_head *list;
+ bkn_switch_info_t *sinfo;
+ int chan;
+
+ list_for_each(list, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)list;
+
+ seq_printf(m, "Rate control (unit %d):\n", unit);
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ seq_printf(m, " Rx%d max rate %8u\n",
+ chan, sinfo->rx[chan].rate_max);
+ seq_printf(m, " Rx%d max burst %8u\n",
+ chan, sinfo->rx[chan].burst_max);
+ seq_printf(m, " Rx%d rate %8u\n",
+ chan, sinfo->rx[chan].rate);
+ seq_printf(m, " Rx%d tokens %8u\n",
+ chan, sinfo->rx[chan].tokens);
+ }
+
+ unit++;
+ }
+ return 0;
+}
+
+static int
+bkn_proc_rate_open(struct inode * inode, struct file * file)
+{
+ return single_open(file, bkn_proc_rate_show, NULL);
+}
+
+/*
+ * Device Rate Control Proc Write Entry
+ *
+ * Syntax:
+ * [<unit>:]rx_rate=<rate0>[,<rate1>[,<rate2]]
+ *
+ * Where <rate0> is packets/sec for the first Rx DMA channel,
+ * <rate1> is packets/sec for the second Rx DMA channel, etc.
+ *
+ * Examples:
+ * rx_rate=5000
+ * 0:rx_rate=10000,10000
+ * 1:rx_rate=10000,5000
+ */
+static ssize_t
+bkn_proc_rate_write(struct file *file, const char *buf,
+ size_t count, loff_t *loff)
+{
+ bkn_switch_info_t *sinfo;
+ char rate_str[80];
+ char *ptr;
+ int unit, chan;
+
+ if (count > sizeof(rate_str)) {
+ count = sizeof(rate_str) - 1;
+ rate_str[count] = '\0';
+ }
+ if (copy_from_user(rate_str, buf, count)) {
+ return -EFAULT;
+ }
+
+ unit = simple_strtol(rate_str, NULL, 10);
+ sinfo = bkn_sinfo_from_unit(unit);
+ if (sinfo == NULL) {
+ gprintk("Warning: unknown unit: %d\n", unit);
+ return count;
+ }
+
+ if ((ptr = strstr(rate_str, "rx_rate=")) != NULL) {
+ ptr += 7;
+ chan = 0;
+ do {
+ ptr++;
+ sinfo->rx[chan].rate_max = simple_strtol(ptr, NULL, 10);
+ } while ((ptr = strchr(ptr, ',')) != NULL && ++chan < sinfo->rx_chans);
+ bkn_rx_rate_config(sinfo);
+ } else if ((ptr = strstr(rate_str, "rx_burst=")) != NULL) {
+ ptr += 8;
+ chan = 0;
+ do {
+ ptr++;
+ sinfo->rx[chan].burst_max = simple_strtol(ptr, NULL, 10);
+ } while ((ptr = strchr(ptr, ',')) != NULL && ++chan < sinfo->rx_chans);
+ bkn_rx_rate_config(sinfo);
+ } else {
+ gprintk("Warning: unknown configuration setting\n");
+ }
+
+ return count;
+}
+
+struct file_operations bkn_proc_rate_file_ops = {
+ owner: THIS_MODULE,
+ open: bkn_proc_rate_open,
+ read: seq_read,
+ llseek: seq_lseek,
+ write: bkn_proc_rate_write,
+ release: single_release,
+};
+
+/*
+ * Driver DMA Proc Entry
+ *
+ * This output can be rather large (> PAGE_SIZE) so we use the
+ * seq_file interface to do the output. Special header records
+ * are indicated by a negative DCB index.
+ */
+typedef struct {
+ int dev_no; /* Current unit */
+ int rx_dma; /* 0: Tx DMA, 1: Rx DMA*/
+ int ch_no; /* DMA channel no. (Rx only) */
+ int idx; /* DCB index */
+} bkn_seq_dma_iter_t;
+
+/* From current record, move forward 'pos' records */
+static int
+bkn_seq_dma_next_pos(bkn_seq_dma_iter_t *iter, loff_t pos)
+{
+ bkn_switch_info_t *sinfo;
+
+ sinfo = bkn_sinfo_from_unit(iter->dev_no);
+ while (pos) {
+ if (iter->rx_dma) {
+ if (++iter->idx >= MAX_RX_DCBS + 1) {
+ iter->idx = -1;
+ if (++iter->ch_no >= sinfo->rx_chans) {
+ iter->rx_dma = 0;
+ iter->ch_no = 0;
+ iter->dev_no++;
+ if ((sinfo = bkn_sinfo_from_unit(iter->dev_no)) == NULL) {
+ return -1;
+ }
+ }
+ }
+ } else {
+ if (++iter->idx >= MAX_TX_DCBS + 1) {
+ iter->idx = -1;
+ iter->rx_dma = 1;
+ }
+ }
+ pos--;
+ }
+ return 0;
+}
+
+/* Initialize private data and move to requested start record */
+static void *
+bkn_seq_dma_start(struct seq_file *s, loff_t *pos)
+{
+ bkn_seq_dma_iter_t *iter;
+
+ iter = kmalloc(sizeof(bkn_seq_dma_iter_t), GFP_KERNEL);
+ if (!iter) {
+ return NULL;
+ }
+ memset(iter, 0, sizeof(*iter));
+ iter->idx = -2;
+ if (bkn_seq_dma_next_pos(iter, *pos) < 0) {
+ kfree(iter);
+ return NULL;
+ }
+ return iter;
+}
+
+/* Move to next record */
+static void *
+bkn_seq_dma_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ bkn_seq_dma_iter_t *iter = (bkn_seq_dma_iter_t *)v;
+ void *rv = iter;
+
+ if (bkn_seq_dma_next_pos(iter, 1) < 0) {
+ return NULL;
+ }
+ (*pos)++;
+ return rv;
+}
+
+/* Release private data */
+static void
+bkn_seq_dma_stop(struct seq_file *s, void *v)
+{
+ if (v) {
+ kfree(v);
+ }
+}
+
+/* Print current record */
+static int
+bkn_seq_dma_show(struct seq_file *s, void *v)
+{
+ bkn_seq_dma_iter_t *iter = (bkn_seq_dma_iter_t *)v;
+ bkn_switch_info_t *sinfo;
+ uint32_t *dcb = NULL;
+ bkn_dcb_chain_t *dcb_chain = NULL;
+ struct list_head *curr, *next;
+ unsigned long flags;
+ int chan, cnt;
+
+ sinfo = bkn_sinfo_from_unit(iter->dev_no);
+ if (sinfo == NULL) {
+ /* Should not happen */
+ return 0;
+ }
+
+ if (iter->rx_dma == 0) {
+ if (iter->idx == -2) {
+ seq_printf(s, "Pending events: 0x%x\n", sinfo->dma_events);
+ } else if (iter->idx == -1) {
+ spin_lock_irqsave(&sinfo->lock, flags);
+ curr = &sinfo->tx.api_dcb_list;
+ dcb_chain = sinfo->tx.api_dcb_chain;
+ while (dcb_chain) {
+ seq_printf(s, " [0x%08lx]--->\n", (unsigned long)dcb_chain->dcb_dma);
+ for (cnt = 0; cnt < dcb_chain->dcb_cnt; cnt++) {
+ dcb = &dcb_chain->dcb_mem[sinfo->dcb_wsize * cnt];
+ if (sinfo->cmic_type == 'x') {
+ seq_printf(s, " DCB %2d: 0x%08x 0x%08x 0x%08x 0x%08x\n", cnt,
+ dcb[0], dcb[1], dcb[2], dcb[sinfo->dcb_wsize-1]);
+ } else {
+ seq_printf(s, " DCB %2d: 0x%08x 0x%08x ... 0x%08x\n", cnt,
+ dcb[0], dcb[1], dcb[sinfo->dcb_wsize-1]);
+ }
+ }
+ next = curr->next;
+ if (next != &sinfo->tx.api_dcb_list) {
+ dcb_chain = list_entry(next, bkn_dcb_chain_t, list);
+ curr = next;
+ } else {
+ dcb_chain = NULL;
+ }
+ }
+ dcb = NULL;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ seq_printf(s,
+ "Tx DCB info (unit %d):\n"
+ " api: %d\n"
+ " dirty: %d\n"
+ " cur: %d\n"
+ " free: %d\n"
+ " pause: %s\n",
+ iter->dev_no,
+ sinfo->tx.api_active,
+ sinfo->tx.dirty,
+ sinfo->tx.cur,
+ sinfo->tx.free,
+ netif_queue_stopped(sinfo->dev) ? "yes" : "no");
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ bkn_desc_info_t *desc = &sinfo->tx.desc[0];
+ uint64_t halt = sinfo->halt_addr[XGS_DMA_TX_CHAN];
+ seq_printf(s,
+ " halt: %d\n",
+ (int)((uint32_t)(halt - desc->dcb_dma) / (sinfo->dcb_wsize * sizeof(uint32_t))));
+ }
+ } else {
+ dcb = sinfo->tx.desc[iter->idx].dcb_mem;
+ if (iter->idx == 0) {
+ seq_printf(s, " [0x%08lx]--->\n", (unsigned long)sinfo->tx.desc[0].dcb_dma);
+ }
+ }
+ } else {
+ if (iter->idx == -1) {
+ chan = iter->ch_no;
+ seq_printf(s,
+ "Rx%d DCB info (unit %d):\n"
+ " api: %d\n"
+ " dirty: %d\n"
+ " cur: %d\n"
+ " free: %d\n"
+ " run: %d\n",
+ chan, iter->dev_no,
+ sinfo->rx[chan].api_active,
+ sinfo->rx[chan].dirty,
+ sinfo->rx[chan].cur,
+ sinfo->rx[chan].free,
+ sinfo->rx[chan].running);
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) && sinfo->rx[chan].use_rx_skb) {
+ bkn_desc_info_t *desc = &sinfo->rx[chan].desc[0];
+ uint64_t halt = sinfo->halt_addr[XGS_DMA_RX_CHAN + chan];
+ seq_printf(s,
+ " halt: %d\n",
+ (int)((uint32_t)(halt - desc->dcb_dma) / (sinfo->dcb_wsize * sizeof(uint32_t))));
+ }
+ } else if (sinfo->rx[iter->ch_no].use_rx_skb) {
+ dcb = sinfo->rx[iter->ch_no].desc[iter->idx].dcb_mem;
+ if (iter->idx == 0) {
+ seq_printf(s, " [0x%08lx]--->\n", (unsigned long)sinfo->rx[iter->ch_no].desc[0].dcb_dma);
+ }
+ } else if (!sinfo->rx[iter->ch_no].use_rx_skb && iter->idx == 0) {
+ spin_lock_irqsave(&sinfo->lock, flags);
+ curr = &sinfo->rx[iter->ch_no].api_dcb_list;
+ dcb_chain = sinfo->rx[iter->ch_no].api_dcb_chain;
+ while (dcb_chain) {
+ seq_printf(s, " [0x%08lx]--->\n", (unsigned long)dcb_chain->dcb_dma);
+ for (cnt = 0; cnt < dcb_chain->dcb_cnt; cnt++) {
+ dcb = &dcb_chain->dcb_mem[sinfo->dcb_wsize * cnt];
+ if (sinfo->cmic_type == 'x') {
+ seq_printf(s, " DCB %2d: 0x%08x 0x%08x 0x%08x 0x%08x\n", cnt,
+ dcb[0], dcb[1], dcb[2], dcb[sinfo->dcb_wsize-1]);
+ } else {
+ seq_printf(s, " DCB %2d: 0x%08x 0x%08x ... 0x%08x\n", cnt,
+ dcb[0], dcb[1], dcb[sinfo->dcb_wsize-1]);
+ }
+ }
+ next = curr->next;
+ if (next != &sinfo->rx[iter->ch_no].api_dcb_list) {
+ dcb_chain = list_entry(next, bkn_dcb_chain_t, list);
+ curr = next;
+ } else {
+ dcb_chain = NULL;
+ }
+ }
+ dcb = NULL;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ }
+ }
+ if (dcb) {
+ if (sinfo->cmic_type == 'x') {
+ seq_printf(s, " DCB %2d: 0x%08x 0x%08x 0x%08x 0x%08x\n", iter->idx,
+ dcb[0], dcb[1], dcb[2], dcb[sinfo->dcb_wsize-1]);
+ } else {
+ seq_printf(s, " DCB %2d: 0x%08x 0x%08x ... 0x%08x\n", iter->idx,
+ dcb[0], dcb[1], dcb[sinfo->dcb_wsize-1]);
+ }
+ }
+ return 0;
+}
+
+static struct seq_operations bkn_seq_dma_ops = {
+ .start = bkn_seq_dma_start,
+ .next = bkn_seq_dma_next,
+ .stop = bkn_seq_dma_stop,
+ .show = bkn_seq_dma_show
+};
+
+static int
+bkn_seq_dma_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &bkn_seq_dma_ops);
+};
+
+static struct file_operations bkn_seq_dma_file_ops = {
+ .owner = THIS_MODULE,
+ .open = bkn_seq_dma_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release
+};
+
+/*
+ * Device Debug Control Proc Write Entry
+ *
+ * Syntax:
+ * [<unit>:]debug=<mask>
+ *
+ * Where <mask> corresponds to the debug module parameter.
+ *
+ * Examples:
+ * debug=0xffff
+ * 0:debug-0x2000
+ */
+static ssize_t
+bkn_proc_debug_write(struct file *file, const char *buf,
+ size_t count, loff_t *loff)
+{
+ bkn_switch_info_t *sinfo;
+ char debug_str[40];
+ char *ptr;
+ int unit;
+
+ if (count > sizeof(debug_str)) {
+ count = sizeof(debug_str) - 1;
+ debug_str[count] = '\0';
+ }
+ if (copy_from_user(debug_str, buf, count)) {
+ return -EFAULT;
+ }
+
+ unit = simple_strtol(debug_str, NULL, 10);
+ sinfo = bkn_sinfo_from_unit(unit);
+ if (sinfo == NULL) {
+ gprintk("Warning: unknown unit: %d\n", unit);
+ return count;
+ }
+
+ if ((ptr = strstr(debug_str, "debug=")) != NULL) {
+ ptr += 6;
+ debug = simple_strtol(ptr, NULL, 0);
+ } else {
+ gprintk("Warning: unknown configuration setting\n");
+ }
+
+ return count;
+}
+
+/*
+ * Driver Debug Proc Entry
+ */
+static int
+bkn_proc_debug_show(struct seq_file *m, void *v)
+{
+ int unit = 0;
+ struct list_head *list;
+ bkn_switch_info_t *sinfo;
+
+ seq_printf(m, "Configuration:\n");
+ seq_printf(m, " debug: 0x%x\n", debug);
+ seq_printf(m, " mac_addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bkn_dev_mac[0], bkn_dev_mac[1], bkn_dev_mac[2],
+ bkn_dev_mac[3], bkn_dev_mac[4], bkn_dev_mac[5]);
+ seq_printf(m, " rx_buffer_size: %d (0x%x)\n",
+ rx_buffer_size, rx_buffer_size);
+ seq_printf(m, " rcpu_mode: %d\n", rcpu_mode);
+ seq_printf(m, " rcpu_dmac: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bkn_rcpu_dmac[0], bkn_rcpu_dmac[1], bkn_rcpu_dmac[2],
+ bkn_rcpu_dmac[3], bkn_rcpu_dmac[4], bkn_rcpu_dmac[5]);
+ seq_printf(m, " rcpu_smac: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bkn_rcpu_smac[0], bkn_rcpu_smac[1], bkn_rcpu_smac[2],
+ bkn_rcpu_smac[3], bkn_rcpu_smac[4], bkn_rcpu_smac[5]);
+ seq_printf(m, " rcpu_ethertype: 0x%x\n", rcpu_ethertype);
+ seq_printf(m, " rcpu_signature: 0x%x\n", rcpu_signature);
+ seq_printf(m, " rcpu_vlan: %d\n", rcpu_vlan);
+ seq_printf(m, " use_rx_skb: %d\n", use_rx_skb);
+ seq_printf(m, " num_rx_prio: %d\n", num_rx_prio);
+ seq_printf(m, " check_rcpu_sig: %d\n", check_rcpu_signature);
+ seq_printf(m, " default_mtu: %d\n", default_mtu);
+ seq_printf(m, " rx_sync_retry: %d\n", rx_sync_retry);
+ seq_printf(m, " use_napi: %d\n", use_napi);
+ seq_printf(m, " napi_weight: %d\n", napi_weight);
+ seq_printf(m, " basedev_susp: %d\n", basedev_suspend);
+ seq_printf(m, "Thread states:\n");
+ seq_printf(m, " Command thread: %d\n", bkn_cmd_ctrl.state);
+ seq_printf(m, " Event thread: %d\n", bkn_evt_ctrl.state);
+ seq_printf(m, "Active IOCTLs:\n");
+ seq_printf(m, " Command: %d\n", ioctl_cmd);
+ seq_printf(m, " Event: %d\n", ioctl_evt);
+
+ list_for_each(list, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)list;
+
+ seq_printf(m, "Device %d:\n", unit);
+ seq_printf(m, " base_addr: 0x%p\n", sinfo->base_addr);
+ seq_printf(m, " dev_no: %d\n", sinfo->dev_no);
+ seq_printf(m, " cmic_type: %c\n", sinfo->cmic_type);
+ seq_printf(m, " dcb_type: %d\n", sinfo->dcb_type);
+ seq_printf(m, " dcb_wsize: %d\n", sinfo->dcb_wsize);
+ seq_printf(m, " pkt_hdr_size: %d\n", sinfo->pkt_hdr_size);
+ seq_printf(m, " rx_chans: %d\n", sinfo->rx_chans);
+ seq_printf(m, " cdma_chans: 0x%x\n", sinfo->cdma_channels);
+ seq_printf(m, " irq_mask: 0x%x\n", sinfo->irq_mask);
+ seq_printf(m, " dma_events: 0x%x\n", sinfo->dma_events);
+ seq_printf(m, " dcb_dma: 0x%p\n", (void *)(sal_paddr_t)sinfo->dcb_dma);
+ seq_printf(m, " dcb_mem_size: 0x%x\n", sinfo->dcb_mem_size);
+ seq_printf(m, " rcpu_sig: 0x%x\n", sinfo->rcpu_sig);
+ seq_printf(m, " napi_poll_mode: %d\n", sinfo->napi_poll_mode);
+ seq_printf(m, " inst_id: 0x%x\n", sinfo->inst_id);
+ seq_printf(m, " evt_queue: %d\n", sinfo->evt_idx);
+
+ unit++;
+ }
+
+ return 0;
+}
+
+static int bkn_proc_debug_open(struct inode * inode, struct file * file)
+{
+ return single_open(file, bkn_proc_debug_show, NULL);
+}
+
+struct file_operations bkn_proc_debug_file_ops = {
+ owner: THIS_MODULE,
+ open: bkn_proc_debug_open,
+ read: seq_read,
+ llseek: seq_lseek,
+ write: bkn_proc_debug_write,
+ release: single_release,
+};
+
+/*
+ * Device Statistics Proc Entry
+ */
+static int
+bkn_proc_stats_show(struct seq_file *m, void *v)
+{
+ int unit = 0;
+ struct list_head *list, *flist;
+ bkn_switch_info_t *sinfo;
+ bkn_filter_t *filter;
+ int chan;
+
+
+ list_for_each(list, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)list;
+
+ seq_printf(m, "Device stats (unit %d):\n", unit);
+ seq_printf(m, " Interrupts %10u\n", sinfo->interrupts);
+ seq_printf(m, " Tx packets %10u\n", sinfo->tx.pkts);
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ seq_printf(m, " Rx%d packets %10u\n", chan, sinfo->rx[chan].pkts);
+ }
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (sinfo->interrupts == 0) {
+ /* Avoid divide-by-zero */
+ seq_printf(m, " Rx%d pkts/intr -\n", chan);
+ } else {
+ seq_printf(m, " Rx%d pkts/intr %8u\n",
+ chan, sinfo->rx[chan].pkts / sinfo->interrupts);
+ }
+ }
+ seq_printf(m, " Timer runs %10u\n", sinfo->timer_runs);
+ seq_printf(m, " NAPI reruns %10u\n", sinfo->napi_not_done);
+
+ list_for_each(flist, &sinfo->rxpf_list) {
+ filter = (bkn_filter_t *)flist;
+
+ seq_printf(m, " Filter %d stats:\n", filter->kf.id);
+ seq_printf(m, " Hits %10lu\n", filter->hits);
+ }
+
+ unit++;
+ }
+ return 0;
+}
+
+static int bkn_proc_stats_open(struct inode * inode, struct file * file)
+{
+ return single_open(file, bkn_proc_stats_show, NULL);
+}
+
+/*
+ * Device Statistics Proc Write Entry
+ *
+ * Syntax:
+ * [<unit>:]clear[=all]
+ *
+ * Where <mask> corresponds to the debug module parameter.
+ *
+ * Examples:
+ * clear
+ * 0:clear=all
+ */
+static ssize_t
+bkn_proc_stats_write(struct file *file, const char *buf,
+ size_t count, loff_t *loff)
+{
+ bkn_switch_info_t *sinfo;
+ struct list_head *flist;
+ bkn_filter_t *filter;
+ char debug_str[40];
+ char *ptr;
+ int unit;
+ int clear_mask;
+ int chan;
+
+ if (count > sizeof(debug_str)) {
+ count = sizeof(debug_str) - 1;
+ debug_str[count] = '\0';
+ }
+ if (copy_from_user(debug_str, buf, count)) {
+ return -EFAULT;
+ }
+
+ unit = simple_strtol(debug_str, NULL, 10);
+ sinfo = bkn_sinfo_from_unit(unit);
+ if (sinfo == NULL) {
+ gprintk("Warning: unknown unit: %d\n", unit);
+ return count;
+ }
+
+ clear_mask = 0;
+ if ((ptr = strstr(debug_str, "clear=")) != NULL) {
+ ptr += 6;
+ if (strncmp(ptr, "all", 3) == 0) {
+ clear_mask = ~0;
+ }
+ } else if ((ptr = strstr(debug_str, "clear")) != NULL) {
+ clear_mask = ~0;
+ } else {
+ gprintk("Warning: unknown configuration setting\n");
+ }
+
+ if (clear_mask) {
+ sinfo->tx.pkts = 0;
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ sinfo->rx[chan].pkts = 0;
+ }
+ sinfo->interrupts = 0;
+ sinfo->timer_runs = 0;
+ sinfo->napi_not_done = 0;
+ list_for_each(flist, &sinfo->rxpf_list) {
+ filter = (bkn_filter_t *)flist;
+ filter->hits = 0;
+ }
+ }
+
+ return count;
+}
+
+struct file_operations bkn_proc_stats_file_ops = {
+ owner: THIS_MODULE,
+ open: bkn_proc_stats_open,
+ read: seq_read,
+ llseek: seq_lseek,
+ write: bkn_proc_stats_write,
+ release: single_release,
+};
+
+/*
+ * Device Debug Statistics Proc Entry
+ */
+static int
+bkn_proc_dstats_show(struct seq_file *m, void *v)
+{
+ int unit = 0;
+ struct list_head *list;
+ bkn_switch_info_t *sinfo;
+ int chan;
+
+ list_for_each(list, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)list;
+
+ seq_printf(m, "Device debug stats (unit %d):\n", unit);
+ seq_printf(m, " Tx drop no skb %10u\n",
+ sinfo->tx.pkts_d_no_skb);
+ seq_printf(m, " Tx drop rcpu encap %10u\n",
+ sinfo->tx.pkts_d_rcpu_encap);
+ seq_printf(m, " Tx drop rcpu sig %10u\n",
+ sinfo->tx.pkts_d_rcpu_sig);
+ seq_printf(m, " Tx drop rcpu meta %10u\n",
+ sinfo->tx.pkts_d_rcpu_meta);
+ seq_printf(m, " Tx drop pad failed %10u\n",
+ sinfo->tx.pkts_d_pad_fail);
+ seq_printf(m, " Tx drop no resource %10u\n",
+ sinfo->tx.pkts_d_dma_resrc);
+ seq_printf(m, " Tx drop callback %10u\n",
+ sinfo->tx.pkts_d_callback);
+ seq_printf(m, " Tx drop no link %10u\n",
+ sinfo->tx.pkts_d_no_link);
+ seq_printf(m, " Tx drop oversized %10u\n",
+ sinfo->tx.pkts_d_over_limit);
+ seq_printf(m, " Tx suspends %10u\n",
+ sinfo->tx.suspends);
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ seq_printf(m, " Rx%d filter to api %10u\n",
+ chan, sinfo->rx[chan].pkts_f_api);
+ seq_printf(m, " Rx%d filter to netif %10u\n",
+ chan, sinfo->rx[chan].pkts_f_netif);
+ seq_printf(m, " Rx%d mirror to api %10u\n",
+ chan, sinfo->rx[chan].pkts_m_api);
+ seq_printf(m, " Rx%d mirror to netif %10u\n",
+ chan, sinfo->rx[chan].pkts_m_netif);
+ seq_printf(m, " Rx%d drop no skb %10u\n",
+ chan, sinfo->rx[chan].pkts_d_no_skb);
+ seq_printf(m, " Rx%d drop no match %10u\n",
+ chan, sinfo->rx[chan].pkts_d_no_match);
+ seq_printf(m, " Rx%d drop unkn netif %10u\n",
+ chan, sinfo->rx[chan].pkts_d_unkn_netif);
+ seq_printf(m, " Rx%d drop unkn dest %10u\n",
+ chan, sinfo->rx[chan].pkts_d_unkn_dest);
+ seq_printf(m, " Rx%d drop callback %10u\n",
+ chan, sinfo->rx[chan].pkts_d_callback);
+ seq_printf(m, " Rx%d drop no link %10u\n",
+ chan, sinfo->rx[chan].pkts_d_no_link);
+ seq_printf(m, " Rx%d sync error %10u\n",
+ chan, sinfo->rx[chan].sync_err);
+ seq_printf(m, " Rx%d sync retry %10u\n",
+ chan, sinfo->rx[chan].sync_retry);
+ seq_printf(m, " Rx%d sync maxloop %10u\n",
+ chan, sinfo->rx[chan].sync_maxloop);
+ seq_printf(m, " Rx%d drop no buffer %10u\n",
+ chan, sinfo->rx[chan].pkts_d_no_api_buf);
+ }
+ unit++;
+ }
+ return 0;
+}
+
+static int bkn_proc_dstats_open(struct inode * inode, struct file * file)
+{
+ return single_open(file, bkn_proc_dstats_show, NULL);
+}
+
+/*
+ * Device Debug Statistics Proc Write Entry
+ *
+ * Syntax:
+ * [<unit>:]clear[=all|tx|rx[<chan>]]
+ *
+ * Where <mask> corresponds to the debug module parameter.
+ *
+ * Examples:
+ * clear
+ * 0:clear=rx1
+ */
+static ssize_t
+bkn_proc_dstats_write(struct file *file, const char *buf,
+ size_t count, loff_t *loff)
+{
+ bkn_switch_info_t *sinfo;
+ char debug_str[40];
+ char *ptr;
+ int unit;
+ int clear_mask;
+ int chan;
+
+ if (count > sizeof(debug_str)) {
+ count = sizeof(debug_str) - 1;
+ debug_str[count] = '\0';
+ }
+ if (copy_from_user(debug_str, buf, count)) {
+ return -EFAULT;
+ }
+
+ unit = simple_strtol(debug_str, NULL, 10);
+ sinfo = bkn_sinfo_from_unit(unit);
+ if (sinfo == NULL) {
+ gprintk("Warning: unknown unit: %d\n", unit);
+ return count;
+ }
+
+ clear_mask = 0;
+ if ((ptr = strstr(debug_str, "clear=")) != NULL) {
+ ptr += 6;
+ if (strncmp(ptr, "all", 3) == 0) {
+ clear_mask = ~0;
+ } else if (strncmp(ptr, "dev", 3) == 0) {
+ clear_mask = 0x20;
+ } else if (strncmp(ptr, "tx", 2) == 0) {
+ clear_mask = 0x10;
+ } else if (strncmp(ptr, "rx0", 3) == 0) {
+ clear_mask = (1 << 0);
+ } else if (strncmp(ptr, "rx1", 3) == 0) {
+ clear_mask = (1 << 1);
+ } else if (strncmp(ptr, "rx", 2) == 0) {
+ clear_mask = 0xf;
+ }
+ } else if ((ptr = strstr(debug_str, "clear")) != NULL) {
+ clear_mask = ~0;
+ } else {
+ gprintk("Warning: unknown configuration setting\n");
+ }
+
+ /* Tx counters */
+ if (clear_mask & 0x10) {
+ sinfo->tx.pkts_d_no_skb = 0;
+ sinfo->tx.pkts_d_rcpu_encap = 0;
+ sinfo->tx.pkts_d_rcpu_sig = 0;
+ sinfo->tx.pkts_d_rcpu_meta = 0;
+ sinfo->tx.pkts_d_pad_fail = 0;
+ sinfo->tx.pkts_d_over_limit = 0;
+ sinfo->tx.pkts_d_dma_resrc = 0;
+ sinfo->tx.suspends = 0;
+ }
+ /* Rx counters */
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (clear_mask & (1 << chan)) {
+ sinfo->rx[chan].pkts_f_api = 0;
+ sinfo->rx[chan].pkts_f_netif = 0;
+ sinfo->rx[chan].pkts_m_api = 0;
+ sinfo->rx[chan].pkts_m_netif = 0;
+ sinfo->rx[chan].pkts_d_no_skb = 0;
+ sinfo->rx[chan].pkts_d_no_match = 0;
+ sinfo->rx[chan].pkts_d_unkn_netif = 0;
+ sinfo->rx[chan].pkts_d_unkn_dest = 0;
+ sinfo->rx[chan].pkts_d_no_api_buf = 0;
+ sinfo->rx[chan].sync_err = 0;
+ sinfo->rx[chan].sync_retry = 0;
+ sinfo->rx[chan].sync_maxloop = 0;
+ }
+ }
+
+ return count;
+}
+
+struct file_operations bkn_proc_dstats_file_ops = {
+ owner: THIS_MODULE,
+ open: bkn_proc_dstats_open,
+ read: seq_read,
+ llseek: seq_lseek,
+ write: bkn_proc_dstats_write,
+ release: single_release,
+};
+
+static int
+bkn_proc_init(void)
+{
+ struct proc_dir_entry *entry;
+
+ PROC_CREATE(entry, "link", 0666, bkn_proc_root, &bkn_proc_link_file_ops);
+ if (entry == NULL) {
+ return -1;
+ }
+ PROC_CREATE(entry, "rate", 0666, bkn_proc_root, &bkn_proc_rate_file_ops);
+ if (entry == NULL) {
+ return -1;
+ }
+ PROC_CREATE(entry, "dma", 0, bkn_proc_root, &bkn_seq_dma_file_ops);
+ if (entry == NULL) {
+ return -1;
+ }
+ PROC_CREATE(entry, "debug", 0666, bkn_proc_root, &bkn_proc_debug_file_ops);
+ if (entry == NULL) {
+ return -1;
+ }
+ PROC_CREATE(entry, "stats", 0666, bkn_proc_root, &bkn_proc_stats_file_ops);
+ if (entry == NULL) {
+ return -1;
+ }
+ PROC_CREATE(entry, "dstats", 0666, bkn_proc_root, &bkn_proc_dstats_file_ops);
+ if (entry == NULL) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+bkn_proc_cleanup(void)
+{
+ remove_proc_entry("link", bkn_proc_root);
+ remove_proc_entry("rate", bkn_proc_root);
+ remove_proc_entry("dma", bkn_proc_root);
+ remove_proc_entry("debug", bkn_proc_root);
+ remove_proc_entry("stats", bkn_proc_root);
+ remove_proc_entry("dstats", bkn_proc_root);
+ return 0;
+}
+
+/*
+ * Generic module functions
+ */
+
+static int
+_pprint(void)
+{
+ pprintf("Broadcom BCM KNET Linux Network Driver\n");
+
+ return 0;
+}
+
+static int
+bkn_knet_dma_info(kcom_msg_dma_info_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ bkn_dcb_chain_t *dcb_chain, *dcb_chain_end;
+ unsigned long flags;
+ int chan;
+ uint64_t dcb_dma;
+ int woffset;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ dcb_chain = kmalloc(sizeof(*dcb_chain), GFP_KERNEL);
+ if (dcb_chain == NULL) {
+ gprintk("Fatal error: No memory for dcb_chain\n");
+ kmsg->hdr.status = KCOM_E_RESOURCE;
+ return sizeof(kcom_msg_hdr_t);
+ }
+ memset(dcb_chain, 0, sizeof(*dcb_chain));
+ dcb_chain->dcb_cnt = kmsg->dma_info.cnt;
+ dcb_chain->dcb_dma = kmsg->dma_info.data.dcb_start;
+ dcb_chain->dcb_mem = kernel_bde->p2l(sinfo->dev_no,
+ (sal_paddr_t)dcb_chain->dcb_dma);
+
+ if (kmsg->dma_info.type == KCOM_DMA_INFO_T_TX_DCB) {
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ /* Hold back packets from kernel */
+ bkn_suspend_tx(sinfo);
+
+ list_add_tail(&dcb_chain->list, &sinfo->tx.api_dcb_list);
+
+ /* Handle for Continuous DMA mode */
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize + 1;
+ if (sinfo->cmic_type == 'x') {
+ woffset += 1;
+ }
+ if ((dcb_chain->dcb_mem[woffset] & ((1 << 18) | (1 << 16))) != 0x50000) {
+ gprintk("Not suitable API DCB chain for Continuous DMA mode\n");
+ list_del(&dcb_chain->list);
+ kfree(dcb_chain);
+ kmsg->hdr.status = KCOM_E_PARAM;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return sizeof(kcom_msg_hdr_t);
+ }
+ dcb_chain_end = sinfo->tx.api_dcb_chain_end;
+ if (dcb_chain_end != NULL) {
+ /* Stitch this chain */
+ woffset = (dcb_chain_end->dcb_cnt - 1) * sinfo->dcb_wsize;
+ dcb_chain_end->dcb_mem[woffset] = dcb_chain->dcb_dma;
+ if (sinfo->cmic_type == 'x') {
+ dcb_chain_end->dcb_mem[woffset + 1] = DMA_TO_BUS_HI(dcb_chain->dcb_dma >> 32);
+ }
+ MEMORY_BARRIER;
+ }
+ sinfo->tx.api_dcb_chain_end = dcb_chain;
+ if (sinfo->tx.api_active) {
+ /* Set new halt location */
+ woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize;
+ dcb_dma = dcb_chain->dcb_dma + woffset * sizeof(uint32_t);
+ /* DMA run to the new halt location */
+ bkn_cdma_goto(sinfo, XGS_DMA_TX_CHAN, dcb_dma);
+ }
+ }
+
+ if (sinfo->tx.free == MAX_TX_DCBS &&
+ !sinfo->tx.api_active &&
+ !sinfo->basedev_suspended) {
+ bkn_api_tx(sinfo);
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ } else if (kmsg->dma_info.type == KCOM_DMA_INFO_T_RX_DCB) {
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ chan = kmsg->dma_info.chan - 1;
+ if ((chan < 0) || (chan > sinfo->rx_chans)) {
+ gprintk("Invalid RX DMA channel specified: %d\n",
+ kmsg->dma_info.chan);
+ kmsg->hdr.status = KCOM_E_PARAM;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ list_add_tail(&dcb_chain->list, &sinfo->rx[chan].api_dcb_list);
+
+ /* Handle for Continuous DMA mode */
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize + 1;
+ if (sinfo->cmic_type == 'x') {
+ woffset += 1;
+ }
+ if ((dcb_chain->dcb_mem[woffset] & ((1 << 18) | (1 << 16))) != 0x50000) {
+ gprintk("Not suitable API DCB chain for Continuous DMA mode\n");
+ list_del(&dcb_chain->list);
+ kfree(dcb_chain);
+ kmsg->hdr.status = KCOM_E_PARAM;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return sizeof(kcom_msg_hdr_t);
+ }
+ dcb_chain_end = sinfo->rx[chan].api_dcb_chain_end;
+ if (dcb_chain_end != NULL) {
+ /* Stitch this chain */
+ woffset = (dcb_chain_end->dcb_cnt - 1) * sinfo->dcb_wsize;
+ dcb_chain_end->dcb_mem[woffset] = dcb_chain->dcb_dma;
+ if (sinfo->cmic_type == 'x') {
+ dcb_chain_end->dcb_mem[woffset + 1] = DMA_TO_BUS_HI(dcb_chain->dcb_dma >> 32);
+ }
+ MEMORY_BARRIER;
+ }
+ sinfo->rx[chan].api_dcb_chain_end = dcb_chain;
+ if (!sinfo->rx[chan].use_rx_skb) {
+ /* Set new halt location */
+ woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize;
+ dcb_dma = dcb_chain->dcb_dma + woffset * sizeof(uint32_t);
+ /* DMA run to the new halt location */
+ bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, dcb_dma);
+ }
+ }
+
+ if (sinfo->rx[chan].api_active == 0) {
+ bkn_api_rx_restart(sinfo, chan);
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ } else {
+ DBG_DCB(("Unknown DCB_INFO type (%d).\n", kmsg->dma_info.type));
+ kfree(dcb_chain);
+ kmsg->hdr.status = KCOM_E_PARAM;
+ }
+
+ return sizeof(kcom_msg_hdr_t);
+}
+
+static int
+bkn_create_inst(uint32 inst_id)
+{
+ bkn_switch_info_t *sinfo;
+ bkn_evt_resource_t *evt;
+ unsigned long flags;
+ int i, evt_idx = -1;
+
+ /* multiple instance mode */
+ for (i = 0; i < kernel_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ evt = &_bkn_evt[i];
+ if (evt->inst_id == inst_id) {
+ evt_idx = i;
+ DBG_INST(("%s evt_idx %d inst_id 0x%x\n",__FUNCTION__, i, inst_id));
+ break;
+ }
+ if ((_bkn_multi_inst == 0) || (evt->inst_id == 0)) {
+ _bkn_multi_inst ++;
+ evt_idx = i;
+ init_waitqueue_head(&evt->evt_wq);
+ evt->inst_id = inst_id;
+ DBG_INST(("%s evt_idx %d inst_id 0x%x\n",__FUNCTION__, i, inst_id));
+ break;
+ }
+ }
+
+ if (evt_idx == -1) {
+ DBG_WARN(("Run out the event queue resource !\n"));
+ return -1;
+ }
+ for (i = 0; i < kernel_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ if (inst_id & (1 << i)) {
+ sinfo = bkn_sinfo_from_unit(i);
+ spin_lock_irqsave(&sinfo->lock, flags);
+ sinfo->evt_idx = evt_idx;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ DBG_INST(("%s d(%d) evt_idx %d \n",__FUNCTION__, i, evt_idx));
+ }
+ }
+ return 0;
+}
+
+/*
+ * Device reprobe driven by application to check if new device is probed or
+ * existed device is changed after inserting KNET module.
+ */
+static int
+bkn_knet_dev_reprobe(void)
+{
+ bkn_switch_info_t *sinfo;
+ int i;
+
+ for (i = 0; i < kernel_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ sinfo = bkn_sinfo_from_unit(i);
+ if (sinfo == NULL) {
+ /* New device found after re-probe. */
+ if (bkn_knet_dev_init(i) < 0) {
+ return -1;
+ }
+ } else {
+ /* Existed device reinit after re-probe. */
+ if (bkn_knet_dev_reinit(i) < 0) {
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Assign the inst_id and evt_idx */
+static int
+bkn_knet_dev_inst_set(kcom_msg_reprobe_t *kmsg)
+{
+ bkn_switch_info_t *sinfo;
+ int d = kmsg->hdr.unit;
+ uint32 inst = 0;
+ unsigned long flags;
+ struct list_head *list;
+
+ sinfo = bkn_sinfo_from_unit(d);
+ lkbde_dev_instid_get(d, &inst);
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+ if (sinfo->inst_id != inst) {
+ /* Instance database changed, reinit the inst_id */
+ sinfo->inst_id = 0;
+ sinfo->evt_idx = -1;
+ }
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ if (inst) {
+ if (sinfo->inst_id == 0) {
+ if (bkn_create_inst(inst) != 0) {
+ return -1;
+ }
+ }
+ spin_lock_irqsave(&sinfo->lock, flags);
+ sinfo->inst_id = inst;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ } else {
+ /* legacy mode */
+ list_for_each(list, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)list;
+ spin_lock_irqsave(&sinfo->lock, flags);
+ sinfo->evt_idx = 0;
+ sinfo->inst_id = 0;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ }
+ }
+ return 0;
+}
+
+static int
+bkn_knet_version(kcom_msg_version_t *kmsg, int len)
+{
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+ kmsg->version = KCOM_VERSION;
+ kmsg->netif_max = KCOM_NETIF_MAX;
+ kmsg->filter_max = KCOM_FILTER_MAX;
+
+ return sizeof(kcom_msg_version_t);
+}
+
+static int
+bkn_knet_hw_reset(kcom_msg_hw_reset_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ unsigned long flags;
+ int chan;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ if (kmsg->channels == 0) {
+ /* Clean all if no channels specified */
+ bkn_dma_abort(sinfo);
+ bkn_clean_dcbs(sinfo);
+ skb_queue_purge(&sinfo->tx_ptp_queue);
+ } else {
+ if (kmsg->channels & (1 << XGS_DMA_TX_CHAN)) {
+ bkn_dma_abort_tx(sinfo);
+ bkn_clean_tx_dcbs(sinfo);
+ skb_queue_purge(&sinfo->tx_ptp_queue);
+ }
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (kmsg->channels & (1 << (XGS_DMA_RX_CHAN + chan))) {
+ bkn_dma_abort_rx(sinfo, chan);
+ bkn_clean_rx_dcbs(sinfo, chan);
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return sizeof(kcom_msg_hdr_t);
+}
+
+static int
+bkn_knet_hw_init(kcom_msg_hw_init_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ uint32_t dev_type;
+ unsigned long flags;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ DBG_DCB(("DCB size %d, type %d\n", kmsg->dcb_size, kmsg->dcb_type));
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ sinfo->cmic_type = kmsg->cmic_type;
+ sinfo->dcb_type = kmsg->dcb_type;
+ sinfo->dcb_wsize = BYTES2WORDS(kmsg->dcb_size);
+ sinfo->pkt_hdr_size = kmsg->pkt_hdr_size;
+ sinfo->dma_hi = kmsg->dma_hi;
+ sinfo->rx_chans = sinfo->cmic_type == 'x' ? NUM_CMICX_RX_CHAN : NUM_CMICM_RX_CHAN;
+ if (sinfo->rx_chans > NUM_RX_CHAN) {
+ sinfo->rx_chans = NUM_RX_CHAN;
+ }
+
+ DBG_DUNE(("CMIC:%c DCB:%d WSIZE:%d DMA HI: 0x%08x HDR size: %d\n",
+ sinfo->cmic_type, sinfo->dcb_type, sinfo->dcb_wsize,
+ sinfo->dma_hi, sinfo->pkt_hdr_size));
+
+ /* Config Continuous DMA mode */
+ sinfo->cdma_channels = kmsg->cdma_channels & ~(~0 << (sinfo->rx_chans + 1));
+
+ /* Ensure 32-bit PCI DMA is mapped properly on 64-bit platforms */
+ dev_type = kernel_bde->get_dev_type(sinfo->dev_no);
+ if (dev_type & BDE_PCI_DEV_TYPE && sinfo->cmic_type != 'x') {
+ if (pci_set_dma_mask(sinfo->pdev, 0xffffffff)) {
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ gprintk("No suitable DMA available for SKBs\n");
+ kmsg->hdr.status = KCOM_E_RESOURCE;
+ return sizeof(kcom_msg_hdr_t);
+ }
+ }
+
+ /* First time called we need to allocate DCBs */
+ if (sinfo->dcb_mem == NULL) {
+ if (bkn_alloc_dcbs(sinfo) < 0) {
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ kmsg->hdr.status = KCOM_E_RESOURCE;
+ return sizeof(kcom_msg_hdr_t);
+ }
+ }
+
+ /* Ensure that we restart properly */
+ bkn_dma_abort(sinfo);
+ bkn_clean_dcbs(sinfo);
+
+ if (basedev_suspend) {
+ if (!netif_running(sinfo->dev)) {
+ sinfo->basedev_suspended = 1;
+ }
+ }
+
+ /* Ensure all interrupts are disabled, e.g. if warmbooting */
+ dev_irq_mask_set(sinfo, 0);
+
+ /* Register interrupt handler */
+ kernel_bde->interrupt_connect(sinfo->dev_no | LKBDE_ISR2_DEV,
+ bkn_isr, sinfo);
+
+ /* Init DCBs */
+ bkn_init_dcbs(sinfo);
+
+ bkn_dma_init(sinfo);
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return sizeof(kcom_msg_hdr_t);
+}
+
+static int
+bkn_knet_detach(kcom_msg_detach_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ unsigned long flags;
+ bkn_evt_resource_t *evt;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ /* Create dummy event to unblock pending IOCTL */
+ sinfo->dma_events |= KCOM_DMA_INFO_F_TX_DONE;
+ evt = &_bkn_evt[sinfo->evt_idx];
+ evt->evt_wq_put++;
+ wake_up_interruptible(&evt->evt_wq);
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ /* Ensure that we return a valid unit number */
+ kmsg->hdr.unit = sinfo->dev_no;
+
+ return sizeof(kcom_msg_detach_t);
+}
+
+static int
+bkn_knet_reprobe(kcom_msg_reprobe_t *kmsg, int len)
+{
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ /* Support pci hot plug and multiple instance */
+ if ((bkn_knet_dev_reprobe() < 0) ||
+ (bkn_knet_dev_inst_set(kmsg) < 0)) {
+ kmsg->hdr.status = KCOM_E_RESOURCE;
+ return sizeof(kcom_msg_reprobe_t);
+ }
+
+ return sizeof(kcom_msg_reprobe_t);
+}
+
+static int
+bkn_knet_netif_create(kcom_msg_netif_create_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ struct net_device *dev;
+ struct list_head *list;
+ bkn_priv_t *priv, *lpriv;
+ unsigned long flags;
+ int found, id;
+ uint8 *ma;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ switch (kmsg->netif.type) {
+ case KCOM_NETIF_T_VLAN:
+ case KCOM_NETIF_T_PORT:
+ case KCOM_NETIF_T_META:
+ break;
+ default:
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+ ma = kmsg->netif.macaddr;
+ if ((ma[0] | ma[1] | ma[2] | ma[3] | ma[4] | ma[5]) == 0) {
+ bkn_dev_mac[5]++;
+ ma = bkn_dev_mac;
+ }
+ if ((dev = bkn_init_ndev(ma, kmsg->netif.name)) == NULL) {
+ kmsg->hdr.status = KCOM_E_RESOURCE;
+ return sizeof(kcom_msg_hdr_t);
+ }
+ priv = netdev_priv(dev);
+ priv->dev = dev;
+ priv->sinfo = sinfo;
+ priv->type = kmsg->netif.type;
+ priv->vlan = kmsg->netif.vlan;
+ if (priv->type == KCOM_NETIF_T_PORT) {
+ priv->port = kmsg->netif.port;
+ if (device_is_dpp(sinfo)) {
+ memcpy(priv->itmh, kmsg->netif.itmh, 4);
+ } else if (device_is_dnx(sinfo)) {
+ memcpy(priv->system_headers, kmsg->netif.system_headers, kmsg->netif.system_headers_size);
+ priv->system_headers_size = kmsg->netif.system_headers_size;
+ }
+ priv->qnum = kmsg->netif.qnum;
+ } else {
+ if (device_is_sand(sinfo)) {
+ if (device_is_dpp(sinfo)) {
+ priv->port = kmsg->netif.port;
+ priv->qnum = kmsg->netif.qnum;
+ }else if (device_is_dnx(sinfo)) {
+ memcpy(priv->system_headers, kmsg->netif.system_headers, kmsg->netif.system_headers_size);
+ priv->system_headers_size = kmsg->netif.system_headers_size;
+ }
+ }
+ else {
+ priv->port = -1;
+ }
+ }
+ priv->flags = kmsg->netif.flags;
+ priv->cb_user_data = kmsg->netif.cb_user_data;
+
+ /* Force RCPU encapsulation if rcpu_mode */
+ if (rcpu_mode) {
+ priv->flags |= KCOM_NETIF_F_RCPU_ENCAP;
+ DBG_RCPU(("RCPU auto-enabled\n"));
+ }
+
+ /* Prevent (incorrect) compiler warning */
+ lpriv = NULL;
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ /*
+ * We insert network interfaces sorted by ID.
+ * In case an interface is destroyed, we reuse the ID
+ * the next time an interface is created.
+ */
+ found = 0;
+ id = 1;
+ list_for_each(list, &sinfo->ndev_list) {
+ lpriv = (bkn_priv_t *)list;
+ if (id < lpriv->id) {
+ found = 1;
+ break;
+ }
+ id = lpriv->id + 1;
+ }
+ priv->id = id;
+ if (found) {
+ /* Replace previously removed interface */
+ list_add_tail(&priv->list, &lpriv->list);
+ } else {
+ /* No holes - add to end of list */
+ list_add_tail(&priv->list, &sinfo->ndev_list);
+ }
+
+ if (id < sinfo->ndev_max) {
+ DBG_NDEV(("Add netif ID %d to table\n", id));
+ sinfo->ndevs[id] = dev;
+ } else {
+ int ndev_max = sinfo->ndev_max + NDEVS_CHUNK;
+ int size = ndev_max * sizeof(struct net_device *);
+ void *ndevs = kmalloc(size, GFP_ATOMIC);
+ if (ndevs != NULL) {
+ DBG_NDEV(("Reallocate netif table for ID %d\n", id));
+ memset(ndevs, 0, size);
+ if (sinfo->ndevs != NULL) {
+ size = sinfo->ndev_max * sizeof(struct net_device *);
+ memcpy(ndevs, sinfo->ndevs, size);
+ kfree(sinfo->ndevs);
+ }
+ sinfo->ndevs = ndevs;
+ sinfo->ndev_max = ndev_max;
+ sinfo->ndevs[id] = dev;
+ }
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ DBG_VERB(("Assigned ID %d to Ethernet device %s\n",
+ priv->id, dev->name));
+
+ kmsg->netif.id = priv->id;
+ memcpy(kmsg->netif.macaddr, dev->dev_addr, 6);
+ memcpy(kmsg->netif.name, dev->name, KCOM_NETIF_NAME_MAX - 1);
+
+ if (device_is_dnx(sinfo)) {
+ int idx = 0;
+ for (idx = 0; idx < priv->system_headers_size; idx++) {
+ DBG_DUNE(("System Header[%d]: 0x%02x\n", idx, priv->system_headers[idx]));
+ }
+ }
+
+ return sizeof(*kmsg);
+}
+
+static int
+bkn_knet_netif_destroy(kcom_msg_netif_destroy_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ struct net_device *dev;
+ bkn_priv_t *priv;
+ struct list_head *list;
+ unsigned long flags;
+ int found;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ found = 0;
+ list_for_each(list, &sinfo->ndev_list) {
+ priv = (bkn_priv_t *)list;
+ if (kmsg->hdr.id == priv->id) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ kmsg->hdr.status = KCOM_E_NOT_FOUND;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ list_del(&priv->list);
+
+ if (priv->id < sinfo->ndev_max) {
+ sinfo->ndevs[priv->id] = NULL;
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ dev = priv->dev;
+ DBG_VERB(("Removing virtual Ethernet device %s (%d).\n",
+ dev->name, priv->id));
+ unregister_netdev(dev);
+ free_netdev(dev);
+
+ return sizeof(kcom_msg_hdr_t);
+}
+
+static int
+bkn_knet_netif_list(kcom_msg_netif_list_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ bkn_priv_t *priv;
+ struct list_head *list;
+ unsigned long flags;
+ int idx;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ idx = 0;
+ list_for_each(list, &sinfo->ndev_list) {
+ if (idx >= KCOM_NETIF_MAX) {
+ DBG_WARN(("Too many network interfaces to list (max %d).\n",
+ KCOM_NETIF_MAX));
+ break;
+ }
+ priv = (bkn_priv_t *)list;
+ kmsg->id[idx] = priv->id;
+ idx++;
+ }
+ kmsg->ifcnt = idx;
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return sizeof(*kmsg) - sizeof(kmsg->id) + (idx * sizeof(kmsg->id[0]));
+}
+
+static int
+bkn_knet_netif_get(kcom_msg_netif_get_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ bkn_priv_t *priv;
+ unsigned long flags;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ priv = bkn_netif_lookup(sinfo, kmsg->hdr.id);
+
+ if (priv == NULL) {
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ kmsg->hdr.status = KCOM_E_NOT_FOUND;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ memcpy(kmsg->netif.macaddr, priv->dev->dev_addr, 6);
+ memcpy(kmsg->netif.name, priv->dev->name, KCOM_NETIF_NAME_MAX - 1);
+ kmsg->netif.vlan = priv->vlan;
+ kmsg->netif.type = priv->type;
+ kmsg->netif.id = priv->id;
+ kmsg->netif.flags = priv->flags;
+
+ if (priv->port < 0) {
+ kmsg->netif.port = 0;
+ } else {
+ kmsg->netif.port = priv->port;
+ }
+ kmsg->netif.qnum = priv->qnum;
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return sizeof(*kmsg);
+}
+
+static int
+bkn_knet_filter_create(kcom_msg_filter_create_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ struct list_head *list;
+ bkn_filter_t *filter, *lfilter;
+ unsigned long flags;
+ int found, id;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ switch (kmsg->filter.type) {
+ case KCOM_FILTER_T_RX_PKT:
+ break;
+ default:
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ /*
+ * Find available ID
+ */
+ found = 1;
+ id = 0;
+ while (found && ++id < KCOM_FILTER_MAX) {
+ found = 0;
+ list_for_each(list, &sinfo->rxpf_list) {
+ lfilter = (bkn_filter_t *)list;
+ if (id == lfilter->kf.id) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (found) {
+ /* Too many filters */
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ kmsg->hdr.status = KCOM_E_RESOURCE;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ filter = kmalloc(sizeof(*filter), GFP_ATOMIC);
+ if (filter == NULL) {
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+ memset(filter, 0, sizeof(*filter));
+ memcpy(&filter->kf, &kmsg->filter, sizeof(filter->kf));
+
+ if (device_is_dnx(sinfo)) {
+ /* Information to parser Dune system headers */
+ sinfo->ftmh_lb_key_ext_size = kmsg->filter.ftmh_lb_key_ext_size;
+ sinfo->ftmh_stacking_ext_size = kmsg->filter.ftmh_stacking_ext_size;
+ sinfo->pph_base_size = kmsg->filter.pph_base_size;
+ memcpy(sinfo->pph_lif_ext_size, kmsg->filter.pph_lif_ext_size, sizeof(sinfo->pph_lif_ext_size));
+ sinfo->udh_enable = kmsg->filter.udh_enable;
+ memcpy(sinfo->udh_length_type, kmsg->filter.udh_length_type, sizeof(sinfo->udh_length_type));
+ }
+
+ filter->kf.id = id;
+
+ /* Add according to priority */
+ found = 0;
+ list_for_each(list, &sinfo->rxpf_list) {
+ lfilter = (bkn_filter_t *)list;
+ if (filter->kf.priority < lfilter->kf.priority) {
+ list_add_tail(&filter->list, &lfilter->list);
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ list_add_tail(&filter->list, &sinfo->rxpf_list);
+ }
+
+ kmsg->filter.id = filter->kf.id;
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ DBG_VERB(("Created filter ID %d (%s).\n",
+ filter->kf.id, filter->kf.desc));
+
+ if (device_is_dnx(sinfo)) {
+ int idx, wsize;
+ wsize = BYTES2WORDS(filter->kf.oob_data_size + filter->kf.pkt_data_size);
+ DBG_DUNE(("Filter: oob_data_size = %d pkt_data_size=%d wsize %d\n", filter->kf.oob_data_size, filter->kf.pkt_data_size, wsize));
+ for (idx = 0; idx < wsize; idx++)
+ {
+ DBG_DUNE(("OOB[%d]: 0x%08x [0x%08x]\n", idx, filter->kf.data.w[idx], filter->kf.mask.w[idx]));
+ }
+ DBG_DUNE(("DNX system headers parameters:LB_KEY_EXT %d, STK_EXT %d, PPH_BASE %d, LIF_EXT %d %d %d, UDH_ENA %d, %d %d %d %d\n",
+ sinfo->ftmh_lb_key_ext_size, sinfo->ftmh_stacking_ext_size, sinfo->pph_base_size,
+ sinfo->pph_lif_ext_size[1],sinfo->pph_lif_ext_size[2], sinfo->pph_lif_ext_size[3],
+ sinfo->udh_enable, sinfo->udh_length_type[0], sinfo->udh_length_type[1], sinfo->udh_length_type[2], sinfo->udh_length_type[3]));
+ }
+
+ return len;
+}
+
+static int
+bkn_knet_filter_destroy(kcom_msg_filter_destroy_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ bkn_filter_t *filter;
+ struct list_head *list;
+ unsigned long flags;
+ int found;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ found = 0;
+ list_for_each(list, &sinfo->rxpf_list) {
+ filter = (bkn_filter_t *)list;
+ if (kmsg->hdr.id == filter->kf.id) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ kmsg->hdr.status = KCOM_E_NOT_FOUND;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ list_del(&filter->list);
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ DBG_VERB(("Removing filter ID %d.\n", filter->kf.id));
+ kfree(filter);
+
+ return sizeof(kcom_msg_hdr_t);
+}
+
+static int
+bkn_knet_filter_list(kcom_msg_filter_list_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ bkn_filter_t *filter;
+ struct list_head *list;
+ unsigned long flags;
+ int idx;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ idx = 0;
+ list_for_each(list, &sinfo->rxpf_list) {
+ if (idx >= KCOM_FILTER_MAX) {
+ DBG_WARN(("Too many filters to list (max %d).\n",
+ KCOM_FILTER_MAX));
+ break;
+ }
+ filter = (bkn_filter_t *)list;
+ kmsg->id[idx] = filter->kf.id;
+ idx++;
+ }
+ kmsg->fcnt = idx;
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return sizeof(*kmsg) - sizeof(kmsg->id) + (idx * sizeof(kmsg->id[0]));
+}
+
+static int
+bkn_knet_filter_get(kcom_msg_filter_get_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ bkn_filter_t *filter;
+ struct list_head *list;
+ unsigned long flags;
+ int found;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ found = 0;
+ list_for_each(list, &sinfo->rxpf_list) {
+ filter = (bkn_filter_t *)list;
+ if (kmsg->hdr.id == filter->kf.id) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ kmsg->hdr.status = KCOM_E_NOT_FOUND;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ memcpy(&kmsg->filter, &filter->kf, sizeof(kmsg->filter));
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return sizeof(*kmsg);
+}
+
+static int
+bkn_knet_dbg_pkt_set(kcom_msg_dbg_pkt_set_t *kmsg, int len)
+{
+ dbg_pkt_enable = kmsg->enable;
+ return sizeof(kcom_msg_dbg_pkt_set_t);
+}
+
+static int
+bkn_knet_dbg_pkt_get(kcom_msg_dbg_pkt_get_t *kmsg, int len)
+{
+ kmsg->value = dbg_pkt_enable;
+ return sizeof(kcom_msg_dbg_pkt_get_t);
+}
+
+static int
+bkn_knet_wb_cleanup(kcom_msg_wb_cleanup_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ bkn_dcb_chain_t *dcb_chain;
+ unsigned long flags;
+ int chan;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (sinfo->rx[chan].api_dcb_chain) {
+ DBG_DCB_RX(("Freeing active Rx%d DCB chain.\n", chan));
+ kfree(sinfo->rx[chan].api_dcb_chain);
+ sinfo->rx[chan].api_dcb_chain = NULL;
+ }
+ while (!list_empty(&sinfo->rx[chan].api_dcb_list)) {
+ dcb_chain = list_entry(sinfo->rx[chan].api_dcb_list.next,
+ bkn_dcb_chain_t, list);
+ list_del(&dcb_chain->list);
+ DBG_DCB_RX(("Freeing Rx%d DCB chain.\n", chan));
+ kfree(dcb_chain);
+ }
+ sinfo->rx[chan].api_dcb_chain_end = NULL;
+ sinfo->rx[chan].api_active = 0;
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return sizeof(kcom_msg_hdr_t);
+}
+
+static int
+bkn_handle_cmd_req(kcom_msg_t *kmsg, int len)
+{
+ /* Silently drop events and unrecognized message types */
+ if (kmsg->hdr.type != KCOM_MSG_TYPE_CMD) {
+ if (kmsg->hdr.opcode == KCOM_M_STRING) {
+ DBG_VERB(("Debug string: '%s'\n", kmsg->string.val));
+ return 0;
+ }
+ DBG_WARN(("Unsupported message (type=%d, opcode=%d)\n",
+ kmsg->hdr.type, kmsg->hdr.opcode));
+ return 0;
+ }
+
+ switch (kmsg->hdr.opcode) {
+ case KCOM_M_DMA_INFO:
+ DBG_CMD(("KCOM_M_DMA_INFO\n"));
+ /* Packet buffer */
+ len = bkn_knet_dma_info(&kmsg->dma_info, len);
+ break;
+ case KCOM_M_VERSION:
+ DBG_CMD(("KCOM_M_VERSION\n"));
+ /* Return procotol version */
+ len = bkn_knet_version(&kmsg->version, len);
+ break;
+ case KCOM_M_HW_RESET:
+ DBG_CMD(("KCOM_M_HW_RESET\n"));
+ /* Shut down DMA and release buffers */
+ len = bkn_knet_hw_reset(&kmsg->hw_reset, len);
+ break;
+ case KCOM_M_HW_INIT:
+ DBG_CMD(("KCOM_M_HW_INIT\n"));
+ /* Initialize DMA */
+ len = bkn_knet_hw_init(&kmsg->hw_init, len);
+ break;
+ case KCOM_M_DETACH:
+ DBG_CMD(("KCOM_M_DETACH\n"));
+ /* Detach kernel module */
+ len = bkn_knet_detach(&kmsg->detach, len);
+ break;
+ case KCOM_M_REPROBE:
+ DBG_CMD(("KCOM_M_REPROBE\n"));
+ /* Reprobe device */
+ len = bkn_knet_reprobe(&kmsg->reprobe, len);
+ break;
+ case KCOM_M_NETIF_CREATE:
+ DBG_CMD(("KCOM_M_NETIF_CREATE\n"));
+ /* Create network interface */
+ len = bkn_knet_netif_create(&kmsg->netif_create, len);
+ break;
+ case KCOM_M_NETIF_DESTROY:
+ DBG_CMD(("KCOM_M_NETIF_DESTROY\n"));
+ /* Destroy network interface */
+ len = bkn_knet_netif_destroy(&kmsg->netif_destroy, len);
+ break;
+ case KCOM_M_NETIF_LIST:
+ DBG_CMD(("KCOM_M_NETIF_LIST\n"));
+ /* Return list of IDs of installed network interfaces */
+ len = bkn_knet_netif_list(&kmsg->netif_list, len);
+ break;
+ case KCOM_M_NETIF_GET:
+ DBG_CMD(("KCOM_M_NETIF_GET\n"));
+ /* Return network interface info */
+ len = bkn_knet_netif_get(&kmsg->netif_get, len);
+ break;
+ case KCOM_M_FILTER_CREATE:
+ DBG_CMD(("KCOM_M_FILTER_CREATE\n"));
+ /* Create packet filter */
+ len = bkn_knet_filter_create(&kmsg->filter_create, len);
+ break;
+ case KCOM_M_FILTER_DESTROY:
+ DBG_CMD(("KCOM_M_FILTER_DESTROY\n"));
+ /* Destroy packet filter */
+ len = bkn_knet_filter_destroy(&kmsg->filter_destroy, len);
+ break;
+ case KCOM_M_FILTER_LIST:
+ DBG_CMD(("KCOM_M_FILTER_LIST\n"));
+ /* Return list of IDs of installed packet filters */
+ len = bkn_knet_filter_list(&kmsg->filter_list, len);
+ break;
+ case KCOM_M_FILTER_GET:
+ DBG_CMD(("KCOM_M_FILTER_GET\n"));
+ /* Return packet filter info */
+ len = bkn_knet_filter_get(&kmsg->filter_get, len);
+ break;
+ case KCOM_M_DBGPKT_SET:
+ DBG_CMD(("KCOM_M_DBGPKT_SET\n"));
+ /* Set debugging packet function */
+ len = bkn_knet_dbg_pkt_set(&kmsg->dbg_pkt_set, len);
+ break;
+ case KCOM_M_DBGPKT_GET:
+ DBG_CMD(("KCOM_M_DBGPKT_GET\n"));
+ /* Get debugging packet function info */
+ len = bkn_knet_dbg_pkt_get(&kmsg->dbg_pkt_get, len);
+ break;
+ case KCOM_M_WB_CLEANUP:
+ DBG_CMD(("KCOM_M_WB_CLEANUP\n"));
+ /* Clean up for warmbooting */
+ len = bkn_knet_wb_cleanup(&kmsg->wb_cleanup, len);
+ break;
+ default:
+ DBG_WARN(("Unsupported command (type=%d, opcode=%d)\n",
+ kmsg->hdr.type, kmsg->hdr.opcode));
+ kmsg->hdr.opcode = 0;
+ len = sizeof(kcom_msg_hdr_t);
+ break;
+ }
+ return len;
+}
+
+static int
+bkn_cmd_thread(void *context)
+{
+ bkn_thread_ctrl_t *tc = (bkn_thread_ctrl_t *)context;
+ kcom_msg_t kmsg;
+ unsigned int len, rlen;
+
+ bkn_thread_boot(tc);
+
+ DBG_VERB(("Command thread starting\n"));
+ tc->state = 1;
+ while (!bkn_thread_should_stop(tc)) {
+ len = sizeof(kmsg);
+ tc->state = 2;
+ if (PROXY_RECV(KCOM_CHAN_KNET, &kmsg, &len) >= 0) {
+ DBG_VERB(("Received %d bytes from KCOM_CHAN_CMD\n", len));
+ tc->state = 3;
+ rlen = bkn_handle_cmd_req(&kmsg, len);
+ tc->state = 4;
+ if (rlen > 0) {
+ PROXY_SEND(KCOM_CHAN_KNET, &kmsg, rlen);
+ }
+ } else {
+ /* Thread interrupted */
+ bkn_sleep(1);
+ }
+ }
+ DBG_VERB(("Command thread done\n"));
+
+ bkn_thread_exit(tc);
+ return 0;
+}
+
+static int
+bkn_get_next_dma_event(kcom_msg_dma_info_t *kmsg)
+{
+ static int last_dev_no = 0;
+ bkn_switch_info_t *sinfo;
+ unsigned long flags;
+ int dev_no, dev_evt;
+ bkn_evt_resource_t *evt;
+
+ dev_evt = kmsg->hdr.unit;
+ sinfo = bkn_sinfo_from_unit(dev_evt);
+ if (sinfo == NULL) {
+ /* The device is not probed or initialized yet.*/
+ return 0;
+ }
+ if (sinfo->evt_idx == -1) {
+ /* Event queue is not ready yet */
+ return 0;
+ }
+
+ DBG_INST(("%s dev %d evt_idx %d\n",__FUNCTION__, dev_evt, sinfo->evt_idx));
+ dev_no = last_dev_no;
+ while (1) {
+ dev_no++;
+ sinfo = bkn_sinfo_from_unit(dev_no);
+ if (sinfo == NULL) {
+ dev_no = 0;
+ sinfo = bkn_sinfo_from_unit(dev_no);
+ }
+
+ if (sinfo && (sinfo->inst_id != 0) &&
+ ((sinfo->inst_id & (1 << dev_evt)) == 0)) {
+ DBG_INST((" %s skip dev(%d)\n",__FUNCTION__,dev_evt));
+ continue;
+ }
+
+ if (sinfo && sinfo->dma_events) {
+ DBG_EVT(("Next DMA events (0x%08x)\n", sinfo->dma_events));
+ kmsg->hdr.unit = sinfo->dev_no;
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+ kmsg->dma_info.flags = sinfo->dma_events;
+ sinfo->dma_events = 0;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ last_dev_no = dev_no;
+ break;
+ }
+
+ if (dev_no == last_dev_no) {
+ evt = &_bkn_evt[sinfo->evt_idx];
+ DBG_INST(("wait queue index %d\n",sinfo->evt_idx));
+ wait_event_interruptible(evt->evt_wq,
+ evt->evt_wq_get != evt->evt_wq_put);
+ DBG_VERB(("Event thread wakeup\n"));
+
+ /* Thread interrupted */
+ if (signal_pending(current)) {
+ return 0;
+ }
+
+ evt->evt_wq_get = evt->evt_wq_put;
+ }
+ }
+ return sizeof(*kmsg);
+}
+
+static int
+bkn_evt_thread(void *context)
+{
+ bkn_thread_ctrl_t *tc = (bkn_thread_ctrl_t *)context;
+ kcom_msg_dma_info_t kmsg;
+ int len;
+
+ bkn_thread_boot(tc);
+
+ memset(&kmsg, 0, sizeof(kmsg));
+ kmsg.hdr.type = KCOM_MSG_TYPE_EVT;
+ kmsg.hdr.opcode = KCOM_M_DMA_INFO;
+
+ DBG_VERB(("Event thread starting\n"));
+ tc->state = 1;
+ while (!bkn_thread_should_stop(tc)) {
+ tc->state = 2;
+ len = bkn_get_next_dma_event(&kmsg);
+ tc->state = 3;
+ if (len) {
+ PROXY_SEND(KCOM_CHAN_KNET, &kmsg, len);
+ } else {
+ /* Thread interrupted */
+ bkn_sleep(1);
+ }
+ }
+ DBG_VERB(("Event thread done\n"));
+
+ bkn_thread_exit(tc);
+ return 0;
+}
+
+static int
+_cleanup(void)
+{
+ struct list_head *list;
+ struct net_device *dev;
+ bkn_filter_t *filter;
+ bkn_priv_t *priv;
+ bkn_switch_info_t *sinfo;
+ unsigned long flags;
+
+ /* Inidicate that we are shutting down */
+ module_initialized = 0;
+
+ /* Shut down event thread */
+ bkn_thread_stop(&bkn_evt_ctrl);
+
+ /* Shut down command thread */
+ bkn_thread_stop(&bkn_cmd_ctrl);
+
+ /* Remove KCOM channel */
+ PROXY_SERVICE_DESTROY(KCOM_CHAN_KNET);
+
+ bkn_proc_cleanup();
+ remove_proc_entry("bcm/knet", NULL);
+ remove_proc_entry("bcm", NULL);
+
+ list_for_each(list, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)list;
+
+ del_timer_sync(&sinfo->timer);
+ del_timer_sync(&sinfo->rxtick);
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+ bkn_dma_abort(sinfo);
+ dev_irq_mask_set(sinfo, 0);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ DBG_IRQ(("Unregister ISR.\n"));
+ kernel_bde->interrupt_disconnect(sinfo->dev_no | LKBDE_ISR2_DEV);
+
+ if (use_napi) {
+ while (sinfo->napi_poll_mode) {
+ bkn_sleep(1);
+ }
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+ bkn_clean_dcbs(sinfo);
+ skb_queue_purge(&sinfo->tx_ptp_queue);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ }
+
+ /* Destroy all switch devices */
+ while (!list_empty(&_sinfo_list)) {
+ sinfo = list_entry(_sinfo_list.next, bkn_switch_info_t, list);
+
+ /* Destroy all associated Rx packet filters */
+ while (!list_empty(&sinfo->rxpf_list)) {
+ filter = list_entry(sinfo->rxpf_list.next, bkn_filter_t, list);
+ list_del(&filter->list);
+ DBG_VERB(("Removing filter ID %d.\n", filter->kf.id));
+ kfree(filter);
+ }
+
+ /* Destroy all associated virtual net devices */
+ while (!list_empty(&sinfo->ndev_list)) {
+ priv = list_entry(sinfo->ndev_list.next, bkn_priv_t, list);
+ list_del(&priv->list);
+ dev = priv->dev;
+ DBG_VERB(("Removing virtual Ethernet device %s.\n", dev->name));
+ unregister_netdev(dev);
+ free_netdev(dev);
+ }
+ if (sinfo->ndevs != NULL) {
+ kfree(sinfo->ndevs);
+ }
+
+ /* Destroy base net device */
+ if (sinfo->dev) {
+ DBG_VERB(("Removing Ethernet device %s.\n", sinfo->dev->name));
+ unregister_netdev(sinfo->dev);
+ free_netdev(sinfo->dev);
+ }
+
+ DBG_VERB(("Removing switch device.\n"));
+ bkn_destroy_sinfo(sinfo);
+ }
+
+ return 0;
+}
+
+static int
+bkn_knet_dev_reinit(int d)
+{
+ bkn_switch_info_t *sinfo;
+ uint32 dev_state;
+ unsigned long flags;
+
+ if (lkbde_dev_state_get(d, &dev_state) < 0) {
+ return -1;
+ }
+ DBG_VERB(("%s dev %d dev_state %d\n",__FUNCTION__, d, dev_state));
+ if (dev_state == BDE_DEV_STATE_CHANGED) {
+ sinfo = bkn_sinfo_from_unit(d);
+ spin_lock_irqsave(&sinfo->lock, flags);
+ sinfo->base_addr = lkbde_get_dev_virt(d);
+ sinfo->dma_dev = lkbde_get_dma_dev(d);
+ sinfo->pdev = lkbde_get_hw_dev(d);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ dev_state = 0;
+ lkbde_dev_state_set(d, dev_state);
+ }
+ return 0;
+}
+
+static int
+bkn_knet_dev_init(int d)
+{
+ uint32_t dev_type;
+ struct net_device *dev;
+ bkn_switch_info_t *sinfo;
+ bkn_priv_t *priv;
+ char *bdev_name;
+ const ibde_dev_t *bde_dev;
+
+ DBG_VERB(("%s dev %d\n",__FUNCTION__, d));
+ /* Base network device name */
+ bdev_name = "bcm%d";
+ if (base_dev_name) {
+ if (strlen(base_dev_name) < IFNAMSIZ) {
+ bdev_name = base_dev_name;
+ } else {
+ DBG_WARN(("Base device name too long\n"));
+ }
+ }
+
+ dev_type = kernel_bde->get_dev_type(d);
+ DBG_VERB(("Found device type 0x%x\n", dev_type));
+ if ((dev_type & BDE_SWITCH_DEV_TYPE) == 0) {
+ DBG_WARN(("Not switch device - skipping\n"));
+ return 0;
+ }
+ switch (dev_type & BDE_DEV_BUS_TYPE_MASK) {
+ case BDE_PCI_DEV_TYPE:
+ case BDE_ICS_DEV_TYPE:
+ case BDE_AXI_DEV_TYPE:
+ break;
+ default:
+ DBG_WARN(("Not PCI/ICS/AXI device - skipping\n"));
+ return 0;
+ }
+
+ if ((sinfo = bkn_create_sinfo(d)) == NULL) {
+ _cleanup();
+ return -ENOMEM;
+ }
+
+ /* Initialize the cpu_no.*/
+ if (dev_type & BDE_AXI_DEV_TYPE) {
+ /* AXI device type implies the activated iProc iHost */
+ sinfo->cpu_no = 1;
+ }
+ /* Initialize default RCPU signature */
+ if ((bde_dev = kernel_bde->get_dev(d)) != NULL) {
+ sinfo->rcpu_sig = bde_dev->device & ~0xf;
+ }
+ /* Check for override */
+ if (rcpu_signature) {
+ sinfo->rcpu_sig = rcpu_signature;
+ }
+
+ /* Create base virtual net device */
+ bkn_dev_mac[5]++;
+ if ((dev = bkn_init_ndev(bkn_dev_mac, bdev_name)) == NULL) {
+ _cleanup();
+ return -ENOMEM;
+ } else {
+ sinfo->dev = dev;
+ priv = netdev_priv(dev);
+ priv->dev = dev;
+ priv->sinfo = sinfo;
+ priv->vlan = 1;
+ priv->port = -1;
+ memset(priv->itmh, 0, sizeof(priv->itmh));
+ priv->id = -1;
+ }
+
+ if (use_napi) {
+ netif_napi_add(dev, &sinfo->napi, bkn_poll, napi_weight);
+ }
+ return 0;
+}
+
+static int
+_init(void)
+{
+ int idx;
+ int num_dev;
+ int rv;
+ bkn_evt_resource_t *evt;
+
+ /* Connect to the kernel bde */
+ if ((linux_bde_create(NULL, &kernel_bde) < 0) || kernel_bde == NULL) {
+ return -ENODEV;
+ }
+
+ /* Randomize Lower 3 bytes of the MAC address (TESTING ONLY) */
+ get_random_bytes(&bkn_dev_mac[3], 3);
+
+ /* Check for user-supplied MAC address (recommended) */
+ if (mac_addr != NULL && strlen(mac_addr) == 17) {
+ for (idx = 0; idx < 6; idx++) {
+ bkn_dev_mac[idx] = simple_strtoul(&mac_addr[idx*3], NULL, 16);
+ }
+ /* Do not allow multicast address */
+ bkn_dev_mac[0] &= ~0x01;
+ }
+
+ /* Optional RCPU MAC addresses */
+ if (rcpu_dmac != NULL && strlen(rcpu_dmac) == 17) {
+ for (idx = 0; idx < 6; idx++) {
+ bkn_rcpu_dmac[idx] = simple_strtoul(&rcpu_dmac[idx*3], NULL, 16);
+ }
+ }
+ if (rcpu_smac != NULL && strlen(rcpu_smac) == 17) {
+ for (idx = 0; idx < 6; idx++) {
+ bkn_rcpu_smac[idx] = simple_strtoul(&rcpu_smac[idx*3], NULL, 16);
+ }
+ }
+
+ /* NAPI implies that base device must be up before we can pass traffic */
+ if (use_napi) {
+ basedev_suspend = 1;
+ }
+
+ num_dev = kernel_bde->num_devices(BDE_ALL_DEVICES);
+ for (idx = 0; idx < num_dev; idx++) {
+ rv = bkn_knet_dev_init(idx);
+ if (rv) {
+ return rv;
+ }
+ }
+
+ /* Initialize proc files */
+ proc_mkdir("bcm", NULL);
+ bkn_proc_root = proc_mkdir("bcm/knet", NULL);
+
+ bkn_proc_init();
+
+ /* Initialize event queue */
+ for (idx = 0; idx < LINUX_BDE_MAX_DEVICES; idx++) {
+ memset(&_bkn_evt[idx], 0, sizeof(bkn_evt_resource_t));
+ }
+ evt = &_bkn_evt[0];
+ init_waitqueue_head(&evt->evt_wq);
+
+ if (use_proxy) {
+ PROXY_SERVICE_CREATE(KCOM_CHAN_KNET, 1, 0);
+
+ DBG_VERB(("Starting command thread\n"));
+ bkn_thread_start(&bkn_cmd_ctrl, "bkncmd", bkn_cmd_thread);
+
+ DBG_VERB(("Starting event thread\n"));
+ bkn_thread_start(&bkn_evt_ctrl, "bknevt", bkn_evt_thread);
+ }
+
+ module_initialized = 1;
+
+ return 0;
+}
+
+static int
+_ioctl(unsigned int cmd, unsigned long arg)
+{
+ bkn_ioctl_t io;
+ kcom_msg_t kmsg;
+
+ if (!module_initialized) {
+ return -EFAULT;
+ }
+
+ if (copy_from_user(&io, (void*)arg, sizeof(io))) {
+ return -EFAULT;
+ }
+
+ if (io.len > sizeof(kmsg)) {
+ return -EINVAL;
+ }
+
+ io.rc = 0;
+
+ switch(cmd) {
+ case 0:
+ if (io.len > 0) {
+ if (copy_from_user(&kmsg, (void *)(unsigned long)io.buf, io.len)) {
+ return -EFAULT;
+ }
+ ioctl_cmd++;
+ io.len = bkn_handle_cmd_req(&kmsg, io.len);
+ ioctl_cmd--;
+ } else {
+ memset(&kmsg, 0, sizeof(kcom_msg_dma_info_t));
+ /*
+ * Retrive the kmsg.hdr.unit from user space. The dma event queue
+ * selection is based the instance derived from unit.
+ */
+ if (copy_from_user(&kmsg, (void *)(unsigned long)io.buf, sizeof(kmsg))) {
+ return -EFAULT;
+ }
+ kmsg.hdr.type = KCOM_MSG_TYPE_EVT;
+ kmsg.hdr.opcode = KCOM_M_DMA_INFO;
+ ioctl_evt++;
+ io.len = bkn_get_next_dma_event((kcom_msg_dma_info_t *)&kmsg);
+ ioctl_evt--;
+ }
+ if (io.len > 0) {
+ if (copy_to_user((void *)(unsigned long)io.buf, &kmsg, io.len)) {
+ return -EFAULT;
+ }
+ }
+ break;
+ default:
+ gprintk("Invalid IOCTL");
+ io.rc = -1;
+ break;
+ }
+
+ if (copy_to_user((void*)arg, &io, sizeof(io))) {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static gmodule_t _gmodule = {
+ name: MODULE_NAME,
+ major: MODULE_MAJOR,
+ init: _init,
+ cleanup: _cleanup,
+ pprint: _pprint,
+ ioctl: _ioctl,
+ open: NULL,
+ close: NULL,
+};
+
+gmodule_t *
+gmodule_get(void)
+{
+ EXPORT_NO_SYMBOLS;
+ return &_gmodule;
+}
+
+/*
+ * Call-back interfaces for other Linux kernel drivers.
+ *
+ * The Rx call-back allows an external module to modify SKB contents
+ * before it is handed off to the Linux network stack.
+ *
+ * The Tx call-back allows an external module to modify SKB contents
+ * before it is injected inot the switch.
+ *
+ * The HW timestamp callbacks invoke an external module to enable, disable
+ * HW timestamp on a specific port which is indicated while the netif is
+ * created through KNET API. KNET can also get device-specific SOBMH and
+ * timestamp for a Tx PTP packet through these callbacks.
+ */
+
+int
+bkn_rx_skb_cb_register(knet_skb_cb_f rx_cb)
+{
+ if (knet_rx_cb != NULL) {
+ return -1;
+ }
+ knet_rx_cb = rx_cb;
+ return 0;
+}
+
+int
+bkn_rx_skb_cb_unregister(knet_skb_cb_f rx_cb)
+{
+ if (rx_cb != NULL && knet_rx_cb != rx_cb) {
+ return -1;
+ }
+ knet_rx_cb = NULL;
+ return 0;
+}
+
+int
+bkn_tx_skb_cb_register(knet_skb_cb_f tx_cb)
+{
+ if (knet_tx_cb != NULL) {
+ return -1;
+ }
+ knet_tx_cb = tx_cb;
+ return 0;
+}
+
+int
+bkn_tx_skb_cb_unregister(knet_skb_cb_f tx_cb)
+{
+ if (tx_cb != NULL && knet_tx_cb != tx_cb) {
+ return -1;
+ }
+ knet_tx_cb = NULL;
+ return 0;
+}
+
+int
+bkn_filter_cb_register(knet_filter_cb_f filter_cb)
+{
+ if (knet_filter_cb != NULL) {
+ return -1;
+ }
+ knet_filter_cb = filter_cb;
+ return 0;
+}
+
+int
+bkn_filter_cb_unregister(knet_filter_cb_f filter_cb)
+{
+ if (filter_cb != NULL && knet_filter_cb != filter_cb) {
+ return -1;
+ }
+ knet_filter_cb = NULL;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_enable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb)
+{
+ if (knet_hw_tstamp_enable_cb != NULL) {
+ return -1;
+ }
+ knet_hw_tstamp_enable_cb = hw_tstamp_enable_cb;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_enable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb)
+{
+ if (hw_tstamp_enable_cb == NULL ||
+ knet_hw_tstamp_enable_cb != hw_tstamp_enable_cb) {
+ return -1;
+ }
+ knet_hw_tstamp_enable_cb = NULL;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_disable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb)
+{
+ if (knet_hw_tstamp_disable_cb != NULL) {
+ return -1;
+ }
+ knet_hw_tstamp_disable_cb = hw_tstamp_disable_cb;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_disable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb)
+{
+ if (hw_tstamp_disable_cb == NULL ||
+ knet_hw_tstamp_disable_cb != hw_tstamp_disable_cb) {
+ return -1;
+ }
+ knet_hw_tstamp_disable_cb = NULL;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_tx_time_get_cb_register(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb)
+{
+ if (knet_hw_tstamp_tx_time_get_cb != NULL) {
+ return -1;
+ }
+ knet_hw_tstamp_tx_time_get_cb = hw_tstamp_tx_time_get_cb;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_tx_time_get_cb_unregister(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb)
+{
+ if (hw_tstamp_tx_time_get_cb == NULL ||
+ knet_hw_tstamp_tx_time_get_cb != hw_tstamp_tx_time_get_cb) {
+ return -1;
+ }
+ knet_hw_tstamp_tx_time_get_cb = NULL;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_tx_meta_get_cb_register(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb)
+{
+ if (knet_hw_tstamp_tx_meta_get_cb != NULL) {
+ return -1;
+ }
+ knet_hw_tstamp_tx_meta_get_cb = hw_tstamp_tx_meta_get_cb;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_tx_meta_get_cb_unregister(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb)
+{
+ if (hw_tstamp_tx_meta_get_cb == NULL ||
+ knet_hw_tstamp_tx_meta_get_cb != hw_tstamp_tx_meta_get_cb) {
+ return -1;
+ }
+ knet_hw_tstamp_tx_meta_get_cb = NULL;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_ptp_clock_index_cb_register(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb)
+{
+ if (knet_hw_tstamp_ptp_clock_index_cb != NULL) {
+ return -1;
+ }
+ knet_hw_tstamp_ptp_clock_index_cb = hw_tstamp_ptp_clock_index_cb;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_ptp_clock_index_cb_unregister(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb)
+{
+ if (hw_tstamp_ptp_clock_index_cb == NULL ||
+ knet_hw_tstamp_ptp_clock_index_cb != hw_tstamp_ptp_clock_index_cb) {
+ return -1;
+ }
+ knet_hw_tstamp_ptp_clock_index_cb = NULL;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_rx_time_upscale_cb_register(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb)
+{
+ if (knet_hw_tstamp_rx_time_upscale_cb != NULL) {
+ return -1;
+ }
+ knet_hw_tstamp_rx_time_upscale_cb = hw_tstamp_rx_time_upscale_cb;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_rx_time_upscale_cb_unregister(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb)
+{
+ if (hw_tstamp_rx_time_upscale_cb == NULL ||
+ knet_hw_tstamp_rx_time_upscale_cb != hw_tstamp_rx_time_upscale_cb) {
+ return -1;
+ }
+ knet_hw_tstamp_rx_time_upscale_cb = NULL;
+ return 0;
+}
+
+LKM_EXPORT_SYM(bkn_rx_skb_cb_register);
+LKM_EXPORT_SYM(bkn_rx_skb_cb_unregister);
+LKM_EXPORT_SYM(bkn_tx_skb_cb_register);
+LKM_EXPORT_SYM(bkn_tx_skb_cb_unregister);
+LKM_EXPORT_SYM(bkn_filter_cb_register);
+LKM_EXPORT_SYM(bkn_filter_cb_unregister);
+LKM_EXPORT_SYM(bkn_hw_tstamp_enable_cb_register);
+LKM_EXPORT_SYM(bkn_hw_tstamp_enable_cb_unregister);
+LKM_EXPORT_SYM(bkn_hw_tstamp_disable_cb_register);
+LKM_EXPORT_SYM(bkn_hw_tstamp_disable_cb_unregister);
+LKM_EXPORT_SYM(bkn_hw_tstamp_tx_time_get_cb_register);
+LKM_EXPORT_SYM(bkn_hw_tstamp_tx_time_get_cb_unregister);
+LKM_EXPORT_SYM(bkn_hw_tstamp_tx_meta_get_cb_register);
+LKM_EXPORT_SYM(bkn_hw_tstamp_tx_meta_get_cb_unregister);
+LKM_EXPORT_SYM(bkn_hw_tstamp_ptp_clock_index_cb_register);
+LKM_EXPORT_SYM(bkn_hw_tstamp_ptp_clock_index_cb_unregister);
+LKM_EXPORT_SYM(bkn_hw_tstamp_rx_time_upscale_cb_register);
+LKM_EXPORT_SYM(bkn_hw_tstamp_rx_time_upscale_cb_unregister);
diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/include/bcm-knet.h b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/include/bcm-knet.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: bcm-knet.h,v 1.4 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+#ifndef __LINUX_BCM_KNET_H__
+#define __LINUX_BCM_KNET_H__
+
+#ifndef __KERNEL__
+#include <stdint.h>
+#endif
+
+typedef struct {
+ int rc;
+ int len;
+ int bufsz;
+ int reserved;
+ uint64_t buf;
+} bkn_ioctl_t;
+
+#ifdef __KERNEL__
+
+/*
+ * Call-back interfaces for other Linux kernel drivers.
+ */
+#include <linux/skbuff.h>
+
+typedef struct {
+ uint32 netif_user_data;
+ uint32 filter_user_data;
+ uint16 dcb_type;
+ int port;
+} knet_skb_cb_t;
+
+#define KNET_SKB_CB(_skb) ((knet_skb_cb_t *)_skb->cb)
+
+typedef struct sk_buff *
+(*knet_skb_cb_f)(struct sk_buff *skb, int dev_no, void *meta);
+
+typedef int
+(*knet_filter_cb_f)(uint8_t *pkt, int size, int dev_no, void *meta,
+ int chan, kcom_filter_t *filter);
+
+typedef int
+(*knet_hw_tstamp_enable_cb_f)(int dev_no, int port);
+
+typedef int
+(*knet_hw_tstamp_tx_time_get_cb_f)(int dev_no, int port, uint8_t *pkt, uint64_t *ts);
+
+typedef int
+(*knet_hw_tstamp_tx_meta_get_cb_f)(int dev_no, struct sk_buff *skb, uint32_t **md);
+
+typedef int
+(*knet_hw_tstamp_ptp_clock_index_cb_f)(int dev_no);
+
+typedef int
+(*knet_hw_tstamp_rx_time_upscale_cb_f)(int dev_no, uint64_t *ts);
+
+extern int
+bkn_rx_skb_cb_register(knet_skb_cb_f rx_cb);
+
+extern int
+bkn_rx_skb_cb_unregister(knet_skb_cb_f rx_cb);
+
+extern int
+bkn_tx_skb_cb_register(knet_skb_cb_f tx_cb);
+
+extern int
+bkn_tx_skb_cb_unregister(knet_skb_cb_f tx_cb);
+
+extern int
+bkn_filter_cb_register(knet_filter_cb_f filter_cb);
+
+extern int
+bkn_filter_cb_unregister(knet_filter_cb_f filter_cb);
+
+extern int
+bkn_hw_tstamp_enable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb);
+
+extern int
+bkn_hw_tstamp_enable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb);
+
+extern int
+bkn_hw_tstamp_disable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb);
+
+extern int
+bkn_hw_tstamp_disable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb);
+
+extern int
+bkn_hw_tstamp_tx_time_get_cb_register(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb);
+
+extern int
+bkn_hw_tstamp_tx_time_get_cb_unregister(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb);
+
+extern int
+bkn_hw_tstamp_tx_meta_get_cb_register(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb);
+
+extern int
+bkn_hw_tstamp_tx_meta_get_cb_unregister(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb);
+
+extern int
+bkn_hw_tstamp_ptp_clock_index_cb_register(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb);
+
+extern int
+bkn_hw_tstamp_ptp_clock_index_cb_unregister(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb);
+
+extern int
+bkn_hw_tstamp_rx_time_upscale_cb_register(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb);
+
+extern int
+bkn_hw_tstamp_rx_time_upscale_cb_unregister(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb);
+
+#endif
+
+#endif /* __LINUX_BCM_KNET_H__ */
diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/include/gmodule.h b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/include/gmodule.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: gmodule.h,v 1.9 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#ifndef __COMMON_LINUX_KRN_GMODULE_H__
+#define __COMMON_LINUX_KRN_GMODULE_H__
+
+#include <lkm.h>
+
+typedef struct gmodule_s {
+
+ const char* name;
+ int major;
+ int minor;
+
+ int (*init)(void);
+ int (*cleanup)(void);
+
+ int (*pprint)(void);
+
+ int (*open)(void);
+ int (*ioctl)(unsigned int cmd, unsigned long arg);
+ int (*close)(void);
+ int (*mmap) (struct file *filp, struct vm_area_struct *vma);
+
+} gmodule_t;
+
+
+/* The framework will ask for your module definition */
+extern gmodule_t* gmodule_get(void);
+
+
+/* Proc Filesystem information */
+extern int pprintf(const char* fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+extern int gmodule_vpprintf(char** page, const char* fmt, va_list args)
+ __attribute__ ((format (printf, 2, 0)));
+extern int gmodule_pprintf(char** page, const char* fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+
+extern int gprintk(const char* fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+extern int gdbg(const char* fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+#define GDBG gdbg
+
+#endif /* __COMMON_LINUX_KRN_GMODULE_H__ */
diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/include/lkm.h b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/include/lkm.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: lkm.h,v 1.22 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#ifndef __COMMON_LINUX_KRN_LKM_H__
+#define __COMMON_LINUX_KRN_LKM_H__
+
+#ifndef __KERNEL__
+# define __KERNEL__
+#endif
+#ifndef MODULE
+# define MODULE
+#endif
+
+#include <linux/init.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include <linux/config.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)
+#include <linux/kconfig.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+#include <linux/slab.h>
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)
+#include <linux/smp_lock.h>
+#endif
+#include <linux/module.h>
+
+/* Helper defines for multi-version kernel support */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#define LKM_2_4
+#else
+#define LKM_2_6
+#endif
+
+#include <linux/kernel.h> /* printk() */
+#include <linux/fs.h> /* everything... */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/proc_fs.h>
+#include <linux/fcntl.h> /* O_ACCMODE */
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/stat.h>
+#include <linux/sched.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)
+#include <linux/sched/signal.h>
+#endif
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/hardirq.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#endif
+
+#define PROC_INTERFACE_KERN_VER_3_10 (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
+
+/* Compatibility Macros */
+
+#ifdef LKM_2_4
+
+#include <linux/compatmac.h>
+#include <linux/wrapper.h>
+#define LKM_MOD_PARAM(n,ot,nt,d) MODULE_PARM(n,ot)
+#define LKM_MOD_PARAM_ARRAY(n,ot,nt,c,d) MODULE_PARM(n,ot)
+#define LKM_EXPORT_SYM(s)
+#define _free_netdev kfree
+
+#else /* LKM_2_6 */
+
+#define LKM_MOD_PARAM(n,ot,nt,d) module_param(n,nt,d)
+#define LKM_MOD_PARAM_ARRAY(n,ot,nt,c,d) module_param_array(n,nt,c,d)
+#define LKM_EXPORT_SYM(s) EXPORT_SYMBOL(s)
+#define _free_netdev free_netdev
+
+#endif /* LKM_2_x */
+
+#ifndef list_for_each_safe
+#define list_for_each_safe(l,t,i) t = 0; list_for_each((l),(i))
+#endif
+
+#ifndef reparent_to_init
+#define reparent_to_init()
+#endif
+
+#ifndef MODULE_LICENSE
+#define MODULE_LICENSE(str)
+#endif
+
+#ifndef EXPORT_NO_SYMBOLS
+#define EXPORT_NO_SYMBOLS
+#endif
+
+#ifndef DEFINE_SPINLOCK
+#define DEFINE_SPINLOCK(_lock) spinlock_t _lock = SPIN_LOCK_UNLOCKED
+#endif
+
+#ifndef __SPIN_LOCK_UNLOCKED
+#define __SPIN_LOCK_UNLOCKED(_lock) SPIN_LOCK_UNLOCKED
+#endif
+
+#ifndef lock_kernel
+#ifdef preempt_disable
+#define lock_kernel() preempt_disable()
+#else
+#define lock_kernel()
+#endif
+#endif
+
+#ifndef unlock_kernel
+#ifdef preempt_enable
+#define unlock_kernel() preempt_enable()
+#else
+#define unlock_kernel()
+#endif
+#endif
+
+#ifndef init_MUTEX_LOCKED
+#define init_MUTEX_LOCKED(_sem) sema_init(_sem, 0)
+#endif
+
+#ifdef CONFIG_BCM98245
+#define CONFIG_BMW
+#endif
+
+#if PROC_INTERFACE_KERN_VER_3_10
+#define PROC_CREATE(_entry, _name, _acc, _path, _fops) \
+ do { \
+ _entry = proc_create(_name, _acc, _path, _fops); \
+ } while (0)
+
+#define PROC_CREATE_DATA(_entry, _name, _acc, _path, _fops, _data) \
+ do { \
+ _entry = proc_create_data(_name, _acc, _path, _fops, _data); \
+ } while (0)
+
+#define PROC_PDE_DATA(_node) PDE_DATA(_node)
+
+#else
+#define PROC_CREATE(_entry, _name, _acc, _path, _fops) \
+ do { \
+ _entry = create_proc_entry(_name, _acc, _path); \
+ if (_entry) { \
+ _entry->proc_fops = _fops; \
+ } \
+ } while (0)
+
+#define PROC_CREATE_DATA(_entry, _name, _acc, _path, _fops, _data) \
+ do { \
+ _entry = create_proc_entry(_name, _acc, _path); \
+ if (_entry) { \
+ _entry->proc_fops = _fops; \
+ _entry->data=_data; \
+ } \
+ } while (0)
+
+#define PROC_PDE_DATA(_node) PROC_I(_node)->pde->data
+#endif
+
+#endif /* __COMMON_LINUX_KRN_LKM_H__ */
diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/knet-cb/Makefile b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/knet-cb/Makefile
@@ -0,0 +1,64 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.3 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+LOCALDIR = systems/linux/kernel/modules/knet-cb
+
+include ${SDK}/make/Make.config
+
+LIBS = $(LIBDIR)/libkern.a
+
+ifeq ($(kernel_version),2_4)
+MODULE = $(LIBDIR)/linux-knet-cb.o
+else
+KERNEL_MODULE_DIR = kernel_module
+
+THIS_MOD_NAME := linux-knet-cb
+MODULE = $(LIBDIR)/$(THIS_MOD_NAME).o
+KMODULE = $(LIBDIR)/$(THIS_MOD_NAME).ko
+
+build: $(MODULE) $(KMODULE)
+endif
+
+KBUILD_EXTRA_SYMBOLS := ${BLDDIR}/../bcm-knet/kernel_module/Module.symvers
+
+# BCM Network Device
+
+$(MODULE): $(BLDDIR)/.tree $(BOBJS) $(LIBS)
+ $(LD) $(MODULE_LDFLAGS) -r -d $(BOBJS) $(LIBS) -o $@
+ifneq ($(kernel_version),2_4)
+$(KMODULE): $(MODULE)
+ rm -fr $(BLDDIR)/$(KERNEL_MODULE_DIR)
+ mkdir $(BLDDIR)/$(KERNEL_MODULE_DIR)
+ cp ${SDK}/make/Makefile.linux-kmodule $(BLDDIR)/$(KERNEL_MODULE_DIR)/Makefile
+ cat ${KBUILD_EXTRA_SYMBOLS} > $(BLDDIR)/$(KERNEL_MODULE_DIR)/Module.symvers
+ MOD_NAME=$(THIS_MOD_NAME) $(MAKE) -C $(BLDDIR)/$(KERNEL_MODULE_DIR) $(THIS_MOD_NAME).ko
+endif
+
+# Make.depend is before clean:: so that Make.depend's clean:: runs first.
+
+include ${SDK}/make/Make.depend
+
+clean::
+ $(RM) $(BLDDIR)/version.c $(BLDDIR)/version.o
+ $(RM) $(BOBJS) $(MODULE)
+
+ifneq ($(kernel_version),2_4)
+.PHONY: build
+endif
diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2014 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+/*
+ * Test driver for call-back functions in Linux KNET driver.
+ *
+ * The module can be built from the standard Linux user mode target
+ * directories using the following command (assuming bash), e.g.
+ *
+ * cd $SDK/systems/linux/user/gto-2_6
+ * BUILD_KNET_CB=1 make -s mod
+ *
+ */
+
+#include <gmodule.h> /* Must be included first */
+#include <kcom.h>
+#include <bcm-knet.h>
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom Linux KNET Call-Back Driver");
+MODULE_LICENSE("GPL");
+
+/* Module Information */
+#define MODULE_MAJOR 121
+#define MODULE_NAME "linux-knet-cb"
+
+static void
+show_mac(struct sk_buff *skb)
+{
+ printk("DMAC=%02X:%02X:%02X:%02X:%02X:%02X\n",
+ skb->data[0], skb->data[1], skb->data[2],
+ skb->data[3], skb->data[4], skb->data[5]);
+}
+
+static struct sk_buff *
+test_rx_cb(struct sk_buff *skb, int dev_no, void *meta)
+{
+ printk("rx_cb for dev %d\n", dev_no);
+ printk("netif user data 0x%x\n", KNET_SKB_CB(skb)->netif_user_data);
+ printk("filter user data 0x%x\n", KNET_SKB_CB(skb)->filter_user_data);
+ printk("dcb type 0x%x\n", KNET_SKB_CB(skb)->dcb_type);
+ if (skb->data[5] == 0x03) {
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+ show_mac(skb);
+ return skb;
+}
+
+static struct sk_buff *
+test_tx_cb(struct sk_buff *skb, int dev_no, void *meta)
+{
+ printk("tx_cb for dev %d\n", dev_no);
+ show_mac(skb);
+ skb->data[5] += 1;
+ return skb;
+}
+
+static int
+test_filter_cb(uint8_t *pkt, int size, int dev_no, void *meta,
+ int chan, kcom_filter_t *kf)
+{
+ printk("filter_cb (%d) for dev %d\n", kf->dest_id, dev_no);
+ if (pkt[12] == 0x81 && pkt[13] == 0x00) {
+ printk(" VTAG %d\n", pkt[15]);
+ kf->dest_type = KCOM_DEST_T_NETIF;
+ kf->dest_id = pkt[15];
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Generic module functions
+ */
+
+static int
+_pprint(void)
+{
+ pprintf("Broadcom Linux KNET Call-Back Driver\n");
+
+ return 0;
+}
+
+static int
+_cleanup(void)
+{
+ bkn_rx_skb_cb_unregister(test_rx_cb);
+ bkn_tx_skb_cb_unregister(test_tx_cb);
+ bkn_filter_cb_unregister(test_filter_cb);
+
+ return 0;
+}
+
+static int
+_init(void)
+{
+ bkn_rx_skb_cb_register(test_rx_cb);
+ bkn_tx_skb_cb_register(test_tx_cb);
+ bkn_filter_cb_register(test_filter_cb);
+
+ return 0;
+}
+
+static gmodule_t _gmodule = {
+ name: MODULE_NAME,
+ major: MODULE_MAJOR,
+ init: _init,
+ cleanup: _cleanup,
+ pprint: _pprint,
+ ioctl: NULL,
+ open: NULL,
+ close: NULL,
+};
+
+gmodule_t*
+gmodule_get(void)
+{
+ EXPORT_NO_SYMBOLS;
+ return &_gmodule;
+}
diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/shared/Makefile b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/shared/Makefile
@@ -0,0 +1,29 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.2 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+LOCALDIR = systems/linux/kernel/modules/shared
+
+include ${SDK}/make/Make.config
+
+lib = libkern
+
+include ${SDK}/make/Make.kernlib
+
+include ${SDK}/make/Make.depend
diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/shared/gmodule.c b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/shared/gmodule.c
@@ -0,0 +1,427 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: gmodule.c,v 1.20 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ * Generic Linux Module Framework
+ *
+ * Hooks up your driver to the kernel
+ */
+
+#include <lkm.h>
+#include <gmodule.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+
+/* Module Vector Table */
+static gmodule_t* _gmodule = NULL;
+
+
+/* Allow DEVFS Support on 2.4 Kernels */
+#if defined(LKM_2_4) && defined(CONFIG_DEVFS_FS)
+#define GMODULE_CONFIG_DEVFS_FS
+#endif
+
+
+#ifdef GMODULE_CONFIG_DEVFS_FS
+devfs_handle_t devfs_handle = NULL;
+#endif
+
+/* FIXME: support dynamic debugging */
+
+static int _dbg_enable = 0;
+
+static int
+gvprintk(const char* fmt, va_list args)
+ __attribute__ ((format (printf, 1, 0)));
+
+static int
+gvprintk(const char* fmt, va_list args)
+{
+ static char _buf[256];
+
+ strcpy(_buf, "");
+ sprintf(_buf, "%s (%d): ", _gmodule->name, current->pid);
+ vsprintf(_buf+strlen(_buf), fmt, args);
+ printk("%s",_buf);
+
+ return 0;
+}
+
+int
+gprintk(const char* fmt, ...)
+{
+ int rv;
+
+ va_list args;
+ va_start(args, fmt);
+ rv = gvprintk(fmt, args);
+ va_end(args);
+ return rv;
+}
+
+int
+gdbg(const char* fmt, ...)
+{
+ int rv = 0;
+
+ va_list args;
+ va_start(args, fmt);
+ if(_dbg_enable) {
+ rv = gvprintk(fmt, args);
+ }
+ va_end(args);
+ return rv;
+}
+
+
+/*
+ * Proc FS Utilities
+ */
+#if PROC_INTERFACE_KERN_VER_3_10
+static struct seq_file* _proc_buf = NULL;
+
+int
+pprintf(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ seq_vprintf(_proc_buf, fmt, args);
+ va_end(args);
+ return 0;
+}
+
+static int _gmodule_proc_show(struct seq_file *m, void *v){
+ _proc_buf = m;
+ _gmodule->pprint();
+ return 0;
+}
+
+static int
+_gmodule_proc_open(struct inode * inode, struct file * file) {
+ if(_gmodule->open) {
+ _gmodule->open();
+ }
+
+ return single_open(file, _gmodule_proc_show, NULL);
+}
+
+static ssize_t
+_gmodule_proc_write(struct file *file, const char *buffer,
+ size_t count, loff_t *loff)
+{
+ /* Workaround to toggle debugging */
+ if(count > 2) {
+ if(buffer[0] == 'd') {
+ _dbg_enable = buffer[1] - '0';
+ GDBG("Debugging Enabled");
+ }
+ }
+ return count;
+}
+
+static int _gmodule_proc_release(struct inode * inode, struct file * file) {
+ if(_gmodule->close) {
+ _gmodule->close();
+ }
+
+ return single_release(inode, file);
+}
+
+struct file_operations _gmodule_proc_fops = {
+ owner: THIS_MODULE,
+ open: _gmodule_proc_open,
+ read: seq_read,
+ llseek: seq_lseek,
+ write: _gmodule_proc_write,
+ release: _gmodule_proc_release,
+};
+#else
+int
+gmodule_vpprintf(char** page_ptr, const char* fmt, va_list args)
+{
+ *page_ptr += vsprintf(*page_ptr, fmt, args);
+ return 0;
+}
+
+int
+gmodule_pprintf(char** page_ptr, const char* fmt, ...)
+{
+ int rv;
+
+ va_list args;
+ va_start(args, fmt);
+ rv = gmodule_vpprintf(page_ptr, fmt, args);
+ va_end(args);
+ return rv;
+}
+
+static char* _proc_buf = NULL;
+
+int
+pprintf(const char* fmt, ...)
+{
+ int rv;
+
+ va_list args;
+ va_start(args, fmt);
+ rv = gmodule_vpprintf(&_proc_buf, fmt, args);
+ va_end(args);
+ return rv;
+}
+
+#define PSTART(b) _proc_buf = b
+#define PPRINT proc_print
+#define PEND(b) (_proc_buf-b)
+
+static int
+_gmodule_pprint(char* buf)
+{
+ PSTART(buf);
+ _gmodule->pprint();
+ return PEND(buf);
+}
+
+static int
+_gmodule_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ *eof = 1;
+ return _gmodule_pprint(page);
+}
+
+static int
+_gmodule_write_proc(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ /* Workaround to toggle debugging */
+ if(count > 2) {
+ if(buffer[0] == 'd') {
+ _dbg_enable = buffer[1] - '0';
+ GDBG("Debugging Enabled");
+ }
+ }
+ return count;
+}
+#endif
+
+static int
+_gmodule_create_proc(void)
+{
+ struct proc_dir_entry* ent;
+#if PROC_INTERFACE_KERN_VER_3_10
+ if((ent = proc_create(_gmodule->name,
+ S_IRUGO | S_IWUGO,
+ NULL,
+ &_gmodule_proc_fops)) != NULL) {
+ return 0;
+ }
+#else
+ if((ent = create_proc_entry(_gmodule->name, S_IRUGO | S_IWUGO, NULL)) != NULL) {
+ ent->read_proc = _gmodule_read_proc;
+ ent->write_proc = _gmodule_write_proc;
+ return 0;
+ }
+#endif
+ return -1;
+}
+
+static void
+_gmodule_remove_proc(void)
+{
+ remove_proc_entry(_gmodule->name, NULL);
+}
+
+static int
+_gmodule_open(struct inode *inode, struct file *filp)
+{
+ if(_gmodule->open) {
+ _gmodule->open();
+ }
+ return 0;
+}
+
+static int
+_gmodule_release(struct inode *inode, struct file *filp)
+{
+ if(_gmodule->close) {
+ _gmodule->close();
+ }
+ return 0;
+}
+
+#ifdef HAVE_UNLOCKED_IOCTL
+static long
+_gmodule_unlocked_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ if(_gmodule->ioctl) {
+ return _gmodule->ioctl(cmd, arg);
+ } else {
+ return -1;
+ }
+}
+#else
+static int
+_gmodule_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ if(_gmodule->ioctl) {
+ return _gmodule->ioctl(cmd, arg);
+ } else {
+ return -1;
+ }
+}
+#endif
+
+#ifdef HAVE_COMPAT_IOCTL
+static long
+_gmodule_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ if(_gmodule->ioctl) {
+ return _gmodule->ioctl(cmd, arg);
+ } else {
+ return -1;
+ }
+}
+#endif
+
+
+static int
+_gmodule_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ if (_gmodule->mmap) {
+ return _gmodule->mmap(filp, vma);
+ }
+#ifdef BCM_PLX9656_LOCAL_BUS
+ vma->vm_flags |= VM_RESERVED | VM_IO;
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+
+ if (io_remap_pfn_range( vma,
+ vma->vm_start,
+ vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
+ return (-EAGAIN);
+ }
+ return (0);
+#else/* BCM_PLX9656_LOCAL_BUS */
+ return -EPERM;
+#endif/* BCM_PLX9656_LOCAL_BUS */
+}
+
+/* FILE OPERATIONS */
+
+struct file_operations _gmodule_fops = {
+#ifdef HAVE_UNLOCKED_IOCTL
+ unlocked_ioctl: _gmodule_unlocked_ioctl,
+#else
+ ioctl: _gmodule_ioctl,
+#endif
+ open: _gmodule_open,
+ release: _gmodule_release,
+ mmap: _gmodule_mmap,
+#ifdef HAVE_COMPAT_IOCTL
+ compat_ioctl: _gmodule_compat_ioctl,
+#endif
+};
+
+
+void __exit
+cleanup_module(void)
+{
+ if(!_gmodule) return;
+
+ /* Specific Cleanup */
+ if(_gmodule->cleanup) {
+ _gmodule->cleanup();
+ }
+
+ /* Remove any proc entries */
+ if(_gmodule->pprint) {
+ _gmodule_remove_proc();
+ }
+
+ /* Finally, remove ourselves from the universe */
+#ifdef GMODULE_CONFIG_DEVFS_FS
+ if(devfs_handle) devfs_unregister(devfs_handle);
+#else
+ unregister_chrdev(_gmodule->major, _gmodule->name);
+#endif
+}
+
+int __init
+init_module(void)
+{
+ int rc;
+
+ /* Get our definition */
+ _gmodule = gmodule_get();
+ if(!_gmodule) return -ENODEV;
+
+
+ /* Register ourselves */
+#ifdef GMODULE_CONFIG_DEVFS_FS
+ devfs_handle = devfs_register(NULL,
+ _gmodule->name,
+ DEVFS_FL_NONE,
+ _gmodule->major,
+ _gmodule->minor,
+ S_IFCHR | S_IRUGO | S_IWUGO,
+ &_gmodule_fops,
+ NULL);
+ if(!devfs_handle) {
+ printk(KERN_WARNING "%s: can't register device with devfs",
+ _gmodule->name);
+ }
+ rc = 0;
+#else
+ rc = register_chrdev(_gmodule->major,
+ _gmodule->name,
+ &_gmodule_fops);
+ if (rc < 0) {
+ printk(KERN_WARNING "%s: can't get major %d",
+ _gmodule->name, _gmodule->major);
+ return rc;
+ }
+
+ if(_gmodule->major == 0) {
+ _gmodule->major = rc;
+ }
+#endif
+
+ /* Specific module Initialization */
+ if(_gmodule->init) {
+ int rc;
+ if((rc = _gmodule->init()) < 0) {
+#ifdef GMODULE_CONFIG_DEVFS_FS
+ if(devfs_handle) devfs_unregister(devfs_handle);
+#else
+ unregister_chrdev(_gmodule->major, _gmodule->name);
+#endif
+ return rc;
+ }
+ }
+
+ /* Add a /proc entry, if valid */
+ if(_gmodule->pprint) {
+ _gmodule_create_proc();
+ }
+
+ return 0; /* succeed */
+}
diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/shared/ksal.c b/sdk-6.5.16/src/gpl-modules/systems/linux/kernel/modules/shared/ksal.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: ksal.c,v 1.1 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#include <sal/core/sync.h>
+#include <sal/core/thread.h>
+
+#include "lkm.h"
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+#include <linux/semaphore.h>
+#else
+#include <asm/semaphore.h>
+#endif
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
+#include <linux/sched/rt.h>
+#endif
+#include <linux/time.h>
+
+#ifdef MAX_USER_RT_PRIO
+/* Assume 2.6 scheduler */
+#define SAL_YIELD(task) \
+ yield()
+#else
+/* Assume 2.4 scheduler */
+#define SAL_YIELD(task) \
+do { \
+ task->policy |= SCHED_YIELD; \
+ schedule(); \
+} while (0)
+#endif
+
+#define SECOND_USEC (1000000)
+#define USECS_PER_JIFFY (SECOND_USEC / HZ)
+#define USEC_TO_JIFFIES(usec) ((usec + (USECS_PER_JIFFY - 1)) / USECS_PER_JIFFY)
+
+#define sal_alloc(size, desc) kmalloc(size, GFP_KERNEL)
+#define sal_free(ptr) kfree(ptr)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
+#define WQ_SLEEP(a, b) wait_event_interruptible_timeout(a, NULL, b)
+#else
+#define WQ_SLEEP(a, b) interruptible_sleep_on_timeout(&(a), b)
+#endif
+/*
+ * sem_ctrl_t
+ *
+ * The semaphore control type uses the binary property to implement
+ * timed semaphores with improved performance using wait queues.
+ */
+
+typedef struct sem_ctrl_s {
+ struct semaphore sem;
+ int binary;
+ int cnt;
+ wait_queue_head_t wq;
+} sem_ctrl_t;
+
+sal_sem_t
+sal_sem_create(char *desc, int binary, int initial_count)
+{
+ sem_ctrl_t *s;
+
+ if ((s = sal_alloc(sizeof(*s), desc)) != 0) {
+ sema_init(&s->sem, initial_count);
+ s->binary = binary;
+ if (s->binary) {
+ init_waitqueue_head(&s->wq);
+ }
+ }
+
+ return (sal_sem_t) s;
+}
+
+void
+sal_sem_destroy(sal_sem_t b)
+{
+ sem_ctrl_t *s = (sem_ctrl_t *) b;
+
+ if (s == NULL) {
+ return;
+ }
+
+ /*
+ * the linux kernel does not have a sema_destroy(s)
+ */
+ sal_free(s);
+}
+
+int
+sal_sem_take(sal_sem_t b, int usec)
+{
+ sem_ctrl_t *s = (sem_ctrl_t *) b;
+ int err;
+
+ if (usec == sal_sem_FOREVER && !in_interrupt()) {
+ err = down_interruptible(&s->sem);
+ } else {
+ int time_wait = 1;
+ int cnt = s->cnt;
+
+ for (;;) {
+ if (down_trylock(&s->sem) == 0) {
+ err = 0;
+ break;
+ }
+
+ if (s->binary) {
+
+ /* Wait for event or timeout */
+
+ if (time_wait > 1) {
+ err = 1;
+ break;
+ }
+ err = wait_event_interruptible_timeout(s->wq, cnt != s->cnt,
+ USEC_TO_JIFFIES(usec));
+ if (err < 0) {
+ break;
+ }
+ time_wait++;
+
+ } else {
+
+ /* Retry algorithm with exponential backoff */
+
+ if (time_wait > usec) {
+ time_wait = usec;
+ }
+
+ sal_usleep(time_wait);
+
+ usec -= time_wait;
+
+ if (usec == 0) {
+ err = ETIMEDOUT;
+ break;
+ }
+
+ if ((time_wait *= 2) > 100000) {
+ time_wait = 100000;
+ }
+ }
+ }
+ }
+ return err ? -1 : 0;
+}
+
+int
+sal_sem_give(sal_sem_t b)
+{
+ sem_ctrl_t *s = (sem_ctrl_t *) b;
+
+ up(&s->sem);
+ if (s->binary) {
+ s->cnt++;
+ wake_up_interruptible(&s->wq);
+ }
+ return 0;
+}
+
+uint32
+sal_time_usecs(void)
+{
+ struct timeval ltv;
+ do_gettimeofday(<v);
+ return (ltv.tv_sec * SECOND_USEC + ltv.tv_usec);
+}
+
+void
+sal_usleep(uint32 usec)
+{
+ uint32 start_usec;
+ wait_queue_head_t queue;
+
+ if (usec <= SECOND_USEC / HZ) {
+ start_usec = sal_time_usecs();
+ do {
+ SAL_YIELD(current);
+ } while ((sal_time_usecs() - start_usec) < usec);
+ } else {
+ init_waitqueue_head(&queue);
+ WQ_SLEEP(queue, USEC_TO_JIFFIES(usec));
+ }
+}
+
+void
+sal_udelay(uint32 usec)
+{
+ static volatile int _sal_udelay_counter;
+ static int loops = 0;
+ int ix, iy;
+
+ if (loops == 0 || usec == 0) { /* Need calibration? */
+ int max_loops;
+ int start = 0, stop = 0;
+ int mpt = USECS_PER_JIFFY; /* usec/tick */
+
+ for (loops = 1; loops < 0x1000 && stop == start; loops <<= 1) {
+ /* Wait for clock turn over */
+ for (stop = start = jiffies; start == stop; start = jiffies) {
+ /* Empty */
+ }
+ sal_udelay(mpt); /* Single recursion */
+ stop = jiffies;
+ }
+
+ max_loops = loops / 2; /* Loop above overshoots */
+
+ start = stop = 0;
+
+ if (loops < 4) {
+ loops = 4;
+ }
+
+ for (loops /= 4; loops < max_loops && stop == start; loops++) {
+ /* Wait for clock turn over */
+ for (stop = start = jiffies; start == stop; start = jiffies) {
+ /* Empty */
+ }
+ sal_udelay(mpt); /* Single recursion */
+ stop = jiffies;
+ }
+ }
+
+ for (iy = 0; iy < usec; iy++) {
+ for (ix = 0; ix < loops; ix++) {
+ _sal_udelay_counter++; /* Prevent optimizations */
+ }
+ }
+}
diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/user/common/Makefile b/sdk-6.5.16/src/gpl-modules/systems/linux/user/common/Makefile
@@ -0,0 +1,229 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.4 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+
+SDK :=$(shell if [ -n "$$SDK" ] ; then\
+ echo $$SDK;\
+ else\
+ cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \
+ dir=`cd ../;pwd`; \
+ if [ "$$dir" = "/" ] ; then \
+ echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \
+ exit 1; \
+ fi ; \
+ cd $$dir; \
+ done ; \
+ pwd; \
+ fi)
+
+ifeq ($(SDK),)
+$(error Please run this in a tree)
+endif
+
+export SDK
+
+override-target=linux-$(platform)
+
+ifeq ($(LINUX_MAKE_SHARED_LIB),1)
+libext = so.$(SHAREDLIBVER)
+else
+libext = a
+endif
+
+ifeq (,$(platform))
+$(error Internal error: platform variable is not set)
+endif
+
+include $(SDK)/make/Make.config
+LOCALDIR=systems/linux/user/common
+include $(SDK)/make/Make.depend
+kernel-override=linux-$(platform)
+ifdef BLDCONFIG
+KERN_BLDROOT=${SDK}/${SDKBUILD}/${BLDCONFIG}/$(kernel-override)$(bldroot_suffix)
+else
+KERN_BLDROOT=${SDK}/${SDKBUILD}/$(kernel-override)$(bldroot_suffix)
+endif
+
+ifeq (,$(kernel_version))
+kernel_version=2_4
+endif
+
+ifeq ($(kernel_version),2_6)
+KOBJ=ko
+else
+KOBJ=o
+endif
+
+ifneq (,$(TOOLS_DIR))
+override PATH := $(TOOLS_DIR):$(PATH)
+endif
+
+ifeq ($(DEST_DIR),)
+DEST_DIR=${BLDDIR}
+endif
+
+KERNEL_BDE_LOCAL :=linux-kernel-bde.$(KOBJ)
+KERNEL_BDE :=$(DEST_DIR)/$(KERNEL_BDE_LOCAL)
+
+USER_BDE_LOCAL :=linux-user-bde.$(KOBJ)
+USER_BDE=$(DEST_DIR)/$(USER_BDE_LOCAL)
+
+KNET_CB_LOCAL := linux-knet-cb.$(KOBJ)
+KNET_CB := $(DEST_DIR)/$(KNET_CB_LOCAL)
+
+BCM_KNET_LOCAL :=linux-bcm-knet.$(KOBJ)
+BCM_KNET=$(DEST_DIR)/$(BCM_KNET_LOCAL)
+
+ifeq (,$(findstring DELIVER,$(MAKECMDGOALS)))
+.DEFAULT_GOAL := all
+all_targets := kernel_modules $(KERNEL_BDE) $(USER_BDE)
+
+LOCAL_TARGETS :=
+
+ifeq ($(NO_LOCAL_TARGETS),)
+LOCAL_TARGETS +=$(patsubst %,$(realpath ..)/$(platform)/%,$(KERNEL_BDE_LOCAL) $(USER_BDE_LOCAL))
+
+all_targets +=$(LOCAL_TARGETS)
+endif
+
+# Build all by default
+ifndef BUILD_KNET
+BUILD_KNET = 1
+endif
+
+ifeq ($(BUILD_KNET),1)
+# Kernel network support
+all_targets += $(BCM_KNET)
+
+ifeq ($(NO_LOCAL_TARGETS),)
+LOCAL_TARGETS +=$(patsubst %,../$(platform)/%,$(BCM_KNET_LOCAL))
+all_targets +=$(LOCAL_TARGETS)
+endif
+
+ifdef BUILD_KNET_CB
+all_targets += $(KNET_CB)
+
+ifeq ($(NO_LOCAL_TARGETS),)
+LOCAL_TARGETS +=$(patsubst %,../$(platform)/%,$(KNET_CB_LOCAL))
+all_targets +=$(LOCAL_TARGETS)
+endif
+endif
+
+ADD_TO_CFLAGS += -I$(SDK)/systems/linux/kernel/modules/include
+COND_KNET_LIBS = libuser.$(libext)
+endif
+
+all: $(BLDDIR)/.tree $(all_targets)
+
+ifeq ($(NO_LOCAL_TARGETS),)
+define LOCAL_TARGET_DEF
+$(1) : $(DEST_DIR)/$(notdir $(1))
+ cp $$? $$@
+endef
+endif
+
+# User BDE libraries
+ADD_TO_CFLAGS += -I$(SDK)/systems/bde/linux/include
+
+# Use raw IOCTL for KNET
+ADD_TO_CFLAGS += -DPROXY_SUPPORT=0
+
+CFLAGS += $(ADD_TO_CFLAGS)
+
+kernel_modules:
+ $(MAKE) -C $(SDK)/systems/bde/linux/kernel kernel_version=$(kernel_version)
+ $(MAKE) -C $(SDK)/systems/bde/linux/user/kernel kernel_version=$(kernel_version)
+ifeq ($(BUILD_KNET),1)
+ $(MAKE) -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \
+ subdirs="shared bcm-knet" override-target=linux-$(platform) CFLAGS="$(CFLAGS)"
+ifdef BUILD_KNET_CB
+ $(MAKE) -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \
+ subdirs="knet-cb" override-target=linux-$(platform) CFLAGS="$(CFLAGS)"
+endif
+endif
+
+$(KERNEL_BDE): $(KERN_BLDROOT)/linux-kernel-bde.$(KOBJ)
+ mkdir -p $(@D)
+ $(OBJCOPY) --strip-debug $< $@
+
+$(USER_BDE): $(KERN_BLDROOT)/linux-user-bde.$(KOBJ)
+ $(OBJCOPY) --strip-debug $< $@
+
+$(BCM_KNET): $(KERN_BLDROOT)/linux-bcm-knet.$(KOBJ)
+ $(OBJCOPY) --strip-debug $< $@
+
+$(KNET_CB): $(KERN_BLDROOT)/linux-knet-cb.$(KOBJ)
+ $(OBJCOPY) --strip-debug $< $@
+
+ifeq ($(NO_LOCAL_TARGETS),)
+$(foreach targ,$(LOCAL_TARGETS),$(eval $(call LOCAL_TARGET_DEF,$(targ))))
+endif
+
+clean::
+ $(MAKE) -C $(SDK)/systems/bde/linux/kernel $@
+ $(MAKE) -C $(SDK)/systems/bde/linux/user/kernel $@
+ $(MAKE) -C $(SDK)/systems/linux/kernel/modules \
+ subdirs="shared bcm-knet knet-cb" \
+ override-target=linux-$(platform) $@
+ $(RM) $(KERNEL_BDE) $(USER_BDE)
+ $(RM) $(BCM_KNET) $(KNET_CB)
+ $(RM) $(KERN_BLDROOT)/linux-kernel-bde.$(KOBJ)
+ $(RM) $(KERN_BLDROOT)/linux-user-bde.$(KOBJ)
+ $(RM) $(KERN_BLDROOT)/linux-bcm-knet.$(KOBJ)
+ $(RM) $(KERN_BLDROOT)/linux-knet-cb.$(KOBJ)
+ $(RM) $(LOCAL_TARGETS)
+
+distclean:: clean
+
+.PHONY: variable
+
+#
+# Echo variable values used for configuration
+# usage: make VAR=CC variable
+#
+variable::
+ @echo $($(VAR))
+
+else
+ifndef DELIVERY
+$(error DELIVERY required)
+endif
+
+DELIVERABLES := $(KERNEL_BDE) $(USER_BDE)
+# 1= source
+define DELIVERY_RULE
+_DEL_TARG += $(DELIVERY)/$(notdir $(1))
+$(DELIVERY)/$(notdir $(1)) : $(1)
+ @mkdir -p $(DELIVERY)
+ifeq ($(filter $(notdir $(BCM)) $(notdir $(BCM).dbg),$(notdir $1)),)
+ $(OBJCOPY) --strip-debug $$< $$@
+else
+ $(CP) -p $$< $$@
+endif
+endef
+
+$(foreach f,$(DELIVERABLES),$(eval $(call DELIVERY_RULE,$(f))))
+
+DELIVER: $(_DEL_TARG)
+endif
+
+# Make.config defines remaining phony targets
+.PHONY: build kernel_modules DELIVER
+
diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/user/iproc-3_14/Makefile b/sdk-6.5.16/src/gpl-modules/systems/linux/user/iproc-3_14/Makefile
@@ -0,0 +1,65 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.7 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+#
+# This make job requires the following environment variables to be set:
+#
+# SDK - path to StrataXGS SDK root directory
+#
+# Optionally the following environment variables can be set to
+# override the default build server configuration:
+#
+# MIPS_TOOLS_DIR - path to build tools (if not in PATH already)
+# MIPS_CROSS_COMPILE - cross compile tools prefix
+# LINUX_INCLUDE - path to Linux kernel include directory
+#
+
+SDK :=$(shell if [ -n "$$SDK" ] ; then\
+ echo $$SDK;\
+ else\
+ cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \
+ dir=`cd ../;pwd`; \
+ if [ "$$dir" = "/" ] ; then \
+ echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \
+ exit 1; \
+ fi ; \
+ cd $$dir; \
+ done ; \
+ pwd; \
+ fi)
+
+ifeq ($(SDK),)
+$(error Please run this in a tree)
+endif
+
+export SDK
+
+override kernel_version=3_14
+platform=iproc-$(kernel_version)
+
+IPROC_BUILD=1
+export IPROC_BUILD
+export BUILD_PLATFORM
+export ARM_LINUX_VERSION
+
+LINUX_MAKE_USER=1
+export ADD_TO_CFLAGS
+
+include ${SDK}/make/Make.linux
diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/user/iproc/Makefile b/sdk-6.5.16/src/gpl-modules/systems/linux/user/iproc/Makefile
@@ -0,0 +1,59 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.7 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+#
+# This make job requires the following environment variables to be set:
+#
+# SDK - path to StrataXGS SDK root directory
+#
+
+SDK :=$(shell if [ -n "$$SDK" ] ; then\
+ echo $$SDK;\
+ else\
+ cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \
+ dir=`cd ../;pwd`; \
+ if [ "$$dir" = "/" ] ; then \
+ echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \
+ exit 1; \
+ fi ; \
+ cd $$dir; \
+ done ; \
+ pwd; \
+ fi)
+
+ifeq ($(SDK),)
+$(error Please run this in a tree)
+endif
+
+export SDK
+
+override kernel_version=4_14
+platform=iproc
+
+IPROC_BUILD=1
+export IPROC_BUILD
+export BUILD_PLATFORM
+export ARM_LINUX_VERSION
+
+LINUX_MAKE_USER=1
+export ADD_TO_CFLAGS
+export BR_NO_CCACHE
+
+include ${SDK}/make/Make.linux
diff --git a/sdk-6.5.16/src/gpl-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile b/sdk-6.5.16/src/gpl-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.2 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+SDK :=$(shell if [ -n "$$SDK" ] ; then\
+ echo $$SDK;\
+ else\
+ cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \
+ dir=`cd ../;pwd`; \
+ if [ "$$dir" = "/" ] ; then \
+ echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \
+ exit 1; \
+ fi ; \
+ cd $$dir; \
+ done ; \
+ pwd; \
+ fi)
+
+ifeq ($(SDK),)
+$(error Please run this in a tree)
+endif
+
+export SDK
+
+override kernel_version=2_6
+platform=x86-smp_generic_64-$(kernel_version)
+
+LINUX_MAKE_USER=1
+include ${SDK}/make/Make.linux
diff --git a/sdk-6.5.16/src/gpl-modules/tools/mktool.pl b/sdk-6.5.16/src/gpl-modules/tools/mktool.pl
@@ -0,0 +1,292 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+#
+# mktool.pl
+#
+# $Id: mktool.pl,v 1.5 Broadcom SDK $
+#
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved. $
+
+use File::Path;
+use File::Find;
+use File::Copy;
+use Cwd;
+
+($prog = $0) =~ s/.*\///;
+
+SWITCH:
+{
+ $op = shift;
+
+ if ($op eq "-rm") { mktool_rm(@ARGV); last SWITCH; }
+ if ($op eq "-cp") { mktool_cp(@ARGV); last SWITCH; }
+ if ($op eq "-md") { mktool_md(@ARGV); last SWITCH; }
+ if ($op eq "-ln") { mktool_ln(@ARGV); last SWITCH; }
+ if ($op eq "-foreach") { mktool_foreach(@ARGV); last SWITCH; }
+ if ($op eq "-dep") { mktool_makedep(@ARGV); last SWITCH; }
+ if ($op eq "-echo") { mktool_echo(@ARGV); last SWITCH; }
+ if ($op eq "-beep") { mktool_beep(@ARGV); last SWITCH; }
+ die("$prog: unknown option '$op'\n");
+}
+
+exit 0;
+
+
+
+
+#
+# mktool_execute
+#
+# Executes a command, returns exist status.
+# Performs token special translation before execution.
+#
+
+sub mktool_execute
+{
+ my $token = shift;
+ my @cmds = @_;
+
+# printf("mktool_execute: token = '$token'\n");
+ foreach $cmd (@cmds)
+ {
+ #printf("mktool_execute: cmd = '$cmd'\n");
+ $cmd =~ s/\#\#/$token/g;
+ if($cmd =~ /^-p/)
+ {
+ $cmd =~ s/^-p//;
+ printf("$cmd\n");
+ }
+ else
+ {
+ system($cmd);
+ my $excode = ($? >> 8);
+ exit $excode if $excode;
+ }
+ }
+}
+
+
+$find_regexp = "";
+@find_cmd;
+
+#
+# mktool_foreach
+#
+sub mktool_foreach
+{
+ if($_[0] eq "-find")
+ {
+ shift;
+ $find_dir = shift;
+ $find_regexp = shift;
+ @find_cmds = @_;
+
+ if(!($find_dir =~ /^\//))
+ {
+ $find_dir = cwd() . "/" . $find_dir;
+ }
+ find(\&_mktool_foreach_find_wanted, $find_dir);
+ }
+ else
+ {
+ my $subdir = 0;
+ if($_[0] eq "-subdir")
+ {
+ $subdir = 1;
+ shift;
+ }
+
+ my @thingies = split(' ', shift);
+
+ foreach $thingy (@thingies)
+ {
+ chdir $thingy unless $subdir == 0;
+ mktool_execute($thingy, @_);
+ chdir ".." unless $subdir == 0;
+ }
+ }
+}
+
+
+
+sub _mktool_foreach_find_wanted
+{
+ my $expr = "\$File::Find::name =~ /\^$find_regexp\$/";
+
+ if(eval($expr))
+ {
+ mktool_execute($File::Find::name, @find_cmds);
+ exit $excode if $excode;
+ }
+}
+
+
+#
+# rm
+#
+# Removes a list of objects
+#
+sub mktool_rm
+{
+ my($f);
+
+ foreach $f (@_) {
+ eval { rmtree($f) };
+ if ($@) {
+ die "$prog $op: failed to remove $f: $@\n";
+ }
+ }
+}
+
+#
+# md
+#
+# Makes a list of directories
+#
+sub mktool_md
+{
+ my($dir);
+
+ foreach $dir (@_) {
+ $dir =~ s!/+$!!;
+ eval { mkpath($dir) };
+ if ($@) {
+ die "$prog $op: failed to make directory $dir: $@\n";
+ }
+ }
+}
+
+
+sub mktool_cp
+{
+ my($from, $to) = @_;
+
+ if (@_ != 2) {
+ die "$prog $op: must have two arguments\n";
+ }
+ copy($from, $to) ||
+ die "$prog $op: failed to copy $from to $to: $!\n";
+}
+
+sub mktool_ln
+{
+ my($old, $new) = @_;
+
+ if (@_ != 2) {
+ die "$prog $op: must have two arguments\n";
+ }
+ link ($old, $new) ||
+ die "$prog $op: failed to link $new to $old: $!\n";
+}
+
+
+# @echo "$@ \\" > ${BLDDIR}/$(notdir $@)
+# @if ($(DEPEND)) >> $(BLDDIR)/$(notdir $@); then \
+# exit 0; \
+# else \
+# rm -f ${BLDDIR}/$(notdir $@); \
+# exit 1; \
+# fi
+
+# $(MAKEDEP) "$@" "$(BLDDIR)/$(notdir $@)" "$(DEPEND)"
+
+sub mktool_makedep
+{
+ my ($source, $target, $cmd, $curdir) = @_;
+ my @result = `$cmd`;
+ my $sdk = $ENV{'SDK'};
+ my $count;
+ my $tmp;
+ local $resultant;
+
+## Comman $cmd
+#Command $cmd
+print <<MKTOOL;
+
+mktool.pl::
+curdir $curdir
+
+MKTOOL
+
+ # derive the path to the target
+ $curdir = "$sdk/$curdir";
+
+ # save the basename
+ $dirName = substr($target,0,rindex($target,"\/"));
+
+ # prepare the top line of the %.d file
+ $resultant="$source \\\n\${BLDDIR}/";
+ if(!$?)
+ {
+ foreach $line (@result)
+ {
+ $line =~ s/^#.*\n//g; # some makedeps produce comments
+ $line =~ s/\n+$//; # toss trailing newlines
+ $line =~ s/(\s+)(\.\/)/ /g; # remove leading ./
+
+ # insert SDK path before ../
+ $line =~ s/(\s+)(\.\.\/)/${1}$curdir\/${2}/g;
+
+ # insert SDK path
+ $line =~ s/(\s+)(\w+)/${1}$curdir\/${2}/g;
+
+ $count=0;
+ $tmp=$line;
+ while( (index($line,"..")>-1) & ($count < 20) )
+ {
+ $line=~s/\/\w+\/\.\.//;
+ # if we hit a major recursion, revert the line, report
+ # this to the output and drop out of the loop, but do
+ # continue, this should not halt generation
+ if($count++>19)
+ {
+ print "mktool.pl: could not process $line \n\n";
+ print ":: curdir $curdir\n";
+ print ":: target $target\n";
+ print ":: cmd $cmd\n";
+ $line=$tmp;
+ }
+ }
+
+ # set all the paths to use the $SDK variable
+ $line =~ s/$ENV{'SDK'}/\$\{SDK\}/g;
+ $resultant=$resultant . $line;
+ }
+
+ # some compilers return extra newlines
+ $resultant=~s/\n//g;
+
+ # now clean up the result
+ $resultant=~s/\\/\\\n/g;
+
+ mktool_md($dirName) unless (-d $dirName);
+ open (TARGET, ">$target") ||
+ die("$prog $op: cannot open '$target' for writing: $!\n");
+ print TARGET "$resultant\n";
+ close(TARGET);
+ }
+}
+
+sub mktool_echo
+{
+ print "@_\n";
+}
+
+sub mktool_beep
+{
+ -t STDOUT && defined $ENV{MAKEBEEP} && print "\007";
+}
diff --git a/sdk-6.5.20/src/gpl-modules/RELEASE b/sdk-6.5.20/src/gpl-modules/RELEASE
diff --git a/sdk-6.5.20/src/gpl-modules/include/ibde.h b/sdk-6.5.20/src/gpl-modules/include/ibde.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: ibde.h,v 1.27 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#ifndef __IBDE_H__
+#define __IBDE_H__
+
+#include <sal/types.h>
+
+/*
+ * Represents a collection of devices
+ */
+
+typedef struct ibde_dev_s {
+ uint16 device;
+ uint8 rev;
+ sal_vaddr_t base_address;
+ sal_vaddr_t base_address1;
+ sal_vaddr_t base_address2;
+ /* a unique number representing the specific device.
+ * Must be different for different devices.
+ * May be used to identify specific devices in the system.
+ * May be implemented as a full PCIe address, a persistent configurable user value, ...
+ * Possible implementation value stores in QSPI flash memory of the device. */
+ uint32 dev_unique_id;
+} ibde_dev_t;
+
+
+typedef struct ibde_s {
+
+ const char *(*name)(void);
+
+ /* Returns the number of devices available */
+ /* Each device is is accessed through a handle */
+ /* Handles are assumed to index the array of devices */
+
+ /* Support SWITCH or ETHERNET or CPU devices */
+ int (*num_devices)(int type);
+#define BDE_ALL_DEVICES 0
+#define BDE_SWITCH_DEVICES 1
+#define BDE_ETHER_DEVICES 2
+#define BDE_CPU_DEVICES 3
+
+ const ibde_dev_t *(*get_dev)(int d);
+
+ /*
+ * Get types of underlaying devices.
+ * A combination of bus type and functional type is returned.
+ * In case of bus type, support PCI and SPI device types.
+ * In case of functional type, specify if underlaying device is
+ * a switching or ethernet device.
+ */
+ uint32 (*get_dev_type)(int d);
+#define BDE_PCI_DEV_TYPE SAL_PCI_DEV_TYPE /* PCI device */
+#define BDE_SPI_DEV_TYPE SAL_SPI_DEV_TYPE /* SPI device */
+#define BDE_EB_DEV_TYPE SAL_EB_DEV_TYPE /* EB device */
+#define BDE_ICS_DEV_TYPE SAL_ICS_DEV_TYPE /* ICS device */
+#define BDE_MII_DEV_TYPE SAL_MII_DEV_TYPE /* MII device */
+#define BDE_I2C_DEV_TYPE SAL_I2C_DEV_TYPE /* I2C device */
+#define BDE_AXI_DEV_TYPE SAL_AXI_DEV_TYPE /* AXI device */
+#define BDE_EMMI_DEV_TYPE SAL_EMMI_DEV_TYPE /* EMMI device */
+#define BDE_DEV_BUS_ALT SAL_DEV_BUS_ALT /* Alternate Access */
+#define BDE_DEV_BUS_MSI SAL_DEV_BUS_MSI /* Message-signaled interrupts */
+
+#define BDE_DEV_BUS_TYPE_MASK SAL_DEV_BUS_TYPE_MASK
+
+#define BDE_SWITCH_DEV_TYPE SAL_SWITCH_DEV_TYPE /* Switch device */
+#define BDE_ETHER_DEV_TYPE SAL_ETHER_DEV_TYPE /* Ethernet device */
+#define BDE_CPU_DEV_TYPE SAL_CPU_DEV_TYPE /* CPU device */
+
+#define BDE_BYTE_SWAP 0x01000000 /* SW byte swap */
+#define BDE_NO_IPROC 0x02000000 /* Device uses two BARs, but is not iProc */
+
+#define BDE_8MB_REG_SPACE 0x10000000 /* 8MB sized CMIC BAR */
+#define BDE_256K_REG_SPACE 0x20000000 /* Map 256K (v 64K) */
+#define BDE_128K_REG_SPACE 0x40000000 /* Map 128K (v 64K) */
+#define BDE_320K_REG_SPACE 0x80000000 /* Map 256K+64K */
+
+/* Bus supports only 16bit reads */
+#define BDE_DEV_BUS_RD_16BIT SAL_DEV_BUS_RD_16BIT
+
+/* Bus supports only 16bit writes */
+#define BDE_DEV_BUS_WR_16BIT SAL_DEV_BUS_WR_16BIT
+
+/* Backward compatibility */
+#define BDE_ET_DEV_TYPE BDE_MII_DEV_TYPE
+
+#define BDE_DEV_MEM_MAPPED(_d) \
+ ((_d) & (BDE_PCI_DEV_TYPE | BDE_ICS_DEV_TYPE | BDE_EB_DEV_TYPE |\
+ BDE_EMMI_DEV_TYPE | BDE_AXI_DEV_TYPE))
+
+ /*
+ * PCI Bus Access
+ */
+ uint32 (*pci_conf_read)(int d, uint32 addr);
+ int (*pci_conf_write)(int d, uint32 addr, uint32 data);
+ void (*pci_bus_features)(int d, int *be_pio, int *be_packet,
+ int *be_other);
+
+ uint32 (*read)(int d, uint32 addr);
+ int (*write)(int d, uint32 addr, uint32 data);
+
+ uint32* (*salloc)(int d, int size, const char *name);
+ void (*sfree)(int d, void *ptr);
+ int (*sflush)(int d, void *addr, int length);
+ int (*sinval)(int d, void *addr, int length);
+
+ int (*interrupt_connect)(int d, void (*)(void*), void *data);
+ int (*interrupt_disconnect)(int d);
+
+ sal_paddr_t (*l2p)(int d, void *laddr);
+ void* (*p2l)(int d, sal_paddr_t paddr);
+
+ /*
+ * SPI Access via SMP
+ */
+ int (*spi_read)(int d, uint32 addr, uint8 *buf, int len);
+ int (*spi_write)(int d, uint32 addr, uint8 *buf, int len);
+ /* Special SPI access addresses */
+#define BDE_DEV_OP_EMMI_INIT SAL_DEV_OP_EMMI_INIT
+
+ /*
+ * iProc register access
+ */
+ uint32 (*iproc_read)(int d, uint32 addr);
+ int (*iproc_write)(int d, uint32 addr, uint32 data);
+
+ /*
+ * Shared memory access
+ */
+ uint32 (*shmem_read)(int dev, uint32 addr, uint8 *buf, uint32 len);
+ void (*shmem_write)(int dev, uint32 addr, uint8 *buf, uint32 len);
+ sal_vaddr_t (*shmem_map)(int dev, uint32 addr, uint32 size);
+
+ /*
+ * cmic
+ */
+ int (*get_cmic_ver)(int d, uint32 *ver);
+
+ /*
+ * I2C operations on the Device, assuming it is connected by I2C to the CPU.
+ */
+ /* Read from the internal device Address space using I2C */
+ int (*i2c_device_read)(
+ int dev, /* The device ID to access */
+ uint32 addr, /* The address to access in the internal device address space */
+ uint32 *value);/* the value to be read. */
+ /* Write to the internal device Address space using I2C */
+ int (*i2c_device_write)(
+ int dev, /* The device ID to access */
+ uint32 addr, /* The address to access in the internal device address space */
+ uint32 value); /* the value to be written. */
+
+} ibde_t;
+
+
+/* System BDE */
+extern ibde_t *bde;
+
+
+#endif /* __IBDE_H__ */
diff --git a/sdk-6.5.20/src/gpl-modules/include/kcom.h b/sdk-6.5.20/src/gpl-modules/include/kcom.h
@@ -0,0 +1,598 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: kcom.h,v 1.9 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ * File: kcom.h
+ * Purpose: User/Kernel message definitions
+ */
+
+#ifndef _KCOM_H
+#define _KCOM_H
+
+#include <sal/types.h>
+
+#define KCOM_CHAN_KNET "KCOM_KNET"
+
+/*
+ * Message types
+ */
+#define KCOM_MSG_TYPE_CMD 1 /* Command */
+#define KCOM_MSG_TYPE_RSP 2 /* Command response */
+#define KCOM_MSG_TYPE_EVT 3 /* Unsolicited event */
+
+/*
+ * Message opcodes
+ */
+#define KCOM_M_NONE 0 /* Should not be used */
+#define KCOM_M_VERSION 1 /* Protocol version */
+#define KCOM_M_STRING 2 /* For debug messages */
+#define KCOM_M_HW_RESET 3 /* H/W not ready */
+#define KCOM_M_HW_INIT 4 /* H/W initialized */
+#define KCOM_M_ETH_HW_CONFIG 5 /* ETH HW config*/
+#define KCOM_M_DETACH 6 /* Detach kernel module */
+#define KCOM_M_REPROBE 7 /* Reprobe device */
+#define KCOM_M_NETIF_CREATE 11 /* Create network interface */
+#define KCOM_M_NETIF_DESTROY 12 /* Destroy network interface */
+#define KCOM_M_NETIF_LIST 13 /* Get list of network interface IDs */
+#define KCOM_M_NETIF_GET 14 /* Get network interface info */
+#define KCOM_M_FILTER_CREATE 21 /* Create Rx filter */
+#define KCOM_M_FILTER_DESTROY 22 /* Destroy Rx filter */
+#define KCOM_M_FILTER_LIST 23 /* Get list of Rx filter IDs */
+#define KCOM_M_FILTER_GET 24 /* Get Rx filter info */
+#define KCOM_M_DMA_INFO 31 /* Tx/Rx DMA info */
+#define KCOM_M_DBGPKT_SET 41 /* Enbale debug packet function */
+#define KCOM_M_DBGPKT_GET 42 /* Get debug packet function info */
+#define KCOM_M_WB_CLEANUP 51 /* Clean up for warmbooting */
+#define KCOM_M_CLOCK_CMD 52 /* Clock Commands */
+
+#define KCOM_VERSION 12 /* Protocol version */
+
+/*
+ * Message status codes
+ */
+#define KCOM_E_NONE 0 /* No errors */
+#define KCOM_E_PARAM 1 /* Invalid/unsupported parameter */
+#define KCOM_E_RESOURCE 2 /* Out of memory or other resource */
+#define KCOM_E_NOT_FOUND 3 /* Requested object not found */
+
+typedef struct kcom_msg_hdr_s {
+ uint8 type;
+ uint8 opcode;
+ uint8 seqno;
+ uint8 status;
+ uint8 unit;
+ uint8 reserved;
+ uint16 id;
+} kcom_msg_hdr_t;
+
+/*
+ * Object types
+ */
+
+/*
+ * System network interface
+ *
+ * Network interface types:
+ *
+ * KCOM_NETIF_T_VLAN
+ * Transmits to this interface will go to ingress PIPE of switch
+ * CPU port using specified VLAN ID. Packet will be switched.
+ *
+ * KCOM_NETIF_T_PORT
+ * Transmits to this interface will go to unmodified to specified
+ * physical switch port. All switching logic is bypassed.
+ *
+ * KCOM_NETIF_T_META
+ * Transmits to this interface will be done using raw meta data
+ * as DMA descriptors. Currently used for RCPU mode only.
+ *
+ * Network interface flags:
+ *
+ * KCOM_NETIF_F_ADD_TAG
+ * Add VLAN tag to packets sent directly to physical port.
+ *
+ * KCOM_NETIF_F_RCPU_ENCAP
+ * Use RCPU encapsulation for packets that enter and exit this
+ * interface.
+ */
+#define KCOM_NETIF_T_VLAN 0
+#define KCOM_NETIF_T_PORT 1
+#define KCOM_NETIF_T_META 2
+
+#define KCOM_NETIF_F_ADD_TAG (1U << 0)
+#define KCOM_NETIF_F_RCPU_ENCAP (1U << 1)
+/* If a netif has this flag, the packet sent to the netif can't be stripped tag or added tag */
+#define KCOM_NETIF_F_KEEP_RX_TAG (1U << 2)
+
+#define KCOM_NETIF_NAME_MAX 16
+
+/*
+ * Max size of Sand System Headers
+ * For DNX, Module Header(20B) + PTCH(2B) + ITMH(5B)
+ * For DPP, PTCH(2B) + ITMH(4B)
+ */
+#define KCOM_NETIF_SYSTEM_HEADERS_SIZE_MAX 27
+
+typedef struct kcom_netif_s {
+ uint16 id;
+ uint8 type;
+ uint8 flags;
+ uint32 cb_user_data;
+ uint8 port;
+ uint8 reserved;
+ uint16 vlan;
+ uint16 qnum;
+ uint8 macaddr[6];
+ uint8 system_headers[KCOM_NETIF_SYSTEM_HEADERS_SIZE_MAX];
+ uint8 system_headers_size;
+ char name[KCOM_NETIF_NAME_MAX];
+ uint8 phys_port;
+} kcom_netif_t;
+
+/*
+ * Packet filters
+ *
+ * Filters work like software TCAMs where a mask is applied to the
+ * source data, and the result is then compared to the filter data.
+ *
+ * Filters are checked in priority order with the lowest priority
+ * values being checked first (i.e. 0 is the highest priority).
+ *
+ * Filter types:
+ *
+ * KCOM_FILTER_T_RX_PKT
+ * Filter data and mask are applied to the Rx DMA control block
+ * as well as to the Rx packet contents.
+ *
+ * Destination types:
+ *
+ * KCOM_DEST_T_NULL
+ * Packet is dropped.
+ *
+ * KCOM_DEST_T_NETIF
+ * Packet is sent to network interface with ID <dest_id>.
+ *
+ * KCOM_DEST_T_API
+ * Packet is sent to Rx API through queue <dest_id>.
+ *
+ * KCOM_DEST_T_CB
+ * Packet destination is obtained from kernel call-back function.
+ *
+ * Filter flags:
+ *
+ * KCOM_FILTER_F_ANY_DATA
+ * When this flags is set the filter will match any packet on
+ * the associated unit.
+ *
+ * KCOM_FILTER_F_STRIP_TAG
+ * Strip VLAN tag before packet is sent to destination.
+ * This flag only applies to KCOM_DEST_T_NETIF.
+ *
+ */
+#define KCOM_FILTER_BYTES_MAX 256
+#define KCOM_FILTER_WORDS_MAX BYTES2WORDS(KCOM_FILTER_BYTES_MAX)
+
+#define KCOM_FILTER_T_RX_PKT 1
+
+#define KCOM_DEST_T_NULL 0
+#define KCOM_DEST_T_NETIF 1
+#define KCOM_DEST_T_API 2
+#define KCOM_DEST_T_CB 3
+
+#define KCOM_FILTER_F_ANY_DATA (1U << 0)
+#define KCOM_FILTER_F_STRIP_TAG (1U << 1)
+
+#define KCOM_FILTER_DESC_MAX 32
+
+typedef struct kcom_filter_s {
+ uint16 id;
+ uint8 type;
+ uint8 priority;
+ char desc[KCOM_FILTER_DESC_MAX];
+ uint32 flags;
+ uint32 cb_user_data;
+ uint16 dest_type;
+ uint16 dest_id;
+ uint16 dest_proto;
+ uint16 mirror_type;
+ uint16 mirror_id;
+ uint16 mirror_proto;
+ uint16 oob_data_offset;
+ uint16 oob_data_size;
+ uint16 pkt_data_offset;
+ uint16 pkt_data_size;
+ union {
+ uint8 b[KCOM_FILTER_BYTES_MAX];
+ uint32 w[KCOM_FILTER_WORDS_MAX];
+ } data;
+ union {
+ uint8 b[KCOM_FILTER_BYTES_MAX];
+ uint32 w[KCOM_FILTER_WORDS_MAX];
+ } mask;
+ /** Mark to match source modid and modport */
+ uint8 is_src_modport;
+ uint8 spa_unit;
+} kcom_filter_t;
+
+/*
+ * DMA buffer information
+ *
+ * Cookie field is reserved use by application (32/64-bit pointer).
+ *
+ * For Tx operation the application will submit the start address of
+ * the Tx DCB chain which is queued for transfer by the kernel module.
+ * Once DMA is done a DMA event is returned to the application with an
+ * optional sequence number.
+ *
+ * For Rx operation the application will submit the start address of
+ * the Rx DCB chain which should be use for packet reception by the
+ * kernel module. Once DMA is done a DMA event is returned to the
+ * application with an optional sequence number.
+ *
+ * Cookie field is reserved use by application (32/64-bit pointer).
+ *
+ * Packet info types:
+ *
+ * KCOM_DMA_INFO_T_TX_DCB
+ * Data is physical start address of Tx DCB chain.
+ *
+ * KCOM_DMA_INFO_T_RX_DCB
+ * Data is physical start address of Rx DCB chain.
+ *
+ * Packet info flags:
+ *
+ * KCOM_DMA_INFO_F_TX_DONE
+ * This flag is set by the kernel module and means that one or more
+ * packets have been sent.
+ *
+ * KCOM_DMA_INFO_F_RX_DONE
+ * This flag is set by the kernel module and means that one or more
+ * Rx buffers contain valid packet data.
+ */
+#define KCOM_DMA_INFO_T_TX_DCB 1
+#define KCOM_DMA_INFO_T_RX_DCB 2
+
+#define KCOM_DMA_INFO_F_TX_DONE (1U << 0)
+#define KCOM_DMA_INFO_F_RX_DONE (1U << 1)
+
+typedef struct kcom_dma_info_s {
+ uint8 type;
+ uint8 cnt;
+ uint16 size;
+ uint16 chan;
+ uint16 flags;
+ union {
+ uint64 dcb_start;
+ struct {
+ uint32 tx;
+ uint32 rx;
+ } seqno;
+ } data;
+ union {
+ void *p;
+ uint8 b[8];
+ } cookie;
+ } kcom_dma_info_t;
+
+/* Default channel configuration */
+#define KCOM_DMA_TX_CHAN 0
+#define KCOM_DMA_RX_CHAN 1
+
+
+#define KCOM_ETH_HW_T_RESET 1
+#define KCOM_ETH_HW_T_INIT 2
+#define KCOM_ETH_HW_T_OTHER 3
+
+#define KCOM_ETH_HW_C_ALL 0xff
+
+#define KCOM_ETH_HW_RESET_F_TX (1U << 0)
+#define KCOM_ETH_HW_RESET_F_RX (1U << 1)
+#define KCOM_ETH_HW_RESET_F_TX_RECLAIM (1U << 2)
+#define KCOM_ETH_HW_RESET_F_RX_RECLAIM (1U << 3)
+
+#define KCOM_ETH_HW_INIT_F_TX (1U << 0)
+#define KCOM_ETH_HW_INIT_F_RX (1U << 1)
+#define KCOM_ETH_HW_INIT_F_RX_FILL (1U << 2)
+
+#define KCOM_ETH_HW_OTHER_F_FIFO_LOOPBACK (1U << 0)
+#define KCOM_ETH_HW_OTHER_F_INTERRUPT (1U << 1)
+
+typedef struct kcom_eth_hw_config_s {
+ uint8 type;
+ uint8 chan;
+ uint32 flags;
+ uint32 value;
+} kcom_eth_hw_config_t;
+
+/*
+ * Message types
+ */
+
+/*
+ * Request KCOM interface version of kernel module.
+ */
+typedef struct kcom_msg_version_s {
+ kcom_msg_hdr_t hdr;
+ uint32 version;
+ uint32 netif_max;
+ uint32 filter_max;
+} kcom_msg_version_t;
+
+/*
+ * Request KCOM interface clock info.
+ */
+#define KSYNC_M_HW_INIT 0
+#define KSYNC_M_HW_DEINIT 1
+#define KSYNC_M_VERSION 2
+#define KSYNC_M_HW_TS_DISABLE 3
+
+typedef struct kcom_clock_info_s {
+ uint8 cmd;
+ int32 data[8];
+} kcom_clock_info_t;
+
+/*
+ * Send literal string to/from kernel module.
+ * Mainly for debugging purposes.
+ */
+#define KCOM_MSG_STRING_MAX 128
+
+typedef struct kcom_msg_string_s {
+ kcom_msg_hdr_t hdr;
+ uint32 len;
+ char val[KCOM_MSG_STRING_MAX];
+} kcom_msg_string_t;
+
+/*
+ * Indicate that eth hardware is about to be reset. Active
+ * DMA operations should be aborted and DMA and interrupts
+ * should be disabled.
+ */
+/*
+ * Indicate that eth hardware has been properly initialized
+ * for DMA operation to commence.
+ */
+typedef struct kcom_msg_eth_hw_config_s {
+ kcom_msg_hdr_t hdr;
+ kcom_eth_hw_config_t config;
+} kcom_msg_eth_hw_config_t;
+
+/*
+ * Indicate that switch hardware is about to be reset. Active
+ * DMA operations should be aborted and DMA and interrupts
+ * should be disabled.
+ */
+typedef struct kcom_msg_hw_reset_s {
+ kcom_msg_hdr_t hdr;
+ uint32 channels;
+} kcom_msg_hw_reset_t;
+
+/*
+ * Indicate that switch hardware has been properly initialized
+ * for DMA operation to commence.
+ */
+typedef struct kcom_msg_hw_init_s {
+ kcom_msg_hdr_t hdr;
+ uint8 cmic_type;
+ uint8 dcb_type;
+ uint8 dcb_size;
+ uint8 pkt_hdr_size;
+ uint32 dma_hi;
+ uint32 cdma_channels;
+ /*
+ * Information to parse Dune system headers
+ */
+ uint32 ftmh_lb_key_ext_size;
+ uint32 ftmh_stacking_ext_size;
+ uint32 pph_base_size;
+ uint32 pph_lif_ext_size[8];
+ uint32 udh_length_type[4];
+ uint32 udh_size;
+ uint32 oamp_punted;
+ uint8 no_skip_udh_check;
+ uint8 system_headers_mode;
+ uint8 udh_enable;
+} kcom_msg_hw_init_t;
+
+/*
+ * Release blocked IOCTL threads and clean up as necessary.
+ */
+typedef struct kcom_msg_detach_s {
+ kcom_msg_hdr_t hdr;
+ uint32 flags;
+} kcom_msg_detach_t;
+
+/*
+ * Reprobe switch device.
+ */
+typedef struct kcom_msg_reprobe_s {
+ kcom_msg_hdr_t hdr;
+ uint32 flags;
+} kcom_msg_reprobe_t;
+
+/*
+ * Enable/Disable debugging packet function.
+ */
+typedef struct kcom_msg_dbg_pkt_set_s {
+ kcom_msg_hdr_t hdr;
+ int enable;
+} kcom_msg_dbg_pkt_set_t;
+
+/*
+ * Get debugging packet function info.
+ */
+typedef struct kcom_msg_dbg_pkt_get_s {
+ kcom_msg_hdr_t hdr;
+ int value;
+} kcom_msg_dbg_pkt_get_t;
+
+/*
+ * Clean up warmboot-related resources.
+ */
+typedef struct kcom_msg_wb_cleanup_s {
+ kcom_msg_hdr_t hdr;
+ uint32 flags;
+} kcom_msg_wb_cleanup_t;
+
+/*
+ * Create new system network interface. The network interface will
+ * be associated with the specified switch unit number.
+ * The interface id and name will be assigned by the kernel module.
+ */
+typedef struct kcom_msg_netif_create_s {
+ kcom_msg_hdr_t hdr;
+ kcom_netif_t netif;
+} kcom_msg_netif_create_t;
+
+/*
+ * Destroy system network interface.
+ */
+typedef struct kcom_msg_netif_destroy_s {
+ kcom_msg_hdr_t hdr;
+} kcom_msg_netif_destroy_t;
+
+/*
+ * Destroy system network interface.
+ */
+typedef struct kcom_msg_clock_s{
+ kcom_msg_hdr_t hdr;
+ kcom_clock_info_t clock_info;
+} kcom_msg_clock_cmd_t;
+
+/*
+ * Get list of currently defined system network interfaces.
+ */
+#ifndef KCOM_NETIF_MAX
+#define KCOM_NETIF_MAX 128
+#endif
+
+typedef struct kcom_msg_netif_list_s {
+ kcom_msg_hdr_t hdr;
+ uint32 ifcnt;
+ uint16 id[KCOM_NETIF_MAX];
+} kcom_msg_netif_list_t;
+
+/*
+ * Get detailed network interface information.
+ */
+typedef struct kcom_msg_netif_get_s {
+ kcom_msg_hdr_t hdr;
+ kcom_netif_t netif;
+} kcom_msg_netif_get_t;
+
+/*
+ * Create new packet filter.
+ * The filter id will be assigned by the kernel module.
+ */
+typedef struct kcom_msg_filter_create_s {
+ kcom_msg_hdr_t hdr;
+ kcom_filter_t filter;
+} kcom_msg_filter_create_t;
+
+/*
+ * Destroy packet filter.
+ */
+typedef struct kcom_msg_filter_destroy_s {
+ kcom_msg_hdr_t hdr;
+} kcom_msg_filter_destroy_t;
+
+/*
+ * Get list of currently defined packet filters.
+ */
+#ifndef KCOM_FILTER_MAX
+#define KCOM_FILTER_MAX 128
+#endif
+
+typedef struct kcom_msg_filter_list_s {
+ kcom_msg_hdr_t hdr;
+ uint32 fcnt;
+ uint16 id[KCOM_FILTER_MAX];
+} kcom_msg_filter_list_t;
+
+/*
+ * Get detailed packet filter information.
+ */
+typedef struct kcom_msg_filter_get_s {
+ kcom_msg_hdr_t hdr;
+ kcom_filter_t filter;
+} kcom_msg_filter_get_t;
+
+/*
+ * DMA info
+ */
+typedef struct kcom_msg_dma_info_s {
+ kcom_msg_hdr_t hdr;
+ kcom_dma_info_t dma_info;
+} kcom_msg_dma_info_t;
+
+/*
+ * All messages (e.g. for generic receive)
+ */
+typedef union kcom_msg_s {
+ kcom_msg_hdr_t hdr;
+ kcom_msg_version_t version;
+ kcom_msg_string_t string;
+ kcom_msg_hw_reset_t hw_reset;
+ kcom_msg_hw_init_t hw_init;
+ kcom_msg_eth_hw_config_t eth_hw_config;
+ kcom_msg_detach_t detach;
+ kcom_msg_reprobe_t reprobe;
+ kcom_msg_netif_create_t netif_create;
+ kcom_msg_netif_destroy_t netif_destroy;
+ kcom_msg_netif_list_t netif_list;
+ kcom_msg_netif_get_t netif_get;
+ kcom_msg_filter_create_t filter_create;
+ kcom_msg_filter_destroy_t filter_destroy;
+ kcom_msg_filter_list_t filter_list;
+ kcom_msg_filter_get_t filter_get;
+ kcom_msg_dma_info_t dma_info;
+ kcom_msg_dbg_pkt_set_t dbg_pkt_set;
+ kcom_msg_dbg_pkt_get_t dbg_pkt_get;
+ kcom_msg_wb_cleanup_t wb_cleanup;
+ kcom_msg_clock_cmd_t clock_cmd;
+} kcom_msg_t;
+
+/*
+ * KCOM communication channel vectors
+ *
+ * open
+ * Open KCOM channel.
+ *
+ * close
+ * Close KCOM channel.
+ *
+ * send
+ * Send KCOM message. If bufsz is non-zero, a synchronous send will be
+ * performed (if supported) and the function will return the number of
+ * bytes in the response.
+ *
+ * recv
+ * Receive KCOM message. This function is used t oreceive unsolicited
+ * messages from the kernel. If synchronous send is not supported, this
+ * function is also used to retrieve responses to command messages.
+ */
+
+typedef struct kcom_chan_s {
+ void *(*open)(char *name);
+ int (*close)(void *handle);
+ int (*send)(void *handle, void *msg, unsigned int len, unsigned int bufsz);
+ int (*recv)(void *handle, void *msg, unsigned int bufsz);
+} kcom_chan_t;
+
+#endif /* _KCOM_H */
diff --git a/sdk-6.5.20/src/gpl-modules/include/sal/core/sync.h b/sdk-6.5.20/src/gpl-modules/include/sal/core/sync.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: sync.h,v 1.1 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#ifndef _SAL_SYNC_H
+#define _SAL_SYNC_H
+
+typedef struct sal_sem_s{
+ char sal_opaque_type;
+} *sal_sem_t;
+
+#define sal_sem_FOREVER (-1)
+#define sal_sem_BINARY 1
+#define sal_sem_COUNTING 0
+
+sal_sem_t sal_sem_create(char *desc, int binary, int initial_count);
+void sal_sem_destroy(sal_sem_t b);
+int sal_sem_take(sal_sem_t b, int usec);
+int sal_sem_give(sal_sem_t b);
+
+#endif /* !_SAL_SYNC_H */
diff --git a/sdk-6.5.20/src/gpl-modules/include/sal/core/thread.h b/sdk-6.5.20/src/gpl-modules/include/sal/core/thread.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: thread.h,v 1.1 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#ifndef _SAL_THREAD_H
+#define _SAL_THREAD_H
+
+#include <sal/types.h>
+
+void sal_usleep(uint32 usec);
+void sal_udelay(uint32 usec);
+
+#endif /* !_SAL_THREAD_H */
diff --git a/sdk-6.5.20/src/gpl-modules/include/sal/types.h b/sdk-6.5.20/src/gpl-modules/include/sal/types.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: types.h,v 1.3 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ * File: types.h
+ * Purpose: SAL type definitions
+ */
+
+#ifndef _SAL_TYPES_H
+#define _SAL_TYPES_H
+
+/*
+ * Define platform-independent types
+ */
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef DONT_CARE
+#define DONT_CARE 0
+#endif
+
+#define VOL volatile
+
+/*
+ * 64-bit type
+ */
+
+#ifdef LONGS_ARE_64BITS
+
+#define COMPILER_64BIT
+#define COMPILER_UINT64 unsigned long
+#define u64_H(v) (((uint32 *) &(v))[u64_MSW])
+#define u64_L(v) (((uint32 *) &(v))[u64_LSW])
+
+#else /* !LONGS_ARE_64BITS */
+
+#define COMPILER_64BIT
+#define COMPILER_UINT64 unsigned long long
+#define u64_H(v) (((uint32 *) &(v))[u64_MSW])
+#define u64_L(v) (((uint32 *) &(v))[u64_LSW])
+
+#endif /* LONGS_ARE_64BITS */
+
+/*
+ * Define unsigned and signed integers with guaranteed sizes.
+ * Adjust if your compiler uses different sizes for short or int.
+ */
+
+typedef unsigned char uint8; /* 8-bit quantity */
+typedef unsigned short uint16; /* 16-bit quantity */
+typedef unsigned int uint32; /* 32-bit quantity */
+typedef COMPILER_UINT64 uint64; /* 64-bit quantity */
+
+typedef signed char int8; /* 8-bit quantity */
+typedef signed short int16; /* 16-bit quantity */
+typedef signed int int32; /* 32-bit quantity */
+
+#define BITS2BYTES(x) (((x) + 7) / 8)
+#define BITS2WORDS(x) (((x) + 31) / 32)
+
+#define BYTES2BITS(x) ((x) * 8)
+#define BYTES2WORDS(x) (((x) + 3) / 4)
+
+#define WORDS2BITS(x) ((x) * 32)
+#define WORDS2BYTES(x) ((x) * 4)
+
+#define COUNTOF(ary) ((int) (sizeof (ary) / sizeof ((ary)[0])))
+
+#ifdef PTRS_ARE_64BITS
+typedef uint64 sal_vaddr_t; /* Virtual address (Host address) */
+typedef uint64 sal_paddr_t; /* Physical address (PCI address) */
+#define PTR_TO_INT(x) ((uint32)(((sal_vaddr_t)(x))&0xFFFFFFFF))
+#define PTR_HI_TO_INT(x) ((uint32)((((sal_vaddr_t)(x))>>32)&0xFFFFFFFF))
+#else
+typedef uint32 sal_vaddr_t; /* Virtual address (Host address) */
+/* Physical address (PCI address) */
+#ifdef PHYS_ADDRS_ARE_64BITS
+typedef uint64 sal_paddr_t;
+#define PTR_HI_TO_INT(x) ((uint32)((((uint64)(x))>>32)&0xFFFFFFFF))
+#else
+typedef uint32 sal_paddr_t;
+#define PTR_HI_TO_INT(x) (0)
+#endif
+#define PTR_TO_INT(x) ((uint32)(x))
+#endif
+
+#define INT_TO_PTR(x) ((void *)((sal_vaddr_t)(x)))
+
+#define PTR_TO_UINTPTR(x) ((sal_vaddr_t)(x))
+#define UINTPTR_TO_PTR(x) ((void *)(x))
+
+typedef union
+{
+ uint8 u8;
+ uint16 u16;
+ uint32 u32;
+ uint64 u64;
+ sal_paddr_t paddr;
+ sal_vaddr_t vaddr;
+ void *ptr;
+} any_t;
+
+/* Device bus types */
+#define SAL_PCI_DEV_TYPE 0x00001 /* PCI device */
+#define SAL_SPI_DEV_TYPE 0x00002 /* SPI device */
+#define SAL_EB_DEV_TYPE 0x00004 /* EB device */
+#define SAL_ICS_DEV_TYPE 0x00008 /* ICS device */
+#define SAL_MII_DEV_TYPE 0x00010 /* MII device */
+#define SAL_RCPU_DEV_TYPE 0x00020 /* RCPU device */
+#define SAL_I2C_DEV_TYPE 0x00040 /* I2C device */
+#define SAL_AXI_DEV_TYPE 0x00080 /* AXI device */
+#define SAL_EMMI_DEV_TYPE 0x10000 /* EMMI device */
+#define SAL_COMPOSITE_DEV_TYPE 0x20000 /* Composite device, composed of sub-devices with buses */
+#define SAL_DEV_BUS_TYPE_MASK 0xf00ff /* Odd for historical reasons */
+
+/* Device types */
+#define SAL_SWITCH_DEV_TYPE 0x00100 /* Switch device */
+#define SAL_ETHER_DEV_TYPE 0x00200 /* Ethernet device */
+#define SAL_CPU_DEV_TYPE 0x00400 /* CPU device */
+#define SAL_DEV_TYPE_MASK 0x00f00
+
+/* Access types */
+#define SAL_DEV_BUS_RD_16BIT 0x01000 /* 16 bit reads on bus */
+#define SAL_DEV_BUS_WR_16BIT 0x02000 /* 16 bit writes on bus */
+#define SAL_DEV_BUS_ALT 0x04000 /* Alternate access */
+#define SAL_DEV_BUS_MSI 0x08000 /* Message-signaled interrupts */
+#define SAL_DEV_FLAG_MASK 0x0f000
+
+/* BDE reserved mask (cannot be used by SAL) */
+#define SAL_DEV_BDE_MASK 0xff000000
+
+/* Backward compatibility */
+#define SAL_ET_DEV_TYPE SAL_MII_DEV_TYPE
+
+/* Special access addresses */
+#define SAL_DEV_OP_EMMI_INIT 0x0fff1000
+
+#endif /* !_SAL_TYPES_H */
diff --git a/sdk-6.5.20/src/gpl-modules/include/sdk_config.h b/sdk-6.5.20/src/gpl-modules/include/sdk_config.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: sdk_config.h,v 1.5 Broadcom SDK $
+ * $Copyright: (c) 2006 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ *
+ */
+
+#ifndef __SDK_CONFIG_H__
+#define __SDK_CONFIG_H__
+
+/*
+ * Include custom overrides
+ */
+#ifdef SDK_INCLUDE_CUSTOM_CONFIG
+#include <sdk_custom_config.h>
+#endif
+
+
+/*
+ * Memory Barrier operation if required.
+ * Defaults to nothing.
+ */
+#ifndef SDK_CONFIG_MEMORY_BARRIER
+#define SDK_CONFIG_MEMORY_BARRIER
+#endif
+
+
+
+#endif /* __SDK_CONFIG_H__ */
diff --git a/sdk-6.5.20/src/gpl-modules/include/soc/devids.h b/sdk-6.5.20/src/gpl-modules/include/soc/devids.h
@@ -0,0 +1,1988 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * Copyright: (c) 2020 Broadcom.
+ * All Rights Reserved.
+ */
+
+#ifndef _SOC_DEVIDS_H
+#define _SOC_DEVIDS_H
+
+
+#define BROADCOM_VENDOR_ID 0x14e4
+
+#define BCM5690_DEVICE_ID 0x5690
+#define BCM5690_A0_REV_ID 1
+#define BCM5690_A1_REV_ID 2
+#define BCM5690_A2_REV_ID 3
+
+#define BCM5691_DEVICE_ID 0x5691
+#define BCM5691_A0_REV_ID 1
+#define BCM5691_A1_REV_ID 2
+#define BCM5691_A2_REV_ID 3
+
+#define BCM5692_DEVICE_ID 0x5692
+#define BCM5692_A0_REV_ID 1
+#define BCM5692_A1_REV_ID 2
+#define BCM5692_A2_REV_ID 3
+
+#define BCM5693_DEVICE_ID 0x5693
+#define BCM5693_A0_REV_ID 1
+#define BCM5693_A1_REV_ID 2
+#define BCM5693_A2_REV_ID 3
+
+#define BCM5695_DEVICE_ID 0x5695
+#define BCM5695_A0_REV_ID 1
+#define BCM5695_A1_REV_ID 2
+#define BCM5695_B0_REV_ID 0x11
+
+#define BCM5696_DEVICE_ID 0x5696
+#define BCM5696_A0_REV_ID 1
+#define BCM5696_A1_REV_ID 2
+#define BCM5696_B0_REV_ID 0x11
+
+#define BCM5697_DEVICE_ID 0x5697
+#define BCM5697_A0_REV_ID 1
+#define BCM5697_A1_REV_ID 2
+#define BCM5697_B0_REV_ID 0x11
+
+#define BCM5698_DEVICE_ID 0x5698
+#define BCM5698_A0_REV_ID 1
+#define BCM5698_A1_REV_ID 2
+#define BCM5698_B0_REV_ID 0x11
+
+#define BCM5670_DEVICE_ID 0x5670
+#define BCM5670_A0_REV_ID 1
+#define BCM5670_A1_REV_ID 2
+
+#define BCM5671_DEVICE_ID 0x5671
+#define BCM5671_A0_REV_ID 1
+#define BCM5671_A1_REV_ID 2
+#define BCM5671_A2_REV_ID 3
+
+#define BCM5675_DEVICE_ID 0x5675
+#define BCM5675_A0_REV_ID 1
+#define BCM5675_A1_REV_ID 2
+
+#define BCM5676_DEVICE_ID 0x5676
+#define BCM5676_A0_REV_ID 1
+#define BCM5676_A1_REV_ID 2
+
+#define BCM5673_DEVICE_ID 0x5673
+#define BCM5673_A0_REV_ID 1
+#define BCM5673_A1_REV_ID 2
+#define BCM5673_A2_REV_ID 3
+
+#define BCM5674_DEVICE_ID 0x5674
+#define BCM5674_A0_REV_ID 1
+
+#define BCM56100_DEVICE_ID 0xb100
+#define BCM56100_A0_REV_ID 1
+#define BCM56100_A1_REV_ID 2
+#define BCM56101_DEVICE_ID 0xb101
+#define BCM56101_A0_REV_ID 1
+#define BCM56101_A1_REV_ID 2
+#define BCM56102_DEVICE_ID 0xb102
+#define BCM56102_A0_REV_ID 1
+#define BCM56102_A1_REV_ID 2
+#define BCM56105_DEVICE_ID 0xb105
+#define BCM56105_A0_REV_ID 1
+#define BCM56105_A1_REV_ID 2
+#define BCM56106_DEVICE_ID 0xb106
+#define BCM56106_A0_REV_ID 1
+#define BCM56106_A1_REV_ID 2
+#define BCM56107_DEVICE_ID 0xb107
+#define BCM56107_A0_REV_ID 1
+#define BCM56107_A1_REV_ID 2
+
+#define BCM56110_DEVICE_ID 0xb110
+#define BCM56110_A0_REV_ID 1
+#define BCM56111_DEVICE_ID 0xb111
+#define BCM56111_A0_REV_ID 1
+#define BCM56112_DEVICE_ID 0xb112
+#define BCM56112_A0_REV_ID 1
+#define BCM56115_DEVICE_ID 0xb115
+#define BCM56115_A0_REV_ID 1
+#define BCM56116_DEVICE_ID 0xb116
+#define BCM56116_A0_REV_ID 1
+#define BCM56117_DEVICE_ID 0xb117
+#define BCM56117_A0_REV_ID 1
+
+#define BCM56300_DEVICE_ID 0xb300
+#define BCM56300_A0_REV_ID 1
+#define BCM56300_A1_REV_ID 2
+#define BCM56300_B0_REV_ID 0x11
+#define BCM56300_B1_REV_ID 0x12
+#define BCM56301_DEVICE_ID 0xb301
+#define BCM56301_A0_REV_ID 1
+#define BCM56301_A1_REV_ID 2
+#define BCM56301_B0_REV_ID 0x11
+#define BCM56301_B1_REV_ID 0x12
+#define BCM56302_DEVICE_ID 0xb302
+#define BCM56302_A0_REV_ID 1
+#define BCM56302_A1_REV_ID 2
+#define BCM56302_B0_REV_ID 0x11
+#define BCM56302_B1_REV_ID 0x12
+#define BCM56303_DEVICE_ID 0xb303
+#define BCM56303_A1_REV_ID 2
+#define BCM56303_A0_REV_ID 1
+#define BCM56303_B0_REV_ID 0x11
+#define BCM56303_B1_REV_ID 0x12
+#define BCM56304_DEVICE_ID 0xb304
+#define BCM56304_A0_REV_ID 1
+#define BCM56304_A1_REV_ID 2
+#define BCM56304_B0_REV_ID 0x11
+#define BCM56304_B1_REV_ID 0x12
+#define BCM56404_DEVICE_ID 0xb404
+#define BCM56404_A0_REV_ID 1
+#define BCM56404_A1_REV_ID 2
+#define BCM56305_DEVICE_ID 0xb305
+#define BCM56305_A0_REV_ID 1
+#define BCM56305_A1_REV_ID 2
+#define BCM56305_B0_REV_ID 0x11
+#define BCM56305_B1_REV_ID 0x12
+#define BCM56306_DEVICE_ID 0xb306
+#define BCM56306_A0_REV_ID 1
+#define BCM56306_A1_REV_ID 2
+#define BCM56306_B0_REV_ID 0x11
+#define BCM56306_B1_REV_ID 0x12
+#define BCM56307_DEVICE_ID 0xb307
+#define BCM56307_A0_REV_ID 1
+#define BCM56307_A1_REV_ID 2
+#define BCM56307_B0_REV_ID 0x11
+#define BCM56307_B1_REV_ID 0x12
+#define BCM56308_DEVICE_ID 0xb308
+#define BCM56308_A0_REV_ID 1
+#define BCM56308_A1_REV_ID 2
+#define BCM56308_B0_REV_ID 0x11
+#define BCM56308_B1_REV_ID 0x12
+#define BCM56309_DEVICE_ID 0xb309
+#define BCM56309_A0_REV_ID 1
+#define BCM56309_A1_REV_ID 2
+#define BCM56309_B0_REV_ID 0x11
+#define BCM56309_B1_REV_ID 0x12
+
+#define BCM56310_DEVICE_ID 0xb310
+#define BCM56310_A0_REV_ID 1
+#define BCM56311_DEVICE_ID 0xb311
+#define BCM56311_A0_REV_ID 1
+#define BCM56312_DEVICE_ID 0xb312
+#define BCM56312_A0_REV_ID 1
+#define BCM56313_DEVICE_ID 0xb313
+#define BCM56313_A0_REV_ID 1
+#define BCM56314_DEVICE_ID 0xb314
+#define BCM56314_A0_REV_ID 1
+#define BCM56315_DEVICE_ID 0xb315
+#define BCM56315_A0_REV_ID 1
+#define BCM56316_DEVICE_ID 0xb316
+#define BCM56316_A0_REV_ID 1
+#define BCM56317_DEVICE_ID 0xb317
+#define BCM56317_A0_REV_ID 1
+#define BCM56318_DEVICE_ID 0xb318
+#define BCM56318_A0_REV_ID 1
+#define BCM56319_DEVICE_ID 0xb319
+#define BCM56319_A0_REV_ID 1
+
+#ifndef EXCLUDE_BCM56324
+#define BCM56322_DEVICE_ID 0xb322
+#define BCM56322_A0_REV_ID 1
+#define BCM56324_DEVICE_ID 0xb324
+#define BCM56324_A0_REV_ID 1
+#endif
+
+#define BCM53300_DEVICE_ID 0xb006
+#define BCM53300_A0_REV_ID 0x11
+#define BCM53300_A1_REV_ID 0x12
+#define BCM53301_DEVICE_ID 0xb206
+#define BCM53301_A0_REV_ID 0x11
+#define BCM53301_A1_REV_ID 0x12
+#define BCM53302_DEVICE_ID 0xb008
+#define BCM53302_A0_REV_ID 0x11
+#define BCM53302_A1_REV_ID 0x12
+
+#define BCM56500_DEVICE_ID 0xb500
+#define BCM56500_A0_REV_ID 1
+#define BCM56500_A1_REV_ID 2
+#define BCM56500_B0_REV_ID 0x11
+#define BCM56500_B1_REV_ID 0x12
+#define BCM56500_B2_REV_ID 0x13
+#define BCM56501_DEVICE_ID 0xb501
+#define BCM56501_A0_REV_ID 1
+#define BCM56501_A1_REV_ID 2
+#define BCM56501_B0_REV_ID 0x11
+#define BCM56501_B1_REV_ID 0x12
+#define BCM56501_B2_REV_ID 0x13
+#define BCM56502_DEVICE_ID 0xb502
+#define BCM56502_A0_REV_ID 1
+#define BCM56502_A1_REV_ID 2
+#define BCM56502_B0_REV_ID 0x11
+#define BCM56502_B1_REV_ID 0x12
+#define BCM56502_B2_REV_ID 0x13
+#define BCM56503_DEVICE_ID 0xb503
+#define BCM56503_A0_REV_ID 1
+#define BCM56503_A1_REV_ID 2
+#define BCM56503_B0_REV_ID 0x11
+#define BCM56503_B1_REV_ID 0x12
+#define BCM56503_B2_REV_ID 0x13
+#define BCM56504_DEVICE_ID 0xb504
+#define BCM56504_A0_REV_ID 1
+#define BCM56504_A1_REV_ID 2
+#define BCM56504_B0_REV_ID 0x11
+#define BCM56504_B1_REV_ID 0x12
+#define BCM56504_B2_REV_ID 0x13
+#define BCM56505_DEVICE_ID 0xb505
+#define BCM56505_A0_REV_ID 1
+#define BCM56505_A1_REV_ID 2
+#define BCM56505_B0_REV_ID 0x11
+#define BCM56505_B1_REV_ID 0x12
+#define BCM56505_B2_REV_ID 0x13
+#define BCM56506_DEVICE_ID 0xb506
+#define BCM56506_A0_REV_ID 1
+#define BCM56506_A1_REV_ID 2
+#define BCM56506_B0_REV_ID 0x11
+#define BCM56506_B1_REV_ID 0x12
+#define BCM56506_B2_REV_ID 0x13
+#define BCM56507_DEVICE_ID 0xb507
+#define BCM56507_A0_REV_ID 1
+#define BCM56507_A1_REV_ID 2
+#define BCM56507_B0_REV_ID 0x11
+#define BCM56507_B1_REV_ID 0x12
+#define BCM56507_B2_REV_ID 0x13
+#define BCM56508_DEVICE_ID 0xb508
+#define BCM56508_A0_REV_ID 1
+#define BCM56508_A1_REV_ID 2
+#define BCM56508_B0_REV_ID 0x11
+#define BCM56508_B1_REV_ID 0x12
+#define BCM56508_B2_REV_ID 0x13
+#define BCM56509_DEVICE_ID 0xb509
+#define BCM56509_A0_REV_ID 1
+#define BCM56509_A1_REV_ID 2
+#define BCM56509_B0_REV_ID 0x11
+#define BCM56509_B1_REV_ID 0x12
+#define BCM56509_B2_REV_ID 0x13
+
+#define BCM56600_DEVICE_ID 0xb600
+#define BCM56600_A0_REV_ID 1
+#define BCM56600_B0_REV_ID 0x11
+#define BCM56600_C0_REV_ID 0x21
+#define BCM56601_DEVICE_ID 0xb601
+#define BCM56601_A0_REV_ID 1
+#define BCM56601_B0_REV_ID 0x11
+#define BCM56601_C0_REV_ID 0x21
+#define BCM56602_DEVICE_ID 0xb602
+#define BCM56602_A0_REV_ID 1
+#define BCM56602_B0_REV_ID 0x11
+#define BCM56602_C0_REV_ID 0x21
+#define BCM56603_DEVICE_ID 0xb603
+#define BCM56603_A0_REV_ID 1
+#define BCM56603_B0_REV_ID 0x11
+#define BCM56603_C0_REV_ID 0x21
+#define BCM56605_DEVICE_ID 0xb605
+#define BCM56605_A0_REV_ID 1
+#define BCM56605_B0_REV_ID 0x11
+#define BCM56605_C0_REV_ID 0x21
+#define BCM56606_DEVICE_ID 0xb606
+#define BCM56606_A0_REV_ID 1
+#define BCM56606_B0_REV_ID 0x11
+#define BCM56606_C0_REV_ID 0x21
+#define BCM56607_DEVICE_ID 0xb607
+#define BCM56607_A0_REV_ID 1
+#define BCM56607_B0_REV_ID 0x11
+#define BCM56607_C0_REV_ID 0x21
+#define BCM56608_DEVICE_ID 0xb608
+#define BCM56608_A0_REV_ID 1
+#define BCM56608_B0_REV_ID 0x11
+#define BCM56608_C0_REV_ID 0x21
+
+#define BCM56580_DEVICE_ID 0xb580
+#define BCM56580_A0_REV_ID 1
+
+#define BCM56700_DEVICE_ID 0xb700
+#define BCM56700_A0_REV_ID 1
+#define BCM56701_DEVICE_ID 0xb701
+#define BCM56701_A0_REV_ID 1
+
+#define BCM56800_DEVICE_ID 0xb800
+#define BCM56800_A0_REV_ID 1
+#define BCM56801_DEVICE_ID 0xb801
+#define BCM56801_A0_REV_ID 1
+#define BCM56802_DEVICE_ID 0xb802
+#define BCM56802_A0_REV_ID 1
+#define BCM56803_DEVICE_ID 0xb803
+#define BCM56803_A0_REV_ID 1
+
+#define BCM56224_DEVICE_ID 0xb224
+#define BCM56224_A0_REV_ID 1
+#define BCM56224_B0_REV_ID 0x11
+#define BCM56225_DEVICE_ID 0xb225
+#define BCM56225_A0_REV_ID 1
+#define BCM56225_B0_REV_ID 0x11
+#define BCM56226_DEVICE_ID 0xb226
+#define BCM56226_A0_REV_ID 1
+#define BCM56226_B0_REV_ID 0x11
+#define BCM56227_DEVICE_ID 0xb227
+#define BCM56227_A0_REV_ID 1
+#define BCM56227_B0_REV_ID 0x11
+#define BCM56228_DEVICE_ID 0xb228
+#define BCM56228_A0_REV_ID 1
+#define BCM56228_B0_REV_ID 0x11
+#define BCM56229_DEVICE_ID 0xb229
+#define BCM56229_A0_REV_ID 1
+#define BCM56229_B0_REV_ID 0x11
+#define BCM56024_DEVICE_ID 0xb024
+#define BCM56024_A0_REV_ID 1
+#define BCM56024_B0_REV_ID 0x11
+#define BCM56025_DEVICE_ID 0xb025
+#define BCM56025_A0_REV_ID 1
+#define BCM56025_B0_REV_ID 0x11
+#define BCM53724_DEVICE_ID 0xc724
+#define BCM53724_A0_REV_ID 1
+#define BCM53724_B0_REV_ID 0x11
+#define BCM53726_DEVICE_ID 0xc726
+#define BCM53726_A0_REV_ID 1
+#define BCM53726_B0_REV_ID 0x11
+
+#define BCM53312_DEVICE_ID 0xc312
+#define BCM53312_A0_REV_ID 1
+#define BCM53312_B0_REV_ID 0x11
+#define BCM53313_DEVICE_ID 0xc313
+#define BCM53313_A0_REV_ID 1
+#define BCM53313_B0_REV_ID 0x11
+#define BCM53314_DEVICE_ID 0xc314
+#define BCM53314_A0_REV_ID 1
+#define BCM53314_B0_REV_ID 0x11
+
+#define BCM53322_DEVICE_ID 0xc322
+#define BCM53322_A0_REV_ID 1
+#define BCM53323_DEVICE_ID 0xc323
+#define BCM53323_A0_REV_ID 1
+#define BCM53324_DEVICE_ID 0xc324
+#define BCM53324_A0_REV_ID 1
+
+
+#define BCM56218_DEVICE_ID 0xB218
+#define BCM56218_A0_REV_ID 1
+#define BCM56218_A1_REV_ID 2
+#define BCM56218_A2_REV_ID 3
+#define BCM56218X_DEVICE_ID 0xc710
+#define BCM56218X_A0_REV_ID 1
+#define BCM56218X_A1_REV_ID 2
+#define BCM56218X_A2_REV_ID 3
+#define BCM56219_DEVICE_ID 0xB219
+#define BCM56219_A0_REV_ID 1
+#define BCM56219_A1_REV_ID 2
+#define BCM56219_A2_REV_ID 3
+#define BCM56218R_DEVICE_ID 0xB21A
+#define BCM56218R_A0_REV_ID 1
+#define BCM56218R_A1_REV_ID 2
+#define BCM56218R_A2_REV_ID 3
+#define BCM56219R_DEVICE_ID 0xB21B
+#define BCM56219R_A0_REV_ID 1
+#define BCM56219R_A1_REV_ID 2
+#define BCM56219R_A2_REV_ID 3
+#define BCM56214_DEVICE_ID 0xB214
+#define BCM56214_A0_REV_ID 1
+#define BCM56214_A1_REV_ID 2
+#define BCM56214_A2_REV_ID 3
+#define BCM56215_DEVICE_ID 0xB215
+#define BCM56215_A0_REV_ID 1
+#define BCM56215_A1_REV_ID 2
+#define BCM56215_A2_REV_ID 3
+#define BCM56214R_DEVICE_ID 0xB21C
+#define BCM56214R_A0_REV_ID 1
+#define BCM56214R_A1_REV_ID 2
+#define BCM56214R_A2_REV_ID 3
+#define BCM56215R_DEVICE_ID 0xB21D
+#define BCM56215R_A0_REV_ID 1
+#define BCM56215R_A1_REV_ID 2
+#define BCM56215R_A2_REV_ID 3
+#define BCM56216_DEVICE_ID 0xB216
+#define BCM56216_A0_REV_ID 1
+#define BCM56216_A1_REV_ID 2
+#define BCM56216_A2_REV_ID 3
+#define BCM56217_DEVICE_ID 0xB217
+#define BCM56217_A0_REV_ID 1
+#define BCM56217_A1_REV_ID 2
+#define BCM56217_A2_REV_ID 3
+#define BCM56212_DEVICE_ID 0xB212
+#define BCM56212_A0_REV_ID 1
+#define BCM56212_A1_REV_ID 2
+#define BCM56212_A2_REV_ID 3
+#define BCM56213_DEVICE_ID 0xB213
+#define BCM56213_A0_REV_ID 1
+#define BCM56213_A1_REV_ID 2
+#define BCM56213_A2_REV_ID 3
+#define BCM53718_DEVICE_ID 0xC71A
+#define BCM53718_A0_REV_ID 1
+#define BCM53718_A1_REV_ID 2
+#define BCM53718_A2_REV_ID 3
+#define BCM53714_DEVICE_ID 0xC71B
+#define BCM53714_A0_REV_ID 1
+#define BCM53714_A1_REV_ID 2
+#define BCM53714_A2_REV_ID 3
+#define BCM53716_DEVICE_ID 0xC716
+#define BCM53716_A0_REV_ID 1
+#define BCM53716_A1_REV_ID 2
+#define BCM53716_A2_REV_ID 3
+#define BCM56018_DEVICE_ID 0xB018
+#define BCM56018_A0_REV_ID 1
+#define BCM56018_A1_REV_ID 2
+#define BCM56018_A2_REV_ID 3
+#define BCM56014_DEVICE_ID 0xB014
+#define BCM56014_A0_REV_ID 1
+#define BCM56014_A1_REV_ID 2
+#define BCM56014_A2_REV_ID 3
+
+#define BCM56510_DEVICE_ID 0xb510
+#define BCM56510_A0_REV_ID 1
+#define BCM56511_DEVICE_ID 0xb511
+#define BCM56511_A0_REV_ID 1
+#define BCM56512_DEVICE_ID 0xb512
+#define BCM56512_A0_REV_ID 1
+#define BCM56513_DEVICE_ID 0xb513
+#define BCM56513_A0_REV_ID 1
+#define BCM56514_DEVICE_ID 0xb514
+#define BCM56514_A0_REV_ID 1
+#define BCM56516_DEVICE_ID 0xb516
+#define BCM56516_A0_REV_ID 1
+#define BCM56517_DEVICE_ID 0xb517
+#define BCM56517_A0_REV_ID 1
+#define BCM56518_DEVICE_ID 0xb518
+#define BCM56518_A0_REV_ID 1
+#define BCM56519_DEVICE_ID 0xb519
+#define BCM56519_A0_REV_ID 1
+
+#define BCM56620_DEVICE_ID 0xb620
+#define BCM56620_A0_REV_ID 1
+#define BCM56620_A1_REV_ID 2
+#define BCM56620_B0_REV_ID 0x11
+#define BCM56620_B1_REV_ID 0x12
+#define BCM56620_B2_REV_ID 0x13
+#define BCM56624_DEVICE_ID 0xb624
+#define BCM56624_A0_REV_ID 1
+#define BCM56624_A1_REV_ID 2
+#define BCM56624_B0_REV_ID 0x11
+#define BCM56624_B1_REV_ID 0x12
+#define BCM56624_B2_REV_ID 0x13
+#define BCM56626_DEVICE_ID 0xb626
+#define BCM56626_A0_REV_ID 1
+#define BCM56626_A1_REV_ID 2
+#define BCM56626_B0_REV_ID 0x11
+#define BCM56626_B1_REV_ID 0x12
+#define BCM56626_B2_REV_ID 0x13
+#define BCM56628_DEVICE_ID 0xb628
+#define BCM56628_A0_REV_ID 1
+#define BCM56628_A1_REV_ID 2
+#define BCM56628_B0_REV_ID 0x11
+#define BCM56628_B1_REV_ID 0x12
+#define BCM56628_B2_REV_ID 0x13
+#define BCM56629_DEVICE_ID 0xb629
+#define BCM56629_A0_REV_ID 1
+#define BCM56629_A1_REV_ID 2
+#define BCM56629_B0_REV_ID 0x11
+#define BCM56629_B1_REV_ID 0x12
+#define BCM56629_B2_REV_ID 0x13
+
+#define BCM56680_DEVICE_ID 0xb680
+#define BCM56680_A0_REV_ID 1
+#define BCM56680_A1_REV_ID 2
+#define BCM56680_B0_REV_ID 0x11
+#define BCM56680_B1_REV_ID 0x12
+#define BCM56680_B2_REV_ID 0x13
+#define BCM56684_DEVICE_ID 0xb684
+#define BCM56684_A0_REV_ID 1
+#define BCM56684_A1_REV_ID 2
+#define BCM56684_B0_REV_ID 0x11
+#define BCM56684_B1_REV_ID 0x12
+#define BCM56684_B2_REV_ID 0x13
+#define BCM56686_DEVICE_ID 0xb686
+#define BCM56686_B0_REV_ID 0x11
+#define BCM56686_B1_REV_ID 0x12
+#define BCM56686_B2_REV_ID 0x13
+
+#define BCM56820_DEVICE_ID 0xb820
+#define BCM56820_A0_REV_ID 1
+#define BCM56820_B0_REV_ID 0x11
+#define BCM56821_DEVICE_ID 0xb821
+#define BCM56821_A0_REV_ID 1
+#define BCM56821_B0_REV_ID 0x11
+#define BCM56822_DEVICE_ID 0xb822
+#define BCM56822_A0_REV_ID 1
+#define BCM56822_B0_REV_ID 0x11
+#define BCM56823_DEVICE_ID 0xb823
+#define BCM56823_A0_REV_ID 1
+#define BCM56823_B0_REV_ID 0x11
+#define BCM56825_DEVICE_ID 0xb825
+#define BCM56825_B0_REV_ID 0x11
+
+#define BCM56720_DEVICE_ID 0xb720
+#define BCM56720_A0_REV_ID 1
+#define BCM56720_B0_REV_ID 0x11
+#define BCM56721_DEVICE_ID 0xb721
+#define BCM56721_A0_REV_ID 1
+#define BCM56721_B0_REV_ID 0x11
+
+#define BCM56725_DEVICE_ID 0xb725
+#define BCM56725_A0_REV_ID 1
+#define BCM56725_B0_REV_ID 0x11
+
+#define BCM56630_DEVICE_ID 0xb630
+#define BCM56630_A0_REV_ID 1
+#define BCM56630_B0_REV_ID 0x11
+#define BCM56634_DEVICE_ID 0xb634
+#define BCM56634_A0_REV_ID 1
+#define BCM56634_B0_REV_ID 0x11
+#define BCM56636_DEVICE_ID 0xb636
+#define BCM56636_A0_REV_ID 1
+#define BCM56636_B0_REV_ID 0x11
+#define BCM56638_DEVICE_ID 0xb638
+#define BCM56638_A0_REV_ID 1
+#define BCM56638_B0_REV_ID 0x11
+#define BCM56639_DEVICE_ID 0xb639
+#define BCM56639_A0_REV_ID 1
+#define BCM56639_B0_REV_ID 0x11
+
+#define BCM56685_DEVICE_ID 0xb685
+#define BCM56685_A0_REV_ID 1
+#define BCM56685_B0_REV_ID 0x11
+#define BCM56689_DEVICE_ID 0xb689
+#define BCM56689_A0_REV_ID 1
+#define BCM56689_B0_REV_ID 0x11
+
+#define BCM56520_DEVICE_ID 0xb520
+#define BCM56520_A0_REV_ID 1
+#define BCM56520_B0_REV_ID 0x11
+#define BCM56521_DEVICE_ID 0xb521
+#define BCM56521_A0_REV_ID 1
+#define BCM56521_B0_REV_ID 0x11
+#define BCM56522_DEVICE_ID 0xb522
+#define BCM56522_A0_REV_ID 1
+#define BCM56522_B0_REV_ID 0x11
+#define BCM56524_DEVICE_ID 0xb524
+#define BCM56524_A0_REV_ID 1
+#define BCM56524_B0_REV_ID 0x11
+#define BCM56526_DEVICE_ID 0xb526
+#define BCM56526_A0_REV_ID 1
+#define BCM56526_B0_REV_ID 0x11
+
+#define BCM56534_DEVICE_ID 0xb534
+#define BCM56534_B0_REV_ID 0x11
+#define BCM56538_DEVICE_ID 0xb538
+#define BCM56538_B0_REV_ID 0x11
+
+#define BCM56331_DEVICE_ID 0xb331
+#define BCM56331_A0_REV_ID 1
+#define BCM56331_B0_REV_ID 0x11
+#define BCM56331_B1_REV_ID 0x12
+#define BCM56333_DEVICE_ID 0xb333
+#define BCM56333_A0_REV_ID 1
+#define BCM56333_B0_REV_ID 0x11
+#define BCM56333_B1_REV_ID 0x12
+#define BCM56334_DEVICE_ID 0xb334
+#define BCM56334_A0_REV_ID 1
+#define BCM56334_B0_REV_ID 0x11
+#define BCM56334_B1_REV_ID 0x12
+#define BCM56338_DEVICE_ID 0xb338
+#define BCM56338_A0_REV_ID 1
+#define BCM56338_B0_REV_ID 0x11
+#define BCM56338_B1_REV_ID 0x12
+
+#define BCM56320_DEVICE_ID 0xb320
+#define BCM56320_A0_REV_ID 1
+#define BCM56320_B0_REV_ID 0x11
+#define BCM56320_B1_REV_ID 0x12
+#define BCM56321_DEVICE_ID 0xb321
+#define BCM56321_A0_REV_ID 1
+#define BCM56321_B0_REV_ID 0x11
+#define BCM56321_B1_REV_ID 0x12
+
+
+#define BCM56548H_DEVICE_ID 0xB54A
+#define BCM56548H_A0_REV_ID 1
+#define BCM56548_DEVICE_ID 0xb548
+#define BCM56548_A0_REV_ID 1
+#define BCM56547_DEVICE_ID 0xb547
+#define BCM56547_A0_REV_ID 1
+
+#define BCM56346_DEVICE_ID 0xb346
+#define BCM56346_A0_REV_ID 1
+#define BCM56345_DEVICE_ID 0xb345
+#define BCM56345_A0_REV_ID 1
+#define BCM56344_DEVICE_ID 0xb344
+#define BCM56344_A0_REV_ID 1
+#define BCM56342_DEVICE_ID 0xb342
+#define BCM56342_A0_REV_ID 1
+#define BCM56340_DEVICE_ID 0xb340
+#define BCM56340_A0_REV_ID 1
+
+#define BCM56049_DEVICE_ID 0xb049
+#define BCM56049_A0_REV_ID 1
+#define BCM56048_DEVICE_ID 0xb048
+#define BCM56048_A0_REV_ID 1
+#define BCM56047_DEVICE_ID 0xb047
+#define BCM56047_A0_REV_ID 1
+
+#define BCM56042_DEVICE_ID 0xb042
+#define BCM56042_A0_REV_ID 1
+#define BCM56041_DEVICE_ID 0xb041
+#define BCM56041_A0_REV_ID 1
+#define BCM56040_DEVICE_ID 0xb040
+#define BCM56040_A0_REV_ID 1
+
+#define BCM56132_DEVICE_ID 0xb132
+#define BCM56132_A0_REV_ID 1
+#define BCM56132_B0_REV_ID 0x11
+#define BCM56132_B1_REV_ID 0x12
+#define BCM56134_DEVICE_ID 0xb134
+#define BCM56134_A0_REV_ID 1
+#define BCM56134_B0_REV_ID 0x11
+#define BCM56134_B1_REV_ID 0x12
+
+#define BCM56230_DEVICE_ID 0xb230
+#define BCM56230_B1_REV_ID 0x12
+#define BCM56231_DEVICE_ID 0xb231
+#define BCM56231_B1_REV_ID 0x12
+
+#define BCM56140_DEVICE_ID 0xb140
+#define BCM56140_A0_REV_ID 1
+#define BCM56142_DEVICE_ID 0xb142
+#define BCM56142_A0_REV_ID 1
+#define BCM56143_DEVICE_ID 0xb143
+#define BCM56143_A0_REV_ID 1
+#define BCM56144_DEVICE_ID 0xb144
+#define BCM56144_A0_REV_ID 1
+#define BCM56146_DEVICE_ID 0xb146
+#define BCM56146_A0_REV_ID 1
+#define BCM56147_DEVICE_ID 0xb147
+#define BCM56147_A0_REV_ID 1
+#define BCM56149_DEVICE_ID 0xb149
+#define BCM56149_A0_REV_ID 1
+
+#define BCM56840_DEVICE_ID 0xb840
+#define BCM56840_A0_REV_ID 1
+#define BCM56840_A1_REV_ID 2
+#define BCM56840_A2_REV_ID 3
+#define BCM56840_A3_REV_ID 4
+#define BCM56840_A4_REV_ID 5
+#define BCM56840_B0_REV_ID 0x11
+#define BCM56840_B1_REV_ID 0x12
+#define BCM56841_DEVICE_ID 0xb841
+#define BCM56841_A0_REV_ID 1
+#define BCM56841_A1_REV_ID 2
+#define BCM56841_A2_REV_ID 3
+#define BCM56841_A3_REV_ID 4
+#define BCM56841_A4_REV_ID 5
+#define BCM56841_B0_REV_ID 0x11
+#define BCM56841_B1_REV_ID 0x12
+#define BCM56843_DEVICE_ID 0xb843
+#define BCM56843_A0_REV_ID 1
+#define BCM56843_A1_REV_ID 2
+#define BCM56843_A2_REV_ID 3
+#define BCM56843_A3_REV_ID 4
+#define BCM56843_A4_REV_ID 5
+#define BCM56843_B0_REV_ID 0x11
+#define BCM56843_B1_REV_ID 0x12
+#define BCM56845_DEVICE_ID 0xb845
+#define BCM56845_A0_REV_ID 1
+#define BCM56845_A1_REV_ID 2
+#define BCM56845_A2_REV_ID 3
+#define BCM56845_A3_REV_ID 4
+#define BCM56845_A4_REV_ID 5
+#define BCM56845_B0_REV_ID 0x11
+#define BCM56845_B1_REV_ID 0x12
+
+#define BCM56743_DEVICE_ID 0xb743
+#define BCM56743_A0_REV_ID 1
+#define BCM56743_A1_REV_ID 2
+#define BCM56743_A2_REV_ID 3
+#define BCM56743_A3_REV_ID 4
+#define BCM56743_A4_REV_ID 5
+#define BCM56743_B0_REV_ID 0x11
+#define BCM56743_B1_REV_ID 0x12
+#define BCM56745_DEVICE_ID 0xb745
+#define BCM56745_A0_REV_ID 1
+#define BCM56745_A1_REV_ID 2
+#define BCM56745_A2_REV_ID 3
+#define BCM56745_A3_REV_ID 4
+#define BCM56745_A4_REV_ID 5
+#define BCM56745_B0_REV_ID 0x11
+#define BCM56745_B1_REV_ID 0x12
+
+#define BCM56260_DEVICE_ID 0xb260
+#define BCM56260_A0_REV_ID 1
+#define BCM56260_B0_REV_ID 0x11
+#define BCM56261_DEVICE_ID 0xb261
+#define BCM56261_A0_REV_ID 1
+#define BCM56261_B0_REV_ID 0x11
+#define BCM56262_DEVICE_ID 0xb262
+#define BCM56262_A0_REV_ID 1
+#define BCM56262_B0_REV_ID 0x11
+#define BCM56263_DEVICE_ID 0xb263
+#define BCM56263_A0_REV_ID 1
+#define BCM56263_B0_REV_ID 0x11
+
+#define BCM56265_DEVICE_ID 0xb265
+#define BCM56265_A0_REV_ID 1
+#define BCM56265_B0_REV_ID 0x11
+#define BCM56266_DEVICE_ID 0xb266
+#define BCM56266_A0_REV_ID 1
+#define BCM56266_B0_REV_ID 0x11
+#define BCM56267_DEVICE_ID 0xb267
+#define BCM56267_A0_REV_ID 1
+#define BCM56267_B0_REV_ID 0x11
+#define BCM56268_DEVICE_ID 0xb268
+#define BCM56268_A0_REV_ID 1
+#define BCM56268_B0_REV_ID 0x11
+
+#define BCM56233_DEVICE_ID 0xb233
+#define BCM56233_B0_REV_ID 0x11
+
+#define BCM56460_DEVICE_ID 0xb460
+#define BCM56460_A0_REV_ID 1
+#define BCM56460_B0_REV_ID 0x11
+#define BCM56461_DEVICE_ID 0xb461
+#define BCM56461_A0_REV_ID 1
+#define BCM56461_B0_REV_ID 0x11
+#define BCM56462_DEVICE_ID 0xb462
+#define BCM56462_A0_REV_ID 1
+#define BCM56462_B0_REV_ID 0x11
+#define BCM56463_DEVICE_ID 0xb463
+#define BCM56463_A0_REV_ID 1
+#define BCM56463_B0_REV_ID 0x11
+
+#define BCM56465_DEVICE_ID 0xb465
+#define BCM56465_A0_REV_ID 1
+#define BCM56465_B0_REV_ID 0x11
+#define BCM56466_DEVICE_ID 0xb466
+#define BCM56466_A0_REV_ID 1
+#define BCM56466_B0_REV_ID 0x11
+#define BCM56467_DEVICE_ID 0xb467
+#define BCM56467_A0_REV_ID 1
+#define BCM56467_B0_REV_ID 0x11
+#define BCM56468_DEVICE_ID 0xb468
+#define BCM56468_A0_REV_ID 1
+#define BCM56468_B0_REV_ID 0x11
+
+#define BCM56270_DEVICE_ID 0xb270
+#define BCM56270_A0_REV_ID 1
+#define BCM56271_DEVICE_ID 0xb271
+#define BCM56271_A0_REV_ID 1
+#define BCM56272_DEVICE_ID 0xb272
+#define BCM56272_A0_REV_ID 1
+
+#define BCM53460_DEVICE_ID 0x8460
+#define BCM53460_A0_REV_ID 1
+#define BCM53461_DEVICE_ID 0x8461
+#define BCM53461_A0_REV_ID 1
+
+#define BCM56842_DEVICE_ID 0xb842
+#define BCM56842_A0_REV_ID 1
+#define BCM56842_A1_REV_ID 2
+#define BCM56844_DEVICE_ID 0xb844
+#define BCM56844_A0_REV_ID 1
+#define BCM56844_A1_REV_ID 2
+#define BCM56846_DEVICE_ID 0xb846
+#define BCM56846_A0_REV_ID 1
+#define BCM56846_A1_REV_ID 2
+#define BCM56549_DEVICE_ID 0xb549
+#define BCM56549_A0_REV_ID 1
+#define BCM56549_A1_REV_ID 2
+#define BCM56053_DEVICE_ID 0xb053
+#define BCM56053_A0_REV_ID 1
+#define BCM56053_A1_REV_ID 2
+#define BCM56831_DEVICE_ID 0xb831
+#define BCM56831_A0_REV_ID 1
+#define BCM56831_A1_REV_ID 2
+#define BCM56835_DEVICE_ID 0xb835
+#define BCM56835_A0_REV_ID 1
+#define BCM56835_A1_REV_ID 2
+#define BCM56838_DEVICE_ID 0xb838
+#define BCM56838_A0_REV_ID 1
+#define BCM56838_A1_REV_ID 2
+#define BCM56847_DEVICE_ID 0xb847
+#define BCM56847_A0_REV_ID 1
+#define BCM56847_A1_REV_ID 2
+#define BCM56847_A2_REV_ID 3
+#define BCM56847_A3_REV_ID 4
+#define BCM56847_A4_REV_ID 5
+#define BCM56847_B0_REV_ID 0x11
+#define BCM56847_B1_REV_ID 0x12
+#define BCM56849_DEVICE_ID 0xb849
+#define BCM56849_A0_REV_ID 1
+#define BCM56849_A1_REV_ID 2
+
+#define BCM56742_DEVICE_ID 0xb742
+#define BCM56742_A0_REV_ID 1
+#define BCM56742_A1_REV_ID 2
+#define BCM56742_A2_REV_ID 3
+#define BCM56744_DEVICE_ID 0xb744
+#define BCM56744_A0_REV_ID 1
+#define BCM56744_A1_REV_ID 2
+#define BCM56746_DEVICE_ID 0xb746
+#define BCM56746_A0_REV_ID 1
+#define BCM56746_A1_REV_ID 2
+
+#define BCM88732_DEVICE_ID 0x0732
+#define BCM88732_A0_REV_ID 1
+#define BCM88732_A1_REV_ID 2
+#define BCM88732_A2_REV_ID 4
+#define BCM88732_B0_REV_ID 0x11
+#define BCM88732_B1_REV_ID 0x12
+#define BCM88732_B2_REV_ID 0x13
+
+#define BCM56640_DEVICE_ID 0xb640
+#define BCM56640_A0_REV_ID 1
+#define BCM56640_A1_REV_ID 2
+#define BCM56640_B0_REV_ID 0x11
+#define BCM56643_DEVICE_ID 0xb643
+#define BCM56643_A0_REV_ID 1
+#define BCM56643_A1_REV_ID 2
+#define BCM56643_B0_REV_ID 0x11
+#define BCM56644_DEVICE_ID 0xb644
+#define BCM56644_A0_REV_ID 1
+#define BCM56644_A1_REV_ID 2
+#define BCM56644_B0_REV_ID 0x11
+#define BCM56648_DEVICE_ID 0xb648
+#define BCM56648_A0_REV_ID 1
+#define BCM56648_A1_REV_ID 2
+#define BCM56648_B0_REV_ID 0x11
+#define BCM56649_DEVICE_ID 0xb649
+#define BCM56649_A0_REV_ID 1
+#define BCM56649_A1_REV_ID 2
+#define BCM56649_B0_REV_ID 0x11
+
+#define BCM56540_DEVICE_ID 0xb540
+#define BCM56540_A0_REV_ID 1
+#define BCM56540_A1_REV_ID 2
+#define BCM56540_B0_REV_ID 0x11
+#define BCM56541_DEVICE_ID 0xb541
+#define BCM56541_A0_REV_ID 1
+#define BCM56541_A1_REV_ID 2
+#define BCM56541_B0_REV_ID 0x11
+#define BCM56542_DEVICE_ID 0xb542
+#define BCM56542_A0_REV_ID 1
+#define BCM56542_A1_REV_ID 2
+#define BCM56542_B0_REV_ID 0x11
+#define BCM56543_DEVICE_ID 0xb543
+#define BCM56543_A0_REV_ID 1
+#define BCM56543_A1_REV_ID 2
+#define BCM56543_B0_REV_ID 0x11
+#define BCM56544_DEVICE_ID 0xb544
+#define BCM56544_A0_REV_ID 1
+#define BCM56544_A1_REV_ID 2
+#define BCM56544_B0_REV_ID 0x11
+
+#define BCM56545_DEVICE_ID 0xb545
+#define BCM56545_A0_REV_ID 1
+#define BCM56545_A1_REV_ID 2
+#define BCM56545_B0_REV_ID 0x11
+#define BCM56546_DEVICE_ID 0xb546
+#define BCM56546_A0_REV_ID 1
+#define BCM56546_A1_REV_ID 2
+#define BCM56546_B0_REV_ID 0x11
+
+#define BCM56044_DEVICE_ID 0xb044
+#define BCM56044_B0_REV_ID 0x11
+#define BCM56045_DEVICE_ID 0xb045
+#define BCM56045_A0_REV_ID 1
+#define BCM56045_A1_REV_ID 2
+#define BCM56045_B0_REV_ID 0x11
+#define BCM56046_DEVICE_ID 0xb046
+#define BCM56046_A0_REV_ID 1
+#define BCM56046_A1_REV_ID 2
+#define BCM56046_B0_REV_ID 0x11
+
+
+#define BCM56440_DEVICE_ID 0xb440
+#define BCM56440_A0_REV_ID 1
+#define BCM56440_B0_REV_ID 0x11
+#define BCM56441_DEVICE_ID 0xb441
+#define BCM56441_A0_REV_ID 1
+#define BCM56441_B0_REV_ID 0x11
+#define BCM56442_DEVICE_ID 0xb442
+#define BCM56442_A0_REV_ID 1
+#define BCM56442_B0_REV_ID 0x11
+#define BCM56443_DEVICE_ID 0xb443
+#define BCM56443_A0_REV_ID 1
+#define BCM56443_B0_REV_ID 0x11
+#define BCM56445_DEVICE_ID 0xb445
+#define BCM56445_A0_REV_ID 1
+#define BCM56445_B0_REV_ID 0x11
+#define BCM56446_DEVICE_ID 0xb446
+#define BCM56446_A0_REV_ID 1
+#define BCM56446_B0_REV_ID 0x11
+#define BCM56447_DEVICE_ID 0xb447
+#define BCM56447_A0_REV_ID 1
+#define BCM56447_B0_REV_ID 0x11
+#define BCM56448_DEVICE_ID 0xb448
+#define BCM56448_A0_REV_ID 1
+#define BCM56448_B0_REV_ID 0x11
+#define BCM56449_DEVICE_ID 0xb449
+#define BCM56449_A0_REV_ID 1
+#define BCM56449_B0_REV_ID 0x11
+#define BCM56240_DEVICE_ID 0xb240
+#define BCM56240_A0_REV_ID 1
+#define BCM56240_B0_REV_ID 0x11
+#define BCM56241_DEVICE_ID 0xb241
+#define BCM56241_A0_REV_ID 1
+#define BCM56241_B0_REV_ID 0x11
+#define BCM56242_DEVICE_ID 0xb242
+#define BCM56242_A0_REV_ID 1
+#define BCM56242_B0_REV_ID 0x11
+#define BCM56243_DEVICE_ID 0xb243
+#define BCM56243_A0_REV_ID 1
+#define BCM56243_B0_REV_ID 0x11
+#define BCM56245_DEVICE_ID 0xb245
+#define BCM56245_A0_REV_ID 1
+#define BCM56245_B0_REV_ID 0x11
+#define BCM56246_DEVICE_ID 0xb246
+#define BCM56246_A0_REV_ID 1
+#define BCM56246_B0_REV_ID 0x11
+#define BCM55440_DEVICE_ID 0xa440
+#define BCM55440_A0_REV_ID 1
+#define BCM55440_B0_REV_ID 0x11
+#define BCM55441_DEVICE_ID 0xa441
+#define BCM55441_A0_REV_ID 1
+#define BCM55441_B0_REV_ID 0x11
+
+#define BCM55450_DEVICE_ID 0xa450
+#define BCM55450_A0_REV_ID 1
+#define BCM55450_B0_REV_ID 0x11
+#define BCM55450_B1_REV_ID 0x12
+
+#define BCM55455_DEVICE_ID 0xa455
+#define BCM55455_A0_REV_ID 1
+#define BCM55455_B0_REV_ID 0x11
+#define BCM55455_B1_REV_ID 0x12
+
+#define BCM56248_DEVICE_ID 0xb248
+#define BCM56248_A0_REV_ID 1
+#define BCM56248_B0_REV_ID 0x11
+#define BCM56248_B1_REV_ID 0x12
+
+#define BCM56450_DEVICE_ID 0xb450
+#define BCM56450_A0_REV_ID 1
+#define BCM56450_B0_REV_ID 0x11
+#define BCM56450_B1_REV_ID 0x12
+
+#define BCM56452_DEVICE_ID 0xb452
+#define BCM56452_A0_REV_ID 1
+#define BCM56452_B0_REV_ID 0x11
+#define BCM56452_B1_REV_ID 0x12
+
+#define BCM56454_DEVICE_ID 0xb454
+#define BCM56454_A0_REV_ID 1
+#define BCM56454_B0_REV_ID 0x11
+#define BCM56454_B1_REV_ID 0x12
+
+#define BCM56455_DEVICE_ID 0xb455
+#define BCM56455_A0_REV_ID 1
+#define BCM56455_B0_REV_ID 0x11
+#define BCM56455_B1_REV_ID 0x12
+
+#define BCM56456_DEVICE_ID 0xb456
+#define BCM56456_A0_REV_ID 1
+#define BCM56456_B0_REV_ID 0x11
+#define BCM56456_B1_REV_ID 0x12
+
+#define BCM56457_DEVICE_ID 0xb457
+#define BCM56457_A0_REV_ID 1
+#define BCM56457_B0_REV_ID 0x11
+#define BCM56457_B1_REV_ID 0x12
+
+#define BCM56458_DEVICE_ID 0xb458
+#define BCM56458_A0_REV_ID 1
+#define BCM56458_B0_REV_ID 0x11
+#define BCM56458_B1_REV_ID 0x12
+
+#define BCM56850_DEVICE_ID 0xb850
+#define BCM56850_A0_REV_ID 1
+#define BCM56850_A1_REV_ID 2
+#define BCM56850_A2_REV_ID 3
+#define BCM56851_DEVICE_ID 0xb851
+#define BCM56851_A0_REV_ID 1
+#define BCM56851_A1_REV_ID 2
+#define BCM56851_A2_REV_ID 3
+#define BCM56852_DEVICE_ID 0xb852
+#define BCM56852_A0_REV_ID 1
+#define BCM56852_A1_REV_ID 2
+#define BCM56852_A2_REV_ID 3
+#define BCM56853_DEVICE_ID 0xb853
+#define BCM56853_A0_REV_ID 1
+#define BCM56853_A1_REV_ID 2
+#define BCM56853_A2_REV_ID 3
+#define BCM56854_DEVICE_ID 0xb854
+#define BCM56854_A0_REV_ID 1
+#define BCM56854_A1_REV_ID 2
+#define BCM56854_A2_REV_ID 3
+#define BCM56855_DEVICE_ID 0xb855
+#define BCM56855_A0_REV_ID 1
+#define BCM56855_A1_REV_ID 2
+#define BCM56855_A2_REV_ID 3
+#define BCM56834_DEVICE_ID 0xb834
+#define BCM56834_A0_REV_ID 1
+#define BCM56834_A1_REV_ID 2
+#define BCM56834_A2_REV_ID 3
+
+#define BCM56860_DEVICE_ID 0xb860
+#define BCM56860_A0_REV_ID 1
+#define BCM56860_A1_REV_ID 2
+#define BCM56861_DEVICE_ID 0xb861
+#define BCM56861_A0_REV_ID 1
+#define BCM56861_A1_REV_ID 2
+#define BCM56862_DEVICE_ID 0xb862
+#define BCM56862_A0_REV_ID 1
+#define BCM56862_A1_REV_ID 2
+#define BCM56864_DEVICE_ID 0xb864
+#define BCM56864_A0_REV_ID 1
+#define BCM56864_A1_REV_ID 2
+#define BCM56865_DEVICE_ID 0xb865
+#define BCM56865_A0_REV_ID 1
+#define BCM56865_A1_REV_ID 2
+#define BCM56866_DEVICE_ID 0xb866
+#define BCM56866_A0_REV_ID 1
+#define BCM56866_A1_REV_ID 2
+#define BCM56867_DEVICE_ID 0xb867
+#define BCM56867_A0_REV_ID 1
+#define BCM56867_A1_REV_ID 2
+#define BCM56868_DEVICE_ID 0xb868
+#define BCM56868_A0_REV_ID 1
+#define BCM56868_A1_REV_ID 2
+#define BCM56832_DEVICE_ID 0xb832
+#define BCM56832_A0_REV_ID 1
+#define BCM56832_A1_REV_ID 2
+#define BCM56833_DEVICE_ID 0xb833
+#define BCM56833_A0_REV_ID 1
+#define BCM56833_A1_REV_ID 2
+#define BCM56836_DEVICE_ID 0xb836
+#define BCM56836_A0_REV_ID 1
+#define BCM56836_A1_REV_ID 2
+
+
+#define BCM56750_DEVICE_ID 0xb750
+#define BCM56750_A0_REV_ID 1
+#define BCM56750_A1_REV_ID 2
+#define BCM56750_A2_REV_ID 3
+
+#define BCM56830_DEVICE_ID 0xb830
+#define BCM56830_A0_REV_ID 1
+#define BCM56830_A1_REV_ID 2
+#define BCM56830_A2_REV_ID 3
+
+#define BCM56150_DEVICE_ID 0xb150
+#define BCM56150_A0_REV_ID 1
+#define BCM56151_DEVICE_ID 0xb151
+#define BCM56151_A0_REV_ID 1
+#define BCM56152_DEVICE_ID 0xb152
+#define BCM56152_A0_REV_ID 1
+
+#define BCM53342_DEVICE_ID 0x8342
+#define BCM53342_A0_REV_ID 1
+#define BCM53343_DEVICE_ID 0x8343
+#define BCM53343_A0_REV_ID 1
+#define BCM53344_DEVICE_ID 0x8344
+#define BCM53344_A0_REV_ID 1
+#define BCM53346_DEVICE_ID 0x8346
+#define BCM53346_A0_REV_ID 1
+#define BCM53347_DEVICE_ID 0x8347
+#define BCM53347_A0_REV_ID 1
+
+#define BCM53333_DEVICE_ID 0x8333
+#define BCM53333_A0_REV_ID 1
+#define BCM53334_DEVICE_ID 0x8334
+#define BCM53334_A0_REV_ID 1
+
+#define BCM53393_DEVICE_ID 0x8393
+#define BCM53393_A0_REV_ID 1
+#define BCM53394_DEVICE_ID 0x8394
+#define BCM53394_A0_REV_ID 1
+
+#define BCM53400_DEVICE_ID 0x8400
+#define BCM53400_A0_REV_ID 1
+#define BCM56060_DEVICE_ID 0xb060
+#define BCM56060_A0_REV_ID 1
+#define BCM56062_DEVICE_ID 0xb062
+#define BCM56062_A0_REV_ID 1
+#define BCM56063_DEVICE_ID 0xb063
+#define BCM56063_A0_REV_ID 1
+#define BCM56064_DEVICE_ID 0xb064
+#define BCM56064_A0_REV_ID 1
+#define BCM56065_DEVICE_ID 0xb065
+#define BCM56065_A0_REV_ID 1
+#define BCM56066_DEVICE_ID 0xb066
+#define BCM56066_A0_REV_ID 1
+#define BCM53401_DEVICE_ID 0x8401
+#define BCM53411_DEVICE_ID 0x8411
+#define BCM53401_A0_REV_ID 1
+#define BCM53402_DEVICE_ID 0x8402
+#define BCM53412_DEVICE_ID 0x8412
+#define BCM53402_A0_REV_ID 1
+#define BCM53403_DEVICE_ID 0x8403
+#define BCM53413_DEVICE_ID 0x8413
+#define BCM53403_A0_REV_ID 1
+#define BCM53404_DEVICE_ID 0x8404
+#define BCM53414_DEVICE_ID 0x8414
+#define BCM53404_A0_REV_ID 1
+#define BCM53405_DEVICE_ID 0x8405
+#define BCM53415_DEVICE_ID 0x8415
+#define BCM53405_A0_REV_ID 1
+#define BCM53406_DEVICE_ID 0x8406
+#define BCM53416_DEVICE_ID 0x8416
+#define BCM53406_A0_REV_ID 1
+#define BCM53408_DEVICE_ID 0x8408
+#define BCM53418_DEVICE_ID 0x8418
+#define BCM53408_A0_REV_ID 1
+#define BCM53365_DEVICE_ID 0x8365
+#define BCM53365_A0_REV_ID 1
+#define BCM53369_DEVICE_ID 0x8369
+#define BCM53369_A0_REV_ID 1
+
+#define BCM53454_DEVICE_ID 0x8454
+#define BCM53455_DEVICE_ID 0x8455
+#define BCM53454_A0_REV_ID 1
+#define BCM53456_DEVICE_ID 0x8456
+#define BCM53457_DEVICE_ID 0x8457
+#define BCM53456_A0_REV_ID 1
+
+#define BCM53422_DEVICE_ID 0x8422
+#define BCM53422_A0_REV_ID 1
+#define BCM53424_DEVICE_ID 0x8424
+#define BCM53424_A0_REV_ID 1
+#define BCM53426_DEVICE_ID 0x8426
+#define BCM53426_A0_REV_ID 1
+
+#define BCM56960_DEVICE_ID 0xb960
+#define BCM56960_A0_REV_ID 1
+#define BCM56960_B0_REV_ID 0x11
+#define BCM56960_B1_REV_ID 0x12
+#define BCM56961_DEVICE_ID 0xb961
+#define BCM56961_A0_REV_ID 1
+#define BCM56961_B0_REV_ID 0x11
+#define BCM56961_B1_REV_ID 0x12
+#define BCM56962_DEVICE_ID 0xb962
+#define BCM56962_A0_REV_ID 1
+#define BCM56962_B0_REV_ID 0x11
+#define BCM56962_B1_REV_ID 0x12
+#define BCM56963_DEVICE_ID 0xb963
+#define BCM56963_A0_REV_ID 1
+#define BCM56963_B0_REV_ID 0x11
+#define BCM56963_B1_REV_ID 0x12
+#define BCM56930_DEVICE_ID 0xb930
+#define BCM56930_A0_REV_ID 1
+#define BCM56930_B0_REV_ID 0x11
+#define BCM56930_B1_REV_ID 0x12
+#define BCM56930_C0_REV_ID 0x21
+#define BCM56931_DEVICE_ID 0xb931
+#define BCM56931_A0_REV_ID 1
+#define BCM56931_B0_REV_ID 0x11
+#define BCM56931_C0_REV_ID 0x21
+#define BCM56935_DEVICE_ID 0xb935
+#define BCM56935_A0_REV_ID 1
+#define BCM56935_B0_REV_ID 0x11
+#define BCM56935_C0_REV_ID 0x21
+#define BCM56936_DEVICE_ID 0xb936
+#define BCM56936_A0_REV_ID 1
+#define BCM56936_B0_REV_ID 0x11
+#define BCM56936_C0_REV_ID 0x21
+#define BCM56939_DEVICE_ID 0xb939
+#define BCM56939_A0_REV_ID 1
+#define BCM56939_B0_REV_ID 0x11
+#define BCM56939_C0_REV_ID 0x21
+
+#define BCM56168_DEVICE_ID 0xb168
+#define BCM56168_A0_REV_ID 1
+#define BCM56168_B0_REV_ID 0x11
+#define BCM56168_B1_REV_ID 0x12
+#define BCM56169_DEVICE_ID 0xb169
+#define BCM56169_A0_REV_ID 1
+#define BCM56169_B0_REV_ID 0x11
+#define BCM56169_B1_REV_ID 0x12
+
+#define BCM56980_DEVICE_ID_MASK 0xFFF0
+#define BCM56980_DEVICE_ID 0xb980
+#define BCM56980_A0_REV_ID 1
+#define BCM56980_B0_REV_ID 0x11
+#define BCM56981_DEVICE_ID 0xb981
+#define BCM56981_A0_REV_ID 1
+#define BCM56981_B0_REV_ID 0x11
+#define BCM56982_DEVICE_ID 0xb982
+#define BCM56982_A0_REV_ID 1
+#define BCM56982_B0_REV_ID 0x11
+#define BCM56983_DEVICE_ID 0xb983
+#define BCM56983_A0_REV_ID 1
+#define BCM56983_B0_REV_ID 0x11
+#define BCM56984_DEVICE_ID 0xb984
+#define BCM56984_A0_REV_ID 1
+#define BCM56984_B0_REV_ID 0x11
+
+#define BCM56968_DEVICE_ID 0xb968
+#define BCM56968_A0_REV_ID 1
+#define BCM56968_B0_REV_ID 0x11
+#define BCM56968_B1_REV_ID 0x12
+
+#define BCM56160_DEVICE_ID 0xb160
+#define BCM56160_A0_REV_ID 1
+#define BCM56160_B0_REV_ID 0x11
+#define BCM56162_DEVICE_ID 0xb162
+#define BCM56162_A0_REV_ID 1
+#define BCM56162_B0_REV_ID 0x11
+
+#define BCM56163_DEVICE_ID 0xb163
+#define BCM56163_A0_REV_ID 1
+#define BCM56163_B0_REV_ID 0x11
+#define BCM56164_DEVICE_ID 0xb164
+#define BCM56164_A0_REV_ID 1
+#define BCM56164_B0_REV_ID 0x11
+#define BCM56166_DEVICE_ID 0xb166
+#define BCM56166_A0_REV_ID 1
+#define BCM56166_B0_REV_ID 0x11
+
+#define BCM56273_DEVICE_ID 0xb273
+#define BCM56273_A0_REV_ID 1
+#define BCM56273_A1_REV_ID 2
+
+#define BCM56274_DEVICE_ID 0xb274
+#define BCM56274_A0_REV_ID 1
+#define BCM56274_A1_REV_ID 2
+
+#define BCM56275_DEVICE_ID 0xb275
+#define BCM56275_A0_REV_ID 1
+#define BCM56275_A1_REV_ID 2
+
+#define BCM56276_DEVICE_ID 0xb276
+#define BCM56276_A0_REV_ID 1
+#define BCM56276_A1_REV_ID 2
+
+#define BCM56277_DEVICE_ID 0xb277
+#define BCM56277_A0_REV_ID 1
+#define BCM56277_A1_REV_ID 2
+
+#define BCM56278_DEVICE_ID 0xb278
+#define BCM56278_A0_REV_ID 1
+#define BCM56278_A1_REV_ID 2
+
+#define BCM56279_DEVICE_ID 0xb279
+#define BCM56279_A1_REV_ID 2
+
+#define BCM56575_DEVICE_ID 0xb575
+#define BCM56575_A1_REV_ID 2
+
+#define BCM53440_DEVICE_ID 0x8440
+#define BCM53440_A0_REV_ID 1
+#define BCM53440_B0_REV_ID 0x11
+#define BCM53442_DEVICE_ID 0x8442
+#define BCM53442_A0_REV_ID 1
+#define BCM53442_B0_REV_ID 0x11
+#define BCM53443_DEVICE_ID 0x8443
+#define BCM53443_A0_REV_ID 1
+#define BCM53443_B0_REV_ID 0x11
+
+#define BCM53434_DEVICE_ID 0x8434
+#define BCM53434_A0_REV_ID 1
+#define BCM53434_B0_REV_ID 0x11
+
+#define BCM56560_DEVICE_ID 0xb560
+#define BCM56560_A0_REV_ID 1
+#define BCM56560_B0_REV_ID 0x11
+
+#define BCM56561_DEVICE_ID 0xb561
+#define BCM56561_A0_REV_ID 1
+#define BCM56561_B0_REV_ID 0x11
+
+#define BCM56562_DEVICE_ID 0xb562
+#define BCM56562_A0_REV_ID 1
+#define BCM56562_B0_REV_ID 0x11
+
+#define BCM56670_DEVICE_ID 0xb670
+#define BCM56670_A0_REV_ID 1
+#define BCM56670_B0_REV_ID 0x11
+#define BCM56670_C0_REV_ID 0x21
+
+
+#define BCM56671_DEVICE_ID 0xb671
+#define BCM56671_A0_REV_ID 1
+#define BCM56671_B0_REV_ID 0x11
+#define BCM56671_C0_REV_ID 0x21
+
+#define BCM56672_DEVICE_ID 0xb672
+#define BCM56672_A0_REV_ID 1
+#define BCM56672_B0_REV_ID 0x11
+#define BCM56672_C0_REV_ID 0x21
+
+#define BCM56675_DEVICE_ID 0xb675
+#define BCM56675_A0_REV_ID 1
+#define BCM56675_B0_REV_ID 0x11
+#define BCM56675_C0_REV_ID 0x21
+
+
+#define BCM56565_DEVICE_ID 0xb565
+#define BCM56565_A0_REV_ID 1
+#define BCM56565_B0_REV_ID 0x11
+
+#define BCM56566_DEVICE_ID 0xb566
+#define BCM56566_A0_REV_ID 1
+#define BCM56566_B0_REV_ID 0x11
+
+#define BCM56567_DEVICE_ID 0xb567
+#define BCM56567_A0_REV_ID 1
+#define BCM56567_B0_REV_ID 0x11
+
+#define BCM56568_DEVICE_ID 0xb568
+#define BCM56568_A0_REV_ID 1
+#define BCM56568_B0_REV_ID 0x11
+
+#define BCM56760_DEVICE_ID 0xb760
+#define BCM56760_A0_REV_ID 1
+#define BCM56760_A1_REV_ID 2
+#define BCM56760_B0_REV_ID 0x11
+
+
+#define BCM56761_DEVICE_ID 0xb761
+#define BCM56761_A0_REV_ID 1
+#define BCM56761_A1_REV_ID 2
+#define BCM56761_B0_REV_ID 0x11
+#define BCM56761_B1_REV_ID 0x12
+
+#define BCM56762_DEVICE_ID 0xb762
+#define BCM56762_A0_REV_ID 1
+#define BCM56762_B0_REV_ID 0x11
+
+#define BCM56764_DEVICE_ID 0xb764
+#define BCM56764_A0_REV_ID 1
+#define BCM56764_B0_REV_ID 0x11
+
+#define BCM56765_DEVICE_ID 0xb765
+#define BCM56765_A0_REV_ID 1
+#define BCM56765_B0_REV_ID 0x11
+
+#define BCM56766_DEVICE_ID 0xb766
+#define BCM56766_A0_REV_ID 1
+#define BCM56766_B0_REV_ID 0x11
+
+#define BCM56768_DEVICE_ID 0xb768
+#define BCM56768_A0_REV_ID 1
+#define BCM56768_B0_REV_ID 0x11
+
+#define BCM56068_DEVICE_ID 0xb068
+#define BCM56068_A0_REV_ID 1
+#define BCM56068_B0_REV_ID 0x11
+
+#define BCM56068_DEVICE_ID 0xb068
+#define BCM56068_A0_REV_ID 1
+#define BCM56068_B0_REV_ID 0x11
+#define BCM56068_B1_REV_ID 0x12
+
+#define BCM56069_DEVICE_ID 0xb069
+#define BCM56069_A0_REV_ID 1
+#define BCM56069_B0_REV_ID 0x11
+
+#define BCM56170_DEVICE_ID 0xb170
+#define BCM56170_A0_REV_ID 1
+#define BCM56170_B0_REV_ID 0x11
+#define BCM56172_DEVICE_ID 0xb172
+#define BCM56172_A0_REV_ID 1
+#define BCM56172_B0_REV_ID 0x11
+#define BCM56174_DEVICE_ID 0xb174
+#define BCM56174_A0_REV_ID 1
+#define BCM56174_B0_REV_ID 0x11
+
+#define BCM53570_DEVICE_ID 0x8570
+#define BCM53570_A0_REV_ID 1
+#define BCM53570_B0_REV_ID 0x11
+#define BCM53575_DEVICE_ID 0x8575
+#define BCM53575_A0_REV_ID 1
+#define BCM53575_B0_REV_ID 0x11
+
+#define BCM56070_DEVICE_ID 0xb070
+#define BCM56070_A0_REV_ID 1
+#define BCM56071_DEVICE_ID 0xb071
+#define BCM56071_A0_REV_ID 1
+#define BCM56072_DEVICE_ID 0xb072
+#define BCM56072_A0_REV_ID 1
+
+
+#define BCM56965_DEVICE_ID 0xb965
+#define BCM56965_A0_REV_ID 1
+#define BCM56965_A1_REV_ID 2
+#define BCM56969_DEVICE_ID 0xb969
+#define BCM56969_A0_REV_ID 1
+#define BCM56966_DEVICE_ID 0xb966
+#define BCM56966_A0_REV_ID 1
+#define BCM56967_DEVICE_ID 0xb967
+#define BCM56967_A0_REV_ID 1
+
+#define BCM56970_DEVICE_ID 0xb970
+#define BCM56970_A0_REV_ID 1
+#define BCM56970_B0_REV_ID 0x11
+#define BCM56971_DEVICE_ID 0xb971
+#define BCM56971_A0_REV_ID 1
+#define BCM56971_B0_REV_ID 0x11
+#define BCM56972_DEVICE_ID 0xb972
+#define BCM56972_A0_REV_ID 1
+#define BCM56972_B0_REV_ID 0x11
+#define BCM56974_DEVICE_ID 0xb974
+#define BCM56974_A0_REV_ID 1
+#define BCM56974_B0_REV_ID 0x11
+#define BCM56975_DEVICE_ID 0xb975
+#define BCM56975_A0_REV_ID 1
+#define BCM56975_B0_REV_ID 0x11
+
+#define BCM56870_DEVICE_ID 0xb870
+#define BCM56870_A0_REV_ID 1
+#define BCM56873_DEVICE_ID 0xb873
+#define BCM56873_A0_REV_ID 1
+
+#define BCM56370_DEVICE_ID 0xb370
+#define BCM56370_A0_REV_ID 1
+#define BCM56370_A1_REV_ID 0x02
+#define BCM56370_A2_REV_ID 0x03
+
+#define BCM56371_DEVICE_ID 0xb371
+#define BCM56371_A0_REV_ID 1
+#define BCM56371_A1_REV_ID 0x02
+#define BCM56371_A2_REV_ID 0x03
+
+#define BCM56372_DEVICE_ID 0xb372
+#define BCM56372_A0_REV_ID 1
+#define BCM56372_A1_REV_ID 0x02
+#define BCM56372_A2_REV_ID 0x03
+
+#define BCM56374_DEVICE_ID 0xb374
+#define BCM56374_A0_REV_ID 1
+#define BCM56374_A1_REV_ID 0x02
+#define BCM56374_A2_REV_ID 0x03
+
+#define BCM56375_DEVICE_ID 0xb375
+#define BCM56375_A0_REV_ID 1
+#define BCM56375_A1_REV_ID 0x02
+#define BCM56375_A2_REV_ID 0x03
+
+#define BCM56376_DEVICE_ID 0xb376
+#define BCM56376_A0_REV_ID 1
+#define BCM56376_A1_REV_ID 0x02
+#define BCM56376_A2_REV_ID 0x03
+
+#define BCM56377_DEVICE_ID 0xb377
+#define BCM56377_A0_REV_ID 1
+#define BCM56377_A1_REV_ID 0x02
+#define BCM56377_A2_REV_ID 0x03
+
+#define BCM56577_DEVICE_ID 0xb577
+#define BCM56577_A0_REV_ID 1
+#define BCM56577_A1_REV_ID 0x02
+#define BCM56577_A2_REV_ID 0x03
+
+#define BCM56578_DEVICE_ID 0xb578
+#define BCM56578_A0_REV_ID 1
+#define BCM56578_A1_REV_ID 0x02
+#define BCM56578_A2_REV_ID 0x03
+
+#define BCM56579_DEVICE_ID 0xb579
+#define BCM56579_A0_REV_ID 1
+#define BCM56579_A1_REV_ID 0x02
+#define BCM56579_A2_REV_ID 0x03
+
+#define BCM56770_DEVICE_ID 0xb770
+#define BCM56770_A0_REV_ID 1
+
+#define BCM56771_DEVICE_ID 0xb771
+#define BCM56771_A0_REV_ID 1
+
+#define BCM56470_DEVICE_ID 0xb470
+#define BCM56470_A0_REV_ID 1
+#define BCM56471_DEVICE_ID 0xb471
+#define BCM56471_A0_REV_ID 1
+#define BCM56472_DEVICE_ID 0xb472
+#define BCM56472_A0_REV_ID 1
+#define BCM56475_DEVICE_ID 0xb475
+#define BCM56475_A0_REV_ID 1
+
+
+#define BCM53540_DEVICE_ID 0x8540
+#define BCM53540_A0_REV_ID 1
+#define BCM53547_DEVICE_ID 0x8547
+#define BCM53547_A0_REV_ID 1
+#define BCM53548_DEVICE_ID 0x8548
+#define BCM53548_A0_REV_ID 1
+#define BCM53549_DEVICE_ID 0x8549
+#define BCM53549_A0_REV_ID 1
+
+#define BCM5665_DEVICE_ID 0x5665
+#define BCM5665_A0_REV_ID 1
+#define BCM5665_B0_REV_ID 0x11
+
+
+#define BCM5655_DEVICE_ID 0x5655
+#define BCM5655_A0_REV_ID 1
+#define BCM5655_B0_REV_ID 0x11
+
+
+#define BCM5650_DEVICE_ID 0x5650
+#define BCM5650_A0_REV_ID 1
+#define BCM5650_B0_REV_ID 0x11
+#define BCM5650_C0_REV_ID 0x21
+
+#define BROADCOM_PHYID_HIGH 0x0040
+
+#define GEDI_DEVICE_ID 0xa100
+#define GEDI_REV_ID 0x0001
+#define ARAD_DEVICE_ID 0x8650
+#define ARAD_A0_REV_ID 0x0000
+#define ARAD_B0_REV_ID 0x0011
+#define ARAD_B1_REV_ID 0x0012
+#define BCM88650_DEVICE_ID ARAD_DEVICE_ID
+#define BCM88650_A0_REV_ID ARAD_A0_REV_ID
+#define BCM88650_B0_REV_ID ARAD_B0_REV_ID
+#define BCM88650_B1_REV_ID ARAD_B1_REV_ID
+#define BCM88750_DEVICE_ID 0x8750
+#define BCM88750_A0_REV_ID 0x0000
+#define BCM88750_B0_REV_ID 0x0011
+#define BCM88753_DEVICE_ID 0x8753
+#define BCM88753_A0_REV_ID 0x0000
+#define BCM88753_B0_REV_ID 0x0011
+#define BCM88754_DEVICE_ID 0x8754
+#define BCM88754_A0_REV_ID 0x0000
+#define BCM88754_ORIGINAL_VENDOR_ID 0x16FC
+#define BCM88754_ORIGINAL_DEVICE_ID 0x020F
+#define BCM88754_A0_ORIGINAL_REV_ID 0x0001
+#define BCM88755_DEVICE_ID 0x8755
+#define BCM88755_B0_REV_ID 0x0011
+#define BCM88770_DEVICE_ID 0x8770
+#define BCM88770_A1_REV_ID 0x0002
+#define BCM88773_DEVICE_ID 0x8773
+#define BCM88773_A1_REV_ID 0x0002
+#define BCM88774_DEVICE_ID 0x8774
+#define BCM88774_A1_REV_ID 0x0002
+#define BCM88775_DEVICE_ID 0x8775
+#define BCM88775_A1_REV_ID 0x0002
+#define BCM88776_DEVICE_ID 0x8776
+#define BCM88776_A1_REV_ID 0x0002
+#define BCM88777_DEVICE_ID 0x8777
+#define BCM88777_A1_REV_ID 0x0002
+#define BCM88950_DEVICE_ID 0x8950
+#define BCM88950_A0_REV_ID 0x0001
+#define BCM88950_A1_REV_ID 0x0002
+#define BCM88953_DEVICE_ID 0x8953
+#define BCM88953_A1_REV_ID 0x0002
+#define BCM88954_DEVICE_ID 0x8954
+#define BCM88954_A1_REV_ID 0x0002
+#define BCM88955_DEVICE_ID 0x8955
+#define BCM88955_A1_REV_ID 0x0002
+#define BCM88956_DEVICE_ID 0x8956
+#define BCM88956_A1_REV_ID 0x0002
+#define DNXC_A0_REV_ID 0x0001
+#define DNXC_A1_REV_ID 0x0002
+#define DNXC_B0_REV_ID 0x0011
+#define DNXC_B1_REV_ID 0x0012
+#define DNXC_DEVID_FAMILY_MASK 0xfff0
+#define BCM88790_DEVICE_ID 0x8790
+#define BCM88790_A0_REV_ID DNXC_A0_REV_ID
+#define BCM88790_B0_REV_ID DNXC_B0_REV_ID
+#define BCM88791_DEVICE_ID 0x8791
+#define BCM88792_DEVICE_ID 0x8792
+#define BCM88793_DEVICE_ID 0x8793
+#define BCM88794_DEVICE_ID 0x8794
+#define BCM88795_DEVICE_ID 0x8795
+#define BCM88796_DEVICE_ID 0x8796
+#define BCM88797_DEVICE_ID 0x8797
+#define BCM88798_DEVICE_ID 0x8798
+#define BCM88799_DEVICE_ID 0x8799
+#define BCM8879A_DEVICE_ID 0x879A
+#define BCM8879B_DEVICE_ID 0x879B
+#define BCM8879C_DEVICE_ID 0x879C
+#define BCM8879D_DEVICE_ID 0x879D
+#define BCM8879E_DEVICE_ID 0x879E
+#define BCM8879F_DEVICE_ID 0x879F
+#define ARADPLUS_DEVICE_ID 0x8660
+#define ARADPLUS_A0_REV_ID 0x0001
+#define BCM88660_DEVICE_ID ARADPLUS_DEVICE_ID
+#define BCM88660_A0_REV_ID ARADPLUS_A0_REV_ID
+#define JERICHO_DEVICE_ID 0x8675
+#define JERICHO_A0_REV_ID 0x0001
+#define JERICHO_B0_REV_ID 0x0011
+#define JERICHO_A1_REV_ID 0x0002
+#define BCM88670_DEVICE_ID 0x8670
+#define BCM88670_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88670_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88671_DEVICE_ID 0x8671
+#define BCM88671_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88671_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88671M_DEVICE_ID 0x867A
+#define BCM88671M_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88671M_A1_REV_ID JERICHO_A1_REV_ID
+
+#define BCM88670_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88671_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88671M_B0_REV_ID JERICHO_B0_REV_ID
+
+#define BCM88672_DEVICE_ID 0x8672
+#define BCM88672_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88672_A1_REV_ID JERICHO_A1_REV_ID
+
+#define BCM88672_B0_REV_ID JERICHO_B0_REV_ID
+
+#define BCM88673_DEVICE_ID 0x8673
+#define BCM88673_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88673_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88674_DEVICE_ID 0x8674
+#define BCM88674_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88674_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88675_DEVICE_ID JERICHO_DEVICE_ID
+#define BCM88675_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88675_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88675M_DEVICE_ID 0x867B
+#define BCM88675M_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88675M_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88676_DEVICE_ID 0x8676
+#define BCM88676_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88676_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88676M_DEVICE_ID 0x867C
+#define BCM88676M_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88676M_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88677_DEVICE_ID 0x8677
+#define BCM88677_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88677_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88678_DEVICE_ID 0x8678
+#define BCM88678_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88678_A1_REV_ID JERICHO_A1_REV_ID
+#define BCM88679_DEVICE_ID 0x8679
+#define BCM88679_A0_REV_ID JERICHO_A0_REV_ID
+#define BCM88679_A1_REV_ID JERICHO_A1_REV_ID
+
+#define BCM88673_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88674_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88675_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88675M_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88676_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88676M_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88677_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88678_B0_REV_ID JERICHO_B0_REV_ID
+#define BCM88679_B0_REV_ID JERICHO_B0_REV_ID
+#define QMX_DEVICE_ID 0x8375
+#define QMX_A0_REV_ID 0x0001
+#define QMX_B0_REV_ID 0x0011
+#define QMX_A1_REV_ID 0x0002
+#define BCM88370_DEVICE_ID 0x8370
+#define BCM88370_A0_REV_ID QMX_A0_REV_ID
+#define BCM88370_A1_REV_ID QMX_A1_REV_ID
+#define BCM88371_DEVICE_ID 0x8371
+#define BCM88371_A0_REV_ID QMX_A0_REV_ID
+#define BCM88371_A1_REV_ID QMX_A1_REV_ID
+#define BCM88371M_DEVICE_ID 0x837A
+#define BCM88371M_A0_REV_ID QMX_A0_REV_ID
+#define BCM88371M_A1_REV_ID QMX_A1_REV_ID
+#define BCM88375_DEVICE_ID QMX_DEVICE_ID
+#define BCM88375_A0_REV_ID QMX_A0_REV_ID
+#define BCM88375_A1_REV_ID QMX_A1_REV_ID
+#define BCM88376_DEVICE_ID 0x8376
+#define BCM88376_A0_REV_ID QMX_A0_REV_ID
+#define BCM88376_A1_REV_ID QMX_A1_REV_ID
+#define BCM88376M_DEVICE_ID 0x837B
+#define BCM88376M_A0_REV_ID QMX_A0_REV_ID
+#define BCM88376M_A1_REV_ID QMX_A1_REV_ID
+#define BCM88377_DEVICE_ID 0x8377
+#define BCM88377_A0_REV_ID QMX_A0_REV_ID
+#define BCM88377_A1_REV_ID QMX_A1_REV_ID
+#define BCM88378_DEVICE_ID 0x8378
+#define BCM88378_A0_REV_ID QMX_A0_REV_ID
+#define BCM88378_A1_REV_ID QMX_A1_REV_ID
+#define BCM88379_DEVICE_ID 0x8379
+#define BCM88379_A0_REV_ID QMX_A0_REV_ID
+#define BCM88379_A1_REV_ID QMX_A1_REV_ID
+
+#define BCM88370_B0_REV_ID QMX_B0_REV_ID
+#define BCM88371_B0_REV_ID QMX_B0_REV_ID
+#define BCM88371M_B0_REV_ID QMX_B0_REV_ID
+#define BCM88375_B0_REV_ID QMX_B0_REV_ID
+#define BCM88376_B0_REV_ID QMX_B0_REV_ID
+#define BCM88376M_B0_REV_ID QMX_B0_REV_ID
+#define BCM88377_B0_REV_ID QMX_B0_REV_ID
+#define BCM88378_B0_REV_ID QMX_B0_REV_ID
+#define BCM88379_B0_REV_ID QMX_B0_REV_ID
+
+
+#define JERICHO_PLUS_DEVICE_ID 0x8680
+#define JERICHO_PLUS_A0_REV_ID 0x0001
+#define BCM88680_DEVICE_ID JERICHO_PLUS_DEVICE_ID
+#define BCM88680_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+#define BCM88680_A1_REV_ID 0x0002
+
+
+#define BCM88681_DEVICE_ID 0x8681
+#define BCM88681_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+
+#define BCM88682_DEVICE_ID 0x8682
+#define BCM88682_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+
+#define BCM88683_DEVICE_ID 0x8683
+#define BCM88683_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+
+#define BCM88684_DEVICE_ID 0x8684
+#define BCM88684_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+
+#define BCM88685_DEVICE_ID 0x8685
+#define BCM88685_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+
+#define BCM88687_DEVICE_ID 0x8687
+#define BCM88687_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+
+#define BCM88380_DEVICE_ID 0x8380
+#define BCM88380_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+#define BCM88381_DEVICE_ID 0x8381
+#define BCM88381_A0_REV_ID JERICHO_PLUS_A0_REV_ID
+
+#define JERICHO2_DEVICE_ID 0x8690
+#define JERICHO2_A0_REV_ID DNXC_A0_REV_ID
+#define JERICHO2_B0_REV_ID DNXC_B0_REV_ID
+#define JERICHO2_B1_REV_ID DNXC_B1_REV_ID
+#define BCM88690_DEVICE_ID JERICHO2_DEVICE_ID
+#define BCM88690_A0_REV_ID JERICHO2_A0_REV_ID
+#define BCM88690_B0_REV_ID JERICHO2_B0_REV_ID
+#define BCM88690_B1_REV_ID JERICHO2_B1_REV_ID
+#define BCM88691_DEVICE_ID 0x8691
+#define BCM88692_DEVICE_ID 0x8692
+#define BCM88693_DEVICE_ID 0x8693
+#define BCM88694_DEVICE_ID 0x8694
+#define BCM88695_DEVICE_ID 0x8695
+#define BCM88696_DEVICE_ID 0x8696
+#define BCM88697_DEVICE_ID 0x8697
+#define BCM88698_DEVICE_ID 0x8698
+#define BCM88699_DEVICE_ID 0x8699
+#define BCM8869A_DEVICE_ID 0x869A
+#define BCM8869B_DEVICE_ID 0x869B
+#define BCM8869C_DEVICE_ID 0x869C
+#define BCM8869D_DEVICE_ID 0x869D
+#define BCM8869E_DEVICE_ID 0x869E
+#define BCM8869F_DEVICE_ID 0x869F
+
+#define J2C_DEVICE_ID 0x8800
+#define J2C_2ND_DEVICE_ID 0x8820
+#define J2C_DEVID_FAMILY_MASK 0xffd0
+#define J2C_A0_REV_ID DNXC_A0_REV_ID
+#define J2C_A1_REV_ID DNXC_A1_REV_ID
+#define BCM88800_DEVICE_ID J2C_DEVICE_ID
+#define BCM88820_DEVICE_ID J2C_2ND_DEVICE_ID
+#define BCM88800_A0_REV_ID J2C_A0_REV_ID
+#define BCM88800_A1_REV_ID J2C_A1_REV_ID
+#define BCM88821_DEVICE_ID 0x8821
+#define BCM88826_DEVICE_ID 0x8826
+#define BCM88802_DEVICE_ID 0x8802
+#define BCM88803_DEVICE_ID 0x8803
+#define BCM88804_DEVICE_ID 0x8804
+#define BCM88805_DEVICE_ID 0x8805
+#define BCM88806_DEVICE_ID 0x8806
+#define BCM88822_DEVICE_ID 0x8822
+#define BCM88823_DEVICE_ID 0x8823
+#define BCM88824_DEVICE_ID 0x8824
+#define BCM88825_DEVICE_ID 0x8825
+
+#define J2P_DEVICE_ID 0x8850
+#define J2P_A0_REV_ID DNXC_A0_REV_ID
+#define BCM88850_DEVICE_ID J2P_DEVICE_ID
+#define BCM88850_A0_REV_ID J2P_A0_REV_ID
+
+#define Q2A_DEVICE_ID 0x8480
+#define Q2A_A0_REV_ID DNXC_A0_REV_ID
+#define Q2A_B0_REV_ID DNXC_B0_REV_ID
+#define Q2A_B1_REV_ID DNXC_B1_REV_ID
+#define BCM88480_DEVICE_ID Q2A_DEVICE_ID
+#define BCM88480_A0_REV_ID Q2A_A0_REV_ID
+#define BCM88480_B0_REV_ID Q2A_B0_REV_ID
+#define BCM88480_B1_REV_ID Q2A_B1_REV_ID
+#define BCM88481_DEVICE_ID 0x8481
+#define BCM88482_DEVICE_ID 0x8482
+#define BCM88483_DEVICE_ID 0x8483
+#define BCM88484_DEVICE_ID 0x8484
+#define BCM88485_DEVICE_ID 0x8485
+#define BCM88486_DEVICE_ID 0x8486
+#define BCM88487_DEVICE_ID 0x8487
+#define BCM88488_DEVICE_ID 0x8488
+#define BCM88489_DEVICE_ID 0x8489
+#define BCM8848A_DEVICE_ID 0x848A
+#define BCM8848B_DEVICE_ID 0x848B
+#define BCM8848C_DEVICE_ID 0x848C
+#define BCM8848D_DEVICE_ID 0x848D
+#define BCM8848E_DEVICE_ID 0x848E
+#define BCM8848F_DEVICE_ID 0x848F
+
+#define Q2U_DEVICE_ID 0x8280
+#define BCM88280_DEVICE_ID Q2U_DEVICE_ID
+#define BCM88281_DEVICE_ID 0x8281
+#define BCM88282_DEVICE_ID 0x8282
+#define BCM88283_DEVICE_ID 0x8283
+#define BCM88284_DEVICE_ID 0x8284
+#define BCM88285_DEVICE_ID 0x8285
+#define BCM88286_DEVICE_ID 0x8286
+#define BCM88287_DEVICE_ID 0x8287
+#define BCM88288_DEVICE_ID 0x8288
+#define BCM88289_DEVICE_ID 0x8289
+#define BCM8828A_DEVICE_ID 0x828A
+#define BCM8828B_DEVICE_ID 0x828B
+#define BCM8828C_DEVICE_ID 0x828C
+#define BCM8828D_DEVICE_ID 0x828D
+#define BCM8828E_DEVICE_ID 0x828E
+#define BCM8828F_DEVICE_ID 0x828F
+
+#define QAX_DEVICE_ID 0x8470
+#define QAX_A0_REV_ID 0x0001
+#define QAX_B0_REV_ID 0x0011
+#define BCM88470_DEVICE_ID QAX_DEVICE_ID
+#define BCM88470_B0_REV_ID QAX_B0_REV_ID
+#define BCM88470P_DEVICE_ID 0x847C
+#define BCM88471_DEVICE_ID 0x8471
+#define BCM88473_DEVICE_ID 0x8473
+#define BCM88474_DEVICE_ID 0x8474
+#define BCM88474H_DEVICE_ID 0x847B
+#define BCM88476_DEVICE_ID 0x8476
+#define BCM88477_DEVICE_ID 0x8477
+
+
+
+
+#define BCM88470_A0_REV_ID QAX_A0_REV_ID
+
+#define QUX_DEVICE_ID 0x8270
+#define QUX_A0_REV_ID 0x0001
+#define QUX_A1_REV_ID 0x0002
+#define QUX_B0_REV_ID 0x0011
+#define BCM88270_DEVICE_ID QUX_DEVICE_ID
+#define BCM88270_A0_REV_ID QUX_A0_REV_ID
+#define BCM88270_A1_REV_ID QUX_A1_REV_ID
+#define BCM88271_DEVICE_ID 0x8271
+#define BCM88272_DEVICE_ID 0x8272
+#define BCM88273_DEVICE_ID 0x8273
+#define BCM88274_DEVICE_ID 0x8274
+#define BCM88276_DEVICE_ID 0x8276
+#define BCM88278_DEVICE_ID 0x8278
+#define BCM88279_DEVICE_ID 0x8279
+
+#define FLAIR_DEVICE_ID 0xF000
+#define FLAIR_A0_REV_ID 0x0001
+#define BCM8206_DEVICE_ID FLAIR_DEVICE_ID
+#define BCM8206_A0_REV_ID FLAIR_A0_REV_ID
+
+#define ARDON_DEVICE_ID 0x8202
+#define ARDON_A0_REV_ID 0x0000
+#define BCM88202_DEVICE_ID ARDON_DEVICE_ID
+#define BCM88202_A0_REV_ID ARDON_A0_REV_ID
+#define ARDON_A1_REV_ID 0x0001
+#define BCM88202_A1_REV_ID ARDON_A1_REV_ID
+#define ARDON_A2_REV_ID 0x0002
+#define BCM88202_A2_REV_ID ARDON_A2_REV_ID
+#define BCM2801PM_DEVICE_ID 0x2801
+#define BCM2801PM_A0_REV_ID 0x0000
+#define BCM88360_DEVICE_ID 0x8360
+#define BCM88360_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88361_DEVICE_ID 0x8361
+#define BCM88361_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88363_DEVICE_ID 0x8363
+#define BCM88363_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88460_DEVICE_ID 0x8460
+#define BCM88460_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88461_DEVICE_ID 0x8461
+#define BCM88461_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88560_DEVICE_ID 0x8560
+#define BCM88560_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88561_DEVICE_ID 0x8561
+#define BCM88561_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88562_DEVICE_ID 0x8562
+#define BCM88562_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88661_DEVICE_ID 0x8661
+#define BCM88661_A0_REV_ID ARADPLUS_A0_REV_ID
+#define BCM88664_DEVICE_ID 0x8664
+#define BCM88664_A0_REV_ID ARADPLUS_A0_REV_ID
+
+
+#define BCM88350_DEVICE_ID 0x8350
+#define BCM88350_B1_REV_ID ARAD_B1_REV_ID
+#define BCM88351_DEVICE_ID 0x8351
+#define BCM88351_B1_REV_ID ARAD_B1_REV_ID
+#define BCM88450_DEVICE_ID 0x8450
+#define BCM88450_B1_REV_ID ARAD_B1_REV_ID
+#define BCM88451_DEVICE_ID 0x8451
+#define BCM88451_B1_REV_ID ARAD_B1_REV_ID
+#define BCM88550_DEVICE_ID 0x8550
+#define BCM88550_B1_REV_ID ARAD_B0_REV_ID
+#define BCM88551_DEVICE_ID 0x8551
+#define BCM88551_B1_REV_ID ARAD_B1_REV_ID
+#define BCM88552_DEVICE_ID 0x8552
+#define BCM88552_B1_REV_ID ARAD_B1_REV_ID
+#define BCM88651_DEVICE_ID 0x8651
+#define BCM88651_B1_REV_ID ARAD_B1_REV_ID
+#define BCM88654_DEVICE_ID 0x8654
+#define BCM88654_B1_REV_ID ARAD_B1_REV_ID
+
+#define BCM88772_DEVICE_ID 0x8772
+#define BCM88952_DEVICE_ID 0x8952
+#define BCM88772_A1_REV_ID 0x0002
+#define BCM88952_A0_REV_ID 0x0001
+#define BCM88952_A1_REV_ID 0x0002
+
+#define BCM88752_DEVICE_ID 0x8752
+#define BCM88752_A0_REV_ID 0x0000
+#define BCM88752_B0_REV_ID 0x0011
+
+
+#define BCM83207_DEVICE_ID 0x3207
+#define BCM83208_DEVICE_ID 0x3208
+#define BCM83207_A0_REV_ID 0x0001
+#define BCM83208_A0_REV_ID 1
+
+#define PCP_PCI_VENDOR_ID 0x1172
+#define PCP_PCI_DEVICE_ID 0x4
+
+#define ACP_PCI_VENDOR_ID 0x10ee
+#define ACP_PCI_DEVICE_ID 0x7011
+#define ACP_PCI_REV_ID 0x0001
+
+#define PLX9056_DEVICE_ID 0x9056
+
+#ifdef BCM_LTSW_SUPPORT
+#define BCM56880_DEVICE_ID 0xb880
+#define BCM56880_A0_REV_ID 0x0001
+#define BCM56880_B0_REV_ID 0x0011
+#define BCM56881_DEVICE_ID 0xb881
+#define BCM56881_A0_REV_ID 0x0001
+#define BCM56881_B0_REV_ID 0x0011
+#define BCM56883_DEVICE_ID 0xb883
+#define BCM56883_A0_REV_ID 0x0001
+#define BCM56883_B0_REV_ID 0x0011
+
+#define BCM56780_DEVICE_ID 0xb780
+#define BCM56780_A0_REV_ID 0x0001
+#define BCM56782_DEVICE_ID 0xb782
+#define BCM56782_A0_REV_ID 0x0001
+#define BCM56784_DEVICE_ID 0xb784
+#define BCM56784_A0_REV_ID 0x0001
+#define BCM56786_DEVICE_ID 0xb786
+#define BCM56786_A0_REV_ID 0x0001
+#define BCM56788_DEVICE_ID 0xb788
+#define BCM56788_A0_REV_ID 0x0001
+
+#define BCM56990_DEVICE_ID 0xb990
+#define BCM56990_A0_REV_ID 0x0001
+#define BCM56990_B0_REV_ID 0x0011
+#define BCM56991_DEVICE_ID 0xb991
+#define BCM56991_A0_REV_ID 0x0001
+#define BCM56991_B0_REV_ID 0x0011
+
+#define BCM56996_DEVICE_ID 0xb996
+#define BCM56996_A0_REV_ID 0x0001
+#define BCM56997_DEVICE_ID 0xb997
+#define BCM56997_A0_REV_ID 0x0001
+#endif
+#endif
+
diff --git a/sdk-6.5.20/src/gpl-modules/make/Make.config b/sdk-6.5.20/src/gpl-modules/make/Make.config
@@ -0,0 +1,358 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Make.config,v 1.3 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+
+ifneq ($(strip $(override-target)),)
+override TARGET=$(override-target)
+endif
+
+export TARGET
+
+#
+# Set up the target name, and the target base variables.
+#
+# target = The full name of the target such as vxworks-bmw
+# targetbase = 1st part of target (e.g. vxworks)
+# targetplat = 2nd part of target (e.g. x86) if any; otherwise same as 1st
+#
+target = ${TARGET}
+targetsplt = $(subst -, , ${target}) # change hyphens to spaces
+targetbase = $(word 1,${targetsplt})
+targetplat = $(subst ${targetbase}-,,${TARGET})
+
+#
+# Common configuration for all platforms
+# (Additional platform-dependent configurations are in Makefile.xxx)
+#
+
+#
+# THIS FILE SHOULD NOT BE MODIFIED LOCALLY, to override, add a file
+# $SDK/make/Make.local that sets your local settings, and/or provide
+# a path to your settings using the MAKE_LOCAL variable. If
+# either of these files exists, their values will override those in this makefile.
+#
+ifdef MAKE_LOCAL
+-include ${MAKE_LOCAL}
+endif
+
+-include ${SDK}/make/Make.local
+
+ifdef ALL_CHIPS
+ ESW_CHIPS = 1
+endif # ALL_CHIPS
+
+#
+# By default, turn off the "changing directory" message.
+#
+MAKEFLAGS += --no-print-directory
+
+#
+# Use gmake by default
+#
+
+include ${SDK}/make/Make.tools
+include ${SDK}/make/Makefile.${target}
+
+# use QUIET=1 to control printing of compilation lines
+ifdef QUIET
+Q:=@
+else
+Q:=
+endif
+
+#
+# Suffix to add to the "target" files to allow local builds with different
+# flags. Set "target_suffix" to XXX to cause the build to put built objects
+# in ${target}${target_suffix}. This allows things like building a debug
+# version with different flags. This may also be set in another Makefile.
+#
+
+#target_suffix :=
+
+#
+# Optional suffix to add to the build directory and output binary files
+# to allow multiple builds to co-exist for various reasons.
+#
+#chip_suffix := -$(shell echo $(CHIP) | tr A-Z a-z)
+
+#
+# Combined suffixes
+#
+all_suffix = ${chip_suffix}${target_suffix}
+
+#
+# Default location to place binaries and make depend files for building
+# purposes.
+#
+ifeq "$(HOSTTYPE)" "Windows2000PC"
+BLDROOTWITHDRIVE = ${SDK}/build/${target}${all_suffix}${bldroot_suffix}
+BLDROOT = ${SDK_NO_DRIVE_NAME}/build/${target}${all_suffix}${bldroot_suffix}
+else # ifeq "$(HOSTTYPE)" "Windows2000PC"
+
+ifndef SDKBUILD
+SDKBUILD :=build
+endif
+
+BLDROOT = ${SDK}/${SDKBUILD}/$(if ${BLDCONFIG},${BLDCONFIG}/)${target}${all_suffix}${bldroot_suffix}
+
+endif # ifeq "$(HOSTTYPE)" "Windows2000PC"
+
+# This is needed because we cannot include Make.vxworks before Make.config
+ifndef DEST_DIR_SUFFIX
+export DEST_DIR_SUFFIX :=$(subst $(realpath $(SDK))/systems,,$(realpath $(CURDIR)/$(dir ($(firstword $(MAKEFILE_LIST))))))
+ifeq ($(MAKELEVEL),0)
+endif
+endif
+
+ifeq ($(DEST_DIR),)
+export DEST_DIR :=${SDK}/${SDKBUILD}$(if ${BLDCONFIG},/${BLDCONFIG})$(DEST_DIR_SUFFIX)
+endif
+
+ifdef LOCALDIR
+BLDDIR = ${BLDROOT}/${LOCALDIR}
+ifeq "$(HOSTTYPE)" "Windows2000PC"
+BLDDIRWITHDRIVE = ${BLDROOTWITHDRIVE}/${LOCALDIR}
+endif
+else # ifdef LOCALDIR
+BLDDIR = ${BLDROOT}
+ifeq "$(HOSTTYPE)" "Windows2000PC"
+BLDDIRWITHDRIVE = ${BLDROOTWITHDRIVE}
+endif
+endif # ifdef LOCALDIR
+
+LIBDIR = ${BLDROOT}
+
+#
+# Export directory, where build objects used by the outside world are
+# placed (exported header files, libs, bins)
+#
+EXPDIR = ${SDK}/export/${target}${all_suffix}
+
+#
+# Standard include paths
+#
+INCDIR = ${SDK}/include
+
+#
+# Compilation Flags
+#
+# Flags may be added to (see below)
+#
+
+INCFLAGS = -I${INCDIR} -I${SDK}/systems
+
+CFLAGS += ${INCFLAGS}
+CXXFLAGS += ${INCFLAGS}
+CPPFLAGS += ${INCFLAGS}
+
+#
+# Debug #ifdef control
+#
+# Compiling out #ifdef DEBUG code saves about 1.3% on executable size.
+# It is recommended to leave debug enabled when developing applications.
+#
+ifndef DEBUG_IFDEFS
+DEBUG_IFDEFS=TRUE
+endif
+
+ifeq ($(DEBUG_IFDEFS),TRUE)
+CFLAGS += -DBROADCOM_DEBUG
+CXXFLAGS += -DBROADCOM_DEBUG
+CPPFLAGS += -DBROADCOM_DEBUG
+endif
+
+#
+# Debug symbol information control
+#
+ifndef DEBUG_SYMBOLS
+DEBUG_SYMBOLS=TRUE
+endif
+
+ifeq ($(DEBUG_SYMBOLS),TRUE)
+CFLAGS += -g
+CXXFLAGS += -g
+CPPFLAGS += -g
+endif
+
+#
+# If DEBUG_CFLAGS is set, add its contents to CFLAGS.
+# May be useful for setting on the command line or adding to Make.local.
+# Example: gmake DEBUG_CFLAGS=-save-temps system.c
+#
+
+ifneq ($(DEBUG_CFLAGS),)
+CFLAGS += $(DEBUG_CFLAGS)
+CXXFLAGS += $(DEBUG_CFLAGS)
+CPPFLAGS += $(DEBUG_CFLAGS)
+endif
+
+#
+# Optimization level
+#
+# Set DEBUG_OPTIMIZE to TRUE (default) to use a normal optimization
+# determined by OPTFLAGS_DEFAULT in the platform Makefile.
+# Set DEBUG_OPTIMIZE to FALSE to use no optimization,
+# strongly recommended when using any debugger.
+# Set DEBUG_OPTIMIZE to any other option string to request specific
+# optimization flags (for example -O2).
+#
+ifndef DEBUG_OPTIMIZE
+DEBUG_OPTIMIZE=TRUE
+endif
+
+ifeq ($(DEBUG_OPTIMIZE),TRUE)
+OPTFLAGS += $(OPTFLAGS_DEFAULT)
+else
+ifneq ($(DEBUG_OPTIMIZE),FALSE)
+OPTFLAGS += $(DEBUG_OPTIMIZE)
+endif
+endif
+
+#
+# Debug assertion control.
+#
+# Compiling out assert() saves about 1.1% on executable size,
+# however doing so is VERY MUCH discouraged.
+#
+ifndef DEBUG_ASSERTS
+DEBUG_ASSERTS=TRUE
+endif
+
+ifeq ($(DEBUG_ASSERTS),FALSE)
+CFLAGS += -DNDEBUG
+CXXFLAGS += -DNDEBUG
+CPPFLAGS += -DNDEBUG
+endif
+
+#
+# GCC pedantic mode.
+#
+ifeq ($(DEBUG_PEDANTIC),TRUE)
+CFGFLAGS += -D__PEDANTIC__
+CFLAGS += --pedantic
+CXXFLAGS += --pedantic
+endif
+
+#
+# In each directory, build a list of local sources, objects, and headers
+#
+LSRCS = $(wildcard *.c *.cpp *.s *.cc *.C)
+LOBJS = $(addsuffix .o, $(basename ${LSRCS}))
+BOBJS = $(addprefix ${BLDDIR}/,${LOBJS})
+LHDRS = $(wildcard *.h *.H)
+LDOTIS = $(wildcard *.i)
+
+
+#
+# Rule to create object file (build) directory
+#
+
+.PHONY: all install clean distclean
+
+.PRECIOUS: ${BLDDIR}/.tree
+
+%/.tree:
+ @$(ECHO) 'Creating build directory $(dir $@)'
+ @$(MKDIR) $(dir $@)
+ @$(ECHO) "Build Directory for ${LOCALDIR} Created" > $@
+
+# Rule allowing build through CPP only, creates .E file from .c file.
+
+%.E: %.c
+ $Q${CC} -E ${CFLAGS} $< | sed -e '/^ *$$/d' -e p -e d > $@
+
+# Rule allowing build through source only, creates .s file from .c file.
+
+%.s: %.c
+ $Q${CC} -S ${CFLAGS} $<
+
+#
+# Default Build rules for .c --> .o, leaving the binary in BLDDIR/X.o,
+# even if file not built from directory of source.
+#
+ifeq ($(FAST),1)
+${BLDDIR}/%.o: %.c
+else
+ifdef GENERATE_C_FILES
+${BLDDIR}/%.o: %.c
+else
+${BLDDIR}/%.o: %.c
+endif
+endif
+ifdef QUIET
+ @${ECHO} Compiling ${LOCALDIR}/$<
+endif
+ifdef LOCAL_D_FILE
+ $Q$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -o $@ -c $< --write-user-dependencies
+ -@/bin/cp $*.d $(BLDDIR)/$*.d
+ -@/bin/rm -f $*.d
+else
+ $Q$(CC) -MD -MF $(BLDDIR)/$*.d $(CFLAGS) $(EXTRA_CFLAGS) -o $@ -c $<
+endif
+ @/bin/cp $(BLDDIR)/$*.d $(BLDDIR)/$*.tmp;\
+ /bin/sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
+ -e '/^$$/ d' -e 's/$$/ :/' \
+ < $(BLDDIR)/$*.d >> $(BLDDIR)/$*.tmp; \
+ /bin/sed \
+ -e 's| \([0-9a-zA-Z]\)| '$(SDK)/$(LOCALDIR)'\/\1|g' \
+ -e 's|^\([0-9a-zA-Z]\)|'$(SDK)/$(LOCALDIR)'/\1|g' \
+ -e 's| \(\.\.\/\)| '$(SDK)/$(LOCALDIR)'\/\1|g' \
+ -e 's|'$(SDK)'|'$$\{SDK\}'|g' \
+ -e 's/\w*\/\.\.\/*//g' \
+ -e 's/\w*\/\.\.\/*//g' \
+ -e 's/\w*\/\.\.\/*//g' \
+ < $(BLDDIR)/$*.tmp > $(BLDDIR)/$*.P; \
+ /bin/rm -f $(BLDDIR)/$*.d $(BLDDIR)/$*.tmp
+
+${BLDDIR}/%.o: %.s
+ifdef QUIET
+ @${ECHO} Assembling ${LOCALDIR}/$<
+endif
+ $Q${CC} ${CFLAGS} ${EXTRA_CFLAGS} -c $< -o $@
+
+${BLDDIR}/%.o: %.cpp
+ifdef QUIET
+ @${ECHO} Compiling ${LOCALDIR}/$<
+endif
+ $Q${CXX} -c ${CXXFLAGS} -c $< -o $@
+
+${BLDDIR}/%.o: %.cc ${BLDDIR}/.tree
+ifdef QUIET
+ @${ECHO} Compiling ${LOCALDIR}/$<
+endif
+ $Q${CXX} -c ${CXXFLAGS} -c $< -o $@
+
+#
+# Cause "make foo.o" in any subdirectory to put the object in the build
+# directory instead of the local directory.
+#
+%.o: ${BLDDIR}/%.o
+ @
+
+#
+# List of directories where built objects live.
+# (we are not making the export directories for now)
+#
+#DIRS = ${BLDDIR} ${EXPDIR}/lib ${EXPDIR}/bin ${EXPDIR}/include
+DIRS = ${BLDDIR}
+
+ifeq (C_COMPILER,$(MAKECMDGOALS))
+C_COMPILER:
+ @echo $(CC)
+endif
diff --git a/sdk-6.5.20/src/gpl-modules/make/Make.depend b/sdk-6.5.20/src/gpl-modules/make/Make.depend
@@ -0,0 +1,108 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Make.depend,v 1.14 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+# Default rule to build dependencies. This builds a x.d file for each
+# x.c file that describes the dependencies. We then conditionally include
+# the generated .d files.
+#
+
+#
+# If making 'clean', do not include any .d files. If they are included,
+# gmake intrinsically tries to remake them all.
+#
+ifeq (,$(findstring clean,$(MAKECMDGOALS)))
+
+ZFS :=$(wildcard *.zf)
+ZFC := $(ZFS:.zf=.c)
+
+ifdef GENERATE_C_FILES
+ifndef GEN_INCS
+$(error "GEN_INCS was not defined")
+endif
+
+ZF_GEN = ${SDK}/tools/zFrameCodeGen.pl
+
+# 1=.zf
+define ZFS_RULE
+$(1:.zf=Console.c) : $(1:.zf=.c)
+ @echo updated $$@ from $$?
+
+$(1:.zf=.c) : $(1) $(ZF_GEN)
+ @$(PERL) $(ZF_GEN) -s -z . -p . -g $1 -t c
+ @echo generated ${LOCALDIR}/$$@ from $(1)
+ @mv $$(*F).cx $$@
+ @if [ -e $$(*F)Console.cx ] ; then \
+ mv $$(*F)Console.cx $$(*F)Console.c; \
+ echo Created $$(*F)Console.c ;\
+ fi
+ @if [ -e $$(*F)Console.hx ] ; then \
+ echo Created $(GEN_INCS)/$$(*F)Console.hx ;\
+ mv $$(*F)Console.hx $(GEN_INCS)/ ; \
+ fi
+ @mv $$(*F).hx $(GEN_INCS)/
+endef
+
+$(foreach zf,$(ZFS),$(eval $(call ZFS_RULE,$(zf))))
+
+${BLDDIR}/%.P : ${BLDDIR}/.tree %.c
+
+.PHONY: GENFILES
+GENFILES: $(ZFC)
+
+$(BOBJS) : $(ZFC)
+
+else
+#
+# Attempt to build the depend files. If it fails, the depend file is
+# removed so that it is not included in later builds.
+#
+${BLDDIR}/%.P : %.c ${BLDDIR}/.tree
+ @$(ECHO) Dependencies for ${LOCALDIR}/$<
+
+${BLDDIR}/%.P : %.cc ${BLDDIR}/.tree
+ @$(ECHO) Dependencies for ${LOCALDIR}/$<
+
+endif
+
+#
+# If there are C or C++ files in this directory, include the
+# depend files for them.
+#
+
+ifeq ($(findstring _COMPILER,$(MAKECMDGOALS))$(findstring variable,$(MAKECMDGOALS)),)
+ifneq ($(strip ${LSRCS}),)
+ifneq (,$(findstring .o,$(MAKECMDGOALS)))
+-include $(addprefix ${BLDDIR}/,$(MAKECMDGOALS:.o=.P)) $(addprefix ${BLDDIR}/,$(MAKECMDGOALS:.o=.sig))
+else
+-include $(addprefix ${BLDDIR}/,$(addsuffix .P,$(basename $(LSRCS)))) $(addprefix ${BLDDIR}/,$(addsuffix .sig,$(basename $(LSRCS))))
+endif
+endif
+endif
+
+endif # !CLEANING
+
+clean_d::
+ifdef QUIET
+ @$(ECHO) Cleaning dependencies for ${LOCALDIR}
+endif
+ifdef GENERATE_C_FILES
+ $Q$(RM) $(ZFC:%=$(SDK)/$(LOCALDIR)/%) $(ZFC:%.c=$(SDK)/$(LOCALDIR)/%Console.c)
+endif
+
+clean:: clean_d
diff --git a/sdk-6.5.20/src/gpl-modules/make/Make.kernlib b/sdk-6.5.20/src/gpl-modules/make/Make.kernlib
@@ -0,0 +1,69 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Make.kernlib,v 1.7 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+# Make rules/targets for handling libraries
+
+.SECONDARY:: ${BOBJS}
+
+targetlibsoname = ${lib}.so.${SHAREDLIBVER}
+targetlibrealname = ${targetlibsoname}
+targetlibso = ${LIBDIR}/${targetlibrealname}
+
+ifeq ($(TOOLS),Borland)
+
+LIBSUFFIX=lib
+
+${LIBDIR}/%.lib: ${BORLAND_BOBJS}
+ $(RM) $@
+ $(FOREACH) -subdir "$(LIBDIR)" \
+ "tlib $@ $(foreach obj, $(BORLAND_LOBJS), +-$(obj))"
+
+else # !Borland
+
+LIBSUFFIX=a
+
+${LIBDIR}/%.a: ${BOBJS}
+ifdef QUIET
+ @$(ECHO) Building library $(notdir $@)
+endif
+ $Q$(RM) $@
+ $Q$(AR) ${ARFLAGS} $@ $(sort ${BOBJS})
+ifeq ($(LINUX_MAKE_SHARED_LIB),1)
+ifeq ($(targetbase),unix)
+ $(CC) -shared -Wl,-soname,${targetlibsoname} -o ${targetlibso} ${BOBJS} -lc
+endif
+endif # LINUX_MAKE_SHARED_LIB #
+endif # !Borland
+
+targetlib = ${LIBDIR}/${lib}.${LIBSUFFIX}
+
+all:: ${BLDDIR}/.tree ${targetlib}
+
+install:: all
+
+clean::
+ifdef QUIET
+ @$(ECHO) Cleaning objects for ${LOCALDIR} and ${lib}
+endif
+ $Q$(RM) ${BOBJS}
+ $Q$(RM) ${targetlib}
+ $Q$(RM) ${targetlibso}
+
+distclean:: clean
+
diff --git a/sdk-6.5.20/src/gpl-modules/make/Make.lib b/sdk-6.5.20/src/gpl-modules/make/Make.lib
@@ -0,0 +1,80 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Make.lib,v 1.14 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+# Make rules/targets for handling libraries
+
+.SECONDARY:: ${BOBJS}
+
+BOBJS_FAST = ${BOBJS}
+BOBJS_MAKE_CMD =
+
+ifeq ($(FAST),1)
+ ifneq ($(strip $(BOBJS)),)
+ BOBJS_FAST =
+ BOBJS_ARGS = -j9
+ BOBJS_MAKE_CMD = pwd && make LSRUN=$(SDK)/tools/lsrun.pl $(BOBJS_ARGS) ${BOBJS}
+ endif
+endif
+
+ifeq ($(TOOLS),Borland)
+
+LIBSUFFIX=lib
+
+${LIBDIR}/%.lib: ${BORLAND_BOBJS}
+ $(RM) $@
+ $(FOREACH) -subdir "$(LIBDIR)" \
+ "tlib $@ $(foreach obj, $(BORLAND_LOBJS), +-$(obj))"
+
+else # !Borland
+
+ifeq ($(LINUX_MAKE_SHARED_LIB),1)
+LIBSUFFIX=so.${SHAREDLIBVER}
+else
+LIBSUFFIX=a
+endif
+
+targetlib = ${LIBDIR}/${lib}.${LIBSUFFIX}
+
+all:: ${BLDDIR}/.tree ${targetlib}
+
+${LIBDIR}/%.${LIBSUFFIX}: ${BOBJS_FAST}
+ $(BOBJS_MAKE_CMD)
+ifdef QUIET
+ @$(ECHO) Building library $(notdir $@)
+endif
+ $Q$(RM) $@
+ifeq ($(LINUX_MAKE_SHARED_LIB),1)
+ $(CC) -shared -Wl,-soname,${lib}.${LIBSUFFIX}${EXTRA_LIB_LDFLAGS} -o ${targetlib} ${BOBJS} -lc
+else
+ $(AR) ${ARFLAGS} $@ $(sort ${BOBJS})
+endif
+
+endif # !Borland
+
+
+install:: all
+
+clean::
+ifdef QUIET
+ @$(ECHO) Cleaning objects for ${LOCALDIR} and ${lib}
+endif
+ $Q$(RM) ${BOBJS}
+ $Q$(RM) ${targetlib}
+
+distclean:: clean
diff --git a/sdk-6.5.20/src/gpl-modules/make/Make.linux b/sdk-6.5.20/src/gpl-modules/make/Make.linux
@@ -0,0 +1,97 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+#
+# $Id: Make.linux,v 1.18 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+# Common make targets for Linux user and kernel builds included by top
+# level Linux makefiles
+#
+# Variables referenced:
+#
+# LINUX_MAKE_FLAGS
+# Additional flags passed to Make
+#
+# LINUX_MAKE_USER
+# Defined: user build
+# Undefined: kernel build
+#
+# LINUX_MAKE_DIR
+# Common makefile location, if it is not ../common
+#
+#
+
+export DEST_DIR_SUFFIX :=$(subst $(realpath $(SDK))/systems,,$(realpath $(CURDIR)/$(dir ($(firstword $(MAKEFILE_LIST))))))
+
+ifeq (,$(kernel_version))
+kernel_version=2_4
+endif
+
+ifndef LINUX_MAKE_SHARED_LIB
+LINUX_MAKE_SHARED_LIB=0
+endif
+
+ifeq (,$(SHAREDLIBVER))
+SHAREDLIBVER=1
+endif
+
+ifndef LINUX_MAKE_DIR
+ifdef LINUX_MAKE_USER
+LINUX_MAKE_DIR := $(SDK)/systems/linux/user/common
+else
+LINUX_MAKE_DIR := $(SDK)/systems/linux/kernel/common
+endif
+endif
+
+ifdef LINUX_MAKE_USER
+ CMD = $(LINUX_MAKE_FLAGS) -C $(LINUX_MAKE_DIR) \
+ platform=$(platform) bldroot_suffix=/$(platform) kernel_version=$(kernel_version) \
+ LINUX_MAKE_SHARED_LIB=$(LINUX_MAKE_SHARED_LIB) SHAREDLIBVER=$(SHAREDLIBVER)
+else
+ export LINUX_MAKE_KERNEL := 1
+ CMD = $(LINUX_MAKE_FLAGS) -C $(LINUX_MAKE_DIR) \
+ platform=$(platform) kernel_version=$(kernel_version)
+endif
+
+ifneq (,$(MIPS_TOOLS_DIR))
+ CMD += MIPS_TOOLS_DIR=$(MIPS_TOOLS_DIR)
+endif
+
+ifneq (,$(MIPS_CROSS_COMPILE))
+ CMD += MIPS_CROSS_COMPILE=$(MIPS_CROSS_COMPILE)
+endif
+
+ifneq (,$(LINUX_INCLUDE))
+ CMD += LINUX_INCLUDE=$(LINUX_INCLUDE)
+endif
+
+# gmake does not understand $(CMD) to be a submake
+# options are to +$(CMD) or $(MAKE) $(CMD)
+# trying the latter
+build:
+ $(MAKE) $(CMD)
+
+DELIVER clean C_COMPILER CXX_COMPILER variable mod bcm user issu:
+ $(MAKE) $(CMD) $@
+
+clean_d: clean
+
+distclean:
+ $(MAKE) $(CMD) $@
+
+.PHONY: build clean distclean clean_d DELIVER variable mod bcm user issu
+
diff --git a/sdk-6.5.20/src/gpl-modules/make/Make.subdirs b/sdk-6.5.20/src/gpl-modules/make/Make.subdirs
@@ -0,0 +1,44 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Make.subdirs,v 1.8 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+# Make rules/targets for handling subdirectories
+
+.PHONY: ${subdirs}
+
+all:: ${subdirs}
+ifdef QUIET
+ @$(ECHO) Subdirectory build for ${subdirs}
+endif
+
+${subdirs}::
+ $Q$(MAKE) -C $@ kernel_version=$(kernel_version) LINUX_MAKE_SHARED_LIB=${LINUX_MAKE_SHARED_LIB} SHAREDLIBVER=${SHAREDLIBVER}
+
+ifeq "$(HOSTTYPE)" "Windows2000PC"
+clean clean_d install distclean::
+ifdef QUIET
+ @$(ECHO) Subdirectory $@ for ${subdirs}
+endif
+ $Q$(FOREACH) "$(subdirs)" "${MAKE} -C ## $@"
+else
+clean clean_d install distclean::
+ifdef QUIET
+ @$(ECHO) Subdirectory $@ for ${subdirs}
+endif
+ @(for name in $(subdirs); do $(MAKE) -C $$name $@; done)
+endif
diff --git a/sdk-6.5.20/src/gpl-modules/make/Make.tools b/sdk-6.5.20/src/gpl-modules/make/Make.tools
@@ -0,0 +1,38 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Make.tools,v 1.2 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+SYSNAME := $(shell uname -s)
+HCC ?=/usr/bin/gcc
+SED = /bin/sed
+COMPRESS = /usr/bin/compress
+PERL = /usr/bin/perl
+LN = /bin/ln
+HOSTTYPE= i386-linux
+
+#
+# Platform Independent
+#
+MKTOOL = $(PERL) ${SDK}/tools/mktool.pl
+RM = $(MKTOOL) -rm
+MKDIR = $(MKTOOL) -md
+FOREACH = $(MKTOOL) -foreach
+CP = $(MKTOOL) -cp
+MAKEDEP = $(MKTOOL) -dep
+ECHO = $(MKTOOL) -echo
+MKBEEP = ${MKTOOL} -beep
diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-gts b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-gts
@@ -0,0 +1,142 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-xlr-4_19,v 0.1 Broadcom SDK $
+# $Copyright: (c) 2015 Broadcom Corp.
+# All Rights Reserved.$
+
+#
+# XLR system make file.
+#
+# Most of this was taken from target x86-smp_generic_64-2_6.
+#
+
+
+#############################################################################
+# this segment is custom and not sourced from any existing makefile #
+# (base thanks to http:<slash><slash>confluence.broadcom.com/display/NTSWSW/X86+System) #
+#############################################################################
+
+# set up a basic feature list. tcl, etc. #
+#ifeq (,$(FEATURE_LIST))
+#FEATURE_LIST = TCL BFD PTP CINT L3 I2C MEM_SCAN EDITLINE BCM_SAL_PROFILE CUSTOMER TEST CHASSIS MSTP RCPU
+#endif
+
+# some basic path variables for tools and kernel source, etc #
+export XLR_TOOLS_BASE = /projects/ntsw-tools/linux/xlr-419
+TOOLCHAIN_DIR = $(XLR_TOOLS_BASE)/buildroot/host/usr
+KERNDIR = $(XLR_TOOLS_BASE)/kernel/linux
+
+# set up cross compile prefix, tools dir variables. #
+export CROSS_COMPILE := x86_64-broadcom-linux-gnu-
+export TOOLS_DIR := $(TOOLCHAIN_DIR)/bin
+
+# architecture. #
+ARCH = x86_64
+TARGET_ARCHITECTURE = x86_64-broadcom-linux-gnu
+
+# Noisy kernel build
+KBUILD_VERBOSE = 1
+
+export ARCH KBUILD_VERBOSE
+
+# set up paths. #
+export LIBRARY_PATH := $(TOOLCHAIN_DIR)/lib:$(TOOLCHAIN_DIR)/lib64:$(LIBRARY_PATH)
+export PATH := $(TOOLCHAIN_DIR)/bin:$(KERNDIR):$(PATH)
+
+# set up SYSINC path #
+export SYSINC := $(XLR_TOOLS_BASE)/buildroot/host/usr/lib/gcc/$(TARGET_ARCHITECTURE)/5.4.0/include
+
+
+# CFLAGS/CFGFLAGS #
+CFLAGS += -DUSE_LINUX_BDE_MMAP=1
+#CFLAGS += -DBDE_LINUX_USE_MSI_INTERRUPT
+CFLAGS += -Wno-error=unused-value
+CFLAGS += -Wno-error=unused-but-set-variable
+CFLAGS += -Wno-error=maybe-uninitialized
+CFLAGS += -Wno-error=cpp
+CFLAGS += -Wno-error=aggressive-loop-optimizations
+CFLAGS += -Wno-error=array-bounds
+CFLAGS += -Wno-error=strict-overflow
+CFLAGS += -L$(TOOLCHAIN_DIR)/lib
+CFLAGS += -L$(TOOLCHAIN_DIR)/lib64
+#CFLAGS += -Wl,--rpath=/lib64 # may need to set rpath and dynamic-linker path here (and possibly in KLFAGS below) in the future, #
+#CFLAGS += -Wl,--dynamic-linker=/lib64/ld-linux-x86-64.so.2 # if we want to build the target executable to be used with shared libs #
+
+#XLDK-568 fix inline references
+CFGFLAGS += -fgnu89-inline
+
+
+# set up KFLAGS appropriately. #
+ifeq (,$(KFLAGS))
+KFLAGS := -L$(TOOLCHAIN_DIR)/lib -L$(TOOLCHAIN_DIR)/lib64 -I$(KERNDIR) -lc -nostdinc -isystem $(SYSINC) -Iinclude -I$(KERNDIR)/arch/x86/include -I$(KERNDIR)/arch/x86/include/generated -I$(KERNDIR)/arch/x86/include/generated/uapi -I$(KERNDIR)/arch/x86/include/uapi -I$(KERNDIR)/include -I$(KERNDIR)/include/generated -I$(KERNDIR)/include/generated/uapi -I$(KERNDIR)/include/uapi -include $(KERNDIR)/include/generated/autoconf.h -D__KERNEL__ -DNDEBUG -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Wno-format-security -fno-delete-null-pointer-checks -O2 -m64 -mtune=generic -mno-red-zone -mcmodel=kernel -funit-at-a-time -maccumulate-outgoing-args -fstack-protector -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -Wframe-larger-than=1024 -fno-omit-frame-pointer -Wdeclaration-after-statement -Wno-pointer-sign -fno-dwarf2-cfi-asm -fconserve-stack
+endif
+
+
+######################################################################
+# this segment comes from make/Makefile.linux-x86-smp_generic_64-2_6 #
+######################################################################
+CFGFLAGS += -DLONGS_ARE_64BITS
+CFGFLAGS += -DPTRS_ARE_64BITS
+CFGFLAGS += -DSAL_SPL_LOCK_ON_IRQ
+
+
+##############################################################
+# This segment comes from make/Makefile.linux-x86-common-2_6 #
+##############################################################
+CFGFLAGS += -DSYS_BE_PIO=0 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=0
+ENDIAN = LE_HOST=1
+CFGFLAGS += -D$(ENDIAN)
+CFGFLAGS += -DBCM_PLATFORM_STRING=\"X86\"
+CFGFLAGS += -DSAL_BDE_DMA_MEM_DEFAULT=32
+
+# Extra variables.
+EXTRA_CFLAGS = -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+
+comma = ,
+basetarget = $(basename $(notdir $@))
+modname = $(basetarget)
+
+name-fix = $(subst $(comma),_,$(subst -,_,$1))
+basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
+modname_flags = $(if $(filter 1,$(words $(modname))),\
+-D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+
+ifdef LTSW_CHIPS
+# Ensure we do not use an out-of-date libelf.so
+ELFUTILS_MIN = 158
+ELFUTILS_DIR ?= /projects/ntsw-tools/lib
+
+# Default open source target build
+OPENSRC_BUILD ?= fed21-x86_64
+
+# Hardware interface (see $SDKLT/bcma/sys/probe directory)
+SYSTEM_INTERFACE ?= ngbde
+
+# Turn on direct register access if running on real hardware.
+ifeq (ngbde,$(SYSTEM_INTERFACE))
+LTSW_ADD_CPPFLAGS += -DBCMDRD_CONFIG_MEMMAP_DIRECT=1
+endif
+
+export SYSTEM_INTERFACE
+endif
+
+ifneq ($(targetplat),user)
+# By default we exclude -Werror from x86 kernel builds
+BCM_CFLAGS = -Wall
+include ${SDK}/make/Makefile.linux-kernel-2_6
+endif
+
+
diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc
@@ -0,0 +1,104 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-iproc Exp $
+# $Copyright: (c) 2007 Broadcom Corp.
+# All Rights Reserved.$
+# Makefile for iproc-CMICd
+
+# User must select one platform from below.By default ARM_LINUX is selected. .
+ifeq (,$(BUILD_PLATFORM))
+BUILD_PLATFORM=ARM_LINUX
+endif
+
+# TOOLCHAIN_BASE_DIR Toolchain base directory for iPROC-CMICd devices
+# TARGET_ARCHITECTURE Compiler for target architecture
+# KERNDIR Kernel directory for iPROC-CMICd devices
+ifeq (BE,$(ENDIAN_MODE))
+#While BE mode is supported, it's use is very limited. We had a specific customer
+#request for BE support but don't currently mainstream it. So a 5.1.0 version
+#has not been built. Continue using 5.0.3 for any BE support
+TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk50-be/XLDK32
+TARGET_ARCHITECTURE:=armeb-broadcom-linux-uclibcgnueabi
+KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux
+else
+TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk51/XLDK32
+TARGET_ARCHITECTURE:= arm-broadcom-linux-uclibcgnueabi
+KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux
+endif
+
+ifeq (,$(CROSS_COMPILE))
+CROSS_COMPILE:= $(TARGET_ARCHITECTURE)-
+endif
+
+# arm9tools
+TOOLCHAIN_BIN_DIR=$(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/bin
+override PATH:=$(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/$(TARGET_ARCHITECTURE)/bin:$(TOOLCHAIN_BIN_DIR):$(PATH)
+LD_LIBRARY_PATH=$(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/lib
+export TOOLCHAIN_BIN_DIR LD_LIBRARY_PATH
+
+CROSS_GCC_VER ?= $(shell $(TOOLCHAIN_BIN_DIR)/$(CROSS_COMPILE)gcc -dumpversion)
+
+# Default Linux include directory
+ifeq (,$(LINUX_INCLUDE))
+LINUX_INCLUDE := $(KERNDIR)/include
+endif
+
+ifeq (BE,$(ENDIAN_MODE))
+CFGFLAGS += -DSYS_BE_PIO=1 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=1
+ENDIAN = BE_HOST=1
+else
+CFGFLAGS += -DSYS_BE_PIO=0 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=0
+ENDIAN = LE_HOST=1
+endif
+
+CFLAGS += -fno-aggressive-loop-optimizations
+CFLAGS += -Wno-error=maybe-uninitialized
+CFLAGS += -Wno-error=array-bounds
+CFLAGS += -fgnu89-inline
+ifeq "$(shell expr `echo $(CROSS_GCC_VER) | cut -f1 -d.` \>= 7)" "1"
+ CFLAGS += -Wno-error=bool-operation
+endif
+
+CFGFLAGS += -D$(ENDIAN) -DIPROC_CMICD
+CFGFLAGS += -DBCM_PLATFORM_STRING=\"IPROC_CMICD\"
+
+ARCH = arm
+KBUILD_VERBOSE = 1
+
+export ARCH KBUILD_VERBOSE
+
+comma = ,
+basetarget = $(basename $(notdir $@))
+modname = $(basetarget)
+
+# Extra variables.
+EXTRA_CFLAGS = -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+
+name-fix = $(subst $(comma),_,$(subst -,_,$1))
+basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
+modname_flags = $(if $(filter 1,$(words $(modname))),\
+ -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+
+KFLAG_INCLD ?= $(LD_LIBRARY_PATH)/gcc/$(TARGET_ARCHITECTURE)/$(CROSS_GCC_VER)/include
+
+ifeq (,$(KFLAGS))
+KFLAGS := -D__LINUX_ARM_ARCH__=7 -D__KERNEL__ -nostdinc -isystem $(KFLAG_INCLD) -I$(LINUX_INCLUDE) -include $(LINUX_INCLUDE)/generated/autoconf.h -I$(KERNDIR)/arch/arm/include -I$(KERNDIR)/arch/arm/include/generated -I$(KERNDIR)/arch/arm/mach-iproc/include -Wall -Wstrict-prototypes -Wno-trigraphs -Os -fno-strict-aliasing -fno-common -marm -mabi=aapcs-linux -fno-pic -pipe -msoft-float -ffreestanding -march=armv7-a -mfpu=vfp -mfloat-abi=softfp -fomit-frame-pointer -g -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign -mlong-calls
+KFLAGS += -I$(LINUX_INCLUDE)/uapi -I$(LINUX_INCLUDE)/generated/uapi -I$(KERNDIR)/arch/arm/include/uapi -I$(KERNDIR)/arch/arm/include/generated/uapi
+endif
+
+ifneq ($(targetplat),user)
+include ${SDK}/make/Makefile.linux-kernel-3_6
+endif
diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc-3_14 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc-3_14
@@ -0,0 +1,103 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-iproc-3_6,v 1.1 Broadcom SDK $
+# $Copyright: (c) 2007 Broadcom Corp.
+# All Rights Reserved.$
+# Makefile for iproc-CMICd
+
+# User must select one platform from below.By default ARM_LINUX is selected. .
+ifeq (,$(BUILD_PLATFORM))
+BUILD_PLATFORM=ARM_LINUX
+endif
+
+# TOOLCHAIN_BASE_DIR Toolchain base directory for iPROC-CMICd devices
+# TARGET_ARCHITECTURE Compiler for target architecture
+# KERNDIR Kernel directory for iPROC-CMICd devices
+ifeq (BE,$(ENDIAN_MODE))
+TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk37-be/buildroot-2013.11-gcc48-opt-broadcom
+TARGET_ARCHITECTURE:=armeb-buildroot-linux-gnueabi
+KERNDIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk37-be/XLDK/kernel/linux
+else
+TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk37/XLDK
+TARGET_ARCHITECTURE:= arm-broadcom-linux-uclibcgnueabi
+KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux
+endif
+
+
+ifeq (,$(CROSS_COMPILE))
+CROSS_COMPILE:= $(TARGET_ARCHITECTURE)-
+endif
+
+# arm9tools
+ifeq (BE,$(ENDIAN_MODE))
+TOOLCHAIN_BIN_DIR=$(TOOLCHAIN_BASE_DIR)/host/usr/bin
+override PATH:=$(TOOLCHAIN_BASE_DIR)/host/usr/$(TARGET_ARCHITECTURE)/bin:$(TOOLCHAIN_BIN_DIR):$(PATH)
+LD_LIBRARY_PATH=$(TOOLCHAIN_BASE_DIR)/host/usr/lib
+else
+TOOLCHAIN_BIN_DIR=$(TOOLCHAIN_BASE_DIR)/buildroot/usr/bin
+override PATH:=$(TOOLCHAIN_BASE_DIR)/buildroot/usr/$(TARGET_ARCHITECTURE)/bin:$(TOOLCHAIN_BIN_DIR):$(PATH)
+LD_LIBRARY_PATH=$(TOOLCHAIN_BASE_DIR)/buildroot/usr/lib
+endif
+
+export TOOLCHAIN_BIN_DIR LD_LIBRARY_PATH
+
+# Default Linux include directory
+ifeq (,$(LINUX_INCLUDE))
+LINUX_INCLUDE := $(KERNDIR)/include
+endif
+
+ifeq (BE,$(ENDIAN_MODE))
+CFGFLAGS += -DSYS_BE_PIO=1 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=1
+ENDIAN = BE_HOST=1
+else
+CFGFLAGS += -DSYS_BE_PIO=0 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=0
+ENDIAN = LE_HOST=1
+endif
+
+CFGFLAGS += -D$(ENDIAN) -DIPROC_CMICD
+CFGFLAGS += -DBCM_PLATFORM_STRING=\"IPROC_CMICD\"
+
+ARCH = arm
+KBUILD_VERBOSE = 1
+
+export ARCH KBUILD_VERBOSE
+
+comma = ,
+basetarget = $(basename $(notdir $@))
+modname = $(basetarget)
+
+# Extra variables.
+EXTRA_CFLAGS = -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+
+name-fix = $(subst $(comma),_,$(subst -,_,$1))
+basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
+modname_flags = $(if $(filter 1,$(words $(modname))),\
+ -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+
+ifeq (BE,$(ENDIAN_MODE))
+KFLAG_INCLD ?= $(TOOLCHAIN_BASE_DIR)/host/usr/lib/gcc/$(TARGET_ARCHITECTURE)/4.8.2/include
+else
+KFLAG_INCLD ?= $(TOOLCHAIN_BASE_DIR)/buildroot/usr/lib/gcc/$(TARGET_ARCHITECTURE)/4.7.2/include
+endif
+
+ifeq (,$(KFLAGS))
+KFLAGS := -D__LINUX_ARM_ARCH__=7 -D__KERNEL__ -nostdinc -isystem $(KFLAG_INCLD) -I$(LINUX_INCLUDE) -include $(LINUX_INCLUDE)/generated/autoconf.h -I$(KERNDIR)/arch/arm/include -I$(KERNDIR)/arch/arm/include/generated -I$(KERNDIR)/arch/arm/mach-northstar/include -I$(KERNDIR)/arch/arm/plat-iproc/include -Wall -Wstrict-prototypes -Wno-trigraphs -Os -fno-strict-aliasing -fno-common -marm -mabi=aapcs-linux -fno-pic -pipe -msoft-float -ffreestanding -march=armv7-a -mfpu=vfp -mfloat-abi=softfp -fomit-frame-pointer -g -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign -mlong-calls
+KFLAGS += -I$(LINUX_INCLUDE)/uapi -I$(LINUX_INCLUDE)/generated/uapi -I$(KERNDIR)/arch/arm/include/uapi -I$(KERNDIR)/arch/arm/include/generated/uapi
+endif
+
+ifneq ($(targetplat),user)
+include ${SDK}/make/Makefile.linux-kernel-3_6
+endif
diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc-4_4 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc-4_4
@@ -0,0 +1,92 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-iproc Exp $
+# $Copyright: (c) 2007 Broadcom Corp.
+# All Rights Reserved.$
+# Makefile for iproc-CMICd
+
+# User must select one platform from below.By default ARM_LINUX is selected. .
+ifeq (,$(BUILD_PLATFORM))
+BUILD_PLATFORM=ARM_LINUX
+endif
+
+# TOOLCHAIN_BASE_DIR Toolchain base directory for iPROC-CMICd devices
+# TARGET_ARCHITECTURE Compiler for target architecture
+# KERNDIR Kernel directory for iPROC-CMICd devices
+ifeq (BE,$(ENDIAN_MODE))
+TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk40-be/XLDK
+TARGET_ARCHITECTURE:=armeb-broadcom-linux-uclibcgnueabi
+KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux
+else
+TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk40/XLDK
+TARGET_ARCHITECTURE:= arm-broadcom-linux-uclibcgnueabi
+KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux
+endif
+
+ifeq (,$(CROSS_COMPILE))
+CROSS_COMPILE:= $(TARGET_ARCHITECTURE)-
+endif
+
+# arm9tools
+TOOLCHAIN_BIN_DIR=$(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/bin
+override PATH:=$(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/$(TARGET_ARCHITECTURE)/bin:$(TOOLCHAIN_BIN_DIR):$(PATH)
+LD_LIBRARY_PATH=$(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/lib
+
+export TOOLCHAIN_BIN_DIR LD_LIBRARY_PATH
+
+# Default Linux include directory
+ifeq (,$(LINUX_INCLUDE))
+LINUX_INCLUDE := $(KERNDIR)/include
+endif
+
+ifeq (BE,$(ENDIAN_MODE))
+CFGFLAGS += -DSYS_BE_PIO=1 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=1
+ENDIAN = BE_HOST=1
+else
+CFGFLAGS += -DSYS_BE_PIO=0 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=0
+ENDIAN = LE_HOST=1
+endif
+
+CFGFLAGS += -D$(ENDIAN) -DIPROC_CMICD
+CFGFLAGS += -DBCM_PLATFORM_STRING=\"IPROC_CMICD\"
+
+ARCH = arm
+KBUILD_VERBOSE = 1
+
+export ARCH KBUILD_VERBOSE
+
+comma = ,
+basetarget = $(basename $(notdir $@))
+modname = $(basetarget)
+
+# Extra variables.
+EXTRA_CFLAGS = -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+
+name-fix = $(subst $(comma),_,$(subst -,_,$1))
+basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
+modname_flags = $(if $(filter 1,$(words $(modname))),\
+ -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+
+KFLAG_INCLD ?= $(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/lib/gcc/$(TARGET_ARCHITECTURE)/4.9.3/include
+
+ifeq (,$(KFLAGS))
+KFLAGS := -D__LINUX_ARM_ARCH__=7 -D__KERNEL__ -nostdinc -isystem $(KFLAG_INCLD) -I$(LINUX_INCLUDE) -include $(LINUX_INCLUDE)/generated/autoconf.h -I$(KERNDIR)/arch/arm/include -I$(KERNDIR)/arch/arm/include/generated -I$(KERNDIR)/arch/arm/mach-iproc/include -Wall -Wstrict-prototypes -Wno-trigraphs -Os -fno-strict-aliasing -fno-common -marm -mabi=aapcs-linux -fno-pic -pipe -msoft-float -ffreestanding -march=armv7-a -mfpu=vfp -mfloat-abi=softfp -fomit-frame-pointer -g -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign -mlong-calls
+KFLAGS += -I$(LINUX_INCLUDE)/uapi -I$(LINUX_INCLUDE)/generated/uapi -I$(KERNDIR)/arch/arm/include/uapi -I$(KERNDIR)/arch/arm/include/generated/uapi
+endif
+
+ifneq ($(targetplat),user)
+include ${SDK}/make/Makefile.linux-kernel-3_6
+endif
diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc_64 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-iproc_64
@@ -0,0 +1,106 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-iproc Exp $
+# $Copyright: (c) 2007 Broadcom Corp.
+# All Rights Reserved.$
+# Makefile for iproc-CMICd
+
+# User must select one platform from below.By default ARM_LINUX is selected. .
+ifeq (,$(BUILD_PLATFORM))
+BUILD_PLATFORM=ARM_LINUX
+endif
+
+# TOOLCHAIN_BASE_DIR Toolchain base directory for iPROC-CMICd devices
+# TARGET_ARCHITECTURE Compiler for target architecture
+# KERNDIR Kernel directory for iPROC-CMICd devices
+ifeq (BE,$(ENDIAN_MODE))
+#We've never actually built a 64 BE executable. Just here for any future
+#customer requirements.
+TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk51-be/XLDK64
+TARGET_ARCHITECTURE ?= aarch64_be-broadcom-linux-uclibc
+KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux
+else
+TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/linux/iproc_ldks/xldk51/XLDK64
+TARGET_ARCHITECTURE ?= aarch64-broadcom-linux-uclibc
+KERNDIR ?= $(TOOLCHAIN_BASE_DIR)/kernel/linux
+endif
+
+ifeq (,$(CROSS_COMPILE))
+CROSS_COMPILE:= $(TARGET_ARCHITECTURE)-
+endif
+
+# A72 tools
+TOOLCHAIN_BIN_DIR=$(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/bin
+override PATH:=$(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/$(TARGET_ARCHITECTURE)/bin:$(TOOLCHAIN_BIN_DIR):$(PATH)
+LD_LIBRARY_PATH=$(TOOLCHAIN_BASE_DIR)/buildroot/host/usr/lib
+export TOOLCHAIN_BIN_DIR LD_LIBRARY_PATH
+
+CROSS_GCC_VER ?= $(shell $(TOOLCHAIN_BIN_DIR)/$(CROSS_COMPILE)gcc -dumpversion)
+
+# Default Linux include directory
+ifeq (,$(LINUX_INCLUDE))
+LINUX_INCLUDE := $(KERNDIR)/include
+endif
+
+ifeq (BE,$(ENDIAN_MODE))
+CFGFLAGS += -DSYS_BE_PIO=1 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=1
+ENDIAN = BE_HOST=1
+else
+CFGFLAGS += -DSYS_BE_PIO=0 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=0
+ENDIAN = LE_HOST=1
+endif
+
+CFLAGS += -DPTRS_ARE_64BITS -DLONGS_ARE_64BITS
+CFLAGS += -DPHYS_ADDRS_ARE_64BITS
+CFLAGS += -fno-aggressive-loop-optimizations -fno-strict-overflow
+CFLAGS += -Wno-error=maybe-uninitialized
+CFLAGS += -Wno-error=array-bounds
+CFLAGS += -fgnu89-inline
+ifeq "$(shell expr `echo $(CROSS_GCC_VER) | cut -f1 -d.` \>= 7)" "1"
+ CFLAGS += -Wno-error=bool-operation
+endif
+
+
+CFGFLAGS += -D$(ENDIAN) -DIPROC_CMICD
+CFGFLAGS += -DBCM_PLATFORM_STRING=\"IPROC_CMICD\"
+CFGFLAGS += -DSAL_BDE_DMA_MEM_DEFAULT=16
+
+ARCH = arm64
+KBUILD_VERBOSE = 1
+
+export ARCH KBUILD_VERBOSE
+
+comma = ,
+basetarget = $(basename $(notdir $@))
+modname = $(basetarget)
+
+# Extra variables.
+EXTRA_CFLAGS = -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+
+name-fix = $(subst $(comma),_,$(subst -,_,$1))
+basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
+modname_flags = $(if $(filter 1,$(words $(modname))),\
+ -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+
+KFLAG_INCLD ?= $(LD_LIBRARY_PATH)/gcc/$(TARGET_ARCHITECTURE)/$(CROSS_GCC_VER)/include
+
+ifeq (,$(KFLAGS))
+KFLAGS := -D__LINUX_ARM_ARCH__=8 -D__KERNEL__ -DPTRS_ARE_64BITS -DLONGS_ARE_64BITS -nostdinc -isystem $(KFLAG_INCLD) -I$(LINUX_INCLUDE) -include $(LINUX_INCLUDE)/generated/autoconf.h -I$(KERNDIR)/arch/arm64/include -I$(KERNDIR)/arch/arm64/include/generated -I$(KERNDIR)/arch/arm64/include/generated/uapi -I$(KERNDIR)/arch/arm64/include/generated/asm -I$(KERNDIR)/include/uapi -I$(KERNDIR)/include/generated/uapi -I$(KERNDIR)/arch/arm64/include/uapi -Wall -Wstrict-prototypes -Wno-trigraphs -Os -fno-strict-aliasing -fno-common -fno-pic -pipe -ffreestanding -fomit-frame-pointer -g -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign -mcmodel=large
+endif
+
+ifneq ($(targetplat),user)
+include ${SDK}/make/Makefile.linux-kernel-3_6
+endif
diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel
@@ -0,0 +1,112 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-kernel,v 1.27 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+# Configuration Flags
+
+# Filter out features that cannot or should not be supported in kernel mode
+_FEATURE_EXCLUDE_LIST += EDITLINE TCL OOB_RCPU CINT APIMODE DUNE_UI C_UNIT
+FEATURE_EXCLUDE_LIST = $(sort $(_FEATURE_EXCLUDE_LIST))
+# Tools
+
+CC = $(CROSS_COMPILE)gcc
+CXX = $(CROSS_COMPILE)g++
+LD = $(CROSS_COMPILE)ld
+AR = $(CROSS_COMPILE)ar
+ARFLAGS = -rc
+STRIP = $(CROSS_COMPILE)strip
+RANLIB = $(CROSS_COMPILE)ranlib
+OBJCOPY = $(CROSS_COMPILE)objcopy
+
+# Handle differences between gcc 2.x and gcc 3.x
+gcc-tune-flag = $(shell if ${CC} -dumpspecs | grep mcpu >/dev/null; then echo cpu; else echo tune; fi)
+
+# Configuration Variables
+
+# OSType Defines: This defines the type of RTOS or microkernel which you
+# are compiling the SAL (and its associated driver) for. New platforms
+# can be created by porting the routines (system.c) to your platform and
+# adding the define in this Makefile.
+
+OSTYPE = LINUX
+
+#
+# ORIGIN is used to Optionally select different CFLAGS. It is used to import
+# source from other vendors. If SOURCE=Broadcom, then the BCM_ flags are added
+# to those passed to the compiler. If SOURCE != Broadcom, BCM_ flags are NOT
+# added.
+#
+# Default specifies Broadcom
+#
+ifndef ORIGIN
+ ORIGIN = Broadcom
+endif
+
+#
+# STD_{C|CPP|CXX}FLAGS - Standard flags used by ALL compilations
+# BCM_{C|CPP|CXX}FLAGS - Flags used for Broadcom source files
+# OPT_{C|CPP|CXX}FLAGS - Defined in local make files BEFORE inclusion of
+# this Makefile, to define local "Extra" flags.
+#
+
+CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \
+ -I$(SDK)/systems/bde/linux/include \
+ -I$(LINUX_INCLUDE)
+
+CFGFLAGS += -DNO_FILEIO -DNO_CTRL_C -DNO_MEMTUNE
+
+CFGFLAGS += -D$(OSTYPE)
+
+# No user sal for the linux kernel
+# NO_SAL_APPL=1
+
+STD_CFLAGS = $(KFLAGS) $(CFGFLAGS)
+
+
+STD_CPPFLAGS = ${STD_CFLAGS}
+STD_CXXFLAGS = ${STD_CFLAGS}
+
+BCM_CFLAGS = -Wall -Werror
+BCM_CPPFLAGS = ${BCM_CFLAGS}
+BCM_CXXFLAGS = ${BCM_CFLAGS}
+
+ifeq (${ORIGIN}, Broadcom)
+ CFLAGS += ${STD_CFLAGS} ${BCM_CFLAGS} ${OPT_CFLAGS}
+ CPPFLAGS += ${STD_CPPFLAGS} ${BCM_CPPFLAGS} ${OPT_CPPFLAGS}
+ CXXFLAGS += ${STD_CXXFLAGS} ${BCM_CXXFLAGS} ${OPT_CXXFLAGS}
+else
+ CFLAGS += ${STD_CFLAGS} ${OPT_CFLAGS}
+ CPPFLAGS += ${STD_CPPFLAGS} ${OPT_CPPFLAGS}
+ CXXFLAGS += ${STD_CXXFLAGS} ${OPT_CXXFLAGS}
+endif
+
+#
+# Ignore pedantic flag for kernel modules
+#
+ifdef DEBUG_PEDANTIC
+DEBUG_PEDANTIC = FALSE
+endif
+
+#
+# DEPEND is used as a command to generate the list of dependencies.
+# The format of the output must be
+# "file.o : file.c a/b/c.h d/e/f.h ...",
+# if it is on multiple lines, each line must end in a backslash.
+# The output MUST be on standard out.
+#
+DEPEND = ${CC} -M $(CFLAGS) $<
diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel-2_6 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel-2_6
@@ -0,0 +1,148 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-kernel-2_6,v 1.40 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+# Configuration Flags
+
+# Filter out features that cannot or should not be supported in kernel mode
+
+_FEATURE_EXCLUDE_LIST += EDITLINE TCL OOB_RCPU CINT APIMODE DUNE_UI C_UNIT
+FEATURE_EXCLUDE_LIST = $(sort $(_FEATURE_EXCLUDE_LIST))
+
+# Tools
+
+# Conditionally Replaces DEFAULT var
+ifeq ($(origin CC),default)
+CC = $(LSRUN) $(CROSS_COMPILE)gcc
+endif
+
+ifeq ($(origin CXX),default)
+CXX = $(CROSS_COMPILE)g++
+endif
+
+ifeq ($(origin LD),default)
+LD = $(CROSS_COMPILE)ld
+endif
+
+ifeq ($(origin AR),default)
+AR = $(CROSS_COMPILE)ar
+endif
+
+ifeq ($(origin AS),default)
+AS = $(CROSS_COMPILE)as
+endif
+
+ifeq ($(origin ARFLAGS),default)
+ ARFLAGS = -rc
+endif
+
+STRIP = $(CROSS_COMPILE)strip
+RANLIB = $(CROSS_COMPILE)ranlib
+OBJCOPY = $(CROSS_COMPILE)objcopy
+NM = $(CROSS_COMPILE)nm
+
+# Handle differences between gcc 2.x and gcc 3.x
+gcc-tune-flag = $(shell if ${CC} -dumpspecs | grep mcpu >/dev/null; then echo cpu; else echo tune; fi)
+
+# Configuration Variables
+
+# OSType Defines: This defines the type of RTOS or microkernel which you
+# are compiling the SAL (and its associated driver) for. New platforms
+# can be created by porting the routines (system.c) to your platform and
+# adding the define in this Makefile.
+
+OSTYPE = LINUX
+
+#
+# ORIGIN is used to Optionally select different CFLAGS. It is used to import
+# source from other vendors. If SOURCE=Broadcom, then the BCM_ flags are added
+# to those passed to the compiler. If SOURCE != Broadcom, BCM_ flags are NOT
+# added.
+#
+# Default specifies Broadcom
+#
+ifndef ORIGIN
+ ORIGIN = Broadcom
+endif
+
+#
+# STD_{C|CPP|CXX}FLAGS - Standard flags used by ALL compilations
+# BCM_{C|CPP|CXX}FLAGS - Flags used for Broadcom source files
+# OPT_{C|CPP|CXX}FLAGS - Defined in local make files BEFORE inclusion of
+# this Makefile, to define local "Extra" flags.
+#
+
+ifdef IPROC_BUILD
+CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \
+ -I$(SDK)/systems/bde/linux/include \
+ -I$(LINUX_INCLUDE) \
+ -I$(KERNDIR)/arch/$(ARCH)
+else
+CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \
+ -I$(SDK)/systems/bde/linux/include \
+ -I$(LINUX_INCLUDE) \
+ -I$(LINUX_INCLUDE)/asm/gcc \
+ -I$(LINUX_INCLUDE)/asm/mach-generic \
+ -I$(KERNDIR)/arch/$(ARCH)
+endif
+
+CFGFLAGS += -DNO_FILEIO -DNO_CTRL_C -DNO_MEMTUNE
+
+CFGFLAGS += -D$(OSTYPE)
+
+# No user sal for the linux kernel
+# NO_SAL_APPL=1
+
+STD_CFLAGS = $(KFLAGS) $(CFGFLAGS)
+
+
+STD_CPPFLAGS = ${STD_CFLAGS}
+STD_CXXFLAGS = ${STD_CFLAGS}
+
+ifndef BCM_CFLAGS
+BCM_CFLAGS = -Wall -Werror
+endif
+
+BCM_CPPFLAGS = ${BCM_CFLAGS}
+BCM_CXXFLAGS = ${BCM_CFLAGS}
+
+ifeq (${ORIGIN}, Broadcom)
+ CFLAGS += ${STD_CFLAGS} ${BCM_CFLAGS} ${OPT_CFLAGS}
+ CPPFLAGS += ${STD_CPPFLAGS} ${BCM_CPPFLAGS} ${OPT_CPPFLAGS}
+ CXXFLAGS += ${STD_CXXFLAGS} ${BCM_CXXFLAGS} ${OPT_CXXFLAGS}
+else
+ CFLAGS += ${STD_CFLAGS} ${OPT_CFLAGS}
+ CPPFLAGS += ${STD_CPPFLAGS} ${OPT_CPPFLAGS}
+ CXXFLAGS += ${STD_CXXFLAGS} ${OPT_CXXFLAGS}
+endif
+
+#
+# Ignore pedantic flag for kernel modules
+#
+ifdef DEBUG_PEDANTIC
+DEBUG_PEDANTIC = FALSE
+endif
+
+#
+# DEPEND is used as a command to generate the list of dependencies.
+# The format of the output must be
+# "file.o : file.c a/b/c.h d/e/f.h ...",
+# if it is on multiple lines, each line must end in a backslash.
+# The output MUST be on standard out.
+#
+DEPEND = ${CC} -M $(CFLAGS) $<
diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel-3_6 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel-3_6
@@ -0,0 +1,148 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-kernel-3_6,v 1.2 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+# Configuration Flags
+
+# Filter out features that cannot or should not be supported in kernel mode
+
+_FEATURE_EXCLUDE_LIST += EDITLINE TCL OOB_RCPU CINT APIMODE DUNE_UI
+FEATURE_EXCLUDE_LIST = $(sort $(_FEATURE_EXCLUDE_LIST))
+
+# Tools
+
+# Conditionally Replaces DEFAULT var
+ifeq ($(origin CC),default)
+CC = $(LSRUN) $(CROSS_COMPILE)gcc
+endif
+
+ifeq ($(origin CXX),default)
+CXX = $(CROSS_COMPILE)g++
+endif
+
+ifeq ($(origin LD),default)
+LD = $(CROSS_COMPILE)ld
+endif
+
+ifeq ($(origin AR),default)
+AR = $(CROSS_COMPILE)ar
+endif
+
+ifeq ($(origin AS),default)
+AS = $(CROSS_COMPILE)as
+endif
+
+ifeq ($(origin ARFLAGS),default)
+ ARFLAGS = -rc
+endif
+
+STRIP = $(CROSS_COMPILE)strip
+RANLIB = $(CROSS_COMPILE)ranlib
+OBJCOPY = $(CROSS_COMPILE)objcopy
+NM = $(CROSS_COMPILE)nm
+
+# Handle differences between gcc 2.x and gcc 3.x
+gcc-tune-flag = $(shell if ${CC} -dumpspecs | grep mcpu >/dev/null; then echo cpu; else echo tune; fi)
+
+# Configuration Variables
+
+# OSType Defines: This defines the type of RTOS or microkernel which you
+# are compiling the SAL (and its associated driver) for. New platforms
+# can be created by porting the routines (system.c) to your platform and
+# adding the define in this Makefile.
+
+OSTYPE = LINUX
+
+#
+# ORIGIN is used to Optionally select different CFLAGS. It is used to import
+# source from other vendors. If SOURCE=Broadcom, then the BCM_ flags are added
+# to those passed to the compiler. If SOURCE != Broadcom, BCM_ flags are NOT
+# added.
+#
+# Default specifies Broadcom
+#
+ifndef ORIGIN
+ ORIGIN = Broadcom
+endif
+
+#
+# STD_{C|CPP|CXX}FLAGS - Standard flags used by ALL compilations
+# BCM_{C|CPP|CXX}FLAGS - Flags used for Broadcom source files
+# OPT_{C|CPP|CXX}FLAGS - Defined in local make files BEFORE inclusion of
+# this Makefile, to define local "Extra" flags.
+#
+
+ifdef IPROC_BUILD
+CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \
+ -I$(SDK)/systems/bde/linux/include \
+ -I$(LINUX_INCLUDE) \
+ -I$(KERNDIR)/arch/$(ARCH)
+else
+CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \
+ -I$(SDK)/systems/bde/linux/include \
+ -I$(LINUX_INCLUDE) \
+ -I$(LINUX_INCLUDE)/asm/gcc \
+ -I$(LINUX_INCLUDE)/asm/mach-generic \
+ -I$(KERNDIR)/arch/$(ARCH)
+endif
+
+CFGFLAGS += -DNO_FILEIO -DNO_CTRL_C -DNO_MEMTUNE
+
+CFGFLAGS += -D$(OSTYPE)
+
+# No user sal for the linux kernel
+# NO_SAL_APPL=1
+
+STD_CFLAGS = $(KFLAGS) $(CFGFLAGS)
+
+
+STD_CPPFLAGS = ${STD_CFLAGS}
+STD_CXXFLAGS = ${STD_CFLAGS}
+
+ifndef BCM_CFLAGS
+BCM_CFLAGS = -Wall -Werror
+endif
+
+BCM_CPPFLAGS = ${BCM_CFLAGS}
+BCM_CXXFLAGS = ${BCM_CFLAGS}
+
+ifeq (${ORIGIN}, Broadcom)
+ CFLAGS += ${STD_CFLAGS} ${BCM_CFLAGS} ${OPT_CFLAGS}
+ CPPFLAGS += ${STD_CPPFLAGS} ${BCM_CPPFLAGS} ${OPT_CPPFLAGS}
+ CXXFLAGS += ${STD_CXXFLAGS} ${BCM_CXXFLAGS} ${OPT_CXXFLAGS}
+else
+ CFLAGS += ${STD_CFLAGS} ${OPT_CFLAGS}
+ CPPFLAGS += ${STD_CPPFLAGS} ${OPT_CPPFLAGS}
+ CXXFLAGS += ${STD_CXXFLAGS} ${OPT_CXXFLAGS}
+endif
+
+#
+# Ignore pedantic flag for kernel modules
+#
+ifdef DEBUG_PEDANTIC
+DEBUG_PEDANTIC = FALSE
+endif
+
+#
+# DEPEND is used as a command to generate the list of dependencies.
+# The format of the output must be
+# "file.o : file.c a/b/c.h d/e/f.h ...",
+# if it is on multiple lines, each line must end in a backslash.
+# The output MUST be on standard out.
+#
+DEPEND = ${CC} -M $(CFLAGS) $<
diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel-4_4 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kernel-4_4
@@ -0,0 +1,157 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-kernel-2_6,v 1.40 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+# Configuration Flags
+
+# Filter out features that cannot or should not be supported in kernel mode
+
+_FEATURE_EXCLUDE_LIST += EDITLINE TCL OOB_RCPU CINT APIMODE DUNE_UI C_UNIT
+FEATURE_EXCLUDE_LIST = $(sort $(_FEATURE_EXCLUDE_LIST))
+
+# Tools
+
+# Conditionally Replaces DEFAULT var
+ifeq ($(origin CC),default)
+CC = $(LSRUN) $(CROSS_COMPILE)gcc
+endif
+
+ifeq ($(origin CXX),default)
+CXX = $(CROSS_COMPILE)g++
+endif
+
+ifeq ($(origin LD),default)
+LD = $(CROSS_COMPILE)ld
+endif
+
+ifeq ($(origin AR),default)
+AR = $(CROSS_COMPILE)ar
+endif
+
+ifeq ($(origin AS),default)
+AS = $(CROSS_COMPILE)as
+endif
+
+ifeq ($(origin ARFLAGS),default)
+ ARFLAGS = -rc
+endif
+
+STRIP = $(CROSS_COMPILE)strip
+RANLIB = $(CROSS_COMPILE)ranlib
+OBJCOPY = $(CROSS_COMPILE)objcopy
+NM = $(CROSS_COMPILE)nm
+
+# Handle differences between gcc 2.x and gcc 3.x
+gcc-tune-flag = $(shell if ${CC} -dumpspecs | grep mcpu >/dev/null; then echo cpu; else echo tune; fi)
+
+# Configuration Variables
+
+# OSType Defines: This defines the type of RTOS or microkernel which you
+# are compiling the SAL (and its associated driver) for. New platforms
+# can be created by porting the routines (system.c) to your platform and
+# adding the define in this Makefile.
+OSTYPE = LINUX
+
+#
+# ORIGIN is used to Optionally select different CFLAGS. It is used to import
+# source from other vendors. If SOURCE=Broadcom, then the BCM_ flags are added
+# to those passed to the compiler. If SOURCE != Broadcom, BCM_ flags are NOT
+# added.
+#
+# Default specifies Broadcom
+#
+ifndef ORIGIN
+ ORIGIN = Broadcom
+endif
+
+#
+# STD_{C|CPP|CXX}FLAGS - Standard flags used by ALL compilations
+# BCM_{C|CPP|CXX}FLAGS - Flags used for Broadcom source files
+# OPT_{C|CPP|CXX}FLAGS - Defined in local make files BEFORE inclusion of
+# this Makefile, to define local "Extra" flags.
+#
+ifdef IPROC_BUILD
+CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \
+ -I$(SDK)/systems/bde/linux/include \
+ -I$(LINUX_INCLUDE) \
+ -I$(LINUX_INCLUDE)/uapi \
+ -I$(LINUX_INCLUDE)/generated/uapi \
+ -I$(KERNDIR)/arch/$(ARCH) \
+ -I$(KERNDIR)/arch/$(ARCH)/include/uapi \
+ -I$(KERNDIR)/arch/$(ARCH)/include/generated \
+ -I$(KERNDIR)/arch/$(ARCH)/include/generated/uapi
+else
+CFGFLAGS += -I$(SDK)/systems/linux/kernel/modules/include \
+ -I$(SDK)/systems/bde/linux/include \
+ -I$(LINUX_INCLUDE) \
+ -I$(LINUX_INCLUDE)/asm/gcc \
+ -I$(LINUX_INCLUDE)/asm/mach-generic \
+ -I$(LINUX_INCLUDE)/uapi \
+ -I$(LINUX_INCLUDE)/generated/uapi \
+ -I$(KERNDIR)/arch/$(ARCH) \
+ -I$(KERNDIR)/arch/$(ARCH)/include/uapi \
+ -I$(KERNDIR)/arch/$(ARCH)/include/generated \
+ -I$(KERNDIR)/arch/$(ARCH)/include/generated/uapi
+endif
+
+CFGFLAGS += -DNO_FILEIO -DNO_CTRL_C -DNO_MEMTUNE
+
+CFGFLAGS += -D$(OSTYPE)
+
+# No user sal for the linux kernel
+# NO_SAL_APPL=1
+
+STD_CFLAGS = $(KFLAGS) $(CFGFLAGS)
+
+
+STD_CPPFLAGS = ${STD_CFLAGS}
+STD_CXXFLAGS = ${STD_CFLAGS}
+
+ifndef BCM_CFLAGS
+BCM_CFLAGS = -Wall -Werror
+endif
+
+BCM_CPPFLAGS = ${BCM_CFLAGS}
+BCM_CXXFLAGS = ${BCM_CFLAGS}
+
+ifeq (${ORIGIN}, Broadcom)
+ CFLAGS += ${STD_CFLAGS} ${BCM_CFLAGS} ${OPT_CFLAGS}
+ CPPFLAGS += ${STD_CPPFLAGS} ${BCM_CPPFLAGS} ${OPT_CPPFLAGS}
+ CXXFLAGS += ${STD_CXXFLAGS} ${BCM_CXXFLAGS} ${OPT_CXXFLAGS}
+else
+ CFLAGS += ${STD_CFLAGS} ${OPT_CFLAGS}
+ CPPFLAGS += ${STD_CPPFLAGS} ${OPT_CPPFLAGS}
+ CXXFLAGS += ${STD_CXXFLAGS} ${OPT_CXXFLAGS}
+endif
+
+#
+# Ignore pedantic flag for kernel modules
+#
+ifdef DEBUG_PEDANTIC
+DEBUG_PEDANTIC = FALSE
+endif
+
+#
+# DEPEND is used as a command to generate the list of dependencies.
+# The format of the output must be
+# "file.o : file.c a/b/c.h d/e/f.h ...",
+# if it is on multiple lines, each line must end in a backslash.
+# The output MUST be on standard out.
+#
+DEPEND = ${CC} -M $(CFLAGS) $<
+
diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kmodule b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-kmodule
@@ -0,0 +1,81 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-kmodule-3_6,v 1.2 Broadcom SDK $
+# $Copyright: (c) 2006 Broadcom Corp.
+# All Rights Reserved.$
+
+# Due to the extensive use of driver libraries, the SDK usually builds
+# kernel modules from a precompiled object. To avoid various warnings
+# and conflicts, the pre-compiled object must be named differently
+# from the target module, and the object file itself should be
+# appended with "_shipped".
+
+# If a module exports any symbols, then the exporting source file must
+# be compiled within the kernel source tree for correct generation of
+# module symbol versions. The symbol source file should be passed to
+# this Makefile via the MODULE_SYM variable.
+
+MODULE := $(MOD_NAME).o
+KMODULE := $(MOD_NAME).ko
+PRE_COMPILED_OBJ := obj_$(MOD_NAME).o
+
+obj-m := $(MODULE)
+$(MOD_NAME)-y := $(MODULE_SYM) $(PRE_COMPILED_OBJ)
+
+
+ifeq (,$(CROSS_COMPILE))
+
+export CROSS_COMPILE
+
+endif
+
+SAVE_CFLAGS := ${CFLAGS}
+
+include $(SDK)/make/Make.config
+
+PWD := $(shell pwd)
+
+ifneq ($(ARCH),)
+# ELDK does not seem to `automatically' define ARCH where other gccs may
+A := ARCH=$(ARCH)
+export ARCH
+endif
+
+# Provide an option in case kernel was built in separate directory
+KERNBLDDIR ?= $(KERNDIR)
+
+# Standard SDK include path for building source files that export
+# kernel symbols.
+
+override EXTRA_CFLAGS = -I${SDK}/include -I${SDK}/systems/linux/kernel/modules/include -I${SDK}/systems/bde/linux/include
+
+# The precopiled object needs a dummy command file to avoid warnings
+# from the Kbuild scripts (modpost stage).
+# Kernels before 2.6.17 do not support external module symbols files,
+# so we create a dummy to prevent build failures.
+
+$(KMODULE):
+ rm -f *.o *.ko .*.cmd
+ rm -fr .tmp_versions
+ ln -s $(LIBDIR)/$(MODULE) $(PRE_COMPILED_OBJ)_shipped
+ if [ ! -f $(KERNBLDDIR)/NO_SUPRESS ]; then echo "# suppress warning" > .$(PRE_COMPILED_OBJ).cmd; fi
+ $(MAKE) -C $(KERNBLDDIR) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) modules
+ if [ ! -f Module.symvers ]; then echo "old kernel (pre-2.6.17)" > Module.symvers; fi
+ cp -f $(KMODULE) $(LIBDIR)
+ rm -f $(PRE_COMPILED_OBJ)_shipped
+
+EXTRA_CFLAGS = $(CFLAGS)
+CFLAGS := ${SAVE_CFLAGS}
diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-slk b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-slk
@@ -0,0 +1,146 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-slk-3_14,v 1.2 Broadcom SDK $
+# $Copyright: (c) 2013 Broadcom Corp.
+# All Rights Reserved.$
+# Makefile for SLK(BCM957812)
+
+# User must select one platform from below.By default ARM_LINUX is selected. .
+ifeq (,$(BUILD_PLATFORM))
+BUILD_PLATFORM=ARM_LINUX
+endif
+
+# Toolchain base directory for NS2 XMC card
+ifeq (BE,$(ENDIAN_MODE))
+TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/toolchains/slk/linaro-be
+TARGET_ARCHITECTURE:=aarch64_be-linux-gnu
+KERNDIR ?= /projects/ntsw-tools/linux/iproc_ldks/slk-be/poky/brcm-released-source/git
+else
+TOOLCHAIN_BASE_DIR ?= /projects/ntsw-tools/toolchains/slk/linaro-le
+# Compiler for target architecture
+TARGET_ARCHITECTURE:= aarch64-linux-gnu
+# Kernel directory
+KERNDIR ?= /projects/ntsw-tools/linux/iproc_ldks/slk/poky/brcm-released-source/git
+endif
+
+ifeq (,$(CROSS_COMPILE))
+CROSS_COMPILE:= $(TARGET_ARCHITECTURE)-
+endif
+
+# armtools
+TOOLCHAIN_BIN_DIR=$(TOOLCHAIN_BASE_DIR)/bin
+override PATH:=$(TOOLCHAIN_BIN_DIR):$(PATH)
+LD_LIBRARY_PATH=$(TOOLCHAIN_BASE_DIR)/lib
+
+export TOOLCHAIN_BIN_DIR LD_LIBRARY_PATH
+
+# Default Linux include directory
+ifeq (,$(LINUX_INCLUDE))
+LINUX_INCLUDE := $(KERNDIR)/include
+endif
+
+ifeq (BE,$(ENDIAN_MODE))
+CFGFLAGS += -DSYS_BE_PIO=1 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=1
+ENDIAN = BE_HOST=1
+else
+CFGFLAGS += -DSYS_BE_PIO=0 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=0
+ENDIAN = LE_HOST=1
+endif
+
+CFGFLAGS += -D$(ENDIAN) -DBCM958525
+CFGFLAGS += -DBCM_PLATFORM_STRING=\"SLK_BCM957812\"
+CFGFLAGS += -DSAL_BDE_DMA_MEM_DEFAULT=32
+ifeq (1,$(SLK_32BIT))
+CFGFLAGS += -DSAL_BDE_32BIT_USER_64BIT_KERNEL
+else
+CFGFLAGS += -DPTRS_ARE_64BITS -DLONGS_ARE_64BITS
+endif
+CFGFLAGS += -DPHYS_ADDRS_ARE_64BITS
+
+CFLAGS += -Wno-unused-value -Wno-unused-but-set-variable -Wno-sizeof-pointer-memaccess -fno-aggressive-loop-optimizations
+
+ifdef DPP_CHIPS
+CFLAGS += -DDUNE_BCM -D__DUNE_LINUX_BCM_CPU_PCP_DMA__
+CFGFLAGS += -DSOC_CM_FUNCTION
+endif
+
+ifdef DFE_CHIPS
+CFLAGS += -DDUNE_BCM
+CFGFLAGS += -DSOC_CM_FUNCTION
+endif
+
+ifdef SAND_CHIPS
+CFLAGS += -D__DUNE_SLK_BCM_CPU__ -D__DUNE_LINUX_BCM_CPU_PCIE__
+endif
+
+# Enable cached DMA memory by default
+ifeq (,$(SAL_BDE_USE_CACHED_DMA_MEM))
+SAL_BDE_USE_CACHED_DMA_MEM = 1
+endif
+ifeq ($(SAL_BDE_USE_CACHED_DMA_MEM),1)
+CFGFLAGS += -DSAL_BDE_CACHE_DMA_MEM
+endif
+
+ifeq (1,$(SLK_32BIT))
+ARCH = arm
+else
+ARCH = arm64
+endif
+
+KBUILD_VERBOSE = 1
+
+export ARCH KBUILD_VERBOSE
+
+comma = ,
+basetarget = $(basename $(notdir $@))
+modname = $(basetarget)
+
+# Extra variables.
+EXTRA_CFLAGS = -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+
+name-fix = $(subst $(comma),_,$(subst -,_,$1))
+basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
+modname_flags = $(if $(filter 1,$(words $(modname))),\
+ -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+
+KFLAG_INCLD = $(TOOLCHAIN_BASE_DIR)/lib/gcc/$(TARGET_ARCHITECTURE)/4.9.2/include
+
+ifeq (,$(KFLAGS))
+KFLAGS := -D__LINUX_ARM_ARCH__=8 -D__KERNEL__ -DPTRS_ARE_64BITS -DLONGS_ARE_64BITS -nostdinc -isystem $(KFLAG_INCLD) -I$(LINUX_INCLUDE) -include $(LINUX_INCLUDE)/generated/autoconf.h -I$(KERNDIR)/arch/arm64/include -I$(KERNDIR)/arch/arm64/include/generated -I$(KERNDIR)/arch/arm64/include/generated/asm -I$(KERNDIR)/include/uapi -I$(KERNDIR)/include/generated/uapi -I$(KERNDIR)/arch/arm64/include/uapi -Wall -Wstrict-prototypes -Wno-trigraphs -Os -fno-strict-aliasing -fno-common -fno-pic -pipe -ffreestanding -fomit-frame-pointer -g -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign
+endif
+
+ifdef LTSW_CHIPS
+# Default open source target build
+ifeq (BE,$(ENDIAN_MODE))
+OPENSRC_BUILD ?= linaro_arm64_be
+else
+OPENSRC_BUILD ?= linaro_arm64_le
+endif
+
+# Hardware interface (see $SDKLT/bcma/sys/probe directory)
+SYSTEM_INTERFACE ?= ngbde
+
+# Turn on direct register access if running on real hardware.
+ifeq (ngbde,$(SYSTEM_INTERFACE))
+LTSW_ADD_CPPFLAGS += -DBCMDRD_CONFIG_MEMMAP_DIRECT=1
+endif
+
+export SYSTEM_INTERFACE
+endif
+
+ifneq ($(targetplat),user)
+include ${SDK}/make/Makefile.linux-kernel-3_6
+endif
diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-x86-common-2_6 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-x86-common-2_6
@@ -0,0 +1,44 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-x86-common-2_6,v 1.13 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+CFGFLAGS += -DSYS_BE_PIO=0 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=0
+ENDIAN = LE_HOST=1
+CFGFLAGS += -D$(ENDIAN)
+CFGFLAGS += -DBCM_PLATFORM_STRING=\"X86\"
+ifeq (,$(findstring -DSAL_BDE_DMA_MEM_DEFAULT,$(CFGFLAGS)))
+CFGFLAGS += -DSAL_BDE_DMA_MEM_DEFAULT=16
+endif
+
+# Extra variables.
+EXTRA_CFLAGS = -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+
+comma = ,
+basetarget = $(basename $(notdir $@))
+modname = $(basetarget)
+
+name-fix = $(subst $(comma),_,$(subst -,_,$1))
+basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
+modname_flags = $(if $(filter 1,$(words $(modname))),\
+-D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+
+ifneq ($(targetplat),user)
+# By default we exclude -Werror from x86 kernel builds
+BCM_CFLAGS = -Wall
+include ${SDK}/make/Makefile.linux-kernel-2_6
+endif
diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-x86-generic-common-2_6 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-x86-generic-common-2_6
@@ -0,0 +1,51 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-x86-generic-common-2_6,v 1.2 Broadcom SDK $
+# $Copyright: (c) 2008 Broadcom Corp.
+# All Rights Reserved.$
+
+# Default kernel source directory
+ifeq (,$(KERNDIR))
+KERNDIR := /lib/modules/$(shell uname -r)/build
+export KERNDIR
+endif
+
+# Default architecture
+ifeq (,$(ARCH))
+ARCH = $(shell uname -p)
+ifneq (x86_64,$(ARCH))
+ARCH = i386
+endif
+endif
+
+# Noisy kernel build
+KBUILD_VERBOSE = 1
+
+export ARCH KBUILD_VERBOSE KERNDIR
+
+# Default Linux include directory
+ifeq (,$(LINUX_INCLUDE))
+LINUX_INCLUDE := $(KERNDIR)/include
+endif
+
+# autoconf.h was moved in later kernels
+AUTOCONF = $(KERNDIR)/include/generated/autoconf.h
+ifeq (,$(shell ls $(AUTOCONF) 2>/dev/null))
+AUTOCONF = $(KERNDIR)/include/linux/autoconf.h
+endif
+
+# gcc system include path
+SYSINC = $(shell $(CC) -print-search-dirs | grep install | cut -c 10-)include
diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-x86-smp_generic_64-2_6 b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-x86-smp_generic_64-2_6
@@ -0,0 +1,56 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-x86-smp_generic_64-2_6,v 1.5 Broadcom SDK $
+# $Copyright: (c) 2008 Broadcom Corp.
+# All Rights Reserved.$
+
+CFGFLAGS += -DLONGS_ARE_64BITS
+CFGFLAGS += -DPTRS_ARE_64BITS
+CFGFLAGS += -DPHYS_ADDRS_ARE_64BITS
+CFGFLAGS += -DSAL_SPL_LOCK_ON_IRQ
+
+include ${SDK}/make/Makefile.linux-x86-generic-common-2_6
+
+ifeq (,$(KFLAGS))
+KFLAGS := -nostdinc -isystem $(SYSINC) -I$(KERNDIR)/include -I$(KERNDIR)/arch/x86/include -include $(AUTOCONF) -D__KERNEL__ -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -fno-delete-null-pointer-checks -Os -m64 -mtune=generic -mno-red-zone -fno-pie -mcmodel=kernel -funit-at-a-time -maccumulate-outgoing-args -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -fno-stack-protector -fomit-frame-pointer -g -Wdeclaration-after-statement -Wno-pointer-sign
+endif
+
+
+LINUX_UAPI = $(LINUX_INCLUDE)/uapi
+ifneq (,$(shell ls $(LINUX_UAPI) 2>/dev/null))
+KFLAGS += -I$(LINUX_INCLUDE)/uapi -I$(LINUX_INCLUDE)/generated/uapi -I$(KERNDIR)/arch/x86/include/generated -I$(KERNDIR)/arch/x86/include/uapi -I$(KERNDIR)/arch/x86/include/generated/uapi
+endif
+
+ifdef LTSW_CHIPS
+# Ensure we do not use an out-of-date libelf.so
+ELFUTILS_MIN = 158
+ELFUTILS_DIR ?= /projects/ntsw-tools/lib
+
+# Default open source target build
+OPENSRC_BUILD ?= x86_64
+
+# Hardware interface (see $SDKLT/bcma/sys/probe directory)
+SYSTEM_INTERFACE ?= ngbde
+
+# Turn on direct register access if running on real hardware.
+ifeq (ngbde,$(SYSTEM_INTERFACE))
+LTSW_ADD_CPPFLAGS += -DBCMDRD_CONFIG_MEMMAP_DIRECT=1
+endif
+
+export SYSTEM_INTERFACE
+endif
+
+include ${SDK}/make/Makefile.linux-x86-common-2_6
diff --git a/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-xlr b/sdk-6.5.20/src/gpl-modules/make/Makefile.linux-xlr
@@ -0,0 +1,142 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# $Id: Makefile.linux-xlr-4_19,v 0.1 Broadcom SDK $
+# $Copyright: (c) 2015 Broadcom Corp.
+# All Rights Reserved.$
+
+#
+# XLR system make file.
+#
+# Most of this was taken from target x86-smp_generic_64-2_6.
+#
+
+
+#############################################################################
+# this segment is custom and not sourced from any existing makefile #
+# (base thanks to http:<slash><slash>confluence.broadcom.com/display/NTSWSW/X86+System) #
+#############################################################################
+
+# set up a basic feature list. tcl, etc. #
+#ifeq (,$(FEATURE_LIST))
+#FEATURE_LIST = TCL BFD PTP CINT L3 I2C MEM_SCAN EDITLINE BCM_SAL_PROFILE CUSTOMER TEST CHASSIS MSTP RCPU
+#endif
+
+# some basic path variables for tools and kernel source, etc #
+export XLR_TOOLS_BASE = /projects/ntsw-tools/linux/xlr-419
+TOOLCHAIN_DIR = $(XLR_TOOLS_BASE)/buildroot/host/usr
+KERNDIR = $(XLR_TOOLS_BASE)/kernel/linux
+
+# set up cross compile prefix, tools dir variables. #
+export CROSS_COMPILE := x86_64-broadcom-linux-gnu-
+export TOOLS_DIR := $(TOOLCHAIN_DIR)/bin
+
+# architecture. #
+ARCH = x86_64
+TARGET_ARCHITECTURE = x86_64-broadcom-linux-gnu
+
+# Noisy kernel build
+KBUILD_VERBOSE = 1
+
+export ARCH KBUILD_VERBOSE
+
+# set up paths. #
+export LIBRARY_PATH := $(TOOLCHAIN_DIR)/lib:$(TOOLCHAIN_DIR)/lib64:$(LIBRARY_PATH)
+export PATH := $(TOOLCHAIN_DIR)/bin:$(KERNDIR):$(PATH)
+
+# set up SYSINC path #
+export SYSINC := $(XLR_TOOLS_BASE)/buildroot/host/usr/lib/gcc/$(TARGET_ARCHITECTURE)/5.4.0/include
+
+
+# CFLAGS/CFGFLAGS #
+CFLAGS += -DUSE_LINUX_BDE_MMAP=1
+#CFLAGS += -DBDE_LINUX_USE_MSI_INTERRUPT
+CFLAGS += -Wno-error=unused-value
+CFLAGS += -Wno-error=unused-but-set-variable
+CFLAGS += -Wno-error=maybe-uninitialized
+CFLAGS += -Wno-error=cpp
+CFLAGS += -Wno-error=aggressive-loop-optimizations
+CFLAGS += -Wno-error=array-bounds
+CFLAGS += -Wno-error=strict-overflow
+CFLAGS += -L$(TOOLCHAIN_DIR)/lib
+CFLAGS += -L$(TOOLCHAIN_DIR)/lib64
+#CFLAGS += -Wl,--rpath=/lib64 # may need to set rpath and dynamic-linker path here (and possibly in KLFAGS below) in the future, #
+#CFLAGS += -Wl,--dynamic-linker=/lib64/ld-linux-x86-64.so.2 # if we want to build the target executable to be used with shared libs #
+
+#XLDK-568 fix inline references
+CFGFLAGS += -fgnu89-inline
+
+
+# set up KFLAGS appropriately. #
+ifeq (,$(KFLAGS))
+KFLAGS := -L$(TOOLCHAIN_DIR)/lib -L$(TOOLCHAIN_DIR)/lib64 -I$(KERNDIR) -lc -nostdinc -isystem $(SYSINC) -Iinclude -I$(KERNDIR)/arch/x86/include -I$(KERNDIR)/arch/x86/include/generated -I$(KERNDIR)/arch/x86/include/generated/uapi -I$(KERNDIR)/arch/x86/include/uapi -I$(KERNDIR)/include -I$(KERNDIR)/include/generated -I$(KERNDIR)/include/generated/uapi -I$(KERNDIR)/include/uapi -include $(KERNDIR)/include/generated/autoconf.h -D__KERNEL__ -DNDEBUG -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Wno-format-security -fno-delete-null-pointer-checks -O2 -m64 -mtune=generic -mno-red-zone -mcmodel=kernel -funit-at-a-time -maccumulate-outgoing-args -fstack-protector -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -Wframe-larger-than=1024 -fno-omit-frame-pointer -Wdeclaration-after-statement -Wno-pointer-sign -fno-dwarf2-cfi-asm -fconserve-stack
+endif
+
+
+######################################################################
+# this segment comes from make/Makefile.linux-x86-smp_generic_64-2_6 #
+######################################################################
+CFGFLAGS += -DLONGS_ARE_64BITS
+CFGFLAGS += -DPTRS_ARE_64BITS
+CFGFLAGS += -DSAL_SPL_LOCK_ON_IRQ
+
+
+##############################################################
+# This segment comes from make/Makefile.linux-x86-common-2_6 #
+##############################################################
+CFGFLAGS += -DSYS_BE_PIO=0 -DSYS_BE_PACKET=0 -DSYS_BE_OTHER=0
+ENDIAN = LE_HOST=1
+CFGFLAGS += -D$(ENDIAN)
+CFGFLAGS += -DBCM_PLATFORM_STRING=\"X86\"
+CFGFLAGS += -DSAL_BDE_DMA_MEM_DEFAULT=32
+
+# Extra variables.
+EXTRA_CFLAGS = -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+
+comma = ,
+basetarget = $(basename $(notdir $@))
+modname = $(basetarget)
+
+name-fix = $(subst $(comma),_,$(subst -,_,$1))
+basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
+modname_flags = $(if $(filter 1,$(words $(modname))),\
+-D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+
+ifdef LTSW_CHIPS
+# Ensure we do not use an out-of-date libelf.so
+ELFUTILS_MIN = 158
+ELFUTILS_DIR ?= /projects/ntsw-tools/lib
+
+# Default open source target build
+OPENSRC_BUILD ?= fed21-x86_64
+
+# Hardware interface (see $SDKLT/bcma/sys/probe directory)
+SYSTEM_INTERFACE ?= ngbde
+
+# Turn on direct register access if running on real hardware.
+ifeq (ngbde,$(SYSTEM_INTERFACE))
+LTSW_ADD_CPPFLAGS += -DBCMDRD_CONFIG_MEMMAP_DIRECT=1
+endif
+
+export SYSTEM_INTERFACE
+endif
+
+ifneq ($(targetplat),user)
+# By default we exclude -Werror from x86 kernel builds
+BCM_CFLAGS = -Wall
+include ${SDK}/make/Makefile.linux-kernel-2_6
+endif
+
+
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/linux/include/linux-bde.h b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/include/linux-bde.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/***********************************************************************
+ *
+ * $Id: linux-bde.h,v 1.24 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ * Linux Broadcom Device Enumerators
+ *
+ *
+ * There are two Linux BDEs:
+ *
+ * 1. Linux Kernel BDE
+ *
+ * This is a kernel module implementing a BDE
+ * for the driver running as part of the kernel.
+ *
+ * It manages the devices through the linux PCI interfaces,
+ * and manages a chunk of contiguous, boot-time allocated
+ * DMA memory. This is all that is needed if the BCM driver
+ * is run as part of the kernel (in another module).
+ *
+ * 2. Linux User BDE
+ *
+ * This is a kernel module and userland library which implement
+ * a complete BDE for applications running in userland.
+ *
+ * The kernel module relies upon the real kernel bde,
+ * and allows a user space application (through the user library)
+ * to talk directly to the devices. It also virtualized the device
+ * interrupts, so the entire driver can be run as a userspace
+ * application.
+ *
+ * While this causes a significant degradation in performance,
+ * because the system runs as a user application, the development
+ * and debugging process is about a gillion times easier.
+ * After the core logic is debugged, it can be retargeted using
+ * only the kernel bde and run in the kernel.
+ *
+ *
+ **********************************************************************/
+
+#ifndef __LINUX_BDE_H__
+#define __LINUX_BDE_H__
+
+#include <sal/types.h>
+
+#include <ibde.h>
+
+
+/*
+ * Device Major Numbers
+ *
+ * The kernel and user bdes need unique major numbers
+ * on systems that do not use devfs.
+ *
+ * They are defined here, along with the module names,
+ * to document them if you need to mknod them (or open) them,
+ * and to keep them unique.
+ *
+ */
+
+#include <linux/version.h>
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+/* Key stone and Raptor has 2.6.21 but don't have definition */
+#if defined(KEYSTONE) || defined(RAPTOR)
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21))
+ #ifdef PHYS_ADDRS_ARE_64BITS
+ typedef u64 phys_addr_t;
+ #else
+ typedef u32 phys_addr_t;
+ #endif
+ #endif
+#endif
+#endif
+
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))
+#define LINUX_BDE_DMA_DEVICE_SUPPORT
+#endif
+
+#define LINUX_KERNEL_BDE_NAME "linux-kernel-bde"
+#define LINUX_KERNEL_BDE_MAJOR 127
+
+#define LINUX_USER_BDE_NAME "linux-user-bde"
+#define LINUX_USER_BDE_MAJOR 126
+
+
+/* Max devices */
+/* 16 switch chips + 2 out-of-band Ethernet + 2 CPUs */
+#define LINUX_BDE_MAX_SWITCH_DEVICES 16
+#define LINUX_BDE_MAX_ETHER_DEVICES 2
+#define LINUX_BDE_MAX_CPU_DEVICES 2
+#define LINUX_BDE_MAX_DEVICES (LINUX_BDE_MAX_SWITCH_DEVICES + \
+ LINUX_BDE_MAX_ETHER_DEVICES + \
+ LINUX_BDE_MAX_CPU_DEVICES)
+
+/*
+ * PCI devices will be initialized by the Linux Kernel,
+ * regardless of architecture.
+ *
+ * You need only provide bus endian settings.
+ */
+
+typedef struct linux_bde_bus_s {
+ int be_pio;
+ int be_packet;
+ int be_other;
+} linux_bde_bus_t;
+
+
+
+/* Device state used for PCI hot swap case. */
+/*
+ * BDE_DEV_STATE_NORMAL : A device is probed normally. Or when the device
+ * resource has been updated after "CHANGED", the state will move back to
+ * "NORMAL".
+ */
+#define BDE_DEV_STATE_NORMAL (0)
+/*
+ * BDE_DEV_STATE_REMOVED : A previous probed device was removed.
+ * We will avoid any device access while the device is in this state.
+ * The state will be moved to "CHANGED" if the device is re-inserted
+ * and re-probed.
+ */
+#define BDE_DEV_STATE_REMOVED (1)
+/*
+ * BDE_DEV_STATE_CHANGED : The device is re-probed after having been removed.
+ * The resouces assigned to the device might have been changed after
+ * re-probing, so we need to re-initialize our resource database accordingly.
+ * The state will change to "NORMAL" when the resource have been updated.
+ */
+#define BDE_DEV_STATE_CHANGED (2)
+
+extern int linux_bde_create(linux_bde_bus_t* bus, ibde_t** bde);
+extern int linux_bde_destroy(ibde_t* bde);
+#ifdef BCM_INSTANCE_SUPPORT
+extern int linux_bde_instance_attach(unsigned int dev_mask,unsigned int dma_size);
+#endif
+
+#ifdef __KERNEL__
+
+/*
+ * Backdoors provided by the kernel bde
+ *
+ */
+
+/*
+ * The user bde needs to get cpu physical address for
+ * the userland code to mmap.
+ * And the second address is bus address, it is either
+ * identical to cpu physical address or another address
+ * (IOVA) translated by IOMMU.
+ */
+extern int lkbde_get_dma_info(phys_addr_t *cpu_pbase, phys_addr_t *dma_pbase, ssize_t *size);
+extern uint32 lkbde_get_dev_phys(int d);
+extern uint32 lkbde_get_dev_phys_hi(int d);
+
+/*
+ * Virtual device address needed by kernel space
+ * interrupt handler.
+ */
+extern void *lkbde_get_dev_virt(int d);
+
+/*
+ * The user bde needs to get some physical addresses for
+ * the userland code to mmap. The following functions
+ * supports multiple resources for a single device.
+ */
+extern int lkbde_get_dev_resource(int d, int rsrc, uint32 *flags,
+ uint32 *phys_lo, uint32 *phys_hi);
+
+/*
+ * Backdoor to retrieve OS device structure to be used for
+ * DMA operations.
+ */
+extern void *lkbde_get_dma_dev(int d);
+
+/*
+ * Backdoor to retrieve original hardware/OS device.
+ */
+extern void *lkbde_get_hw_dev(int d);
+
+/*
+ * Backdoor to retrieve number of switch devices probed.
+ */
+extern int lkbde_get_num_devices(int type);
+
+/*
+ * Retrive the device state from Kernel BDE.
+ * Used for KNET and User BDE for pci hot swap case.
+ */
+extern int lkbde_dev_state_get(int d, uint32 *state);
+extern int lkbde_dev_state_set(int d, uint32 state);
+
+/*
+ * Retrive the mapping between emulated HW device and instance id
+ */
+extern int lkbde_dev_instid_get(int d, uint32 *instid);
+extern int lkbde_dev_instid_set(int d, uint32 instid);
+
+/*
+ * Functions that allow an interrupt handler in user mode to
+ * coexist with interrupt handler in kernel module.
+ */
+extern int lkbde_irq_mask_set(int d, uint32 addr, uint32 mask, uint32 fmask);
+extern int lkbde_irq_mask_get(int d, uint32 *mask, uint32 *fmask);
+
+#ifdef BCM_SAND_SUPPORT
+extern int lkbde_cpu_write(int d, uint32 addr, uint32 *buf);
+extern int lkbde_cpu_read(int d, uint32 addr, uint32 *buf);
+extern int lkbde_cpu_pci_register(int d);
+#endif
+
+/*
+ * This flag must be OR'ed onto the device number when calling
+ * interrupt_connect/disconnect and irq_mask_set functions from
+ * a secondary device driver.
+ */
+#define LKBDE_ISR2_DEV 0x8000
+/*
+ * This flag should be OR'ed onto the device number when calling
+ * irq_mask_set functions from a secondary device driver if the
+ * mask register is iProc register.
+ */
+#define LKBDE_IPROC_REG 0x4000
+
+#ifdef BCM_SAND_SUPPORT
+#include <linux/version.h>
+#if defined(__DUNE_LINUX_BCM_CPU_PCIE__) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+#ifndef _SIMPLE_MEMORY_ALLOCATION_
+#define _SIMPLE_MEMORY_ALLOCATION_ 1
+#endif
+#endif
+#endif
+
+#if defined(IPROC_CMICD) && defined(CONFIG_CMA)
+#ifndef _SIMPLE_MEMORY_ALLOCATION_
+#define _SIMPLE_MEMORY_ALLOCATION_ 1
+#endif
+#endif
+
+/* Allocation via dma_alloc_coherent is turned off by default */
+#ifndef _SIMPLE_MEMORY_ALLOCATION_
+#define _SIMPLE_MEMORY_ALLOCATION_ 9 /* compile in the allocation method, but do not use it by default */
+#endif
+
+/* By default we use our private mmap for DMA pool */
+#ifndef USE_LINUX_BDE_MMAP
+#define USE_LINUX_BDE_MMAP 1
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* __LINUX_BDE_H__ */
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/linux/include/linux_dma.h b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/include/linux_dma.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/***********************************************************************
+ *
+ * $Id: linux_dma.h,v 1.24 Broadcom SDK $
+ * $Copyright: (c) 2016 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ **********************************************************************/
+
+#ifndef __LINUX_DMA_H__
+#define __LINUX_DMA_H__
+
+#include <sal/types.h>
+
+#ifdef __KERNEL__
+
+#ifdef SAL_BDE_XLP
+#define KMALLOC(size, flags) __kmalloc(size, flags)
+#else
+#define KMALLOC(size, flags) kmalloc(size, flags)
+#endif
+
+#if defined(CONFIG_IDT_79EB334) || defined(CONFIG_BCM4702)
+/* ioremap is broken in kernel */
+#define IOREMAP(addr, size) ((void *)KSEG1ADDR(addr))
+#else
+#define IOREMAP(addr, size) ioremap_nocache(addr, size)
+#endif
+
+#if defined (__mips__)
+#if defined(CONFIG_NONCOHERENT_IO) || defined(CONFIG_DMA_NONCOHERENT)
+/* Use flush/invalidate for cached memory */
+#define NONCOHERENT_DMA_MEMORY
+/* Remap virtual DMA addresses to non-cached segment */
+#define REMAP_DMA_NONCACHED
+#endif /* CONFIG_NONCOHERENT_IO || CONFIG_DMA_NONCOHERENT */
+#endif /* __mips__ */
+
+#if defined(BCM958525) && (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,5))
+#define REMAP_DMA_NONCACHED
+#endif
+
+#ifndef DMA_BIT_MASK
+#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
+#endif
+
+extern void _dma_init(int dev_index);
+extern int _dma_cleanup(void);
+extern void _dma_pprint(void);
+extern uint32_t *_salloc(int d, int size, const char *name);
+extern void _sfree(int d, void *ptr);
+extern int _sinval(int d, void *ptr, int length);
+extern int _sflush(int d, void *ptr, int length);
+extern sal_paddr_t _l2p(int d, void *vaddr);
+extern void *_p2l(int d, sal_paddr_t paddr);
+extern int _dma_pool_allocated(void);
+extern int _dma_mmap(struct file *filp, struct vm_area_struct *vma);
+
+#endif /* __KERNEL__ */
+
+#endif /* __LINUX_DMA_H__ */
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/linux/include/mpool.h b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/include/mpool.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: mpool.h,v 1.2 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#ifndef __MPOOL_H__
+#define __MPOOL_H__
+
+struct mpool_mem_s;
+typedef struct mpool_mem_s* mpool_handle_t;
+
+extern int mpool_init(void);
+extern mpool_handle_t mpool_create(void* base_address, int size);
+extern void* mpool_alloc(mpool_handle_t pool, int size);
+extern void mpool_free(mpool_handle_t pool, void* ptr);
+extern int mpool_destroy(mpool_handle_t pool);
+
+extern int mpool_usage(mpool_handle_t pool);
+
+#endif /* __MPOOL_H__ */
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/Makefile b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/Makefile
@@ -0,0 +1,94 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.18 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+# Makefile for Linux kernel BDE
+#
+LOCALDIR = systems/bde/linux/kernel
+
+# Make sure we build for the kernel if this is a user-mode build
+ifneq ($(platform), )
+override-target=linux-$(platform)
+endif
+
+include $(SDK)/make/Make.config
+
+LIBS = $(LIBDIR)/libkern.a
+
+BDE = linux-kernel-bde.o
+
+# need to add vpath sources
+VPATH = ../shared
+
+# Add the srcs to be found by vpath
+LSRCS += mpool.c
+
+# Add shared BDE sources
+VPATH += ../../shared
+LSRCS += shbde_pci.c shbde_iproc.c shbde_mdio.c
+CFLAGS += -I../../shared/include
+
+LHDRS += mpool.h
+LOBJS = $(addsuffix .o, $(basename $(LSRCS)))
+BOBJS = $(addprefix $(BLDDIR)/,$(LOBJS))
+
+ifneq ($(kernel_version),2_4)
+KERNEL_MODULE_DIR = kernel_module
+
+THIS_MOD_NAME := linux-kernel-bde
+MODULE = $(LIBDIR)/$(THIS_MOD_NAME).o
+KMODULE = $(LIBDIR)/$(THIS_MOD_NAME).ko
+
+build: kernel_libs module $(KMODULE)
+else
+MODULE = $(LIBDIR)/linux-kernel-bde.o
+
+build: kernel_libs module
+endif
+
+module: kernel_libs $(MODULE)
+
+$(MODULE): $(BLDDIR)/.tree $(BOBJS)
+ mkdir -p $(@D)
+ $(LD) $(MODULE_LDFLAGS) -r -d $(BOBJS) $(LIBS) -o $@
+ifneq ($(kernel_version),2_4)
+$(KMODULE): $(MODULE)
+ rm -fr $(BLDDIR)/$(KERNEL_MODULE_DIR)
+ mkdir $(BLDDIR)/$(KERNEL_MODULE_DIR)
+ cp ${SDK}/make/Makefile.linux-kmodule $(BLDDIR)/$(KERNEL_MODULE_DIR)/Makefile
+ MOD_NAME=$(THIS_MOD_NAME) $(MAKE) -C $(BLDDIR)/$(KERNEL_MODULE_DIR) $(THIS_MOD_NAME).ko
+endif
+
+kernel_libs:
+ $(MAKE) -C $(SDK)/systems/linux/kernel/modules/shared
+
+include $(SDK)/make/Make.depend
+
+# Make.depend is before clean:: so that Make.depend's clean:: runs first.
+
+clean::
+ $(MAKE) -C $(SDK)/systems/linux/kernel/modules/shared $@
+ $(RM) $(BOBJS) $(MODULE)
+ $(RM) $(BLDDIR)/$(KERNEL_MODULE_DIR)
+
+distclean::
+
+ifneq ($(kernel_version),2_4)
+.PHONY: build kernel_libs
+endif
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux-kernel-bde.c b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux-kernel-bde.c
@@ -0,0 +1,4530 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+
+/*
+ * Linux Kernel BDE
+ */
+
+#include <gmodule.h>
+#include <linux-bde.h>
+#include <linux_dma.h>
+#include <mpool.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <sdk_config.h>
+#include <soc/devids.h>
+#include <linux/version.h>
+
+#include "linux_shbde.h"
+
+#define MEMCPY memcpy
+
+#ifdef CONFIG_X86_64
+#if (defined(__GNUC__) && (__GNUC__ == 8))
+/*
+ * Prevent gcc 8.1.10 using a compiler inline memcpy even if using -fno-builtin or
+ * -fno-builtin-memcpy .
+ * __inline_memcpy and __memcpy are kernel functions that may be used instead,
+ * for either an inline or non-inline implementations of the function
+ */
+#undef MEMCPY
+#define MEMCPY __memcpy
+#endif /* (defined(__GNUC__) && (__GNUC__ == 8)) */
+#endif /* CONFIG_X86_64 */
+
+
+#if defined(CMIC_SOFT_BYTE_SWAP)
+#define CMIC_SWAP32(_x) ((((_x) & 0xff000000) >> 24) \
+ | (((_x) & 0x00ff0000) >> 8) \
+ | (((_x) & 0x0000ff00) << 8) \
+ | (((_x) & 0x000000ff) << 24))
+#endif /* defined(CMIC_SOFT_BYTE_SWAP) */
+
+#define PCI_USE_INT_NONE (-1)
+#define PCI_USE_INT_INTX (0)
+#define PCI_USE_INT_MSI (1)
+#define PCI_USE_INT_MSIX (2)
+#ifdef CONFIG_PCI_MSI
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,110))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+#define msix_table_size(flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1)
+#endif
+#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
+#endif
+#endif
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Kernel BDE");
+MODULE_LICENSE("GPL");
+
+/*
+ * PCIe max payload size in bytes.
+ * The default value if not specified to the kernel module by maxpayload is historically 256.
+ * The default value may be changed using the BDE_PCIE_MAXPAYLOAD_DEFAULT macro.
+ */
+#ifndef BDE_PCIE_MAXPAYLOAD_DEFAULT
+#define BDE_PCIE_MAXPAYLOAD_DEFAULT 256
+#endif
+int maxpayload = BDE_PCIE_MAXPAYLOAD_DEFAULT;
+LKM_MOD_PARAM(maxpayload, "i", int, 0);
+MODULE_PARM_DESC(maxpayload,
+"Limit maximum payload size and request size on PCIe devices");
+
+/* Use MSI or MSIX interrupts */
+int usemsi = -1;
+LKM_MOD_PARAM(usemsi, "i", int, 0);
+MODULE_PARM_DESC(usemsi,
+"Use MSI/ MSIX interrupts if supported by kernel");
+
+/* Ignore all recognized devices (for debug purposes) */
+int nodevices;
+LKM_MOD_PARAM(nodevices, "i", int, 0);
+MODULE_PARM_DESC(nodevices,
+"Ignore all recognized devices (default no)");
+
+int msixcnt = 1;
+
+/*
+ * This usually is defined at /usr/include/linux/pci_ids.h
+ * But this ID is newer.
+ */
+#ifndef PCI_DEVICE_ID_PLX_9656
+#define PCI_DEVICE_ID_PLX_9656 0x9656
+#endif
+
+#ifndef PCI_DEVICE_ID_PLX_9056
+#define PCI_DEVICE_ID_PLX_9056 0x9056
+#endif
+
+/* For 2.4.x kernel support */
+#ifndef IRQF_SHARED
+#define IRQF_SHARED SA_SHIRQ
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+typedef unsigned long resource_size_t;
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */
+
+#ifdef BCM_ICS
+#define BCM_ICS_CMIC_BASE 0x08000000
+#else
+
+/* Force interrupt line */
+static int forceirq = -1;
+static uint32_t forceirqubm = 0xffffffff;
+LKM_MOD_PARAM(forceirq, "i", int, 0);
+LKM_MOD_PARAM(forceirqubm, "i", uint, 0);
+MODULE_PARM_DESC(forceirq,
+"Override IRQ line assigned by boot loader");
+MODULE_PARM_DESC(forceirqubm,
+"Bitmap for overriding the IRQ line assigned by boot loader for given units");
+
+/* Create SPI slave device (cannot be probed) */
+static uint32_t spi_devid = 0;
+LKM_MOD_PARAM(spi_devid, "i", uint, 0);
+MODULE_PARM_DESC(spi_devid,
+"Create SPI slave device using this device ID");
+
+/* Select SPI device revision (cannot be probed) */
+static uint32_t spi_revid = 1;
+LKM_MOD_PARAM(spi_revid, "i", uint, 0);
+MODULE_PARM_DESC(spi_revid,
+"Select device revision for SPI slave device");
+
+#endif /* BCM_ICS */
+
+/* Debug output */
+static int debug;
+LKM_MOD_PARAM(debug, "i", int, 0);
+MODULE_PARM_DESC(debug,
+"Set debug level (default 0");
+/* Use high memory for DMA */
+
+/* module param for probing EB devices. */
+static char *eb_bus;
+LKM_MOD_PARAM(eb_bus, "s", charp, 0);
+MODULE_PARM_DESC(eb_bus,
+"List of EB devices on platform. Input format (BA=%x IRQ=%d RD16=%d WR16=%d");
+
+#ifdef KEYSTONE
+/* Force SPI Frequency */
+static int spifreq = 0;
+LKM_MOD_PARAM(spifreq, "i", int, 0);
+MODULE_PARM_DESC(spifreq,
+"Force SPI Frequency for Keystone CPU (0 for default frequency)");
+#endif
+
+
+/* Compatibility */
+#ifdef LKM_2_4
+#define _ISR_RET void
+#define _ISR_PARAMS(_i,_d,_r) int _i, void *_d, struct pt_regs *_r
+#define IRQ_NONE
+#define IRQ_HANDLED
+#define SYNC_IRQ(_i) synchronize_irq()
+#else /* LKM_2_6 */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
+#define _ISR_RET irqreturn_t
+#else
+#define _ISR_RET int
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19))
+#define _ISR_PARAMS(_i,_d,_r) int _i, void *_d
+#else
+#define _ISR_PARAMS(_i,_d,_r) int _i, void *_d, struct pt_regs *_r
+typedef irqreturn_t (*irq_handler_t)(int _i, void *_d, struct pt_regs *_r);
+#endif
+#define SYNC_IRQ(_i) synchronize_irq(_i)
+char * ___strtok;
+char * strtok(char * s,const char * ct)
+{
+ char *sbegin, *send;
+ sbegin = s ? s : ___strtok;
+ if (!sbegin) {
+ return NULL;
+ }
+ sbegin += strspn(sbegin,ct);
+ if (*sbegin == '\0') {
+ ___strtok = NULL;
+ return( NULL );
+ }
+ send = strpbrk( sbegin, ct);
+ if (send && *send != '\0')
+ *send++ = '\0';
+ ___strtok = send;
+ return (sbegin);
+}
+LKM_EXPORT_SYM(___strtok);
+LKM_EXPORT_SYM(strtok);
+#endif /* LKM_2_x */
+
+/* PCIe capabilities */
+#ifndef PCI_CAP_ID_EXP
+#define PCI_CAP_ID_EXP 0x10
+#endif
+#ifndef PCI_EXP_DEVCAP
+#define PCI_EXP_DEVCAP 4
+#endif
+#ifndef PCI_EXP_DEVCTL
+#define PCI_EXP_DEVCTL 8
+#endif
+#ifndef PCI_EXT_CAP_START
+#define PCI_EXT_CAP_START 0x100
+#endif
+#ifndef PCI_EXT_CAP_ID
+#define PCI_EXT_CAP_ID(_hdr) (_hdr & 0x0000ffff)
+#endif
+#ifndef PCI_EXT_CAP_VER
+#define PCI_EXT_CAP_VER(_hdr) ((_hdr >> 16) & 0xf)
+#endif
+#ifndef PCI_EXT_CAP_NEXT
+#define PCI_EXT_CAP_NEXT(_hdr) ((_hdr >> 20) & 0xffc)
+#endif
+#ifndef PCI_EXT_CAP_ID_VNDR
+#define PCI_EXT_CAP_ID_VNDR 0x0b
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+#define PCI_FIND_DEV(_d, _v, _fr) pci_find_device(_d, _v, _fr)
+#else
+#define PCI_FIND_DEV(_d, _v, _fr) pci_get_device(_d, _v, _fr)
+#endif
+
+#if defined(CONFIG_RESOURCES_64BIT) || defined(CONFIG_PHYS_ADDR_T_64BIT)
+#define PHYS_ADDR_IS_64BIT
+#endif
+
+/* Structure of private SPI device */
+struct spi_dev {
+ uint8 cid; /* Chip ID */
+ uint32 part; /* Part number of the chip */
+ uint8 rev; /* Revision of the chip */
+ void *robo; /* ptr to robo info required to access SPI */
+ unsigned short phyid_high; /* PHYID HIGH in MII regs of detected chip */
+ unsigned short phyid_low; /* PHYID LOW in MII regs of detected chip */
+};
+
+struct bde_spi_device_id {
+ unsigned short phyid_high; /* PHYID HIGH in MII regs of detected chip */
+ unsigned short phyid_low; /* PHYID LOW in MII regs of detected chip */
+ uint32 model_info;
+ uint32 rev_info;
+ uint32 spifreq;
+};
+
+/* Maximum number of I/O windows supported per device. */
+#define BDE_NUM_IOWIN_MAX 3
+
+/* I/O memory window definition. */
+struct memwin_s {
+
+ /* Physical address of I/O window. */
+ resource_size_t addr;
+
+ /* Size of I/O window (in bytes). */
+ resource_size_t size;
+};
+
+/* Control Data */
+typedef struct bde_ctrl_s {
+ struct list_head list;
+
+ /* Specify the type of device, pci, spi, switch, ether ... */
+ uint32 dev_type;
+
+ int domain_no;
+ int bus_no;
+ int be_pio;
+ int use_msi;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+ struct msix_entry *entries;
+#endif
+ int msix_cnt;
+ union {
+ /* Linux PCI device pointer */
+ struct pci_dev* _pci_dev;
+
+ /* SPI device pointer */
+ struct spi_dev* _spi_dev;
+ } dev;
+#define pci_device dev._pci_dev
+#define spi_device dev._spi_dev
+
+#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT
+ struct device *dma_dev;
+#endif
+
+ struct memwin_s iowin[BDE_NUM_IOWIN_MAX];
+
+ /* Secondary mapped base address */
+ sal_vaddr_t alt_base_addr;
+
+ /* BDE device description */
+ ibde_dev_t bde_dev;
+
+ /* Interrupt Handling */
+ int iLine; /* Interrupt line */
+ void (*isr)(void *);
+ void *isr_data;
+
+ /*
+ * Controls to allow two drivers to share a single set of
+ * hardware registers. Typically a kernel driver will handle
+ * a subset of hardware interrupts and a user mode driver
+ * will handle the remaining interrupts.
+ */
+ void (*isr2)(void *);
+ void *isr2_data;
+ uint32_t fmask; /* Interrupts controlled by secondary handler */
+ uint32_t imask; /* Enabled interrupts for primary handler */
+ uint32_t imask2; /* Enabled interrupts for secondary handler */
+ spinlock_t lock; /* Lock for IRQ mask synchronization */
+
+ /* Hardware abstraction for shared BDE functions */
+ shbde_hal_t shbde;
+
+ /* Device state : BDE_DEV_STATE_REMOVED/CHANGED */
+ uint32 dev_state;
+
+ /* inst_id */
+ uint32 inst_id;
+} bde_ctrl_t;
+
+static bde_ctrl_t _devices[LINUX_BDE_MAX_DEVICES];
+static int _ndevices = 0;
+static int _switch_ndevices = 0;
+static int _ether_ndevices = 0;
+static int _cpu_ndevices = 0;
+
+#define VALID_DEVICE(_n) ((_n >= 0) && (_n < _ndevices))
+
+#if defined(IPROC_CMICD) && defined(CONFIG_OF)
+#define ICFG_CHIP_ID_REG 0x10236000
+#define IHOST_CMICX_MAX_INTRS 129
+static uint32 iproc_cmicx_irqs[IHOST_CMICX_MAX_INTRS];
+#endif
+
+/* CPU MMIO area used with CPU cards provided on demo boards */
+#if defined(BCM_SAND_SUPPORT) && (defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__))
+static void *cpu_address = NULL;
+#endif
+
+
+/* Broadcom BCM4704 */
+#define BCM4704_VENDOR_ID 0x14E4
+#define BCM4704_DEVICE_ID 0x4704
+
+/* SiByte PCI Host */
+#define SIBYTE_PCI_VENDOR_ID 0x166D
+#define SIBYTE_PCI_DEVICE_ID 0x0001
+
+/* Intel 21150 PCI-PCI Bridge */
+#define DC21150_VENDOR_ID 0x1011
+#define DC21150_DEVICE_ID 0x0022
+
+/* HiNT HB4 PCI-PCI Bridge (21150 clone) */
+#define HINT_HB4_VENDOR_ID 0x3388
+#define HINT_HB4_DEVICE_ID 0x0022
+
+/* Pericom PI7C8150 PCI-PCI Bridge (21150 clone) */
+#define PI7C8150_VENDOR_ID 0x12D8
+#define PI7C8150_DEVICE_ID 0x8150
+
+/* Pericom PI7C9X130 PCI-PCIE Bridge */
+#define PCI_VNDID_PERICOM 0x12D8
+#define PCI_DEVID_PI7C9X130 0xE130
+#define DEV_CTRL_REG 0xb8
+
+#define MAX_PAYLOAD_256B (1 << 5)
+#define MAX_PAYLOAD_512B (2 << 5)
+#define MAX_READ_REQ_256B (1 << 12)
+
+
+/* Freescale 8548 PCI-E host Bridge */
+#define FSL_VENDOR_ID 0x1957
+#define FSL8548PCIE_DEVICE_ID 0x0013
+#define FSL2020EPCIE_DEVICE_ID 0x0070
+#define FSL8548PCIE_DEV_CTRL_REG 0x54
+
+/* 4716 PCI-E host Bridge */
+#define BCM4716_VENDOR_ID 0x14e4
+#define BCM4716PCIE_DEVICE_ID 0x4716
+#define BCM4716PCIE_DEV_CAP_REG 0xd4
+#define BCM4716PCIE_DEV_CTRL_REG 0xd8
+#define BCM53000_VENDOR_ID 0x14e4
+#define BCM53000PCIE_DEVICE_ID 0x5300
+
+#define BCM53000PCIE_DEV(port) ((port == 0) ? pcie0 : pcie1)
+#define BCM53000PCIE_BASE(port) ((port == 0) ? 0xb8005000 : 0xb800e000)
+#define BCM53000PCIE_FUNC0_COFIG_SPACE 0x400
+#define BCM53000PCIE_SROM_SPACE 0x800
+#define BCM53000PCIE_DEV_CAP_REG 0xd4
+#define BCM53000PCIE_DEV_CTRL_REG 0xd8
+#define BCM53000PCIE_MAX_PAYLOAD_MASK 0x7
+#define BCM53000PCIE_CAP_MAX_PAYLOAD_256B (1 << 0)
+#define BCM53000PCIE_DEFAULT_STATUS 0x00100146
+
+/* 16bit wide register. offset 14, 14*2 = 0x1c */
+#define BCM53000PCIE_SPROM_OFFSET 0x1c
+/* bit 15:13 spromData.MaxPayloadSize. 1: 256 bytes */
+#define BCM53000PCIE_SPROM_MAX_PAYLOAD_MASK 0xe000
+#define BCM53000PCIE_SPROM_MAX_PAYLOAD_256B (1 << 13)
+
+
+/* Intel 21150, HiNT HB4 and other 21150-compatible */
+#define PCI_CFG_DEC21150_SEC_CLK 0x68
+
+#define BCM4704_ENUM_BASE 0x18000000
+#define BCM4704_MEMC_BASE (BCM4704_ENUM_BASE+0x8000)
+#define BCM4704_MEMC_PRIORINV 0x18
+
+/* PLX PCI-E Switch */
+#define PLX_PEX8608_DEV_ID 0x8608
+#define PLX_PEX8617_DEV_ID 0x8617
+#define PLX_PEX86XX_DEV_CTRL_REG 0x70
+
+/* Broadcom BCM58525 */
+#define BCM58525_PCI_VENDOR_ID 0x14E4
+#define BCM58525_PCI_DEVICE_ID 0x8025
+#define BCM58522_PCI_DEVICE_ID 0x8022
+
+/* Broadcom BCM58712 */
+#define BCM58712_PCI_VENDOR_ID 0x14E4
+#define BCM58712_PCI_DEVICE_ID 0x168E
+
+/* Default gicd address if not available in DTB */
+#define IHOST_GICD_REG_ADDR 0x10781100
+#define IHOST_GICD_REG_REMAP_LEN 0x100
+
+#define IHOST_GICD_REG_ADDR_VALID(d, addr) \
+ (_devices[d].bde_dev.base_address1 && \
+ (addr & 0xFFFFFF00) == _devices[d].iowin[1].addr)
+
+#define IHOST_GICD_REG_ADDR_REMAP(d, addr) \
+ (void *)(_devices[d].bde_dev.base_address1 + \
+ (addr - ((sal_vaddr_t)_devices[d].iowin[1].addr)))
+
+static uint32_t _read(int d, uint32_t addr);
+
+#ifdef BCM_ICS
+#else
+/* Used to determine overall memory limits across all devices */
+static uint32_t _pci_mem_start = 0xFFFFFFFF;
+static uint32_t _pci_mem_end = 0;
+
+/* Used to control MSI interrupts */
+static int use_msi = 0;
+#endif
+
+#ifdef BCM_PLX9656_LOCAL_BUS
+
+#define CPLD_OFFSET 0x00800000
+#define CPLD_REVISION_REG 0x0000
+#define CPLD_REVISION_MASK 0xffff
+#define CPLD_RESET_REG 0x0004
+#define CPLD_RESET_NONE 0x0000
+
+#define PL0_OFFSET 0x00800000
+#define PL0_SIZE 0x00040000
+#define PL0_REVISION_REG 0x0000
+
+/* Assume there's only one PLX PCI-to-Local bus bridge if any */
+static bde_ctrl_t plx_ctrl;
+static int num_plx = 0;
+
+#endif /* BCM_PLX9656_LOCAL_BUS */
+
+static spinlock_t bus_lock;
+
+static int
+_parse_eb_args(char *str, char * format, ...)
+ __attribute__ ((format (scanf, 2, 3)));
+
+static int
+_parse_eb_args(char *str, char * format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vsscanf(str, format, args);
+ va_end(args);
+
+ return 0;
+}
+
+static void
+_bde_add_device(void)
+{
+ int add_switch_device = 0;
+ if (_devices[_ndevices].dev_type & BDE_SWITCH_DEV_TYPE) {
+ _switch_ndevices++;
+ add_switch_device = 1;
+ } else if (_devices[_ndevices].dev_type & BDE_ETHER_DEV_TYPE) {
+ _ether_ndevices++;
+ } else if (_devices[_ndevices].dev_type & BDE_CPU_DEV_TYPE) {
+ _cpu_ndevices++;
+ } else {
+ return;
+ }
+ _ndevices++;
+
+ /*
+ * In order to be backward compatible with the user mode BDE
+ * (specifically the interrupt IOCTLs) and the CM, switch devices
+ * *must* come first. If this is not the case (due to the probing
+ * order), we let the non-switch device(s) drop down to the end of
+ * the device array.
+ */
+ if (add_switch_device) {
+ bde_ctrl_t tmp_dev;
+ int i, s = 0;
+
+ while (s < _switch_ndevices) {
+ if (_devices[s].dev_type & BDE_SWITCH_DEV_TYPE) {
+ s++;
+ continue;
+ }
+ tmp_dev = _devices[s];
+ for (i = s; i < _ndevices - 1; i++) {
+ _devices[i] = _devices[i+1];
+ }
+ _devices[i] = tmp_dev;
+ }
+
+ _dma_init(_switch_ndevices-1);
+ }
+
+ /* Initialize device locks */
+ spin_lock_init(&_devices[_ndevices-1].lock);
+}
+
+static int
+_eb_device_create(resource_size_t paddr, int irq, int rd_hw, int wr_hw)
+{
+ bde_ctrl_t *ctrl;
+ uint32 dev_rev_id = 0x0, dev_id;
+
+ dev_id = _ndevices;
+
+ ctrl = _devices + _ndevices;
+
+ ctrl->dev_type |= BDE_EB_DEV_TYPE | BDE_SWITCH_DEV_TYPE;
+ ctrl->pci_device = NULL; /* No PCI bus */
+
+ if(rd_hw) {
+ ctrl->dev_type |= BDE_DEV_BUS_RD_16BIT;
+ }
+
+ if (wr_hw) {
+ ctrl->dev_type |= BDE_DEV_BUS_WR_16BIT;
+ }
+
+ /* Map in the device */
+ ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(paddr, 0x10000);
+ ctrl->iowin[0].addr = paddr;
+ ctrl->iowin[0].size = 0x10000;
+
+ dev_rev_id = _read(dev_id, 0x178); /* CMIC_DEV_REV_ID */
+
+ ctrl->bde_dev.device = dev_rev_id & 0xFFFF;
+ ctrl->bde_dev.rev = (dev_rev_id >> 16) & 0xFF;
+
+ ctrl->iLine = irq;
+ ctrl->isr = NULL;
+ ctrl->isr_data = NULL;
+
+ gprintk("Created EB device at BA=%x IRQ=%d RD16=%d WR16=%d device=0x%x\n",
+ (unsigned int)paddr, irq, rd_hw, wr_hw, ctrl->bde_dev.device);
+
+ _bde_add_device();
+
+ return 0;
+}
+
+#ifdef BCM_SAND_SUPPORT
+
+#include <soc/devids.h>
+
+static int
+sand_device_create(void)
+{
+ bde_ctrl_t* ctrl;
+
+ ctrl = _devices; /* FIX_ME: on petra, take first device */
+
+#ifndef __DUNE_LINUX_BCM_CPU_PCIE__
+ ctrl->dev_type |= BDE_PCI_DEV_TYPE | BDE_SWITCH_DEV_TYPE;
+ ctrl->pci_device = NULL; /* No PCI bus */
+
+ /* Map in the device */ /* FIX_ME: not realy map anything */
+ ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(0x40000000, 0x100000);
+ ctrl->iowin[0].addr = 0x40000000;
+ ctrl->iowin[0].size = 0x100000;
+
+ ctrl->iLine = 0;
+ ctrl->isr = NULL;
+ ctrl->isr_data = NULL;
+
+ ctrl->bde_dev.device = BCM88950_DEVICE_ID;
+ ctrl->bde_dev.rev = BCM88950_A0_REV_ID;
+#endif
+
+ /* Map CPU regs */
+#ifdef __DUNE_WRX_BCM_CPU__
+ cpu_address = IOREMAP(0x18000000, 0x4000000);
+#elif defined(__DUNE_GTO_BCM_CPU__)
+ cpu_address = IOREMAP(0xe0000000, 0x100000);
+#endif
+
+ if ((ctrl->bde_dev.device == PCP_PCI_DEVICE_ID)) {
+ ctrl->bde_dev.device = GEDI_DEVICE_ID;
+ ctrl->bde_dev.rev = GEDI_REV_ID;
+ }
+
+ if ((ctrl->bde_dev.device == ACP_PCI_DEVICE_ID)) {
+ ctrl->dev_type |= BDE_PCI_DEV_TYPE | BDE_SWITCH_DEV_TYPE;
+ }
+
+#ifndef __DUNE_LINUX_BCM_CPU_PCIE__
+ _bde_add_device();
+#endif
+
+ return 0;
+}
+#endif /* BCM_SAND_SUPPORT */
+
+#ifdef IPROC_CMICD
+static void
+iproc_cmicd_get_irqres(ibde_dev_t bde_dev, struct resource *res_irq)
+{
+ shbde_iproc_config_t iproc_config, *icfg = &iproc_config;
+
+ /* iProc configuration parameters */
+ memset(icfg, 0, sizeof(*icfg));
+ shbde_iproc_config_init(icfg, bde_dev.device, bde_dev.rev);
+
+ if ((icfg->iproc_ver == 0) && (debug >= 1)) {
+ gprintk("Unable to determine iProc version\n");
+ }
+
+ if (icfg->iproc_ver == 7) {
+ res_irq->start = 221;
+ } else if (icfg->iproc_ver == 10) {
+ res_irq->start = 184;
+ }
+
+}
+
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+extern int iproc_platform_driver_register(struct platform_driver *drv);
+extern void iproc_platform_driver_unregister(struct platform_driver *drv);
+extern int iproc_platform_device_register(struct platform_device *drv);
+extern void iproc_platform_device_unregister(struct platform_device *drv);
+
+extern struct resource *
+iproc_platform_get_resource(struct platform_device *dev, unsigned int type,
+ unsigned int num);
+
+#define IPROC_CHIPCOMMONA_BASE 0x18000000
+#define IPROC_CMICD_BASE 0x48000000
+#define IPROC_CMICD_SIZE 0x40000
+#define IPROC_CMICD_INT 194
+
+#define IPROC_CMICD_COMPATIBLE "brcm,iproc-cmicd"
+#define IPROC_CMICX_COMPATIBLE "brcm,iproc-cmicx"
+
+static int
+iproc_cmicd_probe(struct platform_device *pldev)
+{
+ bde_ctrl_t *ctrl;
+ uint32 size, dev_rev_id;
+ struct resource *memres, *irqres;
+#ifdef CONFIG_OF
+ if (debug >= 1) {
+ gprintk("iproc_cmicd_probe %s\n", pldev->dev.of_node ? "with device node":"");
+ }
+#endif
+ memres = iproc_platform_get_resource(pldev, IORESOURCE_MEM, 0);
+ if (memres == NULL) {
+ gprintk("Unable to retrieve iProc CMIC resources");
+ return -1;
+ }
+ size = memres->end - memres->start + 1;
+
+ ctrl = _devices + _ndevices;
+
+ ctrl->dev_type = BDE_AXI_DEV_TYPE | BDE_SWITCH_DEV_TYPE | BDE_256K_REG_SPACE;
+ ctrl->pci_device = NULL; /* No PCI bus */
+
+ /* Map CMIC block in the AXI memory space into CPU address space */
+ ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(memres->start, size);
+ if (!ctrl->bde_dev.base_address) {
+ gprintk("Error mapping iProc CMIC registers");
+ return -1;
+ }
+ ctrl->iowin[0].addr = memres->start;
+ ctrl->iowin[0].size = size;
+
+#ifdef CONFIG_OF
+ if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) {
+ uint32 *icfg_chip_id;
+ icfg_chip_id = (uint32 *)IOREMAP(ICFG_CHIP_ID_REG, 2 * sizeof(uint32));
+ if (icfg_chip_id == NULL) {
+ gprintk("Error mapping ICFG_CHIP_ID_REG\n");
+ return -1;
+ }
+ ctrl->bde_dev.device = readl(icfg_chip_id) & 0xffff;
+ ctrl->bde_dev.rev = readl(icfg_chip_id+1) & 0xff;
+ iounmap(icfg_chip_id);
+ /* Map GICD block in the AXI memory space into CPU address space */
+ memres = iproc_platform_get_resource(pldev, IORESOURCE_MEM, 1);
+ if (memres) {
+ ctrl->bde_dev.base_address1 = (sal_vaddr_t)IOREMAP(memres->start, memres->end - memres->start + 1);
+ ctrl->iowin[1].addr = memres->start;
+ ctrl->iowin[1].size = memres->end - memres->start + 1;
+ } else {
+ /* Use default address if not available in DTB */
+ ctrl->bde_dev.base_address1 = (sal_vaddr_t)IOREMAP(IHOST_GICD_REG_ADDR, IHOST_GICD_REG_REMAP_LEN);
+ ctrl->iowin[1].addr = IHOST_GICD_REG_ADDR;
+ ctrl->iowin[1].size = IHOST_GICD_REG_REMAP_LEN;
+ }
+ if (ctrl->bde_dev.base_address1) {
+ if (debug >= 1) {
+ gprintk("base_address1:0x%lx phys_address1:0x%lx\n",
+ (unsigned long)ctrl->bde_dev.base_address1, (unsigned long)ctrl->iowin[1].addr);
+ }
+ } else {
+ gprintk("Error mapping ihost GICD registers\n");
+ }
+ } else
+#endif
+ {
+ /* Read switch device ID from CMIC */
+ dev_rev_id = *((uint32 *)(ctrl->bde_dev.base_address + 0x10224));
+#if defined(BCM_CMICM_SUPPORT) && defined(BE_HOST)
+ ctrl->bde_dev.device = ( (((dev_rev_id >> 16) & 0xff) << 8) |
+ ((dev_rev_id >> 24) & 0xff));
+ ctrl->bde_dev.rev = (dev_rev_id >> 8) & 0xff ;
+#else
+ ctrl->bde_dev.device = dev_rev_id & 0xffff;
+ ctrl->bde_dev.rev = (dev_rev_id >> 16) & 0xff;
+#endif
+ ctrl->bde_dev.base_address1 = 0;
+ }
+
+#ifdef CONFIG_OF
+ if (!pldev->dev.of_node)
+#endif
+ {
+ /* Assign locally if not available from device node */
+ iproc_cmicd_get_irqres(ctrl->bde_dev, &pldev->resource[0]);
+ }
+
+#ifdef CONFIG_OF
+ if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) {
+ int i;
+ memset(iproc_cmicx_irqs, 0, IHOST_CMICX_MAX_INTRS*sizeof(uint32_t));
+ for (i = 0; i < IHOST_CMICX_MAX_INTRS; i++) {
+ irqres = iproc_platform_get_resource(pldev, IORESOURCE_IRQ, i);
+ if (irqres) {
+ iproc_cmicx_irqs[i] = irqres->start;
+ }
+ if (debug >= 1) {
+ gprintk("iproc_cmicx_irqs[%d] = %d\n", i, iproc_cmicx_irqs[i]);
+ }
+ }
+ ctrl->iLine = iproc_cmicx_irqs[0];
+ } else
+#endif
+ {
+ irqres = iproc_platform_get_resource(pldev, IORESOURCE_IRQ, 0);
+ ctrl->iLine = irqres->start;
+ }
+
+ ctrl->isr = NULL;
+ ctrl ->isr_data = NULL;
+
+#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT
+ ctrl->dma_dev = &pldev->dev;
+#endif
+
+ /* Let's boogie */
+ _bde_add_device();
+ return 0;
+}
+
+static int
+iproc_cmicd_remove(struct platform_device *pldev)
+{
+ return 0;
+}
+#ifdef CONFIG_OF
+static const struct of_device_id iproc_cmicd_of_match[] = {
+ { .compatible = IPROC_CMICD_COMPATIBLE },
+ { .compatible = IPROC_CMICX_COMPATIBLE },
+ {},
+};
+MODULE_DEVICE_TABLE(of, iproc_cmicd_of_match);
+#endif
+static char iproc_cmicd_string[] = "bcmiproc-cmicd";
+
+static struct platform_driver iproc_cmicd_driver =
+{
+ .probe = iproc_cmicd_probe,
+ .remove = iproc_cmicd_remove,
+ .driver =
+ {
+ .name = iproc_cmicd_string,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = iproc_cmicd_of_match,
+#endif
+ },
+};
+
+typedef enum {
+ IPROC_CMICD_RES_INTR = 0,
+ IPROC_CMICD_RES_MEM
+} IPROC_CMICD_RES_E;
+
+static struct resource iproc_cmicd_resources[] = {
+ [IPROC_CMICD_RES_INTR] = {
+ .flags = IORESOURCE_IRQ,
+ .start = IPROC_CMICD_INT,
+ },
+ [IPROC_CMICD_RES_MEM] = {
+ .flags = IORESOURCE_MEM,
+ .start = IPROC_CMICD_BASE,
+ .end = IPROC_CMICD_BASE+IPROC_CMICD_SIZE-1,
+ },
+};
+
+static void
+iproc_cmicd_release(struct device *dev)
+{
+}
+
+static u64 iproc_cmicd_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device iproc_cmicd_pdev = {
+ .name = iproc_cmicd_string,
+ .id = 0,
+ .dev = {
+ .release = iproc_cmicd_release,
+ .init_name = iproc_cmicd_string,
+ .dma_mask = &iproc_cmicd_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = iproc_cmicd_resources,
+ .num_resources = ARRAY_SIZE(iproc_cmicd_resources),
+};
+
+static int
+iproc_has_cmicd(void)
+{
+ void *iproc_cca_base;
+ uint32 cca_cid;
+
+ /* Read ChipcommonA chip id register to identify current SOC */
+ iproc_cca_base = IOREMAP(IPROC_CHIPCOMMONA_BASE, 0x3000);
+ if (iproc_cca_base == NULL) {
+ gprintk("iproc_has_cmicd: ioremap of ChipcommonA registers failed");
+ return 0;
+ }
+ cca_cid = readl((uint32 *)iproc_cca_base);
+ cca_cid &= 0xffff;
+ iounmap(iproc_cca_base);
+
+ /* Only allowed accessing CMICD module if the SOC has it */
+ switch (cca_cid) {
+ default:
+ break;
+ }
+
+ /* Device has CMIC */
+ return 1;
+}
+
+#define IPROC_CHIPCOMMONA_EROM_PTR_OFFSET (0x180000fc)
+#define EROM_MAX_SIZE (0x1000)
+#define EROM_PARTNUM_CMICD (0x14)
+
+#define EROM_DESC_COMPIDENT (0x1)
+#define EROM_DESC_MASTER (0x3)
+#define EROM_DESC_ADDR (0x5)
+#define EROM_DESC_END (0xF)
+#define EROM_DESC_EMPTY (0)
+
+#define EROM_IS_DESC_COMPIDENT(x) ((x & 0x7) == EROM_DESC_COMPIDENT)
+#define EROM_IS_DESC_MASTER(x) ((x & 0x7) == EROM_DESC_MASTER)
+#define EROM_IS_DESC_ADDR(x) ((x & 0x7) == EROM_DESC_ADDR)
+#define EROM_IS_DESC_END(x) ((x & 0xF) == EROM_DESC_END)
+
+#define EROM_GET_PARTNUM(x) ((x >> 8) & (0xFFF)) /* Bit 8~19 */
+#define EROM_GET_ADDRESS(x) ((x >> 12) & (0xFFFFF)) /* Bit 12~31 */
+#define EROM_GET_SIZETYPE(x) ((x >> 4) & (0x3)) /* Bit 4~5 */
+#define EROM_GET_AG32(x) ((x >> 3) & (0x1)) /* Bit 3 */
+#define EROM_GET_SIZE(x) ((x >> 12) & (0xFFFFF)) /* Bit 12~31 */
+#define EROM_GET_SG32(x) ((x >> 3) & (0x1)) /* Bit 3 */
+
+#define EROM_ADDR_SIZETYPE_4K (0)
+#define EROM_ADDR_SIZETYPE_8K (1)
+#define EROM_ADDR_SIZETYPE_16K (2)
+#define EROM_ADDR_SIZETYPE_MORE (3)
+
+#define EROM_ADDR_FLAG_AG32 (1) /* Address space greater than 32 bit */
+#define EROM_ADDR_FLAG_SIZE (2) /* Addition size descriptor */
+#define EROM_ADDR_FLAG_SG32 (4) /* Size descriptor greater than 32 bit */
+
+static void
+iproc_cmicd_get_memregion(struct resource *res_mem)
+{
+ void *erom_ptr_oft;
+ uint32_t erom_phy_addr;
+ uint32_t *erom_base;
+ uint32_t i = 0;
+ uint32_t word = 0;
+ uint8_t more_addr_word = 0; /* bit 0: AG32; bit 1: SIZE; bit 2: SG32 */
+ uint8_t found_cmicd_dev = 0;
+ uint8_t size_type = 0;
+ bool is_compident_a = 1; /* 1: CompidentA; o/w: CompidentB */
+
+ erom_ptr_oft = IOREMAP(IPROC_CHIPCOMMONA_EROM_PTR_OFFSET, 0x100);
+
+ erom_phy_addr = readl((uint32 *)(erom_ptr_oft));
+ iounmap(erom_ptr_oft);
+
+ erom_base = IOREMAP(erom_phy_addr, EROM_MAX_SIZE);
+
+ while (1) {
+ word = readl((uint32 *)(erom_base + i));
+
+ if (EROM_IS_DESC_ADDR(word) || more_addr_word) {
+ if (more_addr_word == 0) { /* Normal Addr Desc */
+ if (EROM_GET_AG32(word) == 1) {
+ more_addr_word |= EROM_ADDR_FLAG_AG32;
+ }
+
+ size_type = EROM_GET_SIZETYPE(word);
+ if (size_type == EROM_ADDR_SIZETYPE_MORE) {
+ more_addr_word |= EROM_ADDR_FLAG_SIZE;
+ }
+
+ if (found_cmicd_dev == 1) {
+ res_mem->start = EROM_GET_ADDRESS(word) << 12;
+ if (size_type < EROM_ADDR_SIZETYPE_MORE) {
+ res_mem->end = res_mem->start + 4096 * (1 << size_type) - 1;
+ }
+ }
+ }
+ else if (more_addr_word & EROM_ADDR_FLAG_AG32) { /* UpperAddr Desc */
+ more_addr_word &= ~EROM_ADDR_FLAG_AG32;
+
+ if (found_cmicd_dev == 1) {
+ /* res_mem->start |= word << 32; */
+ gprintk("Expect cmicd address to be 32-bit\n");
+ }
+ }
+ else if (more_addr_word & EROM_ADDR_FLAG_SIZE) { /* Size Desc */
+ if (EROM_GET_SG32(word) == 1) {
+ more_addr_word |= EROM_ADDR_FLAG_SG32;
+ }
+
+ more_addr_word &= ~EROM_ADDR_FLAG_SIZE;
+
+ if (found_cmicd_dev == 1) {
+ res_mem->end = res_mem->start + (EROM_GET_SIZE(word) << 12) - 1;
+ }
+ }
+ else if (more_addr_word & EROM_ADDR_FLAG_SG32) { /* UpperSize Desc */
+ more_addr_word &= ~EROM_ADDR_FLAG_SG32;
+
+ if (found_cmicd_dev == 1) {
+ /* res_mem->end += (word) << 32; */
+ gprintk("Expect cmicd size to be 32-bit\n");
+ }
+ }
+
+ if (found_cmicd_dev == 1 && more_addr_word == 0) {
+ break; /* We have gotten all necessary information, exit the loop */
+ }
+ }
+ else if (EROM_IS_DESC_COMPIDENT(word)) {
+ if (is_compident_a == 1) {
+ if (EROM_GET_PARTNUM(word) == EROM_PARTNUM_CMICD) {
+ found_cmicd_dev = 1;
+ }
+ }
+
+ is_compident_a = 1 - is_compident_a;
+ }
+ else if (EROM_IS_DESC_END(word)) {
+ break;
+ }
+
+ i++;
+ }
+ iounmap(erom_base);
+
+ if (debug >= 1) {
+ gprintk("CMICD info by %s: cmicd_mem.start=%lx, cmicd_mem.end=%lx\n",
+ found_cmicd_dev ? "EROM" : "Default",
+ (unsigned long)iproc_cmicd_resources[IPROC_CMICD_RES_MEM].start,
+ (unsigned long)iproc_cmicd_resources[IPROC_CMICD_RES_MEM].end);
+ }
+}
+#endif /* IPROC_CMICD */
+
+#ifdef BCM_ICS
+static int
+_ics_bde_create(void)
+{
+ bde_ctrl_t *ctrl;
+ uint32 dev_rev_id = 0x0;
+ resource_size_t paddr;
+
+ if (_ndevices == 0) {
+ ctrl = _devices + _ndevices;
+
+ ctrl->dev_type |= BDE_ICS_DEV_TYPE | BDE_SWITCH_DEV_TYPE;
+ ctrl->pci_device = NULL; /* No PCI bus */
+
+ /* Map in the device */
+ paddr = BCM_ICS_CMIC_BASE;
+ ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(paddr, 0x10000);
+ ctrl->iowin[0].addr = paddr;
+ ctrl->iowin[0].size = 0x10000;
+
+ dev_rev_id = *((unsigned int *)(KSEG1ADDR(paddr + 0x178)));
+
+ ctrl->bde_dev.device = dev_rev_id & 0xFFFF;
+ ctrl->bde_dev.rev = (dev_rev_id >> 16) & 0xFF;
+
+ ctrl->iLine = 5; /* From raptor linux BSP */
+
+ ctrl->isr = NULL;
+ ctrl->isr_data = NULL;
+ printk("Created ICS device ..%x\n", ctrl->bde_dev.base_address);
+ _bde_add_device();
+ }
+
+ return 0;
+}
+
+#else /* !BCM_ICS */
+
+extern struct pci_bus *pci_find_bus(int domain, int busnr);
+
+/*
+ * PCI device table.
+ * Populated from the include/soc/devids.h file.
+ */
+
+static const struct pci_device_id _id_table[] = {
+ { BROADCOM_VENDOR_ID, BCM5675_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM5676_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56218X_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56218_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56219_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56218R_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56219R_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56214_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56215_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56214R_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56215R_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56216_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56217_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56212_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56213_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56230_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56231_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53718_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53714_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53716_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56018_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56014_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56224_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56225_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56226_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56227_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56228_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56229_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56024_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56025_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53724_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53726_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56100_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56101_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56102_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56105_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56106_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56107_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56110_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56111_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56112_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56115_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56116_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56117_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56300_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56301_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56302_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56303_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56304_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56404_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56305_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56306_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56307_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56308_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56309_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56310_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56311_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56312_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56313_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56314_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56315_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56316_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56317_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56318_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56319_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#ifndef EXCLUDE_BCM56324
+ { BROADCOM_VENDOR_ID, BCM56322_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56324_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#endif /* EXCLUDE_BCM56324 */
+ { BROADCOM_VENDOR_ID, BCM53312_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53313_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53314_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53324_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53333_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53334_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53342_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53343_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53344_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53346_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53347_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53393_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53394_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53300_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53301_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53302_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56500_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56501_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56502_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56503_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56504_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56505_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56506_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56507_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56508_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56509_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56510_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56511_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56512_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56513_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56514_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56516_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56517_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56518_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56519_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56580_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56620_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56624_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56626_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56628_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56629_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56680_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56684_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56700_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56701_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56720_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56721_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56725_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56800_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56801_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56802_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56803_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56820_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56821_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56822_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56823_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56825_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56630_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56634_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56636_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56638_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56639_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56538_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56520_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56521_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56522_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56524_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56526_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56534_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56685_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56689_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56331_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56333_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56334_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56338_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56320_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56321_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56132_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56134_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88732_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56140_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56142_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56143_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56144_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56146_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56147_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56149_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56150_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56151_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56152_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56930_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56931_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56936_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56939_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56840_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56841_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56842_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56843_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56844_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56845_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56846_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56847_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56549_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56053_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56838_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56831_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56835_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56849_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56742_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56743_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56744_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56745_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56746_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56640_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56548_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56547_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56346_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56345_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56344_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56342_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56340_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56049_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56048_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56047_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56042_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56041_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56040_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56643_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56644_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56648_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56649_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56540_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56541_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56542_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56543_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56544_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56545_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56546_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56044_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56045_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56046_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM55440_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56440_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56441_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56442_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56443_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56445_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56446_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56447_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56448_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56449_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56240_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56241_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56242_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56243_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56245_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56246_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM55450_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM55455_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56260_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56270_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56271_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56272_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53460_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53461_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56261_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56262_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56263_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56265_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56266_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56267_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56268_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56233_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56460_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56461_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56462_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56463_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56465_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56466_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56467_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56468_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56246_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56248_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56450_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56452_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56454_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56455_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56456_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56457_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56458_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56850_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56851_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56852_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56853_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56854_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56855_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56834_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56750_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56830_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM55440_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM55441_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56060_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56062_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56063_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56064_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56065_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56066_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53401_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53411_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53402_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53412_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53403_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53413_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53404_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53414_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53405_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53415_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53406_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53416_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53408_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53418_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53454_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53455_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53456_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53457_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53422_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53424_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53426_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53365_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53369_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56960_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56961_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56962_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56963_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56930_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56968_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56970_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56971_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56972_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56974_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56975_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56168_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56169_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56560_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56561_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56562_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56565_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56566_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56567_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56670_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56671_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56672_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56675_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56568_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56670_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56760_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56761_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56762_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56764_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56765_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56766_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56768_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56069_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56068_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56160_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56162_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56163_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56164_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56166_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53440_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53443_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53442_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53434_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56965_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56969_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56966_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56967_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56170_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56172_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56174_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53570_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53575_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56070_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56071_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56072_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9656, PCI_ANY_ID, PCI_ANY_ID },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9056, PCI_ANY_ID, PCI_ANY_ID },
+ { BCM53000_VENDOR_ID, BCM53000PCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#ifdef BCM_PETRA_SUPPORT
+ { BROADCOM_VENDOR_ID, BCM88650_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88350_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88351_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88450_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88451_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88550_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88551_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88552_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88651_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88654_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { PCP_PCI_VENDOR_ID, PCP_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { ACP_PCI_VENDOR_ID, ACP_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88660_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88670_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88671_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88671M_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88672_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88673_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88674_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88675_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88675M_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88676_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88676M_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88677_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88678_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88679_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88370_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88371_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88371M_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88375_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88470_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88470P_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88471_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88473_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88474_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88474H_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88476_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88477_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+
+
+ { BROADCOM_VENDOR_ID, BCM88270_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88271_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88272_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88273_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88274_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88276_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88278_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88279_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+
+ { BROADCOM_VENDOR_ID, BCM8206_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+
+ { BROADCOM_VENDOR_ID, BCM88376_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88376M_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88377_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88378_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88379_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88680_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88681_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88682_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88683_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88684_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88685_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88687_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88380_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88381_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88202_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88360_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88361_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88363_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88460_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88461_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88560_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88561_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88562_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88661_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88664_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#endif
+#ifdef BCM_DNX_SUPPORT
+ { BROADCOM_VENDOR_ID, BCM88690_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88690_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88691_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88692_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88693_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88694_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88695_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88696_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88697_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88698_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88699_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8869A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8869B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8869C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8869D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8869E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8869F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88800_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88821_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88826_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88802_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88803_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88804_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88805_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88806_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88820_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88822_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88823_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88824_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88825_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88480_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88481_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88482_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88483_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88484_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88485_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88486_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88487_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88488_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88489_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8848A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8848B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8848C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8848D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8848E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8848F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88280_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88281_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88282_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88283_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88284_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88285_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88286_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88287_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88288_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88289_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8828A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8828B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8828C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8828D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8828E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8828F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88850_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#endif /* BCM_DNX_SUPPORT */
+#ifdef BCM_DFE_SUPPORT
+ { BROADCOM_VENDOR_ID, BCM88750_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88753_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88755_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88770_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88773_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88774_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88775_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88776_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88777_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#ifndef DNX_IGNORE_FE3200
+ { BROADCOM_VENDOR_ID, BCM88950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#endif
+ { BROADCOM_VENDOR_ID, BCM88953_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88954_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88955_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88956_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88752_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88772_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88952_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#endif
+#ifdef BCM_DNXF_SUPPORT
+ { BROADCOM_VENDOR_ID, BCM88790_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88791_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88792_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88793_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88794_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88795_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88796_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88797_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88798_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM88799_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8879A_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8879B_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8879C_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8879D_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM8879F_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+#endif
+ { BROADCOM_VENDOR_ID, BCM56860_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56861_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56862_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56864_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56865_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56866_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56867_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56868_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56833_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56832_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56836_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56870_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56273_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56274_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56275_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56276_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56277_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56278_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56279_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56575_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56370_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56371_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56372_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56374_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56375_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56376_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56377_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56577_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56578_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56579_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56873_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56770_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56771_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56980_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56981_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56982_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56983_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56984_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53540_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53547_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53548_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM53549_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56470_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56471_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56472_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { BROADCOM_VENDOR_ID, BCM56475_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+ { 0, 0, 0, 0 }
+};;
+
+MODULE_DEVICE_TABLE(pci, _id_table);
+
+#define pci_bus_b(n) list_entry(n, struct pci_bus, node)
+#define pci_dev_b(n) list_entry(n, struct pci_dev, bus_list)
+#define MAX_RC_NUM 4
+
+static struct pci_bus *
+pci_do_bus_find(struct pci_bus* bus, int rc, int vendor, int device)
+{
+ struct list_head *tmp;
+ struct pci_dev *dev;
+ struct pci_bus *sub_bus;
+ int func = 0;
+
+ if (unlikely(list_empty(&bus->children))) {
+ return NULL;
+ }
+ list_for_each(tmp, &bus->children) {
+ sub_bus = pci_bus_b(tmp);
+ dev = sub_bus->self;
+ func = dev->devfn & 0x7;
+ if (dev->vendor == vendor && dev->device == device && rc == func) {
+ if (debug >= 1) {
+ gprintk("pci_do_bus_find: dev->vendor = 0x%x, dev->device = 0x%x on rc(%d)\n",
+ dev->vendor, dev->device, rc);
+ }
+ return sub_bus;
+ }
+ }
+ return NULL;
+}
+
+static struct pci_dev *
+_pci_do_bus_dev_find(struct pci_bus* bus, unsigned int vendor, unsigned int device)
+{
+ struct list_head *tmp;
+ struct pci_dev *dev;
+
+ if (unlikely(list_empty(&bus->devices))) {
+ return NULL;
+ }
+ list_for_each(tmp, &bus->devices) {
+ dev = pci_dev_b(tmp);
+ if (dev->vendor == vendor && (device == PCI_ANY_ID || dev->device == device)) {
+ if (debug >= 1) {
+ gprintk("_pci_do_rc_dev_find: vendor = %x, device = %x\n", vendor, device);
+ }
+ return dev;
+ }
+ }
+ return NULL;
+}
+
+static struct pci_dev *
+pci_do_rc_dev_find(int rc)
+{
+ struct pci_bus *root_bus = pci_find_bus(0,0);
+ struct pci_bus *bus_rc = NULL;
+ struct pci_dev *dev_on_rc = NULL;
+ unsigned int pci_dev_id = 0;
+
+ if(NULL == root_bus) {
+ if (debug >= 1) gprintk("Not find root bus\n");
+ return NULL;
+ }
+ bus_rc = pci_do_bus_find(root_bus, rc, 0x184e, 0x1004);
+ if (NULL == bus_rc) {
+ if (debug >= 1) {
+ gprintk("Not find vendor(0x184e) device(0x1004) bus\n");
+ }
+ return NULL;
+ }
+ for(pci_dev_id = 0; pci_dev_id < sizeof(_id_table)/sizeof(struct pci_device_id); pci_dev_id++) {
+ dev_on_rc = _pci_do_bus_dev_find(bus_rc, _id_table[pci_dev_id].vendor, _id_table[pci_dev_id].device);
+ if (NULL != dev_on_rc) {
+ return dev_on_rc;
+ }
+ }
+ if (debug >= 1) {
+ gprintk("Not find device at rc(%d)\n", rc);
+ }
+ return NULL;
+}
+
+/*
+ * Function: p2p_bridge
+ *
+ * Purpose:
+ * Finalize initialization secondary PCI-PCI bridge.
+ * Parameters:
+ * membase - start of memory address space for secondary PCI bus
+ * Returns:
+ * 0
+ * Notes:
+ * The membase depends on the processor architecture, and is
+ * derived from the memory space addresses set up by the kernel.
+ */
+static int
+p2p_bridge(void)
+{
+ struct pci_dev *dev, *dev_on_rc;
+ uint16 cmd;
+ uint16 mem_base;
+ uint16 mem_limit;
+ uint8 bridge_ctrl;
+ uint8 rc_index;
+
+ if ((dev = PCI_FIND_DEV(DC21150_VENDOR_ID, DC21150_DEVICE_ID, NULL)) != NULL ||
+ (dev = PCI_FIND_DEV(HINT_HB4_VENDOR_ID, HINT_HB4_DEVICE_ID, NULL)) != NULL ||
+ (dev = PCI_FIND_DEV(PI7C8150_VENDOR_ID, PI7C8150_DEVICE_ID, NULL)) != NULL) {
+
+ if (debug >= 1) gprintk("fixing up PCI-to-PCI bridge\n");
+ /* Adjust command register */
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ /* Disable device */
+ pci_write_config_word(dev, PCI_COMMAND, 0);
+ /* Initialize non-prefetchable memory window if needed */
+ pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base);
+ if (mem_base == 0) {
+ mem_base = (uint16)((_pci_mem_start & 0xFFF00000) >> 16);
+ mem_limit = (uint16)((_pci_mem_end & 0xFFF00000) >> 16);
+ pci_write_config_word(dev, PCI_MEMORY_BASE, mem_base);
+ pci_write_config_word(dev, PCI_MEMORY_LIMIT, mem_limit);
+ }
+ /* Enable PCI clocks on remote end */
+ pci_write_config_word(dev, PCI_CFG_DEC21150_SEC_CLK, 0);
+ /* Re-enable config space */
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+ /* Avoid DMA data corruption */
+ if (dev->vendor == HINT_HB4_VENDOR_ID) {
+ /* Fix for HiNT bridge and BCM4704 DMA problem */
+ if ((dev = PCI_FIND_DEV(BCM4704_VENDOR_ID, BCM4704_DEVICE_ID, NULL)) != NULL) {
+ /* Reset PrefetchEn (PE) */
+ pci_write_config_dword(dev, 0x8c, 1);
+ if (debug >= 1) {
+ gprintk("reset PrefetchEn on BCM4704 when HiNT bridge is present\n");
+ }
+ }
+ }
+ }
+ /* Enable fast back-to-back read/write */
+ if ((dev = PCI_FIND_DEV(PI7C8150_VENDOR_ID, PI7C8150_DEVICE_ID, NULL)) != NULL) {
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_FAST_BACK;
+ pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bridge_ctrl);
+ bridge_ctrl |= PCI_BRIDGE_CTL_FAST_BACK;
+ pci_write_config_word(dev, PCI_COMMAND, 0);
+ pci_write_config_byte(dev, PCI_BRIDGE_CONTROL, bridge_ctrl);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ /* Netlogic XLP CPU */
+ for(rc_index = 0; rc_index < MAX_RC_NUM; rc_index++) {
+ dev_on_rc = pci_do_rc_dev_find(rc_index);
+ if (dev_on_rc != NULL ) {
+ dev = PCI_FIND_DEV(0x184e, 0x1004, NULL);
+ if (dev != NULL ) {
+ pci_write_config_dword(dev,0x78,MAX_PAYLOAD_256B |
+ MAX_READ_REQ_256B);
+ }
+ }
+ }
+ if ((dev = PCI_FIND_DEV(0x14e4, 0xb634, NULL)) != NULL) {
+ pci_write_config_dword(dev,0x78,MAX_PAYLOAD_256B |
+ MAX_READ_REQ_256B);
+ }
+
+ if ((dev = PCI_FIND_DEV(PCI_VNDID_PERICOM, PCI_DEVID_PI7C9X130, NULL)) != NULL) {
+ /*
+ * Configure the PCIE cap: Max payload size: 256, Max Read
+ * Request size: 256, disabling relax ordering.
+ * Writes to the PCIE capability device control register
+ */
+ pci_write_config_dword(dev, DEV_CTRL_REG,
+ MAX_PAYLOAD_256B | MAX_READ_REQ_256B);
+ }
+
+ if ((dev = PCI_FIND_DEV(FSL_VENDOR_ID, FSL8548PCIE_DEVICE_ID, NULL)) != NULL ||
+ (dev = PCI_FIND_DEV(FSL_VENDOR_ID, FSL2020EPCIE_DEVICE_ID, NULL)) != NULL) {
+ /*
+ * Configure the PCIE cap: Max payload size: 256, Max Read
+ * Request size: 256, disabling relax ordering.
+ * Writes to the PCIE capability device control register
+ */
+ pci_write_config_dword(dev, FSL8548PCIE_DEV_CTRL_REG,
+ MAX_PAYLOAD_256B | MAX_READ_REQ_256B);
+ }
+ if ((dev = PCI_FIND_DEV(BCM4716_VENDOR_ID, BCM4716PCIE_DEVICE_ID, NULL)) != NULL ||
+ (dev = PCI_FIND_DEV(BCM53000_VENDOR_ID, BCM53000PCIE_DEVICE_ID, NULL)) != NULL) {
+ uint32 tmp, maxpayld, device_bmp=0, mask;
+ unsigned long addr;
+ uint16 tmp16, tmp161;
+ int i, bus0 = -1, bus1 = -1, port;
+ struct pci_dev *pcie0, *pcie1;
+
+ pcie0 = dev;
+ bus0 = dev->bus->number;
+ if ((pcie1 = PCI_FIND_DEV(BCM53000_VENDOR_ID, BCM53000PCIE_DEVICE_ID, pcie0)) != NULL) {
+ bus1 = pcie1->bus->number;
+ }
+
+ for(i = 0; i < _ndevices; i++) {
+ bde_ctrl_t *ctrl = _devices + i;
+
+ mask = BDE_SWITCH_DEV_TYPE | BDE_PCI_DEV_TYPE;
+ if ((ctrl->dev_type & mask) == mask) {
+ if (ctrl->pci_device->bus->number == bus0) {
+ device_bmp |= 1 << 0;
+ }
+ if (ctrl->pci_device->bus->number == bus1) {
+ device_bmp |= 1 << 1;
+ }
+ }
+ }
+
+ /* configure the PCIE cap: Max payload size: 256, Max Read
+ * Request size: 256, disabling relax ordering.
+ * Writes to the PCIE capability device control register
+ */
+
+ i = 0;
+ while(device_bmp) {
+ if (device_bmp & (1 << i)){
+ port = i ;
+ pci_read_config_dword(BCM53000PCIE_DEV(port),
+ BCM53000PCIE_DEV_CAP_REG, &tmp);
+ maxpayld = (tmp & BCM53000PCIE_MAX_PAYLOAD_MASK);
+ if (debug >= 1) {
+ gprintk("port %d\n",port);
+ gprintk("DevCap (@%x): 0x%x%c\n", BCM53000PCIE_DEV_CAP_REG, tmp,
+ (maxpayld != BCM53000PCIE_CAP_MAX_PAYLOAD_256B) ? ' ':'\n');
+ }
+ if (maxpayld != BCM53000PCIE_CAP_MAX_PAYLOAD_256B) {
+ addr = BCM53000PCIE_BASE(port);
+ addr |= (BCM53000PCIE_SROM_SPACE | BCM53000PCIE_SPROM_OFFSET);
+ tmp16 = *((uint16 *)addr);
+ if (debug >= 1){
+ gprintk("addr %lx spromData.MaxPayloadSize: 0x%x\n", addr, tmp16);
+ }
+ mask = BCM53000PCIE_SPROM_MAX_PAYLOAD_MASK;
+ if ((tmp16 & mask) != BCM53000PCIE_SPROM_MAX_PAYLOAD_256B) {
+ tmp161 = (tmp16 & ~mask) | BCM53000PCIE_SPROM_MAX_PAYLOAD_256B;
+ *((uint16 *)addr) = tmp161;
+ if (debug >= 1) {
+ tmp16 = 0;
+ tmp16 = *((uint16 *)addr);
+ gprintk("Enable spromData.MaxPayloadSize to 1 (256 bytes): "
+ "0x%x (%s w/ 0x%x)\n", tmp161,
+ ((tmp16 & mask) == BCM53000PCIE_SPROM_MAX_PAYLOAD_256B) ?
+ "Success":"Fail",
+ tmp16);
+ }
+ }
+ pci_read_config_dword(BCM53000PCIE_DEV(port),
+ BCM53000PCIE_DEV_CAP_REG, &tmp);
+ if (debug >= 1){
+ gprintk("DevCap (@%x): now is 0x%x\n\n",
+ BCM53000PCIE_DEV_CAP_REG, tmp);
+ }
+ }
+
+ addr = BCM53000PCIE_BASE(port);
+ addr |= (BCM53000PCIE_FUNC0_COFIG_SPACE | BCM53000PCIE_DEV_CTRL_REG);
+ tmp16 = *((uint16 *)addr);
+ if (debug >= 1) {
+ gprintk("DevControl (@%x): 0x%x\n", BCM53000PCIE_DEV_CTRL_REG, tmp16);
+ }
+ if (!(tmp16 & MAX_PAYLOAD_256B) || !(tmp16 & MAX_READ_REQ_256B)) {
+ tmp161 = tmp16 | MAX_PAYLOAD_256B | MAX_READ_REQ_256B;
+ *((uint16 *)addr) = tmp161;
+ if (debug >= 1) {
+ tmp16 = 0;
+ tmp16 = *((uint16 *)addr);
+ gprintk("addr %lx Enable DevControl MaxPayloadSize to 1 (256 bytes): "
+ "0x%x (%s w/ 0x%x)\n", addr, tmp161,
+ (tmp16 & MAX_PAYLOAD_256B) ? "Success":"Fail",
+ tmp16);
+ gprintk("Enable DevControl MaxReadRequestSize to 1 (256 bytes): "
+ "0x%x (%s w/ 0x%x)\n\n", tmp161,
+ (tmp16 & MAX_READ_REQ_256B) ? "Success":"Fail",
+ tmp16);
+ }
+ }
+ device_bmp &= ~(1 << i);
+ }
+ i++;
+ }
+ }
+
+ /*
+ * Configure max payload to 512 on all ports in the PLX8608/PLX8617.
+ * The device supports 128, 512, and 1024 max payload sizes.
+ */
+ dev = NULL;
+ while ((dev = PCI_FIND_DEV(PCI_VENDOR_ID_PLX, PCI_ANY_ID, dev)) != NULL) {
+ if ((dev->device == PLX_PEX8608_DEV_ID) ||
+ (dev->device == PLX_PEX8617_DEV_ID)) {
+ uint16 ctrl_reg;
+ pci_read_config_word(dev, PLX_PEX86XX_DEV_CTRL_REG, &ctrl_reg);
+ ctrl_reg = (ctrl_reg & ~(7<<5)) | MAX_PAYLOAD_512B;
+ pci_write_config_word(dev, PLX_PEX86XX_DEV_CTRL_REG, ctrl_reg);
+ }
+ }
+ return 0;
+}
+
+#ifdef BCM_PLX9656_LOCAL_BUS
+
+#define PLX_LAS0_BA 0x00000004 /* LAS0 Local Base Address Remap */
+#define PLX_LAS1_BA 0x000000f4 /* LAS1 Local Base Address Remap */
+#define PLX_LAS_EN 0x00000001 /* Space Enable bit */
+
+#define PLX_MMAP_PCIBAR0 0 /* Memory-Mapped Config (PCIBAR0) */
+#define PLX_LAS0_PCIBAR2 2 /* Local Address Space 0 (PCIBAR2) */
+#define PLX_LAS1_PCIBAR3 3 /* Local Address Space 1 (PCIBAR3) */
+
+STATIC int
+_plx_las_bar_get(struct pci_dev *dev)
+{
+ void *local_config_addr;
+ int bar = -1;
+
+ local_config_addr = IOREMAP(pci_resource_start(dev, PLX_MMAP_PCIBAR0),
+ pci_resource_len(dev, PLX_MMAP_PCIBAR0));
+ if (local_config_addr) {
+ uint32 las_remap_reg;
+ /*
+ * Make sure LAS0BA or LAS1BA is enabled before returning
+ * BAR that will be used to access the Local Bus
+ */
+ las_remap_reg = ioread32(local_config_addr + PLX_LAS0_BA);
+ if (las_remap_reg & PLX_LAS_EN) {
+ bar = PLX_LAS0_PCIBAR2;
+ } else {
+ las_remap_reg = ioread32(local_config_addr + PLX_LAS1_BA);
+ if (las_remap_reg & PLX_LAS_EN) {
+ bar = PLX_LAS1_PCIBAR3;
+ }
+ }
+ }
+ iounmap(local_config_addr);
+ return bar;
+}
+#endif /* BCM_PLX9656_LOCAL_BUS */
+
+static void
+_shbde_log_func(int level, const char *str, int param)
+{
+ level = (level >= SHBDE_DBG) ? 1 : 0;
+ if (debug >= level) {
+ gprintk("%s (%d)\n", str, param);
+ }
+}
+/*
+ * Function: _device_rescan_validate
+ *
+ * Purpose:
+ * Check if the device is ever probed or not.
+ * Parameters:
+ * dev - Linux PCI device structure
+ * Returns:
+ * >= 0 : dev is ever probed
+ * reutrn value is the index point to the _devices[]
+ * -1 : dev is not probed before.
+ */
+static int
+_device_rescan_validate(struct pci_dev *dev)
+{
+ bde_ctrl_t *ctrl;
+ int i;
+
+ if (PCI_FUNC(dev->devfn) > 0) {
+ return -1;
+ }
+ ctrl = NULL;
+ for (i = 0; i < _ndevices; i ++) {
+ ctrl = _devices + i;
+ /* check the device id */
+ if (dev->device == ctrl->bde_dev.device) {
+ /* check the bus number */
+ if ((dev->bus)) {
+ if ((dev->bus->number == ctrl->bus_no) &&
+ (pci_domain_nr(dev->bus) == ctrl->domain_no)) {
+ return i;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+#ifdef CONFIG_PCI_MSI
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+/**
+ * _pci_msix_table_size - return the number of device's MSI-X table entries
+ * @dev: pointer to the pci_dev data structure of MSI-X device function
+ */
+static int
+_pci_msix_table_size(struct pci_dev *dev)
+{
+ int nr_entries = 0;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,110))
+ u16 control;
+ int pos;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+ if (pos) {
+ pci_read_config_word(dev, msi_control_reg(pos), &control);
+ nr_entries = msix_table_size(control);
+ }
+#else
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0))
+{
+ /* Pass large entry value to enable MSIX to get # of entires */
+ struct msix_entry *entries;
+ entries = kmalloc(sizeof(struct msix_entry) *
+ PCI_MSIX_FLAGS_QSIZE, GFP_KERNEL);
+ if (entries != NULL) {
+ nr_entries = pci_enable_msix(dev,
+ entries, PCI_MSIX_FLAGS_QSIZE);
+ if (nr_entries < 0) {
+ nr_entries = 0;
+ }
+ pci_disable_msix(dev);
+ kfree(entries);
+ }
+}
+#else
+ nr_entries = pci_msix_vec_count(dev);
+#endif
+#endif
+
+ return nr_entries;
+}
+#endif
+
+static int
+_msi_connect(bde_ctrl_t *ctrl)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+ int ret;
+ if (ctrl->use_msi == PCI_USE_INT_MSIX) {
+ int i;
+
+ ret = _pci_msix_table_size(ctrl->pci_device);
+ if (ret == 0) {
+ /* MSI-X failed */
+ gprintk("MSI-X not supported.\n");
+ goto er_intx;
+ }
+ ctrl->entries = kcalloc(ret, sizeof(struct msix_entry), GFP_KERNEL);
+
+ if (!ctrl->entries) {
+ goto er_intx;
+ }
+ /* Only one vector is mapped by default */
+ /* May be more in future, can be controlled using module param */
+ ctrl->msix_cnt = msixcnt;
+ if (unlikely(debug > 1))
+ gprintk("MSIX Table size = %d\n", ctrl->msix_cnt);
+ for (i = 0; i < ctrl->msix_cnt; i++)
+ ctrl->entries[i].entry = i;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0)
+ ret = pci_enable_msix_range(ctrl->pci_device,
+ ctrl->entries, ctrl->msix_cnt, ctrl->msix_cnt);
+#else
+ ret = pci_enable_msix(ctrl->pci_device,
+ ctrl->entries, ctrl->msix_cnt);
+ if (ret > 0) {
+ /* Not enough vectors available , Retry MSI-X */
+ gprintk("Retrying with MSI-X interrupts = %d\n", ret);
+ ctrl->msix_cnt = ret;
+ msixcnt = ret;
+ ret = pci_enable_msix(ctrl->pci_device,
+ ctrl->entries, ctrl->msix_cnt);
+ if (ret != 0)
+ goto er_intx_free;
+ }
+#endif
+ if (ret < 0) {
+ /* Error */
+ goto er_intx_free;
+ } else {
+ gprintk("Enabled MSI-X interrupts = %d\n", ctrl->msix_cnt);
+ return 0;
+ }
+ }
+#endif
+
+ if (ctrl->use_msi == PCI_USE_INT_MSI) {
+ if (pci_enable_msi(ctrl->pci_device) == 0) {
+ ctrl->iLine = ctrl->pci_device->irq;
+ } else {
+ /* MSI failed */
+ gprintk("Failed to initialize MSI interrupts.\n");
+ goto er_intx;
+ }
+ } else {
+ /* failed */
+ gprintk("Not MSI/MSIX interrupt.\n");
+ goto er_intx;
+ }
+ return 0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+er_intx_free:
+ gprintk("Failed to enable MSI-X interrupts = %d\n", ret);
+ kfree(ctrl->entries);
+#endif
+er_intx:
+ return -1;
+
+}
+
+static int
+_msi_disconnect(bde_ctrl_t *ctrl)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+ if (ctrl->use_msi == PCI_USE_INT_MSIX) {
+ if (ctrl->msix_cnt) {
+ pci_disable_msix(ctrl->pci_device);
+ kfree(ctrl->entries);
+ ctrl->entries = NULL;
+ ctrl->msix_cnt = 0;
+ }
+ }
+#endif
+ if (ctrl->use_msi == PCI_USE_INT_MSI) {
+ pci_disable_msi(ctrl->pci_device);
+ } else {
+ gprintk("MSI not used\n");
+ }
+ return 0;
+}
+
+#endif
+
+
+static void
+config_pci_intr_type(struct pci_dev *dev, bde_ctrl_t *ctrl, int iproc)
+{
+#ifdef CONFIG_PCI_MSI
+ int ret;
+ shbde_iproc_config_t icfg;
+
+ /* Each device follows global policy by default */
+ ctrl->use_msi = use_msi;
+
+ if (unlikely(debug > 1))
+ gprintk("%s: msi = %d\n", __func__, ctrl->use_msi);
+
+ /* Check IPROC version for MSIX support */
+ if (iproc && ctrl->bde_dev.base_address1 &&
+ (ctrl->use_msi == PCI_USE_INT_MSIX)) {
+ if (shbde_pci_iproc_version_get(&ctrl->shbde, dev, &icfg.iproc_ver,
+ &icfg.cmic_ver, &icfg.cmic_rev)) {
+ if (icfg.iproc_ver < 0xe) {
+ gprintk("%s: MSI-X not supported, using MSI.\n", __func__);
+ ctrl->use_msi = PCI_USE_INT_MSI;
+ }
+ }
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+ if (ctrl->use_msi == PCI_USE_INT_MSIX) {
+ /* check for support MSIX vector */
+ ret = _pci_msix_table_size(ctrl->pci_device);
+ if (ret == 0) {
+ gprintk("%s: Zero MSIX table size\n", __func__);
+ ctrl->use_msi = PCI_USE_INT_MSI;
+ }
+ }
+#endif
+
+ if (ctrl->use_msi == PCI_USE_INT_MSI) {
+ /* check for support MSI vector */
+ ret = pci_enable_msi(ctrl->pci_device);
+ if (ret < 0) {
+ ctrl->use_msi = PCI_USE_INT_INTX;
+ gprintk("%s: Failed to enable MSI, using INTx.\n", __func__);
+ } else {
+ pci_disable_msi(ctrl->pci_device);
+ }
+ }
+#else
+ ctrl->use_msi = PCI_USE_INT_INTX;
+#endif
+}
+
+/*
+ * Function: _pci_probe
+ *
+ * Purpose:
+ * Device initialization callback used by the Linux PCI
+ * subsystem. Called as a result of pci_register_driver().
+ * Parameters:
+ * dev - Linux PCI device structure
+ * Returns:
+ * 0
+ */
+static int
+_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
+{
+ bde_ctrl_t *ctrl;
+ resource_size_t paddr;
+ uint16 cmd = 0;
+ uint32 bar_len;
+ int i, cmic_bar;
+ int baroff = 0;
+ int iproc = 0;
+ int plx_dev = 0;
+ int eth_dev = 0;
+ int cpu_dev = 0;
+ int update_devid = 0;
+ int paxb_core = 0;
+ int add_dev = 0, rescan = 0, rescan_idx = -1;
+ shbde_hal_t shared_bde, *shbde = &shared_bde;
+
+ if (debug >= 4) {gprintk("probing: vendor_id=0x%x, device_id=0x%x\n", dev->vendor, dev->device);}
+ if (nodevices == 1) {
+ return 0;
+ }
+
+ /* Initialize Linux hardware abstraction for shared BDE functions */
+ linux_shbde_hal_init(shbde, _shbde_log_func);
+
+ /*
+ * If an AXI-based switch device has been found already, then it means
+ * that the AXI bus has been probed, and that we should ignore devices
+ * found on PCI bus zero.
+ */
+
+#if defined(IPROC_CMICD)
+ if ((dev->bus) && (dev->bus->number == 0)) {
+ int i;
+ uint32 mask = BDE_SWITCH_DEV_TYPE | BDE_AXI_DEV_TYPE;
+
+ for (i = 0; i < _ndevices; i++) {
+ ctrl = _devices + i;
+
+ if ((ctrl->dev_type & mask) == mask) {
+ return 0;
+ }
+ }
+ }
+#endif /* IPROC_CMICD */
+
+ /*
+ * Note that a few supported devices have a non-Broadcom PCI vendor ID,
+ * but since none of their associated PCI device IDs collide with the
+ * Broadcom device IDs, the probe code below only checks the device ID.
+ */
+
+ switch (dev->device) {
+ case PCI_DEVICE_ID_PLX_9056:
+#ifdef DNX_TEST_BOARD
+ break; /* a PCIe bridge to a non PCIe device should be treated as the device */
+#endif /* DNX_TEST_BOARD */
+ case PCI_DEVICE_ID_PLX_9656:
+ plx_dev = 1;
+ break;
+ case BCM53000PCIE_DEVICE_ID:
+ cpu_dev = 1;
+ break;
+ /*
+ * The device ID for 56500, 56100 and 56300 family of devices may
+ * be incorrect just after a PCI HW reset. It needs to be read
+ * again after stabilization.
+ */
+ case BCM56102_DEVICE_ID:
+ case BCM56504_DEVICE_ID:
+ case BCM56304_DEVICE_ID:
+ case BCM56314_DEVICE_ID:
+ case BCM56112_DEVICE_ID:
+ update_devid = 1;
+ break;
+ default:
+ break;
+ }
+
+ /* Check if the device is ever probed. */
+ rescan_idx = _device_rescan_validate(dev);
+ if (rescan_idx != -1) {
+ rescan = 1;
+ }
+
+ ctrl = NULL;
+ if (plx_dev) {
+#if defined(BCM_PLX9656_LOCAL_BUS)
+ /* PLX chip itself won't be part of _devices[]. */
+ baroff = _plx_las_bar_get(dev);
+ if (baroff == -1) {
+ gprintk("No Local Address Space enabled in PLX\n");
+ return 0;
+ }
+ ctrl = &plx_ctrl;
+ num_plx++;
+#endif
+ } else if (eth_dev) {
+ if (_ether_ndevices >= LINUX_BDE_MAX_ETHER_DEVICES) {
+ return 0;;
+ }
+ ctrl = _devices + _ndevices;
+ ctrl->dev_type |= BDE_ETHER_DEV_TYPE;
+ ctrl->iLine = dev->irq;
+ add_dev = 1;
+ if (debug >= 1)
+ gprintk("Found PCI device %04x:%04x as Ethernet device\n",
+ dev->vendor, dev->device);
+ } else if (cpu_dev) {
+ if (_cpu_ndevices >= LINUX_BDE_MAX_CPU_DEVICES) {
+ return 0;;
+ }
+ ctrl = _devices + _ndevices;
+ ctrl->dev_type |= BDE_CPU_DEV_TYPE;
+ add_dev = 1;
+ if (debug >= 1)
+ gprintk("Found PCI device %04x:%04x as CPU device\n",
+ dev->vendor, dev->device);
+ } else {
+ if (PCI_FUNC(dev->devfn) > 0) {
+ return 0;
+ }
+ if (_switch_ndevices >= LINUX_BDE_MAX_SWITCH_DEVICES) {
+ return 0;
+ }
+
+ if (rescan) {
+ if (debug >= 1) {
+ gprintk("PCI device %04x:%04x is re-probed \n",
+ dev->vendor, dev->device);
+ }
+ ctrl = _devices + rescan_idx;
+ ctrl->dev_state = BDE_DEV_STATE_CHANGED;
+ } else {
+ ctrl = _devices + _ndevices;
+ ctrl->dev_type |= BDE_SWITCH_DEV_TYPE;
+ ctrl->domain_no = pci_domain_nr(dev->bus);
+ ctrl->bus_no = dev->bus->number;
+ ctrl->dev_state = BDE_DEV_STATE_NORMAL;
+ add_dev = 1;
+ }
+
+ /* Save shared BDE HAL in device structure */
+ MEMCPY(&ctrl->shbde, shbde, sizeof(ctrl->shbde));
+
+ if (update_devid) {
+ /* Re-read the device ID */
+ pci_read_config_word(dev,
+ PCI_DEVICE_ID,
+ &ctrl->bde_dev.device);
+ dev->device = ctrl->bde_dev.device;
+ }
+
+ if (debug >= 4) {gprintk("Enabling PCI device : vendor_id=0x%x, device_id=0x%x\n", dev->vendor, dev->device);}
+ if (pci_enable_device(dev)) {
+ gprintk("Cannot enable PCI device : vendor_id = %x, device_id = %x\n",
+ dev->vendor, dev->device);
+ }
+
+ /* FIXME: "workarounds" previously called "total h_acks" */
+ /*
+ * These are workarounds to get around some existing
+ * kernel problems :(
+ */
+
+ /*
+ * While probing we determine the overall limits for the PCI
+ * memory windows across all devices. These limits are used
+ * later on by the PCI-PCI bridge code.
+ */
+ if (pci_resource_start(dev, baroff) < _pci_mem_start) {
+ _pci_mem_start = pci_resource_start(dev, baroff);
+ }
+ if (pci_resource_end(dev, baroff) > _pci_mem_end) {
+ _pci_mem_end = pci_resource_end(dev, baroff);
+ }
+
+#ifdef CONFIG_SANDPOINT
+ /*
+ * Something wrong with the PCI subsystem in the mousse kernel.
+ * The device is programmed correctly, but the irq in the pci
+ * structure is hosed. This checks for the hosed-ness and fixes it.
+ */
+ if (dev->irq > 100) {
+ dev->irq = 2;
+ gprintk("irq problem: setting irq = %d\n", dev->irq);
+ }
+#endif
+
+#ifdef CONFIG_BMW
+ /*
+ * PCI subsystem does not always program the system correctly.
+ */
+ if (dev->irq < 16 && dev->irq != 2) {
+ dev->irq = 2;
+ gprintk("irq problem: setting irq = %d\n", dev->irq);
+ }
+#endif
+
+#ifdef CONFIG_IDT_79EB334
+ /*
+ * IDT kernel is not currently mapping interrupts correctly
+ * Hardwired to core mips interrupt, irq 3 for kernel 2.4.18
+ */
+ if (dev->irq != 3) {
+ dev->irq = 3;
+ gprintk("irq problem: setting irq = %d\n", dev->irq);
+ }
+#endif
+
+#ifdef CONFIG_BCM94702_CPCI
+ /*
+ * Hardwired to core mips interrupt irq 6 on MBZ
+ */
+ if (dev->irq != 6) {
+ dev->irq = 6;
+ gprintk("irq problem: setting irq = %d\n", dev->irq);
+ }
+#endif
+
+ if ((PCI_FIND_DEV(BCM4704_VENDOR_ID, BCM4704_DEVICE_ID, NULL)) != NULL) {
+ /*
+ * Decrease the PCI bus priority for the CPU for better overall
+ * system performance. This change significantly reduces the
+ * number of PCI retries from other devices on the PCI bus.
+ */
+ void * _mc_vbase = IOREMAP(BCM4704_MEMC_BASE, 0x1000);
+ int priorinv = 0x80;
+ static int done = 0;
+ if (!done) {
+ done = 1;
+ writel(priorinv, _mc_vbase + BCM4704_MEMC_PRIORINV);
+ if (debug >= 1)
+ gprintk("set BCM4704 PriorInvTim register to 0x%x\n", priorinv);
+ iounmap(_mc_vbase);
+ }
+ }
+
+ if ((PCI_FIND_DEV(SIBYTE_PCI_VENDOR_ID, SIBYTE_PCI_DEVICE_ID, NULL)) != NULL) {
+ /*
+ * The BCM91125CPCI CPU boards with a PCI-PCI bridge use the same
+ * interrupt line for all switch ships behind the bridge.
+ */
+ if (PCI_FIND_DEV(DC21150_VENDOR_ID, DC21150_DEVICE_ID, NULL) ||
+ PCI_FIND_DEV(HINT_HB4_VENDOR_ID, HINT_HB4_DEVICE_ID, NULL) ||
+ PCI_FIND_DEV(PI7C8150_VENDOR_ID, PI7C8150_DEVICE_ID, NULL)) {
+ /*
+ * By default we try to guess the correct IRQ based on the design.
+ * For now we only look at the bridge vendor, but it may be necessary
+ * to look at the switch chip configuration as well.
+ */
+ if (forceirq == -1) {
+ if ((PCI_FIND_DEV(HINT_HB4_VENDOR_ID, HINT_HB4_DEVICE_ID, NULL)) ||
+ ((dev->device == BCM5674_DEVICE_ID) &&
+ (PCI_FIND_DEV(PI7C8150_VENDOR_ID, PI7C8150_DEVICE_ID, NULL)))) {
+ forceirq = 58;
+ } else {
+ forceirq = 56;
+ }
+ }
+ }
+ }
+
+ if (((PCI_FIND_DEV(BCM58525_PCI_VENDOR_ID, BCM58525_PCI_DEVICE_ID, NULL)) != NULL) ||
+ ((PCI_FIND_DEV(BCM58525_PCI_VENDOR_ID, BCM58522_PCI_DEVICE_ID, NULL)) != NULL) ||
+ ((PCI_FIND_DEV(BCM58712_PCI_VENDOR_ID, BCM58712_PCI_DEVICE_ID, NULL)) != NULL) ) {
+ /* BCM58525/BCM58712 CPU boards support 128 Max payload size */
+ if (maxpayload && maxpayload != 128) {
+ maxpayload = 128;
+ if (debug >= 1) gprintk("force max payload size to 128\n");
+ }
+ }
+
+ if (forceirq > 0 && dev->irq != (uint32) forceirq) {
+ if (forceirqubm & (1U << (_ndevices - 1))) {
+ dev->irq = forceirq;
+ if (debug >= 1) gprintk("force irq to %d\n", forceirq);
+ }
+ } else if (debug >= 1) gprintk("found irq %d\n", dev->irq);
+
+ ctrl->iLine = dev->irq;
+ if (unlikely(debug > 1))
+ gprintk("%s:irq = %d\n",__func__, ctrl->iLine);
+
+ if (shbde_pci_is_pcie(shbde, dev)) {
+ /* Set PCIe max payload */
+ shbde_pci_max_payload_set(shbde, dev, maxpayload);
+ } else {
+ /* Set PCI retry to infinite on non-PCIe switch device */
+ pci_write_config_word(dev, 0x40, 0x0080);
+ if (debug >= 1) gprintk("set DMA retry to infinite on switch device\n");
+ }
+ }
+
+#if defined(BCM_DFE_SUPPORT)
+ switch (dev->device) {
+ case BCM88750_DEVICE_ID:
+ case BCM88753_DEVICE_ID:
+ case BCM88755_DEVICE_ID:
+ case BCM88770_DEVICE_ID:
+ case BCM88773_DEVICE_ID:
+ case BCM88774_DEVICE_ID:
+ case BCM88775_DEVICE_ID:
+ case BCM88776_DEVICE_ID:
+ case BCM88777_DEVICE_ID:
+ case BCM88950_DEVICE_ID:
+ case BCM88953_DEVICE_ID:
+ case BCM88954_DEVICE_ID:
+ case BCM88955_DEVICE_ID:
+ case BCM88956_DEVICE_ID:
+ case BCM88752_DEVICE_ID:
+ case BCM88772_DEVICE_ID:
+ case BCM88952_DEVICE_ID:
+
+ /*
+ * For DMA transactions - set Max_Payload_Size and
+ * Max_Read_Request_Size to 128 bytes.
+ */
+ pci_write_config_byte(dev, 0xb5, 0x0c);
+ pci_write_config_byte(dev, 0xb4, 0x0);
+ break;
+ default:
+ break;
+ }
+#endif /* BCM_DFE_SUPPORT */
+
+ /* Prevent compiler warning */
+ if (ctrl == NULL) {
+ return 0;
+ }
+
+ ctrl->be_pio = 0;
+ ctrl->dev_type |= BDE_PCI_DEV_TYPE;
+ ctrl->pci_device = dev;
+ pci_set_drvdata(dev, ctrl);
+
+ /*
+ * Sample setting of unique ID, used the PCIe address of the device:
+ * domain, bus, slot, function in hex digits: DDDDBBSS (SS includes the slot/device and function.
+ * Tested with old kernels from 2.6 .
+ * Do not use the PCI_DEVID macro which old kernel versions don't have. */
+ ctrl->bde_dev.dev_unique_id = dev->bus ?
+ (((uint32)pci_domain_nr(dev->bus)) << 16) ^ (((uint32)dev->bus->number) << 8) ^ dev->devfn :
+ dev->devfn;
+
+ /* Check for iProc device */
+ if (shbde_pci_is_iproc(shbde, dev, &cmic_bar)) {
+ iproc = 1;
+ if (cmic_bar >= 0) {
+ baroff = cmic_bar;
+ }
+ }
+#ifdef DNX_TEST_BOARD
+ else if (dev->device == PLX9056_DEVICE_ID && baroff == 0) {
+ baroff = 2;
+ ctrl->dev_type |= BDE_NO_IPROC/* | BDE_BYTE_SWAP*/;
+ }
+#endif /* DNX_TEST_BOARD */
+
+ /* Get the device revision */
+ pci_read_config_byte(dev, PCI_REVISION_ID, &ctrl->bde_dev.rev);
+
+ /* Map in the device */
+ ctrl->bde_dev.device = dev->device;
+ paddr = pci_resource_start(dev, baroff);
+
+ switch (dev->device) {
+#if defined(BCM_PETRA_SUPPORT) && defined(__DUNE_LINUX_BCM_CPU_PCIE__)
+ case GEDI_DEVICE_ID:
+ case PCP_PCI_DEVICE_ID:
+ bar_len = 0x1000000;
+ break;
+#endif
+ default:
+ bar_len = pci_resource_len(dev, baroff);
+ break;
+ }
+
+ ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(paddr, bar_len);
+ ctrl->iowin[0].addr = paddr;
+ ctrl->iowin[0].size = bar_len;
+
+ if (debug >= 3) {
+ gprintk("BAR %d: kernel addr:0x%lx phys addr:0x%lx length:%lx\n",
+ baroff, (unsigned long)ctrl->bde_dev.base_address, (unsigned long)paddr, (unsigned long)bar_len);
+ }
+
+ /* Map secondary address spaces */
+ for (i = 1; i < BDE_NUM_IOWIN_MAX; i++) {
+ ctrl->iowin[i].addr = 0;
+ ctrl->iowin[i].size = 0;
+ }
+ ctrl->bde_dev.base_address1 = 0;
+
+ if (iproc
+#ifdef DNX_TEST_BOARD
+ || (dev->device == PLX9056_DEVICE_ID && baroff == 2)
+#endif /* DNX_TEST_BOARD */
+ ) {
+ paddr = pci_resource_start(dev, 0);
+ bar_len = pci_resource_len(dev, 0);
+ ctrl->bde_dev.base_address1 = (sal_vaddr_t)IOREMAP(paddr, bar_len);
+ ctrl->iowin[1].addr = paddr;
+ ctrl->iowin[1].size = bar_len;
+ if (debug >= 3) {
+ gprintk("BAR 0: kernel addr:0x%lx phys addr:0x%lx length:%lx\n",
+ (unsigned long)ctrl->bde_dev.base_address1, (unsigned long)paddr, (unsigned long)bar_len);
+ }
+ }
+
+ /* configure interrupt type */
+ config_pci_intr_type(dev, ctrl, iproc);
+
+ /* Configure iProc PCI-AXI bridge */
+ if (iproc && ctrl->bde_dev.base_address1) {
+ void *iproc_regs;
+ shbde_iproc_config_t *icfg = &shbde->icfg;
+
+ /* Mapped iProc regs in PCI BAR 0 */
+ iproc_regs = (void *)ctrl->bde_dev.base_address1;
+
+ /* iProc configuration parameters */
+ (void)shbde_pci_iproc_version_get(shbde, dev, &icfg->iproc_ver,
+ &icfg->cmic_ver, &icfg->cmic_rev);
+ shbde_iproc_config_init(icfg, ctrl->bde_dev.device, ctrl->bde_dev.rev);
+
+ if (debug >= 2) {
+ gprintk("iproc version = %x dma_hi_bits = %x\n", icfg->iproc_ver, icfg->dma_hi_bits);
+ }
+ icfg->use_msi = ctrl->use_msi;
+
+ /* Call shared function */
+ paxb_core = shbde_iproc_paxb_init(shbde, iproc_regs, icfg);
+
+ /* Save PCI core information for CMIC */
+ if (paxb_core == 1) {
+ ctrl->dev_type |= BDE_DEV_BUS_ALT;
+ }
+
+ /* Save MSI enable state information */
+ if (ctrl->use_msi) {
+ ctrl->dev_type |= BDE_DEV_BUS_MSI;
+ }
+
+ /* iProc PCIe preemphasis */
+ shbde_iproc_pcie_preemphasis_set(shbde, iproc_regs, icfg, dev);
+ }
+
+ /* Save shared BDE HAL in device structure */
+ MEMCPY(&ctrl->shbde, shbde, sizeof(ctrl->shbde));
+
+
+ ctrl->isr = NULL;
+ ctrl->isr_data = NULL;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ if (!(cmd & PCI_COMMAND_MEMORY) || !(cmd & PCI_COMMAND_MASTER)) {
+ cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ if (debug >= 1) gprintk("enable PCI resources 0x%x (PCI_COMMAND)\n", cmd);
+ }
+
+ /* Check if we need 256 KB memory window (default is 64 KB) */
+ bar_len = pci_resource_len(dev, baroff);
+ if (bar_len == 0x40000) {
+ ctrl->dev_type |= BDE_256K_REG_SPACE;
+ if (debug >= 1) gprintk("PCI resource len 256K\n");
+ } else if (bar_len == 0x800000) {
+ ctrl->dev_type |= BDE_256K_REG_SPACE | BDE_8MB_REG_SPACE;
+ if (debug >= 1) gprintk("PCI resource len 8MB\n");
+ }
+
+
+#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT
+ ctrl->dma_dev = &dev->dev;
+#endif
+
+ if (debug >= 2) {
+ gprintk("_pci_probe: configured dev:0x%x rev:0x%x with base_addresses: 0x%lx 0x%lx\n",
+ (unsigned)ctrl->bde_dev.device, (unsigned)ctrl->bde_dev.rev,
+ (unsigned long)ctrl->bde_dev.base_address, (unsigned long)ctrl->bde_dev.base_address1);
+ }
+
+ if (add_dev) {
+ _bde_add_device();
+ }
+ /* Let's boogie */
+ return 0;
+}
+
+/*
+ * Function: _pci_remove
+ *
+ * Purpose:
+ * Detach driver from device. Called from pci_unregister_driver().
+ * Parameters:
+ * dev - Linux PCI device structure
+ * Returns:
+ * 0
+ */
+static void
+_pci_remove(struct pci_dev* dev)
+{
+ bde_ctrl_t *ctrl;
+
+ if (nodevices == 1) {
+ return;
+ }
+
+#if defined(BCM_DFE_SUPPORT)
+ if (dev->device == PCI_DEVICE_ID_PLX_9056) {
+ return;
+ }
+#endif
+
+ ctrl = (bde_ctrl_t *) pci_get_drvdata(dev);
+
+ if (ctrl == NULL) {
+ /* Unused device */
+ return;
+ }
+ ctrl->dev_state = BDE_DEV_STATE_REMOVED;
+ if (debug >= 1) {
+ gprintk("PCI device %04x:%04x is removed. \n",
+ dev->vendor, dev->device);
+ }
+ if (ctrl->bde_dev.base_address1) {
+ iounmap((void *)ctrl->bde_dev.base_address1);
+ }
+ if (ctrl->bde_dev.base_address) {
+ iounmap((void *)ctrl->bde_dev.base_address);
+ }
+
+ /* Free our interrupt handler, if we have one */
+ if (ctrl->isr || ctrl->isr2) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+ if (ctrl->use_msi >= PCI_USE_INT_MSIX) {
+ int i;
+ for (i = 0; i < ctrl->msix_cnt; i++)
+ free_irq(ctrl->entries[i].vector, ctrl);
+ }
+ else
+#endif
+ {
+ free_irq(ctrl->iLine, ctrl);
+ }
+ }
+#ifdef CONFIG_PCI_MSI
+ _msi_disconnect(ctrl);
+#endif
+ ctrl->isr = NULL;
+ ctrl->isr_data = NULL;
+ ctrl->isr2 = NULL;
+ ctrl->isr2_data = NULL;
+}
+
+static struct pci_driver _device_driver = {
+ probe: _pci_probe,
+ remove: _pci_remove,
+ id_table: _id_table,
+ /* The rest are dynamic */
+};
+
+static void
+_spi_device_setup(void) {
+ bde_ctrl_t *ctrl;
+ ctrl = _devices + _ndevices;
+ ctrl->dev_type |= BDE_SWITCH_DEV_TYPE;
+ ctrl->iLine = 0xa3;
+ ctrl->be_pio = 0;
+ ctrl->dev_type |= BDE_SPI_DEV_TYPE;
+ ctrl->bde_dev.device = spi_devid;
+ ctrl->bde_dev.rev = spi_revid;
+ if (debug >= 1) {
+ gprintk("SPI Slave Mode: force ctrl->bde_dev.device=0x%x\n",ctrl->bde_dev.device);
+ gprintk("SPI Slave Mode: force ctrl->bde_dev.rev=0x%x\n",ctrl->bde_dev.rev);
+ gprintk("SPI Slave Mode: force ctrl->dev_type=0x%x\n",ctrl->dev_type);
+ }
+ _bde_add_device();
+}
+#endif /* BCM_ICS */
+
+
+
+
+#if defined(BCM_METROCORE_LOCAL_BUS)
+static bde_ctrl_t*
+map_local_bus(uint64_t addr, uint32_t size)
+{
+ bde_ctrl_t *ctrl;
+
+ ctrl = _devices + _ndevices;
+
+ /*
+ * For now: use EB type as `local bus'
+ * (memory mapped, no DMA, no interrupts)
+ * metrocore local bus supports interrupts, but we don't use them.
+ */
+ ctrl->dev_type |= BDE_EB_DEV_TYPE | BDE_SWITCH_DEV_TYPE
+ | (size > 64 * 1024 ? BDE_128K_REG_SPACE : 0);
+ ctrl->pci_device = NULL; /* No PCI bus */
+
+ /* Map in the device */
+ ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(addr, size);
+ ctrl->iowin[0].addr = addr;
+ ctrl->iowin[0].size = size;
+
+ _bde_add_device();
+ return(ctrl);
+}
+
+#define BME_REVISION_OFFSET (0x0)
+
+#endif
+
+#ifdef BCM_PLX9656_LOCAL_BUS
+
+#if 1
+#define DEV_REG_BASE_OFFSET PL0_OFFSET /* Polaris register base */
+#define DEV_REG_DEVID 0 /* Device ID is first register */
+#endif
+
+/*
+ * The difference at map_local_bus2:
+ *
+ * The PLX9656 PCI-to-LOCAL bridge chip already has been iomapped the
+ * whole address space. So the devices off local bus don't need to be
+ * mapped again. They only need to claim their own sub-space.
+ */
+static bde_ctrl_t *
+map_local_bus2(bde_ctrl_t *plx_ctrl, uint32_t dev_base, uint32_t size)
+{
+ uint32_t dev_rev_id;
+ uint8_t *addr;
+ bde_ctrl_t *ctrl;
+
+ ctrl = _devices + _ndevices;
+
+ /*
+ * For now: use EB type as `local bus'
+ * (memory mapped, no DMA, no interrupts)
+ * metrocore local bus supports interrupts, but we don't use them.
+ */
+ ctrl->dev_type |= BDE_EB_DEV_TYPE | BDE_SWITCH_DEV_TYPE;
+ ctrl->dev_type |= BDE_320K_REG_SPACE; /* Polaris 18 bits address + FPGA */
+ ctrl->pci_device = NULL; /* No PCI bus */
+
+ /* Map in the device */
+ ctrl->bde_dev.base_address = plx_ctrl->bde_dev.base_address + dev_base;
+ ctrl->iowin[0].addr = plx_ctrl->iowin[0].addr + (resource_size_t)dev_base;
+ ctrl->iowin[0].size = size;
+
+#if 1
+ addr = (uint8_t *)ctrl->bde_dev.base_address + PL0_REVISION_REG;
+#endif
+ dev_rev_id = readl(addr);
+ ctrl->bde_dev.device = dev_rev_id >> 16;
+ ctrl->bde_dev.rev = (dev_rev_id & 0xFF);
+
+
+ _bde_add_device();
+
+ switch (ctrl->bde_dev.device) {
+ default:
+ return 0;
+ }
+ return(ctrl);
+}
+
+static int
+probe_plx_local_bus(void)
+{
+ bde_ctrl_t *ctrl;
+ uint32_t val;
+ uint8_t *addr;
+ char addr_hi_str[16];
+
+ if (num_plx > 1) {
+ printk(KERN_ERR "There's more than one PLX 9656/9056 chip\n");
+ return -1;
+ }
+ addr_hi_str[0] = 0;
+#ifdef PHYS_ADDR_IS_64BIT
+ sprintf(addr_hi_str, "%08x", (uint32_t)(plx_ctrl.iowin[0].addr >> 32));
+#endif
+ printk(KERN_ERR "Found PLX %04x:%04x vir: 0x%08x phy: 0x%s%08x\n",
+ plx_ctrl.bde_dev.device, plx_ctrl.bde_dev.rev,
+ plx_ctrl.bde_dev.base_address, addr_hi_str,
+ (uint32_t)(plx_ctrl.iowin[0].addr));
+
+ addr = (uint8_t *)plx_ctrl.bde_dev.base_address + CPLD_OFFSET + CPLD_REVISION_REG;
+ val = readl(addr);
+ printk(KERN_ERR "plx: CPLD revision %d\n", val & CPLD_REVISION_MASK);
+#if 000
+ addr = (uint8_t *)plx_ctrl.bde_dev.base_address + CPLD_OFFSET + CPLD_RESET_REG;
+ writel(CPLD_RESET_NONE, addr);
+#endif
+#if 1
+ ctrl = map_local_bus2(&plx_ctrl, PL0_OFFSET, PL0_SIZE);
+#endif
+ if (ctrl == 0)
+ return -1;
+
+ /* Uses PLX IRQ for Polaris LC */
+ ctrl->iLine = 48;
+ ctrl->isr = NULL;
+ ctrl->isr_data = NULL;
+
+ return 0;
+}
+
+#endif /* BCM_PLX9656_LOCAL_BUS */
+
+
+
+
+/*
+ * Generic module functions
+ */
+
+/*
+ * Function: _init
+ *
+ * Purpose:
+ * Module initialization.
+ * Attaches to kernel BDE.
+ * Parameters:
+ * None
+ * Returns:
+ * 0 on success, < 0 on error.
+ */
+static int
+_init(void)
+{
+#ifdef IPROC_CMICD
+#ifdef CONFIG_OF
+ if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) {
+ iproc_platform_driver_register(&iproc_cmicd_driver);
+ } else
+#endif
+ if (iproc_has_cmicd()) {
+ iproc_cmicd_get_memregion(&iproc_cmicd_resources[IPROC_CMICD_RES_MEM]);
+ iproc_platform_driver_register(&iproc_cmicd_driver);
+#ifdef CONFIG_OF
+ if (!of_find_compatible_node(NULL, NULL, IPROC_CMICD_COMPATIBLE))
+#endif
+ {
+ /* Register platform device if no device node in dtb */
+ iproc_platform_device_register(&iproc_cmicd_pdev);
+ }
+ }
+#endif /* IPROC_CMICD */
+
+#ifdef BCM_ICS
+ _ics_bde_create();
+#else /* PCI */
+ /* Register our goodies */
+ _device_driver.name = LINUX_KERNEL_BDE_NAME;
+
+
+ /* Configure MSI interrupt support */
+ use_msi = usemsi;
+
+#ifdef CONFIG_PCI_MSI
+ if (use_msi == PCI_USE_INT_NONE) {
+ /* Compilation flag determines default value */
+#ifdef BDE_LINUX_USE_MSIX_INTERRUPT
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+ use_msi = PCI_USE_INT_MSIX;
+#else
+ use_msi = PCI_USE_INT_MSI;
+#endif
+#elif defined(BDE_LINUX_USE_MSI_INTERRUPT)
+ use_msi = PCI_USE_INT_MSI;
+#else
+ use_msi = PCI_USE_INT_INTX;
+#endif
+ }
+#else
+ if (use_msi > PCI_USE_INT_INTX) {
+ /* Warn if invalid configuration */
+ gprintk("MSI interrupts not supported by kernel\n");
+ }
+ use_msi = PCI_USE_INT_INTX;
+#endif /* CONFIG_PCI_MSI */
+
+ if (unlikely(debug >= 1))
+ gprintk("%s(%d):use_msi = %d\n", __func__, __LINE__, use_msi);
+ if (spi_devid) {
+ _spi_device_setup();
+ } else {
+ if (pci_register_driver(&_device_driver) < 0) {
+ return -ENODEV;
+ }
+ }
+
+ /* Note: PCI-PCI bridge uses results from pci_register_driver */
+ p2p_bridge();
+
+#ifdef BCM_METROCORE_LOCAL_BUS
+ if (probe_metrocore_local_bus()) {
+ return -1;
+ }
+#endif
+#ifdef BCM_PLX9656_LOCAL_BUS
+ if (num_plx > 0) {
+ probe_plx_local_bus();
+ }
+#endif
+#endif /* BCM_ICS */
+
+
+#ifdef BCM_SAND_SUPPORT
+ sand_device_create();
+#endif
+
+ /*
+ * Probe for EB Bus devices.
+ */
+ if (eb_bus) {
+ char *tok;
+ uint irq = -1, eb_rd16bit=0, eb_wr16bit =0;
+ unsigned int eb_ba = 0x0;
+
+ gprintk("EB bus info: %s\n", eb_bus);
+ tok = strtok(eb_bus,",");
+ while (tok) {
+ _parse_eb_args(tok, "BA=%x IRQ=%d RD16=%d WR16=%d",
+ &eb_ba, &irq, &eb_rd16bit, &eb_wr16bit);
+ _eb_device_create(eb_ba, irq, eb_rd16bit, eb_wr16bit);
+ tok = strtok(NULL,",");
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Function: _cleanup
+ *
+ * Purpose:
+ * Module cleanup function.
+ * Parameters:
+ * None
+ * Returns:
+ * Always 0
+ */
+static int
+_cleanup(void)
+{
+ int i;
+
+ _dma_cleanup();
+
+#ifdef IPROC_CMICD
+#ifdef CONFIG_OF
+ if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) {
+ iproc_platform_driver_unregister(&iproc_cmicd_driver);
+ } else
+#endif
+ if (iproc_has_cmicd()) {
+#ifdef CONFIG_OF
+ if (!of_find_compatible_node(NULL, NULL, IPROC_CMICD_COMPATIBLE))
+#endif
+ {
+ iproc_platform_device_unregister(&iproc_cmicd_pdev);
+ }
+ iproc_platform_driver_unregister(&iproc_cmicd_driver);
+ }
+#endif
+
+ for (i = 0; i < _ndevices; i++) {
+ bde_ctrl_t *ctrl = _devices + i;
+
+ /* free allocated kernel space memory */
+ if (ctrl->dev_type & BDE_SPI_DEV_TYPE) {
+ if (ctrl->spi_device) {
+ kfree(ctrl->spi_device);
+ }
+ }
+ }
+#if defined(BCM_SAND_SUPPORT) && (defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__))
+ if (cpu_address) { /* unmap CPU card MMIO */
+ iounmap(cpu_address);
+ cpu_address = NULL;
+ }
+#endif
+
+#ifdef BCM_ICS
+#else
+ pci_unregister_driver(&_device_driver);
+#endif /* BCM_ICS */
+ return 0;
+}
+
+/*
+ * Function: _pprint
+ *
+ * Purpose:
+ * Print proc filesystem information.
+ * Parameters:
+ * None
+ * Returns:
+ * Always 0
+ */
+static int
+_pprint(void)
+{
+ int i = 0;
+
+ pprintf("Broadcom Device Enumerator (%s)\n", LINUX_KERNEL_BDE_NAME);
+
+ pprintf("Module parameters:\n");
+ pprintf("\tmaxpayload=%d\n", maxpayload);
+ pprintf("\tusemsi=%d\n", usemsi);
+
+ _dma_pprint();
+
+ if (_ndevices == 0) {
+ pprintf("No devices found\n");
+ } else {
+ pprintf("Devices:\n");
+ }
+ for (i = 0; i < _ndevices; i++) {
+ bde_ctrl_t *ctrl = _devices + i;
+
+ if (ctrl->dev_type & BDE_SWITCH_DEV_TYPE) {
+ pprintf("\t%d (swi) : ", i);
+ } else if (ctrl->dev_type & BDE_ETHER_DEV_TYPE) {
+ pprintf("\t%d (eth) : ", i);
+ } else if (ctrl->dev_type & BDE_CPU_DEV_TYPE) {
+ pprintf("\t%d (cpu) : ", i);
+ } else {
+ pprintf("\t%d (?) : ", i);
+ }
+
+ if (ctrl->dev_state == BDE_DEV_STATE_REMOVED) {
+ pprintf("PCI device 0x%x:0x%x:%d REMOVED\n",
+ ctrl->pci_device->vendor,
+ ctrl->pci_device->device,
+ ctrl->bde_dev.rev);
+ continue;
+ }
+ if (ctrl->dev_type & BDE_PCI_DEV_TYPE) {
+ pprintf("PCI device %02x:%02x.%x 0x%x:0x%x:%d:0x%.8lx:0x%.8lx:%d%s\n",
+ (unsigned int)ctrl->pci_device->bus->number,
+ PCI_SLOT(ctrl->pci_device->devfn),
+ PCI_FUNC(ctrl->pci_device->devfn),
+ ctrl->pci_device->vendor,
+ ctrl->pci_device->device,
+ ctrl->bde_dev.rev,
+ (unsigned long)pci_resource_start(ctrl->pci_device, 0),
+ (unsigned long)pci_resource_start(ctrl->pci_device, 2),
+ ctrl->pci_device->irq,
+ ctrl->use_msi ? " (MSI)" : "");
+ } else if (ctrl->dev_type & BDE_SPI_DEV_TYPE) {
+ pprintf("SPI Device %d:%x:%x:0x%x:0x%x:%d\n",
+ ctrl->spi_device->cid,
+ ctrl->spi_device->part,
+ ctrl->spi_device->rev,
+ ctrl->spi_device->phyid_high,
+ ctrl->spi_device->phyid_low,
+ ctrl->bde_dev.rev);
+ } else if (ctrl->dev_type & BDE_ICS_DEV_TYPE) {
+ pprintf("ICS Device 0x%x:0x%x\n",
+ ctrl->bde_dev.device,
+ ctrl->bde_dev.rev);
+ } else if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ pprintf("AXI Device 0x%x:0x%x:0x%.8lx:%d\n",
+ ctrl->bde_dev.device,
+ ctrl->bde_dev.rev,
+ (unsigned long)ctrl->iowin[0].addr,
+ ctrl->iLine);
+ } else if (ctrl->dev_type & BDE_EB_DEV_TYPE) {
+ pprintf("EB Bus Device 0x%x:0x%x\n",
+ ctrl->bde_dev.device,
+ ctrl->bde_dev.rev);
+ }
+ if (debug >= 1) {
+ pprintf("\t\timask:imask2:fmask 0x%x:0x%x:0x%x\n",
+ ctrl->imask,
+ ctrl->imask2,
+ ctrl->fmask);
+ }
+ }
+ return 0;
+}
+/*
+ * Some kernels are configured to prevent mapping of kernel RAM memory
+ * into user space via the /dev/mem device.
+ *
+ * The function below provides a backdoor to map IO and DMA memory to
+ * user space via the BDE device file.
+ */
+static int
+_bde_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ unsigned long paddr = vma->vm_pgoff << PAGE_SHIFT;
+ unsigned long size = vma->vm_end - vma->vm_start;
+ int i, j, pio_range_valid = 0;
+
+ for(i = 0; i < _ndevices; i++) {
+ bde_ctrl_t *ctrl = _devices + i;
+ if (ctrl->dev_type & BDE_SWITCH_DEV_TYPE) {
+ for (j = 0; j < BDE_NUM_IOWIN_MAX; j++) {
+ if (paddr >= (unsigned long)ctrl->iowin[j].addr &&
+ (paddr + size) <= (unsigned long)(ctrl->iowin[j].addr + ctrl->iowin[j].size)) {
+ pio_range_valid = 1;
+ break;
+ }
+ if ((ctrl->dev_type & BDE_AXI_DEV_TYPE) && (paddr == ctrl->iowin[j].addr)) {
+ pio_range_valid = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ if (pio_range_valid) {
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ if (remap_pfn_range(vma,
+ vma->vm_start,
+ vma->vm_pgoff,
+ size,
+ vma->vm_page_prot)) {
+ gprintk("Failed to mmap phys range 0x%lx-0x%lx to 0x%lx-0x%lx\n",
+ paddr, paddr + size, vma->vm_start,vma->vm_end);
+ return -EAGAIN;
+ }
+ return 0;
+ }
+
+ return _dma_mmap(filp, vma);
+}
+
+/* Workaround for broken Busybox/PPC insmod */
+static char _modname[] = LINUX_KERNEL_BDE_NAME;
+
+static gmodule_t _gmodule = {
+ name: LINUX_KERNEL_BDE_NAME,
+ major: LINUX_KERNEL_BDE_MAJOR,
+ init: _init,
+ cleanup: _cleanup,
+ pprint: _pprint,
+ mmap: _bde_mmap,
+};
+
+gmodule_t *
+gmodule_get(void)
+{
+ _gmodule.name = _modname;
+ return &_gmodule;
+}
+
+
+/*
+ * BDE Interface
+ */
+
+static const char *
+_name(void)
+{
+ return LINUX_KERNEL_BDE_NAME;
+}
+
+static int
+_num_devices(int type)
+{
+ switch (type) {
+ case BDE_ALL_DEVICES:
+ return _ndevices;
+ case BDE_SWITCH_DEVICES:
+ return _switch_ndevices;
+ case BDE_ETHER_DEVICES:
+ return _ether_ndevices;
+ case BDE_CPU_DEVICES:
+ return _cpu_ndevices;
+ }
+
+ return 0;
+}
+
+static const ibde_dev_t *
+_get_dev(int d)
+{
+ if (!VALID_DEVICE(d)) {
+ gprintk("_get_dev: Invalid device index %d\n", d);
+ return NULL;
+ }
+
+ return &_devices[d].bde_dev;
+}
+
+static uint32
+_get_dev_type(int d)
+{
+ if (!VALID_DEVICE(d)) {
+ gprintk("_get_dev: Invalid device index %d\n", d);
+ return 0;
+ }
+
+ return _devices[d].dev_type;
+}
+
+static uint32
+_pci_conf_read(int d, uint32 addr)
+{
+#ifdef BCM_ICS
+ return 0xFFFFFFFF;
+#else
+ uint32 rc = 0;
+
+ if (!VALID_DEVICE(d)) {
+ gprintk("_pci_conf_read: Invalid device index %d\n", d);
+ return 0xFFFFFFFF;
+ }
+
+ if (!(_devices[d].dev_type & BDE_PCI_DEV_TYPE)) {
+ gprintk("_pci_conf_read: Not PCI device %d, type %x\n",
+ d, _devices[d].dev_type);
+ return 0xFFFFFFFF;
+ }
+
+ pci_read_config_dword(_devices[d].pci_device, addr, &rc);
+ return rc;
+#endif /* BCM_ICS */
+}
+
+static int
+_pci_conf_write(int d, uint32 addr, uint32 data)
+{
+#ifdef BCM_ICS
+ return -1;
+#else
+ if (!VALID_DEVICE(d)) {
+ gprintk("_pci_conf_write: Invalid device index %d\n", d);
+ return -1;
+ }
+
+ if (!(_devices[d].dev_type & BDE_PCI_DEV_TYPE)) {
+ gprintk("_pci_conf_write: Not PCI device %d, type %x\n",
+ d, _devices[d].dev_type);
+ return -1;
+ }
+
+ pci_write_config_dword(_devices[d].pci_device, addr, data);
+ return 0;
+#endif /* BCM_ICS */
+}
+
+/* Initialized when the bde is created */
+static linux_bde_bus_t _bus;
+
+static void
+_pci_bus_features(int unit, int *be_pio, int *be_packet, int *be_other)
+{
+ if ((_devices[unit].bde_dev.device & 0xFF00) != 0x5600 &&
+ (_devices[unit].bde_dev.device & 0xF000) != 0xc000 &&
+ (_devices[unit].bde_dev.device & 0xF000) != 0xb000 &&
+ (_devices[unit].bde_dev.device & 0xF000) != 0x8000 &&
+ (_devices[unit].bde_dev.device & 0xFFF0) != 0x0230 &&
+ (_devices[unit].bde_dev.device & 0xFFF0) != 0xa440) {
+ if (be_pio) *be_pio = 0;
+ if (be_packet) *be_packet = 0;
+ if (be_other) *be_other = 0;
+ } else {
+ if (be_pio) *be_pio = _bus.be_pio;
+ if (be_packet) *be_packet = _bus.be_packet;
+ if (be_other) *be_other = _bus.be_other;
+ }
+#if defined(BCM_METROCORE_LOCAL_BUS)
+ if (_devices[unit].dev_type & BDE_EB_DEV_TYPE && be_pio) {
+ *be_pio = 1;
+ }
+#endif
+
+}
+
+static uint32_t
+_read(int d, uint32_t addr)
+{
+ unsigned long flags;
+ volatile uint16 msb, lsb;
+ uint32 sl_addr, data;
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ return -1;
+ }
+
+ if (_devices[d].dev_type & BDE_DEV_BUS_RD_16BIT) {
+ /*
+ * Adjust the address presented to Eb slave. Move A15:A0 to A16:A1.
+ */
+ sl_addr = (addr & 0xffff0000) | ((addr & 0xffff) << 1);
+ /* Disable interrupts */
+ spin_lock_irqsave(&bus_lock, flags);
+
+ lsb = *((uint16 *)(_devices[d].bde_dev.base_address + sl_addr));
+ msb = *((uint16 *)(_devices[d].bde_dev.base_address + sl_addr));
+ spin_unlock_irqrestore(&bus_lock, flags);
+
+ return (msb << 16) | lsb;
+ } else {
+ data = ((VOL uint32_t *)_devices[d].bde_dev.base_address)[addr / 4];
+#if defined(CMIC_SOFT_BYTE_SWAP)
+ data = CMIC_SWAP32(data);
+#endif
+ return data;
+ }
+}
+
+static int
+_write(int d, uint32_t addr, uint32_t data)
+{
+ unsigned long flags;
+ uint32 sl_addr;
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ return -1;
+ }
+
+ if (_devices[d].dev_type & BDE_DEV_BUS_WR_16BIT) {
+ /*
+ * Adjust the address presented to Eb slave. Move A15:A0 to A16:A1.
+ */
+ sl_addr = (addr & 0xffff0000) | ((addr & 0xffff) << 1);
+
+ /* Disable interrupts */
+ spin_lock_irqsave(&bus_lock, flags);
+
+ *((VOL uint16 *)(_devices[d].bde_dev.base_address + sl_addr)) =
+ data & 0xffff;
+ *((VOL uint16 *)(_devices[d].bde_dev.base_address + sl_addr)) =
+ (data >> 16) & 0xffff;
+ spin_unlock_irqrestore(&bus_lock, flags);
+ } else {
+#if defined(CMIC_SOFT_BYTE_SWAP)
+ data = CMIC_SWAP32(data);
+#endif
+ ((VOL uint32_t *)_devices[d].bde_dev.base_address)[addr / 4] = data;
+#ifdef KEYSTONE
+ /* Enforce PCIe transaction ordering. Commit the write transaction */
+ __asm__ __volatile__("sync");
+#endif
+ }
+ return 0;
+
+}
+
+static _ISR_RET
+_isr(_ISR_PARAMS(irq, dev_id, iregs))
+{
+ bde_ctrl_t *ctrl = (bde_ctrl_t *) dev_id;
+
+ if (ctrl && ctrl->isr) {
+ ctrl->isr(ctrl->isr_data);
+ }
+ if (ctrl && ctrl->isr2) {
+ ctrl->isr2(ctrl->isr2_data);
+ }
+ return IRQ_HANDLED;
+}
+
+static int
+_interrupt_connect(int d,
+ void (*isr)(void *),
+ void *isr_data)
+{
+ bde_ctrl_t *ctrl;
+ unsigned long irq_flags;
+ int isr2_dev;
+ int isr_active;
+ int ret = 0;
+
+ isr2_dev = d & LKBDE_ISR2_DEV;
+ d &= ~LKBDE_ISR2_DEV;
+
+ if (!VALID_DEVICE(d)) {
+ gprintk("_interrupt_connect: Invalid device index %d\n", d);
+ return -1;
+ }
+ if (debug >= 1) {
+ gprintk("_interrupt_connect d %d\n", d);
+ }
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ gprintk("_interrupt_connect: Not PCI device %d, type %x\n",
+ d, _devices[d].dev_type);
+ return -1;
+ }
+
+ ctrl = _devices + d;
+
+ isr_active = (ctrl->isr || ctrl->isr2) ? 1 : 0;
+
+ if (unlikely(debug > 1))
+ gprintk("%s:isr_active = %d\n", __func__, isr_active);
+
+ if (isr2_dev) {
+ if (debug >= 1) {
+ gprintk("connect secondary isr\n");
+ }
+ ctrl->isr2_data = isr_data;
+ ctrl->isr2 = isr;
+ if (isr_active) {
+ /* Main handler (_isr) already installed */
+ return 0;
+ }
+ } else {
+ if (debug >= 1) {
+ gprintk("connect primary isr\n");
+ }
+ ctrl->isr = isr;
+ ctrl->isr_data = isr_data;
+ if (isr_active) {
+ /* Main handler (_isr) already installed */
+ return 0;
+ }
+ }
+
+ if (ctrl->iLine != -1) {
+ irq_flags = IRQF_SHARED;
+#ifdef CONFIG_PCI_MSI
+ if (ctrl->use_msi >= PCI_USE_INT_MSI) {
+ ret = _msi_connect(ctrl);
+ if(ret != 0)
+ goto msi_exit;
+ }
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+ if (ctrl->use_msi == PCI_USE_INT_MSIX) {
+ int i;
+ for (i = 0; i < ctrl->msix_cnt; i++) {
+ if (unlikely(debug >= 1)) {
+ gprintk("%s(%d):device# = %d, irq = %d\n",
+ __func__, __LINE__, d, ctrl->entries[i].vector);
+ }
+ ret = request_irq(ctrl->entries[i].vector, (irq_handler_t)_isr, 0,
+ LINUX_KERNEL_BDE_NAME, ctrl);
+ if (ret < 0)
+ break;
+ }
+ if (ret < 0) {
+ while (i >= 0)
+ free_irq(ctrl->entries[i--].vector, ctrl);
+
+ goto err_disable_msi;
+ }
+ }
+ else
+#endif
+ {
+#if defined(IPROC_CMICD) && defined(CONFIG_OF)
+ if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) {
+ int i, j;
+ for (i = 0; i < IHOST_CMICX_MAX_INTRS; i++) {
+ if (!iproc_cmicx_irqs[i]) {
+ continue;
+ }
+ if (unlikely(debug >= 1))
+ gprintk("%s(%d):device# = %d, request_irq(%d)\n",
+ __func__, __LINE__, d, iproc_cmicx_irqs[i]);
+ ret = request_irq(iproc_cmicx_irqs[i], (irq_handler_t)_isr,
+ irq_flags, LINUX_KERNEL_BDE_NAME, ctrl);
+ if (ret < 0) {
+ gprintk("request_irq(%d) failed(%d)\n", iproc_cmicx_irqs[i], ret);
+ break;
+ }
+ }
+ if (ret < 0) {
+ for (j = 0; j < i; j++) {
+ if (!iproc_cmicx_irqs[j]) {
+ continue;
+ }
+ free_irq(iproc_cmicx_irqs[j], ctrl);
+ }
+ goto err_disable_msi;
+ }
+ } else
+#endif
+ {
+ ret = request_irq(ctrl->iLine, _isr, irq_flags,
+ LINUX_KERNEL_BDE_NAME, ctrl);
+ if (ret < 0)
+ goto err_disable_msi;
+
+ if (unlikely(debug >= 1))
+ gprintk("%s(%d):device# = %d, irq_flags = %lu, irq = %d\n",
+ __func__, __LINE__, d,
+ irq_flags, ctrl->pci_device ? ctrl->pci_device->irq : ctrl->iLine);
+ }
+ }
+ }
+ return 0;
+
+err_disable_msi:
+#ifdef CONFIG_PCI_MSI
+ _msi_disconnect(ctrl);
+
+msi_exit:
+#endif
+ gprintk("could not request IRQ\n");
+ ctrl->isr = NULL;
+ ctrl->isr_data = NULL;
+ ctrl->isr2 = NULL;
+ ctrl->isr2_data = NULL;
+
+ return -1;
+}
+
+static int
+_interrupt_disconnect(int d)
+{
+ bde_ctrl_t *ctrl;
+ int isr2_dev;
+ int isr_active;
+
+ isr2_dev = d & LKBDE_ISR2_DEV;
+ d &= ~LKBDE_ISR2_DEV;
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ if (debug >= 1) {
+ gprintk("_interrupt_disconnect d %d\n", d);
+ }
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ gprintk("_interrupt_disconnect: Not PCI device %d, type %x\n",
+ d, _devices[d].dev_type);
+ return -1;
+ }
+
+ ctrl = _devices + d;
+
+ isr_active = (ctrl->isr || ctrl->isr2) ? 1 : 0;
+
+ if (unlikely(debug > 1))
+ gprintk("%s: isr_active = %d\n", __func__, isr_active);
+
+ if (isr2_dev) {
+ if (debug >= 1) {
+ gprintk("disconnect secondary isr\n");
+ }
+ ctrl->isr2 = NULL;
+ ctrl->isr2_data = NULL;
+ ctrl->fmask = 0;
+ if (ctrl->isr) {
+ /* Primary handler still active */
+ SYNC_IRQ(ctrl->iLine);
+ return 0;
+ }
+ } else {
+ if (debug >= 1) {
+ gprintk("disconnect primary isr\n");
+ }
+ ctrl->isr = NULL;
+ ctrl->isr_data = NULL;
+ if (ctrl->isr2) {
+ /* Secondary handler still active */
+ SYNC_IRQ(ctrl->iLine);
+ return 0;
+ }
+ }
+
+ if (isr_active) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,84))
+ if (ctrl->use_msi >= PCI_USE_INT_MSIX) {
+ int i;
+ for (i = 0; i < ctrl->msix_cnt; i++) {
+ if (unlikely(debug > 1)) {
+ gprintk("%s(%d):device# = %d, irq = %d\n",
+ __func__, __LINE__, d, ctrl->entries[i].vector);
+ }
+ free_irq(ctrl->entries[i].vector, ctrl);
+ }
+ }
+ else
+#endif
+#if defined(IPROC_CMICD) && defined(CONFIG_OF)
+ if (of_find_compatible_node(NULL, NULL, IPROC_CMICX_COMPATIBLE)) {
+ int i;
+ for (i = 0; i < IHOST_CMICX_MAX_INTRS; i++) {
+ if (!iproc_cmicx_irqs[i]) {
+ continue;
+ }
+ if (unlikely(debug > 1)) {
+ gprintk("%s(%d):device# = %d, free_irq(%d)\n",
+ __func__, __LINE__, d, iproc_cmicx_irqs[i]);
+ }
+ free_irq(iproc_cmicx_irqs[i], ctrl);
+ }
+ } else
+#endif
+ {
+ free_irq(ctrl->iLine, ctrl);
+ }
+#ifdef CONFIG_PCI_MSI
+ if (ctrl->use_msi >= PCI_USE_INT_MSI) {
+ _msi_disconnect(ctrl);
+ }
+#endif
+ }
+
+ return 0;
+}
+
+static uint32_t
+_iproc_ihost_read(int d, uint32_t addr)
+{
+ uint32_t *mapaddr;
+ uint32_t reg_val;
+ mapaddr = IOREMAP(addr, sizeof(uint32_t));
+ if (mapaddr == NULL) {
+ return -1;
+ }
+ reg_val = readl(mapaddr);
+ iounmap(mapaddr);
+ return reg_val;
+}
+
+static int
+_iproc_ihost_write(int d, uint32_t addr, uint32_t data)
+{
+ uint32_t *mapaddr;
+ mapaddr = IOREMAP(addr, sizeof(uint32_t));
+ if (mapaddr == NULL) {
+ return -1;
+ }
+ writel(data, mapaddr);
+ iounmap(mapaddr);
+ return 0;
+}
+
+static uint32_t
+_iproc_read(int d, uint32_t addr)
+{
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ return -1;
+ }
+
+ if (_devices[d].dev_type & BDE_AXI_DEV_TYPE) {
+ if (IHOST_GICD_REG_ADDR_VALID(d, addr)) {
+ return readl(IHOST_GICD_REG_ADDR_REMAP(d, addr));
+ }
+ return _iproc_ihost_read(d, addr);
+ }
+
+ return shbde_iproc_pci_read(&_devices[d].shbde,
+ (void *)_devices[d].bde_dev.base_address1,
+ addr);
+}
+
+static int
+_iproc_write(int d, uint32_t addr, uint32_t data)
+{
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ return -1;
+ }
+
+ if (_devices[d].dev_type & BDE_AXI_DEV_TYPE) {
+ if (IHOST_GICD_REG_ADDR_VALID(d, addr)) {
+ writel(data, IHOST_GICD_REG_ADDR_REMAP(d, addr));
+ return 0;
+ }
+ return _iproc_ihost_write(d, addr, data);
+ }
+
+ shbde_iproc_pci_write(&_devices[d].shbde,
+ (void *)_devices[d].bde_dev.base_address1,
+ addr, data);
+
+ return 0;
+}
+
+static int
+_get_cmic_ver(int d , uint32_t *ver)
+{
+
+ unsigned int cap_base;
+ uint32_t rval = 0;
+
+ if (!VALID_DEVICE(d)) {
+ gprintk("%s: Invalid device index %d\n", __func__, d);
+ return -1;
+ }
+
+ if (!(_devices[d].dev_type & BDE_PCI_DEV_TYPE)) {
+ gprintk("%s: Not PCI device %d, type %x\n", __func__,
+ d, _devices[d].dev_type);
+ return -1;
+ }
+
+ /* Look for PCIe vendor-specific extended capability (VSEC) */
+ cap_base = PCI_EXT_CAP_START;
+ while (cap_base) {
+ pci_read_config_dword(_devices[d].pci_device, cap_base, &rval);
+ if (rval == 0xffffffff) {
+ /* Assume PCI HW read error */
+ gprintk("%s: PCI HW read error\n", __func__);
+ return -1;
+ }
+
+ if (PCI_EXT_CAP_ID(rval) == PCI_EXT_CAP_ID_VNDR) {
+ break;
+ }
+ cap_base = PCI_EXT_CAP_NEXT(rval);
+ }
+ if (cap_base) {
+ /*
+ * VSEC layout:
+ *
+ * 0x00: PCI Express Extended Capability Header
+ * 0x04: Vendor-Specific Header
+ * 0x08: Vendor-Specific Register 1
+ * 0x0c: Vendor-Specific Register 2
+ * ...
+ * 0x24: Vendor-Specific Register 8
+ */
+ pci_read_config_dword(_devices[d].pci_device, cap_base + 8, &rval);
+ if (unlikely(debug > 1))
+ gprintk("%s:Found VSEC = %u\n", __func__, rval);
+
+ /* Determine if CMICX */
+ rval = ((rval >> 12) & 0xf);
+ *ver = rval;
+
+ return 0;
+ } else {
+ gprintk("%s:VSEC not found\n", __func__);
+ }
+
+ return -1;
+}
+
+#ifdef BCM_SAND_SUPPORT
+int
+lkbde_cpu_write(int d, uint32 addr, uint32 *buf)
+{
+#if defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__)
+ *((uint32_t*)((uint8_t*)cpu_address + addr)) = *buf;
+#endif
+
+ return 0;
+}
+
+int
+lkbde_cpu_read(int d, uint32 addr, uint32 *buf)
+{
+#if defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__)
+ *buf = *((uint32_t*)((uint8_t*)cpu_address + addr));
+#else
+ *buf = (uint32_t)(-1);
+#endif
+
+ return 0;
+}
+
+int
+lkbde_cpu_pci_register(int d)
+{
+ bde_ctrl_t* ctrl;
+ uint16 cmd = 0;
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ ctrl = &_devices[d];
+
+ /* enable device */
+ if (pci_enable_device(ctrl->pci_device)) {
+ gprintk("Cannot enable pci device : vendor_id = %x, device_id = %x\n",
+ ctrl->pci_device->vendor, ctrl->pci_device->device);
+ }
+
+ /* Add PCI_COMMAND_MEMORY and PCI_COMMAND_MASTER */
+ pci_read_config_word(ctrl->pci_device, PCI_COMMAND, &cmd);
+ if (!(cmd & PCI_COMMAND_MEMORY) || !(cmd & PCI_COMMAND_MASTER)) {
+ cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ pci_write_config_word(ctrl->pci_device, PCI_COMMAND, cmd);
+ }
+
+ switch (ctrl->bde_dev.device) {
+ case GEDI_DEVICE_ID:
+ /* Fix bar 0 address */ /* FIXME: write full phy address */
+ pci_write_config_byte(ctrl->pci_device, 0x13, 0x60);
+
+ /* Fix Max payload size */
+ pci_write_config_byte(ctrl->pci_device, 0x88, 0x2f);
+ pci_write_config_byte(ctrl->pci_device, 0x89, 0x10);
+ break;
+ case BCM88750_DEVICE_ID:
+ case BCM88753_DEVICE_ID:
+ case BCM88755_DEVICE_ID:
+ case BCM88770_DEVICE_ID:
+ case BCM88773_DEVICE_ID:
+ case BCM88774_DEVICE_ID:
+ case BCM88775_DEVICE_ID:
+ case BCM88776_DEVICE_ID:
+ case BCM88777_DEVICE_ID:
+ case BCM88950_DEVICE_ID:
+ case BCM88953_DEVICE_ID:
+ case BCM88954_DEVICE_ID:
+ case BCM88955_DEVICE_ID:
+ case BCM88956_DEVICE_ID:
+ case BCM88752_DEVICE_ID:
+ case BCM88772_DEVICE_ID:
+ case BCM88952_DEVICE_ID:
+ case ACP_PCI_DEVICE_ID:
+ case BCM88650_DEVICE_ID:
+
+ case BCM88670_DEVICE_ID:
+ case BCM88671_DEVICE_ID:
+ case BCM88671M_DEVICE_ID:
+ case BCM88672_DEVICE_ID:
+ case BCM88673_DEVICE_ID:
+ case BCM88674_DEVICE_ID:
+ case BCM88675_DEVICE_ID:
+ case BCM88675M_DEVICE_ID:
+ case BCM88676_DEVICE_ID:
+ case BCM88676M_DEVICE_ID:
+ case BCM88677_DEVICE_ID:
+ case BCM88678_DEVICE_ID:
+ case BCM88679_DEVICE_ID:
+
+ case BCM88370_DEVICE_ID:
+ case BCM88371_DEVICE_ID:
+ case BCM88371M_DEVICE_ID:
+ case BCM88375_DEVICE_ID:
+ case BCM88376_DEVICE_ID:
+ case BCM88376M_DEVICE_ID:
+ case BCM88377_DEVICE_ID:
+ case BCM88378_DEVICE_ID:
+ case BCM88379_DEVICE_ID:
+ case BCM88681_DEVICE_ID:
+ case BCM88682_DEVICE_ID:
+ case BCM88683_DEVICE_ID:
+ case BCM88684_DEVICE_ID:
+ case BCM88685_DEVICE_ID:
+ case BCM88687_DEVICE_ID:
+ case BCM88380_DEVICE_ID:
+ case BCM88381_DEVICE_ID:
+ case BCM88680_DEVICE_ID:
+ case BCM88470_DEVICE_ID:
+ case BCM88470P_DEVICE_ID:
+ case BCM88471_DEVICE_ID:
+ case BCM88473_DEVICE_ID:
+ case BCM88474_DEVICE_ID:
+ case BCM88474H_DEVICE_ID:
+ case BCM88476_DEVICE_ID:
+ case BCM88477_DEVICE_ID:
+ case BCM88270_DEVICE_ID:
+ case BCM88271_DEVICE_ID:
+ case BCM88272_DEVICE_ID:
+ case BCM88273_DEVICE_ID:
+ case BCM88274_DEVICE_ID:
+ case BCM88276_DEVICE_ID:
+ case BCM88278_DEVICE_ID:
+ case BCM8206_DEVICE_ID:
+ case BCM88350_DEVICE_ID:
+ case BCM88351_DEVICE_ID:
+ case BCM88450_DEVICE_ID:
+ case BCM88451_DEVICE_ID:
+ case BCM88550_DEVICE_ID:
+ case BCM88551_DEVICE_ID:
+ case BCM88552_DEVICE_ID:
+ case BCM88651_DEVICE_ID:
+ case BCM88654_DEVICE_ID:
+ case BCM88660_DEVICE_ID:
+ case BCM88360_DEVICE_ID:
+ case BCM88361_DEVICE_ID:
+ case BCM88363_DEVICE_ID:
+ case BCM88460_DEVICE_ID:
+ case BCM88461_DEVICE_ID:
+ case BCM88560_DEVICE_ID:
+ case BCM88561_DEVICE_ID:
+ case BCM88562_DEVICE_ID:
+ case BCM88661_DEVICE_ID:
+ case BCM88664_DEVICE_ID:
+ /* Fix bar 0 address */ /* FIXME: write full phy address */
+ pci_write_config_byte(ctrl->pci_device, 0x12, 0x10);
+ pci_write_config_byte(ctrl->pci_device, 0x13, 0x60);
+
+ /*
+ * For DMA transactions - set Max_Payload_Size and
+ * Max_Read_Request_Size to 128 bytes.
+ */
+ pci_write_config_byte(ctrl->pci_device, 0xb5, 0x0c);
+ pci_write_config_byte(ctrl->pci_device, 0xb4, 0x0);
+ break;
+ default:
+ break;
+ }
+
+ /* configure iproc >=14 devices by device family */
+#if defined(BCM_DNXF_SUPPORT) || defined(BCM_DNX_SUPPORT)
+ switch (ctrl->bde_dev.device & DNXC_DEVID_FAMILY_MASK) {
+#ifdef BCM_DNX_SUPPORT
+ case JERICHO2_DEVICE_ID:
+ case J2C_DEVICE_ID:
+ case J2C_2ND_DEVICE_ID:
+ case Q2A_DEVICE_ID:
+ case Q2U_DEVICE_ID:
+ case J2P_DEVICE_ID:
+#endif
+#ifdef BCM_DNXF_SUPPORT
+ case BCM88790_DEVICE_ID:
+#endif
+ /*
+ * For DMA transactions - set Max_Payload_Size and
+ * Max_Read_Request_Size to 128 bytes.
+ */
+ pci_write_config_byte(ctrl->pci_device, 0xb5, 0x0c);
+ pci_write_config_byte(ctrl->pci_device, 0xb4, 0x0);
+ break;
+ }
+#endif /* defined(BCM_DNXF_SUPPORT) || defined(BCM_DNX_SUPPORT) */
+
+ /* Redo ioremap */
+ if (ctrl->bde_dev.base_address) {
+ iounmap((void *)ctrl->bde_dev.base_address);
+ }
+ ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(ctrl->iowin[0].addr, 0x1000000);
+
+ if (debug >= 1) {
+ gprintk("%s, %s(): info:\n", __FILE__, __FUNCTION__);
+ gprintk("_ndevices=%d, _switch_ndevices=%d\n",
+ _ndevices, _switch_ndevices);
+ gprintk("ctrl->dev_type=0x%x, ctrl->phys_address=0x%lx\n",
+ ctrl->dev_type, (unsigned long)ctrl->iowin[0].addr);
+ gprintk("ctrl->bde_dev.device=0x%x, ctrl->bde_dev.rev=0x%x, "
+ "ctrl->bde_dev.base_address=0x%lx\n",
+ ctrl->bde_dev.device, ctrl->bde_dev.rev,
+ (unsigned long)ctrl->bde_dev.base_address);
+ }
+
+ return 0;
+}
+
+/*
+ * Export Low level access function - currently for PCP DMA Kernel module.
+ */
+int
+lkbde_mem_write(int d, uint32 addr, uint32 *buf)
+{
+ bde_ctrl_t* ctrl;
+ void *full_addr;
+
+ if (!VALID_DEVICE(d)) return -1;
+ ctrl = &_devices[d];
+
+ full_addr = (void *)ctrl->bde_dev.base_address + addr;
+ *((uint32_t*)full_addr) = *buf;
+ return 0;
+}
+LKM_EXPORT_SYM(lkbde_mem_write);
+
+int
+lkbde_mem_read(int d, uint32 addr, uint32 *buf)
+{
+ bde_ctrl_t* ctrl;
+ void *full_addr;
+
+ if (!VALID_DEVICE(d)) return -1;
+ ctrl = &_devices[d];
+
+ full_addr = (void *)ctrl->bde_dev.base_address + addr;
+ *buf = *((uint32_t*)full_addr);
+ return 0;
+}
+LKM_EXPORT_SYM(lkbde_mem_read);
+#endif /* BCM_SAND_SUPPORT */
+
+static ibde_t _ibde = {
+ name: _name,
+ num_devices: _num_devices,
+ get_dev: _get_dev,
+ get_dev_type: _get_dev_type,
+ pci_conf_read: _pci_conf_read,
+ pci_conf_write: _pci_conf_write,
+ pci_bus_features: _pci_bus_features,
+ read: _read,
+ write: _write,
+ salloc: _salloc,
+ sfree: _sfree,
+ sinval: _sinval,
+ sflush: _sflush,
+ interrupt_connect: _interrupt_connect,
+ interrupt_disconnect: _interrupt_disconnect,
+ l2p: _l2p,
+ p2l: _p2l,
+
+ NULL,
+ NULL,
+ iproc_read: _iproc_read,
+ iproc_write: _iproc_write,
+ get_cmic_ver: _get_cmic_ver,
+};
+
+/*
+ * Function: linux_bde_create
+ *
+ * Purpose:
+ * Creator function for this BDE interface.
+ * Parameters:
+ * bus - pointer to the bus features structure you want this
+ * bde to export. Depends on the system.
+ * ibde - pointer to a location to recieve the bde interface pointer.
+ * Returns:
+ * 0 on success
+ * -1 on failure.
+ * Notes:
+ * This is the main BDE create function for this interface.
+ * Used by the external system initialization code.
+ */
+int
+linux_bde_create(linux_bde_bus_t *bus, ibde_t **ibde)
+{
+
+ memset(&_bus, 0, sizeof(_bus));
+
+ if (bus) {
+ _bus = *bus;
+ }
+#ifdef NONCOHERENT_DMA_MEMORY
+#ifdef REMAP_DMA_NONCACHED
+ /*
+ * If we have a non-cached DMA memory pool
+ * there is no need to flush and invalidate.
+ */
+ if (_dma_pool_allocated()) {
+ _ibde.sinval = NULL;
+ _ibde.sflush = NULL;
+ }
+#endif
+#else
+ _ibde.sinval = NULL;
+ _ibde.sflush = NULL;
+#endif
+ *ibde = &_ibde;
+ return 0;
+}
+
+/*
+ * Function: linux_bde_destroy
+ *
+ * Purpose:
+ * destroy this bde
+ * Parameters:
+ * BDE interface pointer
+ * Returns:
+ * 0 on success, < 0 on error.
+ */
+int
+linux_bde_destroy(ibde_t *ibde)
+{
+ /* nothing */
+ return 0;
+}
+
+/*
+ * Backdoors provided by the kernel bde
+ */
+
+uint32_t
+lkbde_get_dev_phys(int d)
+{
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ gprintk("lkbde_get_dev_phys: Not PCI device %d, type %x\n",
+ d, _devices[d].dev_type);
+ return 0;
+ }
+ return _devices[d].iowin[0].addr;
+}
+
+uint32_t
+lkbde_get_dev_phys_hi(int d)
+{
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ gprintk("lkbde_get_dev_phys: Not PCI device %d, type %x\n",
+ d, _devices[d].dev_type);
+ return 0;
+ }
+#ifdef PHYS_ADDR_IS_64BIT
+ return (uint32_t)(_devices[d].iowin[0].addr >> 32);
+#else
+ return 0;
+#endif
+}
+
+void *
+lkbde_get_dev_virt(int d)
+{
+ if (!VALID_DEVICE(d)) {
+ return NULL;
+ }
+
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ gprintk("lkbde_get_dev_virt: Not PCI device %d, type %x\n",
+ d, _devices[d].dev_type);
+ return 0;
+ }
+
+ if (_devices[d].alt_base_addr) {
+ return (void *)_devices[d].alt_base_addr;
+ }
+
+ return (void *)_devices[d].bde_dev.base_address;
+}
+
+int
+lkbde_get_dev_resource(int d, int rsrc, uint32_t *flags,
+ uint32_t *phys_lo, uint32_t *phys_hi)
+{
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ *flags = 0;
+ *phys_lo = 0;
+ *phys_hi = 0;
+
+ if (!(BDE_DEV_MEM_MAPPED(_devices[d].dev_type))) {
+ gprintk("lkbde_get_dev_phys: Not PCI device %d, type %x\n",
+ d, _devices[d].dev_type);
+ return 0;
+ }
+
+ switch (rsrc) {
+ case 0:
+ *phys_lo = (uint32_t)(_devices[d].iowin[0].addr);
+#ifdef PHYS_ADDR_IS_64BIT
+ *phys_hi = (uint32_t)(_devices[d].iowin[0].addr >> 32);
+#endif
+ break;
+ case 1:
+ *phys_lo = (uint32_t)(_devices[d].iowin[1].addr);
+#ifdef PHYS_ADDR_IS_64BIT
+ *phys_hi = (uint32_t)(_devices[d].iowin[1].addr >> 32);
+#endif
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+void *
+lkbde_get_dma_dev(int d)
+{
+ if (!VALID_DEVICE(d)) {
+ return NULL;
+ }
+
+#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT
+ return (void *)_devices[d].dma_dev;
+#else
+ return (void *)_devices[d].pci_device;
+#endif
+}
+
+void *
+lkbde_get_hw_dev(int d)
+{
+ if (!VALID_DEVICE(d)) {
+ return NULL;
+ }
+
+ return (void *)_devices[d].pci_device;
+}
+
+int
+lkbde_dev_state_set(int d, uint32 state)
+{
+ bde_ctrl_t *ctrl;
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+ ctrl = _devices + d;
+ ctrl->dev_state = state;
+ return 0;
+}
+
+int
+lkbde_dev_state_get(int d, uint32 *state)
+{
+ bde_ctrl_t *ctrl;
+ if (!VALID_DEVICE(d)) {
+ gprintk("_get_dev: Invalid device index %d\n", d);
+ return -1;
+ }
+ ctrl = _devices + d;
+
+ *state = ctrl->dev_state;
+ return 0;
+}
+
+int
+lkbde_dev_instid_set(int d, uint32 instid)
+{
+ bde_ctrl_t *ctrl;
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+ ctrl = _devices + d;
+ ctrl->inst_id = instid;
+
+ return 0;
+}
+
+int
+lkbde_dev_instid_get(int d, uint32 *instid)
+{
+ bde_ctrl_t *ctrl;
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+ ctrl = _devices + d;
+ *instid = ctrl->inst_id;
+
+ return 0;
+}
+/*
+ * When a secondary interrupt handler is installed this function
+ * is used for synchronizing hardware access to the IRQ mask
+ * register. The secondary driver will supply a non-zero fmask
+ * (filter mask) to indicate which interrupt bits it controls.
+ * The fmask is ignored for the primary driver.
+ */
+int
+lkbde_irq_mask_set(int d, uint32_t addr, uint32_t mask, uint32_t fmask)
+{
+ bde_ctrl_t *ctrl;
+ int isr2_dev, iproc_reg;
+ unsigned long flags;
+
+ isr2_dev = d & LKBDE_ISR2_DEV;
+ iproc_reg = d & LKBDE_IPROC_REG;
+ d &= ~(LKBDE_ISR2_DEV | LKBDE_IPROC_REG);
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ ctrl = _devices + d;
+
+ /* Lock is required to synchronize access from user space */
+ spin_lock_irqsave(&ctrl->lock, flags);
+
+ if (isr2_dev) {
+ /* This is the secondary interrupt handler */
+ ctrl->fmask = fmask;
+ ctrl->imask2 = mask & ctrl->fmask;
+ } else {
+ /* This is the primary interrupt handler */
+ ctrl->imask = mask & ~ctrl->fmask;
+ }
+
+ if (iproc_reg) {
+ _iproc_write(d, addr, ctrl->imask | ctrl->imask2);
+ } else {
+ _write(d, addr, ctrl->imask | ctrl->imask2);
+ }
+
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+
+ return 0;
+}
+
+/*
+ * When a secondary interrupt handler is installed, this function
+ * is used to avoid activating the user mode interrupt handler
+ * thread if all pending interrupts are handled in kernel space.
+ *
+ * The mask returned is the mask of all interrupts, it can be used
+ * to do a logical AND with fmask, the result will tell you if
+ * the user mode interrupt handler needs to be invoked.
+ *
+ * Note that if no secondary handler is installed, the value of
+ * "mask & fmask" will be zero, and hence there will be no need to read the
+ * current interrupt status from hardware (from kernel space).
+ */
+int
+lkbde_irq_mask_get(int d, uint32_t *mask, uint32_t *fmask)
+{
+ bde_ctrl_t *ctrl;
+
+ d &= ~(LKBDE_ISR2_DEV | LKBDE_IPROC_REG);
+
+ if (!VALID_DEVICE(d)) {
+ return -1;
+ }
+
+ if (mask == NULL || fmask == NULL) {
+ return -1;
+ }
+
+ ctrl = _devices + d;
+
+ *fmask = ctrl->fmask;
+ *mask = ctrl->imask | ctrl->imask2;
+
+ return 0;
+}
+
+int
+lkbde_get_num_devices(int type)
+{
+ return _num_devices(type);
+}
+
+/*
+ * Export functions
+ */
+LKM_EXPORT_SYM(linux_bde_create);
+LKM_EXPORT_SYM(linux_bde_destroy);
+LKM_EXPORT_SYM(lkbde_get_dev_phys);
+LKM_EXPORT_SYM(lkbde_get_dev_virt);
+LKM_EXPORT_SYM(lkbde_get_dev_resource);
+LKM_EXPORT_SYM(lkbde_get_hw_dev);
+LKM_EXPORT_SYM(lkbde_get_dma_dev);
+LKM_EXPORT_SYM(lkbde_irq_mask_set);
+LKM_EXPORT_SYM(lkbde_irq_mask_get);
+LKM_EXPORT_SYM(lkbde_get_dev_phys_hi);
+LKM_EXPORT_SYM(lkbde_dev_state_set);
+LKM_EXPORT_SYM(lkbde_dev_state_get);
+LKM_EXPORT_SYM(lkbde_dev_instid_set);
+LKM_EXPORT_SYM(lkbde_dev_instid_get);
+#ifdef BCM_SAND_SUPPORT
+LKM_EXPORT_SYM(lkbde_cpu_write);
+LKM_EXPORT_SYM(lkbde_cpu_read);
+LKM_EXPORT_SYM(lkbde_cpu_pci_register);
+#endif
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux_dma.c b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux_dma.c
@@ -0,0 +1,1026 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: linux_dma.c,v 1.414 Broadcom SDK $
+ * $Copyright: (c) 2016 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ * Linux Kernel BDE DMA memory allocation
+ *
+ *
+ * DMA memory allocation modes
+ * ===========================
+ *
+ * 1. Using private pool in kernel memory
+ * --------------------------------------
+ * In this mode the BDE module will try to assemble a physically contiguous
+ * of memory using the kernel page allocator. This memory block is then
+ * administered by the mpool allocation functions. Note that once a system
+ * has been running for a while, the memory fragmentation may prevent the
+ * allocator from assembling a contiguous memory block, however, if the
+ * module is loaded shortly after system startup, it is very unlikely to
+ * fail.
+ *
+ * This allocation method is used by default.
+ *
+ * 2. Using private pool in high memory
+ * ------------------------------------
+ * In this mode the BDE module will assume that unused physical memory is
+ * present at the high_memory address, i.e. memory not managed by the Linux
+ * memory manager. This memory block is mapped into kernel space and
+ * administered by the mpool allocation functions. High memory must be
+ * reserved using either the mem=xxx kernel parameter (recommended), or by
+ * hardcoding the memory limit in the kernel image.
+ *
+ * The module parameter himem=1 enables this allocation mode.
+ *
+ * 3. Using kernel allocators (kmalloc, __get_free_pages)
+ * ------------------------------------------------------
+ * In this mode all DMA memory is allocated from the kernel on the fly, i.e.
+ * no private DMA memory pool will be created. If large memory blocks are
+ * only allocated at system startup (or not at all), this allocation method
+ * is the most flexible and memory-efficient, however, it is not recommended
+ * for non-coherent memory platforms due to an overall system performance
+ * degradation arising from the use of cache flush/invalidate instructions.
+ *
+ * The module parameter dmasize=0M enables this allocation mode, however if
+ * DMA memory is requested from a user mode application, a private memory
+ * pool will be created and used irrespectively.
+ */
+
+#include <gmodule.h>
+#include <linux-bde.h>
+#include <linux_dma.h>
+#include <mpool.h>
+#include <sdk_config.h>
+
+#if defined(IPROC_CMICD) && defined(CONFIG_OF)
+#include <linux/of.h>
+#endif
+
+#ifdef BCM_PLX9656_LOCAL_BUS
+#include <asm/cacheflush.h>
+#endif
+
+/* allocation types/methods for the DMA memory pool */
+#define ALLOC_TYPE_CHUNK 0 /* use small allocations and join them */
+#define ALLOC_TYPE_API 1 /* use one allocation */
+
+#if _SIMPLE_MEMORY_ALLOCATION_
+#include <linux/dma-mapping.h>
+#if defined(CONFIG_CMA) && defined(CONFIG_CMA_SIZE_MBYTES)
+#define DMA_MAX_ALLOC_SIZE (CONFIG_CMA_SIZE_MBYTES * 1024 * 1024)
+#else
+#define DMA_MAX_ALLOC_SIZE (1 << (MAX_ORDER - 1 + PAGE_SHIFT)) /* Maximum size the kernel can allocate in one allocation */
+#endif
+#endif /* _SIMPLE_MEMORY_ALLOCATION_ */
+
+#if _SIMPLE_MEMORY_ALLOCATION_ == 1
+/* Use Linux DMA API to allocate contiguous memory */
+#define ALLOC_METHOD_DEFAULT ALLOC_TYPE_API
+#if defined(__arm__)
+#define USE_DMA_MMAP_COHERENT
+#define _PGPROT_NONCACHED(x) x = pgprot_noncached((x))
+#elif defined(__aarch64__ )
+#define USE_DMA_MMAP_COHERENT
+#define _PGPROT_NONCACHED(x) x = pgprot_writecombine((x))
+#endif
+#else
+#define ALLOC_METHOD_DEFAULT ALLOC_TYPE_CHUNK
+#endif
+
+#ifndef _PGPROT_NONCACHED
+#ifdef REMAP_DMA_NONCACHED
+#define _PGPROT_NONCACHED(x) x = pgprot_noncached((x))
+#else
+#define _PGPROT_NONCACHED(x)
+#endif
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
+#include <linux/slab.h>
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))
+#define VIRT_TO_PAGE(p) virt_to_page((void*)(p))
+#else
+#define VIRT_TO_PAGE(p) virt_to_page((p))
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
+#define BDE_DMA_MAPPING_ERROR(d, p) dma_mapping_error((d),(p))
+#else
+#define BDE_DMA_MAPPING_ERROR(d, p) dma_mapping_error((p))
+#endif
+
+#ifndef KMALLOC_MAX_SIZE
+#define KMALLOC_MAX_SIZE (1UL << (MAX_ORDER - 1 + PAGE_SHIFT))
+#endif
+
+/* Compatibility */
+#ifdef LKM_2_4
+#define MEM_MAP_RESERVE mem_map_reserve
+#define MEM_MAP_UNRESERVE mem_map_unreserve
+#else /* LKM_2_6 */
+#define MEM_MAP_RESERVE SetPageReserved
+#define MEM_MAP_UNRESERVE ClearPageReserved
+#endif /* LKM_2_x */
+
+#ifndef GFP_DMA32
+#define GFP_DMA32 0
+#endif
+
+/* Flags for memory allocations */
+#ifdef SAL_BDE_XLP
+static int mem_flags = GFP_ATOMIC | GFP_KERNEL | GFP_DMA;
+#else
+#if defined(CONFIG_ZONE_DMA32)
+static int mem_flags = GFP_ATOMIC | GFP_DMA32;
+#else
+static int mem_flags = GFP_ATOMIC | GFP_DMA;
+#endif
+#endif
+
+/* Debug output */
+static int dma_debug = 0;
+module_param(dma_debug, int, 0);
+MODULE_PARM_DESC(dma_debug,
+"DMA debug output enable (default 0).");
+
+/* DMA memory pool size */
+static char *dmasize;
+LKM_MOD_PARAM(dmasize, "s", charp, 0);
+MODULE_PARM_DESC(dmasize,
+"Specify DMA memory size (default 4MB)");
+
+/* Select DMA memory pool allocation method */
+static int dmaalloc = ALLOC_METHOD_DEFAULT;
+LKM_MOD_PARAM(dmaalloc, "i", int, 0);
+MODULE_PARM_DESC(dmaalloc, "Select DMA memory allocation method");
+
+/* Use high memory for DMA */
+static char *himem;
+LKM_MOD_PARAM(himem, "s", charp, 0);
+MODULE_PARM_DESC(himem,
+"Use high memory for DMA (default no)");
+
+/* Physical high memory address to use for DMA */
+static char *himemaddr = 0;
+LKM_MOD_PARAM(himemaddr, "s", charp, 0);
+MODULE_PARM_DESC(himemaddr,
+"Physical address to use for high memory DMA");
+
+/* DMA memory allocation */
+
+#define ONE_KB 1024
+#define ONE_MB (1024*1024)
+#define ONE_GB (1024*1024*1024)
+
+/* Default DMA memory size */
+#ifdef SAL_BDE_DMA_MEM_DEFAULT
+#define DMA_MEM_DEFAULT (SAL_BDE_DMA_MEM_DEFAULT * ONE_MB)
+#else
+#define DMA_MEM_DEFAULT (8 * ONE_MB)
+#endif
+
+/* We try to assemble a contiguous segment from chunks of this size */
+#define DMA_BLOCK_SIZE (512 * ONE_KB)
+
+typedef struct _dma_segment {
+ struct list_head list;
+ unsigned long req_size; /* Requested DMA segment size */
+ unsigned long blk_size; /* DMA block size */
+ unsigned long blk_order; /* DMA block size in alternate format */
+ unsigned long seg_size; /* Current DMA segment size */
+ unsigned long seg_begin; /* Logical address of segment */
+ unsigned long seg_end; /* Logical end address of segment */
+ unsigned long *blk_ptr; /* Array of logical DMA block addresses */
+ int blk_cnt_max; /* Maximum number of block to allocate */
+ int blk_cnt; /* Current number of blocks allocated */
+} dma_segment_t;
+
+static unsigned int _dma_mem_size = DMA_MEM_DEFAULT;
+static mpool_handle_t _dma_pool = NULL;
+static void __iomem *_dma_vbase = NULL;
+/* cpu physical address for mmap */
+static phys_addr_t _cpu_pbase = 0;
+/*
+ * DMA bus address, it is either identical to cpu physical address
+ * or another address(IOVA) translated by IOMMU.
+ */
+static phys_addr_t _dma_pbase = 0;
+static int _use_himem = 0;
+static unsigned long _himemaddr = 0;
+static int _use_dma_mapping = 0;
+static LIST_HEAD(_dma_seg);
+
+#define DMA_DEV_INDEX 0 /* Device index to allocate memory pool */
+#define DMA_DEV(n) lkbde_get_dma_dev(n)
+#define BDE_NUM_DEVICES(t) lkbde_get_num_devices(t)
+
+/*
+ * Function: _find_largest_segment
+ *
+ * Purpose:
+ * Find largest contiguous segment from a pool of DMA blocks.
+ * Parameters:
+ * dseg - DMA segment descriptor
+ * Returns:
+ * 0 on success, < 0 on error.
+ * Notes:
+ * Assembly stops if a segment of the requested segment size
+ * has been obtained.
+ *
+ * Lower address bits of the DMA blocks are used as follows:
+ * 0: Untagged
+ * 1: Discarded block
+ * 2: Part of largest contiguous segment
+ * 3: Part of current contiguous segment
+ */
+static int
+_find_largest_segment(dma_segment_t *dseg)
+{
+ int i, j, blks, found;
+ unsigned long b, e, a;
+
+ blks = dseg->blk_cnt;
+ /* Clear all block tags */
+ for (i = 0; i < blks; i++) {
+ dseg->blk_ptr[i] &= ~3;
+ }
+ for (i = 0; i < blks && dseg->seg_size < dseg->req_size; i++) {
+ /* First block must be an untagged block */
+ if ((dseg->blk_ptr[i] & 3) == 0) {
+ /* Initial segment size is the block size */
+ b = dseg->blk_ptr[i];
+ e = b + dseg->blk_size;
+ dseg->blk_ptr[i] |= 3;
+ /* Loop looking for adjacent blocks */
+ do {
+ found = 0;
+ for (j = i + 1; j < blks && (e - b) < dseg->req_size; j++) {
+ a = dseg->blk_ptr[j];
+ /* Check untagged blocks only */
+ if ((a & 3) == 0) {
+ if (a == (b - dseg->blk_size)) {
+ /* Found adjacent block below current segment */
+ dseg->blk_ptr[j] |= 3;
+ b = a;
+ found = 1;
+ } else if (a == e) {
+ /* Found adjacent block above current segment */
+ dseg->blk_ptr[j] |= 3;
+ e += dseg->blk_size;
+ found = 1;
+ }
+ }
+ }
+ } while (found);
+ if ((e - b) > dseg->seg_size) {
+ /* The current block is largest so far */
+ dseg->seg_begin = b;
+ dseg->seg_end = e;
+ dseg->seg_size = e - b;
+ /* Re-tag current and previous largest segment */
+ for (j = 0; j < blks; j++) {
+ if ((dseg->blk_ptr[j] & 3) == 3) {
+ /* Tag current segment as the largest */
+ dseg->blk_ptr[j] &= ~1;
+ } else if ((dseg->blk_ptr[j] & 3) == 2) {
+ /* Discard previous largest segment */
+ dseg->blk_ptr[j] ^= 3;
+ }
+ }
+ } else {
+ /* Discard all blocks in current segment */
+ for (j = 0; j < blks; j++) {
+ if ((dseg->blk_ptr[j] & 3) == 3) {
+ dseg->blk_ptr[j] &= ~2;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * Function: _alloc_dma_blocks
+ *
+ * Purpose:
+ * Allocate DMA blocks and add them to the pool.
+ * Parameters:
+ * dseg - DMA segment descriptor
+ * blks - number of DMA blocks to allocate
+ * Returns:
+ * 0 on success, < 0 on error.
+ * Notes:
+ * DMA blocks are allocated using the page allocator.
+ */
+static int
+_alloc_dma_blocks(dma_segment_t *dseg, int blks)
+{
+ int i, start;
+ unsigned long addr;
+
+ if (dseg->blk_cnt + blks > dseg->blk_cnt_max) {
+ gprintk("No more DMA blocks\n");
+ return -1;
+ }
+ start = dseg->blk_cnt;
+ for (i = 0; i < blks; i++) {
+ /*
+ * Note that we cannot use pci_alloc_consistent when we
+ * want to be able to map DMA memory to user space.
+ *
+ * The GFP_DMA flag is omitted as this imposes the ISA
+ * addressing limitations on x86 platforms. As long as
+ * we have less than 1GB of memory, we can do PCI DMA
+ * to all physical RAM locations.
+ */
+ addr = __get_free_pages(mem_flags, dseg->blk_order);
+ if (addr) {
+ dseg->blk_ptr[start + i] = addr;
+ ++dseg->blk_cnt;
+ } else {
+ gprintk("DMA allocation failed: allocated %d of %d "
+ "requested blocks\n", i, blks);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Function: _dma_segment_alloc
+ *
+ * Purpose:
+ * Allocate large physically contiguous DMA segment.
+ * Parameters:
+ * size - requested DMA segment size
+ * blk_size - assemble segment from blocks of this size
+ * Returns:
+ * DMA segment descriptor.
+ * Notes:
+ * Since we cannot allocate large blocks of contiguous
+ * memory from the kernel, we simply keep allocating
+ * smaller chunks until we can assemble a contiguous
+ * block of the desired size.
+ *
+ * When system allowed maximum bytes of memory has been allocated
+ * without a successful assembly of a contiguous DMA
+ * segment, the allocation function will return the
+ * largest contiguous segment found so far. It is up
+ * to the calling function to decide whether this
+ * amount is sufficient to proceed.
+ */
+static dma_segment_t *
+_dma_segment_alloc(size_t size, size_t blk_size)
+{
+ dma_segment_t *dseg;
+ int i, blk_ptr_size;
+ unsigned long page_addr;
+ struct sysinfo si;
+
+ /* Sanity check */
+ if (size == 0 || blk_size == 0) {
+ return NULL;
+ }
+ /* Allocate an initialize DMA segment descriptor */
+ if ((dseg = kmalloc(sizeof(dma_segment_t), GFP_KERNEL)) == NULL) {
+ return NULL;
+ }
+ memset(dseg, 0, sizeof(dma_segment_t));
+ dseg->req_size = size;
+ dseg->blk_size = PAGE_ALIGN(blk_size);
+ while ((PAGE_SIZE << dseg->blk_order) < dseg->blk_size) {
+ dseg->blk_order++;
+ }
+
+ si_meminfo(&si);
+ dseg->blk_cnt_max = (si.totalram << PAGE_SHIFT) / dseg->blk_size;
+ blk_ptr_size = dseg->blk_cnt_max * sizeof(unsigned long);
+ if (blk_ptr_size > KMALLOC_MAX_SIZE) {
+ blk_ptr_size = KMALLOC_MAX_SIZE;
+ dseg->blk_cnt_max = KMALLOC_MAX_SIZE / sizeof(unsigned long);
+ }
+ /* Allocate an initialize DMA block pool */
+ dseg->blk_ptr = KMALLOC(blk_ptr_size, GFP_KERNEL);
+ if (dseg->blk_ptr == NULL) {
+ kfree(dseg);
+ return NULL;
+ }
+ memset(dseg->blk_ptr, 0, blk_ptr_size);
+ /* Allocate minimum number of blocks */
+ if (_alloc_dma_blocks(dseg, dseg->req_size / dseg->blk_size) != 0) {
+ gprintk("Failed to allocate minimum number of DMA blocks\n");
+ /*
+ * _alloc_dma_blocks() returns -1 if it fails to allocate the requested
+ * number of blocks, but it may still have allocated something. Fall
+ * through and return dseg filled in with as much memory as we could
+ * allocate.
+ */
+ }
+ /* Allocate more blocks until we have a complete segment */
+ do {
+ _find_largest_segment(dseg);
+ if (dseg->seg_size >= dseg->req_size) {
+ break;
+ }
+ } while (_alloc_dma_blocks(dseg, 8) == 0);
+ /* Reserve all pages in the DMA segment and free unused blocks */
+ for (i = 0; i < dseg->blk_cnt; i++) {
+ if ((dseg->blk_ptr[i] & 3) == 2) {
+ dseg->blk_ptr[i] &= ~3;
+ for (page_addr = dseg->blk_ptr[i];
+ page_addr < dseg->blk_ptr[i] + dseg->blk_size;
+ page_addr += PAGE_SIZE) {
+ MEM_MAP_RESERVE(VIRT_TO_PAGE(page_addr));
+ }
+ } else if (dseg->blk_ptr[i]) {
+ dseg->blk_ptr[i] &= ~3;
+ free_pages(dseg->blk_ptr[i], dseg->blk_order);
+ dseg->blk_ptr[i] = 0;
+ }
+ }
+ return dseg;
+}
+
+/*
+ * Function: _dma_segment_free
+ *
+ * Purpose:
+ * Release resources used by DMA segment.
+ * Parameters:
+ * dseg - DMA segment descriptor
+ * Returns:
+ * Nothing.
+ */
+static void
+_dma_segment_free(dma_segment_t *dseg)
+{
+ int i;
+ unsigned long page_addr;
+
+ if (dseg->blk_ptr) {
+ for (i = 0; i < dseg->blk_cnt; i++) {
+ if (dseg->blk_ptr[i]) {
+ for (page_addr = dseg->blk_ptr[i];
+ page_addr < dseg->blk_ptr[i] + dseg->blk_size;
+ page_addr += PAGE_SIZE) {
+ MEM_MAP_UNRESERVE(VIRT_TO_PAGE(page_addr));
+ }
+ free_pages(dseg->blk_ptr[i], dseg->blk_order);
+ }
+ }
+ kfree(dseg->blk_ptr);
+ kfree(dseg);
+ }
+}
+
+/*
+ * Function: _pgalloc
+ *
+ * Purpose:
+ * Allocate DMA memory using page allocator
+ * Parameters:
+ * size - number of bytes to allocate
+ * Returns:
+ * Pointer to allocated DMA memory or NULL if failure.
+ * Notes:
+ * For any sizes less than DMA_BLOCK_SIZE, we ask the page
+ * allocator for the entire memory block, otherwise we try
+ * to assemble a contiguous segment ourselves.
+ */
+static void *
+_pgalloc(size_t size)
+{
+ dma_segment_t *dseg;
+ size_t blk_size;
+
+ blk_size = (size < DMA_BLOCK_SIZE) ? size : DMA_BLOCK_SIZE;
+ if ((dseg = _dma_segment_alloc(size, blk_size)) == NULL) {
+ return NULL;
+ }
+ if (dseg->seg_size < size) {
+ /* If we didn't get the full size then forget it */
+ gprintk("_pgalloc() failed to get requested size %zu: "
+ "only got %lu contiguous across %d blocks\n",
+ size, dseg->seg_size, dseg->blk_cnt);
+ _dma_segment_free(dseg);
+ return NULL;
+ }
+ list_add(&dseg->list, &_dma_seg);
+ return (void *)dseg->seg_begin;
+}
+
+/*
+ * Function: _pgfree
+ *
+ * Purpose:
+ * Free memory allocated by _pgalloc
+ * Parameters:
+ * ptr - pointer returned by _pgalloc
+ * Returns:
+ * 0 if succesfully freed, otherwise -1.
+ */
+static int
+_pgfree(void *ptr)
+{
+ struct list_head *pos;
+ list_for_each(pos, &_dma_seg) {
+ dma_segment_t *dseg = list_entry(pos, dma_segment_t, list);
+ if (ptr == (void *)dseg->seg_begin) {
+ list_del(&dseg->list);
+ _dma_segment_free(dseg);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/*
+ * Function: _pgcleanup
+ *
+ * Purpose:
+ * Free all memory allocated by _pgalloc
+ * Parameters:
+ * None
+ * Returns:
+ * Nothing.
+ */
+static void
+_pgcleanup(void)
+{
+ switch (dmaalloc) {
+#if _SIMPLE_MEMORY_ALLOCATION_
+ case ALLOC_TYPE_API:
+ if (_dma_vbase) {
+ if (dma_debug >= 1) gprintk("freeing v=%p p=0x%lx size=0x%lx\n", _dma_vbase,(unsigned long) _dma_pbase, (unsigned long)_dma_mem_size);
+ dma_free_coherent(DMA_DEV(DMA_DEV_INDEX), _dma_mem_size, _dma_vbase, _dma_pbase);
+ }
+ break;
+#endif /* _SIMPLE_MEMORY_ALLOCATION_ */
+
+ case ALLOC_TYPE_CHUNK: {
+ struct list_head *pos, *tmp;
+ int i, ndevices;
+ if (_use_dma_mapping) {
+ ndevices = BDE_NUM_DEVICES(BDE_SWITCH_DEVICES);
+ for (i = 0; i < ndevices && DMA_DEV(i); i ++) {
+ dma_unmap_single(DMA_DEV(i), (dma_addr_t)_dma_pbase, _dma_mem_size, DMA_BIDIRECTIONAL);
+ }
+ _use_dma_mapping = 0;
+ }
+ list_for_each_safe(pos, tmp, &_dma_seg) {
+ dma_segment_t *dseg = list_entry(pos, dma_segment_t, list);
+ list_del(&dseg->list);
+ _dma_segment_free(dseg);
+ }
+ break;
+ }
+
+ default:
+ gprintk("DMA memory allocation method dmaalloc=%d is not supported\n", dmaalloc);
+ }
+}
+
+/*
+ * Function: _alloc_mpool
+ *
+ * Purpose:
+ * Allocate DMA memory pool
+ * Parameters:
+ * size - size of DMA memory pool
+ * Returns:
+ * Nothing.
+ * Notes:
+ * If set up to use high memory, we simply map the memory into
+ * kernel space.
+ * It is assumed there is only one pool.
+ */
+static void
+_alloc_mpool(size_t size)
+{
+ unsigned long pbase = 0;
+ struct device *dev = DMA_DEV(DMA_DEV_INDEX);
+ int dma64_support = 0;
+
+#if defined(IPROC_CMICD) && defined(CONFIG_OF)
+ if (of_find_compatible_node(NULL, NULL, "brcm,iproc-cmicx")) {
+ dma64_support = 1;
+ }
+#endif
+
+#if defined(__arm__) && !defined(CONFIG_HIGHMEM)
+ if (_use_himem) {
+ gprintk("DMA in high memory requires CONFIG_HIGHMEM on ARM CPUs.\n");
+ return;
+ }
+#endif
+
+ if (_use_himem) {
+ /* Use high memory for DMA */
+ if (_himemaddr) {
+ pbase = _himemaddr;
+ } else {
+ pbase = virt_to_bus(high_memory);
+ }
+ if (((pbase + (size - 1)) >> 16) > DMA_BIT_MASK(16)) {
+ gprintk("DMA in high memory at 0x%lx size 0x%lx is beyond the 4GB limit and not supported.\n", pbase, (unsigned long)size);
+ return;
+ }
+ _cpu_pbase = _dma_pbase = pbase;
+ _dma_vbase = IOREMAP(_dma_pbase, size);
+ } else {
+ /* Get DMA memory from kernel */
+ if (dma_debug >= 1) {
+ gprintk("Allocating DMA memory using method dmaalloc=%d\n", dmaalloc);
+ }
+ switch (dmaalloc) {
+#if _SIMPLE_MEMORY_ALLOCATION_
+ case ALLOC_TYPE_API: {
+ size_t alloc_size = size; /* size of memory allocated in current iteration */
+ if (alloc_size > DMA_MAX_ALLOC_SIZE) {
+ alloc_size = DMA_MAX_ALLOC_SIZE;
+ }
+ /* get a memory allocation from the kernel */
+ {
+ dma_addr_t dma_handle;
+ _dma_vbase = dma_alloc_coherent(dev, alloc_size, &dma_handle, GFP_KERNEL);
+ if (!_dma_vbase || !dma_handle) {
+ gprintk("Failed to allocate coherent memory pool of size 0x%lx\n", (unsigned long)alloc_size);
+ return;
+ }
+ _cpu_pbase = pbase = dma_handle;
+ }
+
+ if (alloc_size != size) {
+ gprintk("allocated 0x%lx bytes instead of 0x%lx bytes.\n",
+ (unsigned long)alloc_size, (unsigned long)size);
+ }
+ size = _dma_mem_size = alloc_size;
+ break;
+ }
+#endif /* _SIMPLE_MEMORY_ALLOCATION_ */
+
+ case ALLOC_TYPE_CHUNK:
+ _dma_vbase = _pgalloc(size);
+ if (!_dma_vbase) {
+ gprintk("Failed to allocate memory pool of size 0x%lx\n", (unsigned long)size);
+ return;
+ }
+ _cpu_pbase = virt_to_bus(_dma_vbase);
+ /* Use dma_map_single to obtain DMA bus address or IOVA if iommu is present. */
+ if (dev) {
+ pbase = dma_map_single(dev, _dma_vbase, size, DMA_BIDIRECTIONAL);
+ if (BDE_DMA_MAPPING_ERROR(dev, pbase)) {
+ gprintk("Failed to map memory at %p\n", _dma_vbase);
+ _pgcleanup();
+ _dma_vbase = NULL;
+ return;
+ }
+ _use_dma_mapping = 1;
+ } else {
+ pbase = _cpu_pbase;
+ }
+ break;
+ default:
+ _dma_vbase = NULL;
+ gprintk("DMA memory allocation method dmaalloc=%d is not supported\n", dmaalloc);
+ return;
+ }
+
+ _dma_pbase = pbase;
+
+ if (!dma64_support && ((pbase + (size - 1)) >> 16) > DMA_BIT_MASK(16)) {
+ gprintk("DMA memory allocated at 0x%lx size 0x%lx is beyond the 4GB limit and not supported.\n", pbase, (unsigned long)size);
+ _pgcleanup();
+ _dma_vbase = NULL;
+ _dma_pbase = 0;
+ return;
+ }
+
+#ifdef REMAP_DMA_NONCACHED
+ _dma_vbase = IOREMAP(_dma_pbase, size);
+#endif
+ if (dma_debug >= 1) {
+ gprintk("_use_dma_mapping:%d _dma_vbase:%p _dma_pbase:%lx _cpu_pbase:%lx allocated:%lx dmaalloc:%d, dma64_support:%d\n",
+ _use_dma_mapping, _dma_vbase, (unsigned long)_dma_pbase,
+ (unsigned long)_cpu_pbase, (unsigned long)size, dmaalloc, dma64_support);
+ }
+ }
+}
+
+/*
+ * Function: _dma_cleanup
+ *
+ * Purpose:
+ * DMA cleanup function.
+ * Parameters:
+ * None
+ * Returns:
+ * Always 0
+ */
+int
+_dma_cleanup(void)
+{
+ if (_dma_vbase) {
+ mpool_destroy(_dma_pool);
+ if (_use_himem) {
+ iounmap(_dma_vbase);
+ } else {
+#ifdef REMAP_DMA_NONCACHED
+ iounmap(_dma_vbase);
+#endif
+ _pgcleanup();
+ }
+ _dma_vbase = NULL;
+ _dma_pbase = 0;
+ _cpu_pbase = 0;
+ }
+ return 0;
+}
+
+void _dma_init(int dev_index)
+{
+ unsigned long pbase;
+
+ if (dev_index > DMA_DEV_INDEX) {
+ if (_use_dma_mapping && DMA_DEV(dev_index) && _dma_vbase) {
+ pbase = dma_map_single(DMA_DEV(dev_index), _dma_vbase, _dma_mem_size, DMA_BIDIRECTIONAL);
+ if (BDE_DMA_MAPPING_ERROR(DMA_DEV(dev_index), pbase)) {
+ gprintk("Failed to map memory for device %d at %p\n", dev_index, _dma_vbase);
+ return;
+ }
+ if (pbase != (unsigned long)_dma_pbase) {
+ /* Bus address/IOVA must be identical for all devices. */
+ gprintk("Device %d has different pbase: %lx (should be %lx)\n",
+ dev_index, pbase, (unsigned long)_dma_pbase);
+ }
+ }
+ return;
+ }
+
+ /* DMA Setup */
+ if (dmasize) {
+ if ((dmasize[strlen(dmasize)-1] & ~0x20) == 'M') {
+ _dma_mem_size = simple_strtoul(dmasize, NULL, 0);
+ _dma_mem_size *= ONE_MB;
+ } else {
+ gprintk("DMA memory size must be specified as e.g. dmasize=8M\n");
+ }
+ if (_dma_mem_size & (_dma_mem_size-1)) {
+ gprintk("dmasize must be a power of 2 (1M, 2M, 4M, 8M etc.)\n");
+ _dma_mem_size = 0;
+ }
+ }
+
+ if (himem) {
+ if ((himem[0] & ~0x20) == 'Y' || himem[0] == '1') {
+ _use_himem = 1;
+ } else if ((himem[0] & ~0x20) == 'N' || himem[0] == '0') {
+ _use_himem = 0;
+ }
+ }
+
+ if (himemaddr && strlen(himemaddr) > 0) {
+ char suffix = (himemaddr[strlen(himemaddr)-1] & ~0x20);
+ _himemaddr = simple_strtoul(himemaddr, NULL, 0);
+ if (suffix == 'M') {
+ _himemaddr *= ONE_MB;
+ } else if (suffix == 'G') {
+ _himemaddr *= ONE_GB;
+ } else {
+ gprintk("DMA high memory address must be specified as e.g. himemaddr=8[MG]\n");
+ }
+ }
+
+ if (_dma_mem_size) {
+ _alloc_mpool(_dma_mem_size);
+ if (_dma_vbase == NULL) {
+ gprintk("no DMA memory available\n");
+ } else {
+ mpool_init();
+ _dma_pool = mpool_create(_dma_vbase, _dma_mem_size);
+ }
+ }
+}
+
+/*
+ * Some kernels are configured to prevent mapping of kernel RAM memory
+ * into user space via the /dev/mem device.
+ *
+ * The function below provides a backdoor to mapping the DMA pool to
+ * user space via the BDE device file.
+ */
+int _dma_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ unsigned long phys_addr = vma->vm_pgoff << PAGE_SHIFT;
+ unsigned long size = vma->vm_end - vma->vm_start;
+
+ if (phys_addr < (unsigned long )_cpu_pbase ||
+ (phys_addr + size) > ((unsigned long )_cpu_pbase + _dma_mem_size)) {
+ gprintk("range 0x%lx-0x%lx outside DMA pool 0x%lx-0x%lx\n",
+ phys_addr, phys_addr + size, (unsigned long )_cpu_pbase,
+ (unsigned long )_cpu_pbase + _dma_mem_size);
+ return -EINVAL;
+ }
+
+#ifdef USE_DMA_MMAP_COHERENT
+ if (dmaalloc == ALLOC_TYPE_API) {
+ vma->vm_pgoff = 0;
+ return dma_mmap_coherent(DMA_DEV(DMA_DEV_INDEX), vma, (void *)_dma_vbase, phys_addr, size);
+ }
+#endif
+
+ _PGPROT_NONCACHED(vma->vm_page_prot);
+
+ if (remap_pfn_range(vma,
+ vma->vm_start,
+ vma->vm_pgoff,
+ size,
+ vma->vm_page_prot)) {
+ gprintk("Failed to mmap phys range 0x%lx-0x%lx to 0x%lx-0x%lx\n",
+ phys_addr, phys_addr + size, vma->vm_start,vma->vm_end);
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+/*
+ * Function: _dma_pool_allocated
+ *
+ * Purpose:
+ * Check if DMA pool has been allocated.
+ * Parameters:
+ * None
+ * Returns:
+ * 0 : not allocated
+ * 1 : allocated
+ */
+int
+_dma_pool_allocated(void)
+{
+ return (_dma_vbase) ? 1 : 0;
+}
+
+sal_paddr_t
+_l2p(int d, void *vaddr)
+{
+ if (_dma_mem_size) {
+ /* dma memory is a contiguous block */
+ if (vaddr) {
+ return _dma_pbase + (PTR_TO_UINTPTR(vaddr) - PTR_TO_UINTPTR(_dma_vbase));
+ }
+ return 0;
+ }
+ return ((sal_paddr_t)virt_to_bus(vaddr));
+}
+
+void *
+_p2l(int d, sal_paddr_t paddr)
+{
+ sal_vaddr_t vaddr = (sal_vaddr_t)_dma_vbase;
+
+ if (_dma_mem_size) {
+ /* DMA memory is a contiguous block */
+ if (paddr == 0) {
+ return NULL;
+ }
+ return (void *)(vaddr + (sal_vaddr_t)(paddr - _dma_pbase));
+ }
+ return bus_to_virt(paddr);
+}
+
+/*
+ * Some of the driver malloc's are too large for
+ * kmalloc(), so 'sal_alloc' and 'sal_free' in the
+ * linux kernel sal cannot be implemented with kmalloc().
+ *
+ * Instead, they expect someone to provide an allocator
+ * that can handle the gimongous size of some of the
+ * allocations, and we provide it here, by allocating
+ * this memory out of the boot-time dma pool.
+ *
+ * These are the functions in question:
+ */
+
+void* kmalloc_giant(int sz)
+{
+ return mpool_alloc(_dma_pool, sz);
+}
+
+void kfree_giant(void* ptr)
+{
+ return mpool_free(_dma_pool, ptr);
+}
+
+uint32_t *
+_salloc(int d, int size, const char *name)
+{
+ void *ptr;
+
+ if (_dma_mem_size) {
+ return mpool_alloc(_dma_pool, size);
+ }
+ if ((ptr = kmalloc(size, mem_flags)) == NULL) {
+ ptr = _pgalloc(size);
+ }
+ return ptr;
+}
+
+void
+_sfree(int d, void *ptr)
+{
+ if (_dma_mem_size) {
+ return mpool_free(_dma_pool, ptr);
+ }
+ if (_pgfree(ptr) < 0) {
+ kfree(ptr);
+ }
+}
+
+int
+_sinval(int d, void *ptr, int length)
+{
+#if defined(dma_cache_wback_inv)
+ dma_cache_wback_inv((unsigned long)ptr, length);
+#else
+#if defined(IPROC_CMICD) || defined(BCM958525)
+ /* FIXME: need proper function to replace dma_cache_sync */
+ dma_sync_single_for_cpu(NULL, (unsigned long)ptr, length, DMA_BIDIRECTIONAL);
+#else
+ dma_cache_sync(NULL, ptr, length, DMA_BIDIRECTIONAL);
+#endif
+#endif
+ return 0;
+}
+
+int
+_sflush(int d, void *ptr, int length)
+{
+#if defined(dma_cache_wback_inv)
+ dma_cache_wback_inv((unsigned long)ptr, length);
+#else
+#if defined(IPROC_CMICD) || defined(BCM958525)
+ /* FIXME: need proper function to replace dma_cache_sync */
+ dma_sync_single_for_cpu(NULL, (unsigned long)ptr, length, DMA_BIDIRECTIONAL);
+#else
+ dma_cache_sync(NULL, ptr, length, DMA_BIDIRECTIONAL);
+#endif
+#endif
+
+ return 0;
+}
+
+int
+lkbde_get_dma_info(phys_addr_t* cpu_pbase, phys_addr_t* dma_pbase, ssize_t* size)
+{
+ if (_dma_vbase == NULL) {
+ if (_dma_mem_size == 0) {
+ _dma_mem_size = DMA_MEM_DEFAULT;
+ }
+ _alloc_mpool(_dma_mem_size);
+ }
+ *cpu_pbase = _cpu_pbase;
+ *dma_pbase = _dma_pbase;
+ *size = (_dma_vbase) ? _dma_mem_size : 0;
+ return 0;
+}
+
+void
+_dma_pprint(void)
+{
+ pprintf("\tdmasize=%s\n", dmasize);
+ pprintf("\thimem=%s\n", himem);
+ pprintf("\thimemaddr=%s\n", himemaddr);
+ pprintf("DMA Memory (%s): %d bytes, %d used, %d free%s\n",
+ (_use_himem) ? "high" : "kernel",
+ (_dma_vbase) ? _dma_mem_size : 0,
+ (_dma_vbase) ? mpool_usage(_dma_pool) : 0,
+ (_dma_vbase) ? _dma_mem_size - mpool_usage(_dma_pool) : 0,
+ USE_LINUX_BDE_MMAP ? ", local mmap" : "");
+}
+
+/*
+ * Export functions
+ */
+LKM_EXPORT_SYM(kmalloc_giant);
+LKM_EXPORT_SYM(kfree_giant);
+LKM_EXPORT_SYM(lkbde_get_dma_info);
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.c b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2014 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#include <gmodule.h>
+#include <shbde.h>
+#include <shbde_iproc.h>
+#include "linux_shbde.h"
+
+/* Hardware abstractions for shared BDE functions */
+
+static unsigned short
+linux_pcic16_read(void *pci_dev, unsigned int addr)
+{
+ u16 data = 0;
+
+ pci_read_config_word((struct pci_dev *)pci_dev, addr, &data);
+
+ return data;
+}
+
+static void
+linux_pcic16_write(void *pci_dev, unsigned int addr, unsigned short data)
+{
+ pci_write_config_word((struct pci_dev *)pci_dev, addr, (u16)data);
+}
+
+static unsigned int
+linux_pcic32_read(void *pci_dev, unsigned int addr)
+{
+ u32 data = 0;
+
+ pci_read_config_dword((struct pci_dev *)pci_dev, addr, &data);
+
+ return data;
+}
+
+static void
+linux_pcic32_write(void *pci_dev, unsigned int addr, unsigned int data)
+{
+ pci_write_config_dword((struct pci_dev *)pci_dev, addr, (u32)data);
+}
+
+static unsigned int
+linux_io32_read(void *addr)
+{
+ return *((volatile u32 *)addr);
+}
+
+static void
+linux_io32_write(void *addr, unsigned int data)
+{
+ *((volatile u32 *)addr) = data;
+}
+
+static void
+linux_usleep(int usec)
+{
+ udelay(usec);
+}
+
+
+/* To get the PCI parent device under linux, from only the device pointer */
+static void *
+linux_pci_parent_device_get(void *pci_dev)
+{
+ return (void *)(((struct pci_dev *)pci_dev)->bus->self);
+}
+
+
+/*
+ * Function:
+ * linux_shbde_hal_init
+ * Purpose:
+ * Initialize hardware abstraction module for Linux kernel.
+ * Parameters:
+ * shbde - pointer to uninitialized hardware abstraction module
+ * log_func - optional log output function
+ * Returns:
+ * Always 0
+ */
+int
+linux_shbde_hal_init(shbde_hal_t *shbde, shbde_log_func_t log_func)
+{
+ memset(shbde, 0, sizeof(*shbde));
+
+ shbde->log_func = log_func;
+
+ shbde->pcic16_read = linux_pcic16_read;
+ shbde->pcic16_write = linux_pcic16_write;
+ shbde->pcic32_read = linux_pcic32_read;
+ shbde->pcic32_write = linux_pcic32_write;
+
+ shbde->io32_read = linux_io32_read;
+ shbde->io32_write = linux_io32_write;
+
+ shbde->usleep = linux_usleep;
+
+ shbde->pci_parent_device_get = linux_pci_parent_device_get;
+
+ return 0;
+}
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.h b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/kernel/linux_shbde.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2014 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#ifndef __LINUX_SHBDE_H__
+#define __LINUX_SHBDE_H__
+
+#include <shbde.h>
+#include <shbde_pci.h>
+#include <shbde_iproc.h>
+
+extern int
+linux_shbde_hal_init(shbde_hal_t *shbde, shbde_log_func_t log_func);
+
+#endif /* __LINUX_SHBDE_H__ */
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/linux/shared/mpool.c b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/shared/mpool.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: mpool.c,v 1.18 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#include <mpool.h>
+
+#ifdef __KERNEL__
+
+/*
+ * Abstractions used when compiling for Linux kernel mode.
+ */
+
+#include <lkm.h>
+
+/*
+ * We cannot use the linux kernel SAL for MALLOC/FREE because
+ * the current implementation of sal_alloc() allocates memory
+ * out of an mpool created by this module...
+ */
+#define MALLOC(x) kmalloc(x, GFP_ATOMIC)
+#define FREE(x) kfree(x)
+
+static spinlock_t _mpool_lock;
+#define MPOOL_LOCK_INIT() spin_lock_init(&_mpool_lock)
+#define MPOOL_LOCK() unsigned long flags; spin_lock_irqsave(&_mpool_lock, flags)
+#define MPOOL_UNLOCK() spin_unlock_irqrestore(&_mpool_lock, flags)
+
+#else /* !__KERNEL__*/
+
+/*
+ * Abstractions used when compiling for Linux user mode.
+ */
+
+#include <stdlib.h>
+#include <sal/core/sync.h>
+
+#define MALLOC(x) malloc(x)
+#define FREE(x) free(x)
+
+static sal_sem_t _mpool_lock;
+#define MPOOL_LOCK_INIT() _mpool_lock = sal_sem_create("mpool_lock", 1, 1)
+#define MPOOL_LOCK() sal_sem_take(_mpool_lock, sal_sem_FOREVER)
+#define MPOOL_UNLOCK() sal_sem_give(_mpool_lock)
+
+#endif /* __KERNEL__ */
+
+/* Allow external override for system cache line size */
+#ifndef BCM_CACHE_LINE_BYTES
+#ifdef L1_CACHE_BYTES
+#define BCM_CACHE_LINE_BYTES L1_CACHE_BYTES
+#else
+#define BCM_CACHE_LINE_BYTES 128 /* Should be fine on most platforms */
+#endif
+#endif
+
+#define MPOOL_BUF_SIZE 1024
+#define MPOOL_BUF_ALLOC_COUNT_MAX 16
+
+typedef struct mpool_mem_s {
+ unsigned char *address;
+ int size;
+ struct mpool_mem_s *prev;
+ struct mpool_mem_s *next;
+} mpool_mem_t;
+
+static int _buf_alloc_count;
+static mpool_mem_t *mpool_buf[MPOOL_BUF_ALLOC_COUNT_MAX];
+static mpool_mem_t *free_list;
+
+#define ALLOC_INIT_MPOOL_BUF(ptr) \
+ ptr = MALLOC((sizeof(mpool_mem_t) * MPOOL_BUF_SIZE)); \
+ if (ptr) { \
+ int i; \
+ for (i = 0; i < MPOOL_BUF_SIZE - 1; i++) { \
+ ptr[i].next = &ptr[i+1]; \
+ } \
+ ptr[MPOOL_BUF_SIZE - 1].next = NULL; \
+ free_list = &ptr[0]; \
+ }
+
+/*
+ * Function: mpool_init
+ *
+ * Purpose:
+ * Initialize mpool lock.
+ * Parameters:
+ * None
+ * Returns:
+ * Always 0
+ */
+int
+mpool_init(void)
+{
+ MPOOL_LOCK_INIT();
+ return 0;
+}
+
+#ifdef TRACK_DMA_USAGE
+static int _dma_mem_used = 0;
+#endif
+
+/*
+ * Function: mpool_alloc
+ *
+ * Purpose:
+ * Allocate memory block from mpool.
+ * Parameters:
+ * pool - mpool handle (from mpool_create)
+ * size - size of memory block to allocate
+ * Returns:
+ * Pointer to allocated memory block or NULL if allocation fails.
+ */
+void *
+mpool_alloc(mpool_handle_t pool, int size)
+{
+ mpool_mem_t *ptr = pool, *newptr = NULL;
+ int mod;
+
+ MPOOL_LOCK();
+
+ if (size < BCM_CACHE_LINE_BYTES) {
+ size = BCM_CACHE_LINE_BYTES;
+ }
+
+ mod = size & (BCM_CACHE_LINE_BYTES - 1);
+ if (mod != 0 ) {
+ size += (BCM_CACHE_LINE_BYTES - mod);
+ }
+ while (ptr && ptr->next) {
+ if (ptr->next->address - (ptr->address + ptr->size) >= size) {
+ break;
+ }
+ ptr = ptr->next;
+ }
+
+ if (!(ptr && ptr->next)) {
+ MPOOL_UNLOCK();
+ return NULL;
+ }
+
+ if (!free_list) {
+ if (_buf_alloc_count == MPOOL_BUF_ALLOC_COUNT_MAX) {
+ MPOOL_UNLOCK();
+ return NULL;
+ }
+
+ ALLOC_INIT_MPOOL_BUF(mpool_buf[_buf_alloc_count]);
+
+ if (mpool_buf[_buf_alloc_count] == NULL) {
+ MPOOL_UNLOCK();
+ return NULL;
+ }
+
+ _buf_alloc_count++;
+ }
+
+ newptr = free_list;
+ free_list = free_list->next;
+
+ newptr->address = ptr->address + ptr->size;
+ newptr->size = size;
+ newptr->next = ptr->next;
+ newptr->prev = ptr;
+ ptr->next->prev = newptr;
+ ptr->next = newptr;
+#ifdef TRACK_DMA_USAGE
+ _dma_mem_used += size;
+#endif
+
+ MPOOL_UNLOCK();
+ return newptr->address;
+}
+
+
+/*
+ * Function: mpool_free
+ *
+ * Purpose:
+ * Free memory block allocated from mpool..
+ * Parameters:
+ * pool - mpool handle (from mpool_create)
+ * addr - address of memory block to free
+ * Returns:
+ * Nothing
+ */
+void
+mpool_free(mpool_handle_t pool, void *addr)
+{
+ unsigned char *address = (unsigned char *)addr;
+ mpool_mem_t *head = pool, *ptr = NULL;
+
+ MPOOL_LOCK();
+
+ if (!(head && head->prev)) {
+ MPOOL_UNLOCK();
+ return;
+ }
+
+ ptr = head->prev->prev;
+
+ while (ptr && (ptr != head)) {
+ if (ptr->address == address) {
+#ifdef TRACK_DMA_USAGE
+ _dma_mem_used -= ptr->size;
+#endif
+ ptr->prev->next = ptr->next;
+ ptr->next->prev = ptr->prev;
+ ptr->next = free_list;
+ free_list = ptr;
+ break;
+ }
+ ptr = ptr->prev;
+ }
+
+ MPOOL_UNLOCK();
+}
+
+/*
+ * Function: mpool_create
+ *
+ * Purpose:
+ * Create and initialize mpool control structures.
+ * Parameters:
+ * base_ptr - pointer to mpool memory block
+ * size - total size of mpool memory block
+ * Returns:
+ * mpool handle
+ * Notes
+ * The mpool handle returned must be used for subsequent
+ * memory allocations from the mpool.
+ */
+mpool_handle_t
+mpool_create(void *base_ptr, int size)
+{
+ mpool_mem_t *head, *tail;
+ int mod = (int)(((unsigned long)base_ptr) & (BCM_CACHE_LINE_BYTES - 1));
+ int i;
+
+ MPOOL_LOCK();
+
+ for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) {
+ mpool_buf[i] = NULL;
+ }
+
+ _buf_alloc_count = 0;
+
+ ALLOC_INIT_MPOOL_BUF(mpool_buf[_buf_alloc_count]);
+
+ if (mpool_buf[_buf_alloc_count] == NULL) {
+ MPOOL_UNLOCK();
+ return NULL;
+ }
+
+ _buf_alloc_count++;
+
+ if (mod) {
+ base_ptr = (char*)base_ptr + (BCM_CACHE_LINE_BYTES - mod);
+ size -= (BCM_CACHE_LINE_BYTES - mod);
+ }
+ size &= ~(BCM_CACHE_LINE_BYTES - 1);
+
+ head = free_list;
+ free_list = free_list->next;
+ tail = free_list;
+ free_list = free_list->next;
+
+ head->size = tail->size = 0;
+ head->address = base_ptr;
+ tail->address = head->address + size;
+ head->prev = tail;
+ head->next = tail;
+ tail->prev = head;
+ tail->next = NULL;
+
+ MPOOL_UNLOCK();
+ return head;
+}
+
+/*
+ * Function: mpool_destroy
+ *
+ * Purpose:
+ * Free mpool control structures.
+ * Parameters:
+ * pool - mpool handle (from mpool_create)
+ * Returns:
+ * Always 0
+ */
+int
+mpool_destroy(mpool_handle_t pool)
+{
+ int i;
+
+ MPOOL_LOCK();
+
+ if ((mpool_mem_t *)pool != mpool_buf[0]) {
+ MPOOL_UNLOCK();
+ return 0;
+ }
+
+ for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) {
+ if (mpool_buf[i]) {
+ FREE(mpool_buf[i]);
+ mpool_buf[i] = NULL;
+ }
+ }
+
+ MPOOL_UNLOCK();
+
+ return 0;
+}
+
+/*
+ * Function: mpool_usage
+ *
+ * Purpose:
+ * Report total sum of allocated mpool memory.
+ * Parameters:
+ * pool - mpool handle (from mpool_create)
+ * Returns:
+ * Number of bytes currently allocated using mpool_alloc.
+ */
+int
+mpool_usage(mpool_handle_t pool)
+{
+ int usage = 0;
+ mpool_mem_t *ptr;
+
+ MPOOL_LOCK();
+
+ for (ptr = pool; ptr; ptr = ptr->next) {
+ usage += ptr->size;
+ }
+
+ MPOOL_UNLOCK();
+
+ return usage;
+}
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/linux/user/kernel/Makefile b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/user/kernel/Makefile
@@ -0,0 +1,70 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.1 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+LOCALDIR = systems/bde/linux/user/kernel
+
+# Make sure we build for the kernel if this is a user-mode build
+ifneq ($(platform), )
+override-target=linux-$(platform)
+endif
+
+include $(SDK)/make/Make.config
+
+LIBS = $(LIBDIR)/libkern.a
+
+ifneq ($(kernel_version),2_4)
+KERNEL_MODULE_DIR = kernel_module
+
+THIS_MOD_NAME := linux-user-bde
+MODULE = $(LIBDIR)/$(THIS_MOD_NAME).o
+KMODULE = $(LIBDIR)/$(THIS_MOD_NAME).ko
+
+build: kernel_libs $(MODULE) $(KMODULE)
+else
+MODULE = $(LIBDIR)/linux-user-bde.o
+
+build: kernel_libs $(MODULE)
+endif
+
+KBUILD_EXTRA_SYMBOLS := ${BLDDIR}/../../kernel/kernel_module/Module.symvers
+
+$(MODULE): $(BLDDIR)/.tree $(BOBJS) $(LIBS)
+ $(LD) $(MODULE_LDFLAGS) -r -d $(BOBJS) $(LIBS) -o $@
+ifneq ($(kernel_version),2_4)
+$(KMODULE): $(MODULE)
+ rm -fr $(BLDDIR)/$(KERNEL_MODULE_DIR)
+ mkdir $(BLDDIR)/$(KERNEL_MODULE_DIR)
+ cp ${SDK}/make/Makefile.linux-kmodule $(BLDDIR)/$(KERNEL_MODULE_DIR)/Makefile
+ cat ${KBUILD_EXTRA_SYMBOLS} > $(BLDDIR)/$(KERNEL_MODULE_DIR)/Module.symvers
+ MOD_NAME=$(THIS_MOD_NAME) $(MAKE) -C $(BLDDIR)/$(KERNEL_MODULE_DIR) $(THIS_MOD_NAME).ko
+endif
+
+kernel_libs:
+ $(MAKE) -C $(SDK)/systems/linux/kernel/modules/shared
+
+include $(SDK)/make/Make.depend
+
+# Make.depend is before clean:: so that Make.depend's clean:: runs first.
+
+clean::
+ $(MAKE) -C $(SDK)/systems/linux/kernel/modules/shared $@
+ $(RM) $(BOBJS) $(MODULE)
+
+.PHONY: build kernel_libs
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.c b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.c
@@ -0,0 +1,1661 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+
+/*
+ * Linux User BDE Helper Module
+ */
+#include <gmodule.h>
+#include <mpool.h>
+#include <linux-bde.h>
+
+#include <sal/core/thread.h>
+#include <sal/core/sync.h>
+#include <soc/devids.h>
+#include <linux/jiffies.h>
+#include "linux-user-bde.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0)
+#include <linux/uaccess.h>
+#endif
+
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("User BDE Helper Module");
+MODULE_LICENSE("GPL");
+
+/* CMIC/CMICe defines */
+#define CMIC_IRQ_STAT 0x00000144
+#define CMIC_IRQ_MASK 0x00000148
+#define CMIC_IRQ_MASK_1 0x0000006C
+#define CMIC_IRQ_MASK_2 0x00000070
+
+/* CMICm defines */
+#define CMIC_CMCx_IRQ_STAT0_OFFSET(x) (0x31400 + (0x1000 * x))
+#define CMIC_CMCx_IRQ_STAT1_OFFSET(x) (0x31404 + (0x1000 * x))
+#define CMIC_CMCx_IRQ_STAT2_OFFSET(x) (0x31408 + (0x1000 * x))
+#define CMIC_CMCx_IRQ_STAT3_OFFSET(x) (0x3140c + (0x1000 * x))
+#define CMIC_CMCx_IRQ_STAT4_OFFSET(x) (0x31410 + (0x1000 * x))
+
+#define CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(x) (0x31414 + (0x1000 * x))
+#define CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(x) (0x31418 + (0x1000 * x))
+#define CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(x) (0x3141c + (0x1000 * x))
+#define CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(x) (0x31420 + (0x1000 * x))
+#define CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(x) (0x31424 + (0x1000 * x))
+
+/* CMICd defines */
+#define CMIC_CMCx_IRQ_STAT5_OFFSET(x) (0x314b0 + (0x1000 * x))
+#define CMIC_CMCx_IRQ_STAT6_OFFSET(x) (0x314b4 + (0x1000 * x))
+#define CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(x) (0x314b8 + (0x1000 * x))
+#define CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(x) (0x314bc + (0x1000 * x))
+#define CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(x) (0x314c0 + (0x1000 * x))
+#define CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(x) (0x314c4 + (0x1000 * x))
+
+#define CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(x) (0x31428 + (0x1000 * x))
+#define CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(x) (0x3142c + (0x1000 * x))
+#define CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(x) (0x31430 + (0x1000 * x))
+#define CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(x) (0x31434 + (0x1000 * x))
+#define CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(x) (0x31438 + (0x1000 * x))
+
+/* CMICX defines */
+#define INTC_INTR_REG_NUM (8)
+#define PAXB_INTRCLR_DELAY_REG_NUM (16)
+/*
+TODO:HX5
+The INTR base address values are changed for HX5,
+hence making new #defines so runtime decisions can
+be made.
+*/
+#define PAXB_0_PAXB_IC_INTRCLR_0 (0x180123a0)
+#define PAXB_0_PAXB_IC_INTRCLR_1 (0x180123a4)
+#define PAXB_0_PAXB_IC_INTRCLR_MODE_0 (0x180123a8)
+#define PAXB_0_PAXB_IC_INTRCLR_MODE_1 (0x180123ac)
+#define PAXB_0_PAXB_INTR_STATUS (0x18012f38)
+#define PAXB_0_PAXB_IC_INTR_PACING_CTRL (0x18012398)
+#define PAXB_0_PAXB_INTRCLR_DELAY_UNIT (0x1801239c)
+#define PAXB_0_PAXB_IC_INTRCLR_DELAY_REG0 (0x180123b0)
+#define PAXB_0_PCIE_ERROR_STATUS (0x18012024)
+
+#define HX5_PAXB_0_PAXB_IC_INTRCLR_0 (0x102303a0)
+#define HX5_PAXB_0_PAXB_IC_INTRCLR_1 (0x102303a4)
+
+#define HX5_PAXB_0_PAXB_IC_INTRCLR_MODE_0 (0x102303a8)
+#define HX5_PAXB_0_PAXB_IC_INTRCLR_MODE_1 (0x102303ac)
+#define HX5_PAXB_0_PAXB_INTR_STATUS (0x10230f38)
+#define HX5_PAXB_0_PAXB_IC_INTR_PACING_CTRL (0x10230398)
+#define HX5_PAXB_0_PAXB_INTRCLR_DELAY_UNIT (0x1023039c)
+#define HX5_PAXB_0_PAXB_IC_INTRCLR_DELAY_REG0 (0x102303b0)
+#define HX5_PAXB_0_PCIE_ERROR_STATUS (0x10230024)
+
+#define PAXB_0_PAXB_IC_INTRCLR_DELAY_BASE (PAXB_0_PAXB_IC_INTRCLR_DELAY_REG0)
+#define HX5_PAXB_0_PAXB_IC_INTRCLR_DELAY_BASE (HX5_PAXB_0_PAXB_IC_INTRCLR_DELAY_REG0)
+
+#define INTC_INTR_ENABLE_REG0 (0x180130f0)
+#define INTC_INTR_STATUS_REG0 (0x18013190)
+#define INTC_INTR_RAW_STATUS_REG0 (0x18013140)
+
+#define INTC_INTR_ENABLE_BASE (INTC_INTR_ENABLE_REG0)
+#define INTC_INTR_STATUS_BASE (INTC_INTR_STATUS_REG0)
+#define INTC_INTR_RAW_STATUS_BASE (INTC_INTR_RAW_STATUS_REG0)
+
+#define HX5_INTC_INTR_ENABLE_REG0 (0x102310f0)
+#define HX5_INTC_INTR_STATUS_REG0 (0x10231190)
+#define HX5_INTC_INTR_RAW_STATUS_REG0 (0x10231140)
+
+#define HX5_INTC_INTR_ENABLE_BASE (HX5_INTC_INTR_ENABLE_REG0)
+#define HX5_INTC_INTR_STATUS_BASE (HX5_INTC_INTR_STATUS_REG0)
+#define HX5_INTC_INTR_RAW_STATUS_BASE (HX5_INTC_INTR_RAW_STATUS_REG0)
+
+#define IOREMAP(addr, size) ioremap_nocache(addr, size)
+
+#define HX5_IHOST_GICD_ISENABLERN_0 (0x10781100)
+#define HX5_IHOST_GICD_ISENABLERN_1 (0x10781104)
+#define HX5_IHOST_GICD_ICENABLERN_1 (0x10781184)
+#define HX5_IHOST_GICD_ICENABLERN_8 (0x107811a0)
+#define HX5_IHOST_GICD_ISPENDRN_8 (0x10781220)
+/* Offset between ISENABLERN_1 and ICENABLERN_1 in 4-bytes */
+#define HX5_IHOST_IRQ_MASK_OFFSET 0x20
+/* Offset between ISENABLERN_1 and ISPENDRN_1 in 4-bytes */
+#define HX5_IHOST_IRQ_PEND_OFFSET 0x40
+#define HX5_IHOST_INTR_MAP_NUM (HX5_IHOST_GICD_ISPENDRN_8 - HX5_IHOST_GICD_ISENABLERN_0)
+#define HX5_IHOST_INTR_STATUS_MAP_NUM (INTC_INTR_REG_NUM * (sizeof(uint32)))
+#define IRQ_BIT(intr) (intr % (sizeof(uint32)*8))
+#define IRQ_MASK_INDEX(intr) (intr / (sizeof(uint32)*8))
+#define HX5_SW_PROG_INTR_PRIORITY 73
+#define INTR_SW_PROG_INTR_BITPOS (1 << IRQ_BIT(HX5_SW_PROG_INTR_PRIORITY))
+#define INTC_SW_PROG_INTR_REG_IND IRQ_MASK_INDEX(HX5_SW_PROG_INTR_PRIORITY)
+#define HX5_CHIP_INTR_LOW_PRIORITY 119
+#define INTR_LOW_PRIORITY_BITPOS (1 << IRQ_BIT(HX5_CHIP_INTR_LOW_PRIORITY))
+#define INTC_LOW_PRIORITY_INTR_REG_IND IRQ_MASK_INDEX(HX5_CHIP_INTR_LOW_PRIORITY)
+#define INTC_PDMA_INTR_REG_IND 4
+
+#define READ_INTC_INTR(d, reg, v) \
+ (v = user_bde->iproc_read(d, reg))
+#define WRITE_INTC_INTR(d, reg, v) \
+ (user_bde->iproc_write(d, reg, v))
+
+#define IHOST_READ_INTR(d, reg, v) \
+ (v = readl((reg)))
+#define IHOST_WRITE_INTR(d, reg, v) \
+ (writel((v), (reg)))
+
+/* Allow override of default CMICm CMC */
+#ifndef BDE_CMICM_PCIE_CMC
+#define BDE_CMICM_PCIE_CMC 0
+#endif
+
+/* Allow override of default CMICm CMC */
+#ifndef BDE_CMICD_PCIE_CMC
+#define BDE_CMICD_PCIE_CMC 0
+#endif
+
+/* Defines used to distinguish CMICe from CMICm */
+#define CMICE_DEV_REV_ID (0x178 / sizeof(uint32))
+
+static uint32 *ihost_intr_status_base = NULL;
+static uint32 *ihost_intr_enable_base = NULL;
+
+/* Module parameter for Interruptible timeout */
+static int intr_timeout = 0;
+LKM_MOD_PARAM(intr_timeout, "i", int, (S_IRUGO | S_IWUSR));
+MODULE_PARM_DESC(intr_timeout,
+"Interruptible wait timeout in milliseconds for Interrupt to be triggered.");
+
+static ulong intr_count = 0;
+LKM_MOD_PARAM(intr_count, "intr_count", ulong, (S_IRUGO | S_IWUSR));
+MODULE_PARM_DESC(intr_count,
+"Interrupt count provides information about the number of times the ISR is called.");
+
+/* Debug output */
+static int debug;
+LKM_MOD_PARAM(debug, "i", int, (S_IRUGO | S_IWUSR));
+MODULE_PARM_DESC(debug,
+"Set debug level (default 0).");
+
+static ibde_t *user_bde = NULL;
+
+typedef void (*isr_f)(void *);
+
+typedef struct _intr_regs_s {
+ uint32 intc_intr_status_base;
+ uint32 intc_intr_enable_base;
+ uint32 intc_intr_raw_status_base;
+ uint32 intc_intr_clear_0;
+ uint32 intc_intr_clear_1;
+ uint32 intc_intr_clear_mode_0;
+ uint32 intc_intr_clear_mode_1;
+ uint32 intc_intr_status;
+ uint32 intc_intr_pacing_ctrl;
+ uint32 intc_intr_clear_delay_unit;
+ uint32 intc_intr_clear_delay_base;
+ uint32 intc_intr_pcie_err_status;
+} _intr_regs_t;
+
+typedef struct bde_ctrl_s {
+ uint32 dev_type;
+ int irq;
+ int enabled;
+ int devid;
+ isr_f isr;
+ uint32 *ba;
+ int inst; /* associate to _bde_inst_resource[] */
+ int timeout_count;
+ _intr_regs_t intr_regs;
+} bde_ctrl_t;
+
+#define VALID_DEVICE(_n) (_n < LINUX_BDE_MAX_DEVICES)
+
+static bde_ctrl_t _devices[LINUX_BDE_MAX_DEVICES];
+
+static wait_queue_head_t _ether_interrupt_wq;
+static atomic_t _ether_interrupt_has_taken_place = ATOMIC_INIT(0);
+
+/*
+ * Multiple instance resource data structure.
+ * To keep the DMA resource per instance.
+ * And track the DMA pool usage.
+ */
+static int _bde_multi_inst = 0;
+
+typedef struct {
+ unsigned int inst_id;
+ unsigned int dma_offset;
+ unsigned int dma_size;
+ wait_queue_head_t intr_wq;
+ atomic_t intr;
+} bde_inst_resource_t;
+
+static bde_inst_resource_t _bde_inst_resource[LINUX_BDE_MAX_DEVICES];
+
+typedef struct {
+ phys_addr_t cpu_pbase; /* CPU physical base address of the DMA pool */
+ phys_addr_t dma_pbase; /* Bus base address of the DMA pool */
+ uint32 total_size; /* Total size of the pool in MB */
+ uint32 offset; /* Current offset of the pool in MB */
+}_dma_pool_t;
+
+static _dma_pool_t _dma_pool;
+
+#define ONE_MB (1024 * 1024)
+
+#ifdef KEYSTONE
+/*
+ * Enforce PCIE transaction ordering. Commit the write transaction.
+ */
+
+#define SSOC_WRITEL(val, addr) \
+ do { \
+ writel((val), (addr)); \
+ __asm__ __volatile__("sync"); \
+ } while(0)
+
+#else
+
+#define SSOC_WRITEL(val, addr) \
+ writel((val), (addr))
+
+#endif
+/*
+ * Function: _interrupt
+ *
+ * Purpose:
+ * Interrupt Handler.
+ * Mask all interrupts on device and wake up interrupt
+ * thread. It is assumed that the interrupt thread unmasks
+ * interrupts again when interrupt handling is complete.
+ * Parameters:
+ * ctrl - BDE control structure for this device.
+ * Returns:
+ * Nothing
+ */
+static void
+_cmic_interrupt(bde_ctrl_t *ctrl)
+{
+ int d;
+ uint32_t mask = 0, stat, imask = 0, fmask = 0;
+ bde_inst_resource_t *res;
+
+ d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
+ res = &_bde_inst_resource[ctrl->inst];
+
+ /* Check for secondary interrupt handler */
+ if (lkbde_irq_mask_get(d, &mask, &fmask) < 0) {
+ fmask = 0;
+ }
+
+ if (fmask != 0) {
+ imask = mask & ~fmask;
+ /* Check for pending user mode interrupts */
+ stat = user_bde->read(d, CMIC_IRQ_STAT);
+ if ((stat & imask) == 0) {
+ /* All handled in kernel mode */
+ lkbde_irq_mask_set(d, CMIC_IRQ_MASK, imask, 0);
+ return;
+ }
+ }
+
+ lkbde_irq_mask_set(d, CMIC_IRQ_MASK, 0, 0);
+
+ atomic_set(&res->intr, 1);
+
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wake_up(&res->intr_wq);
+#else
+ wake_up_interruptible(&res->intr_wq);
+#endif
+}
+
+void
+dump_interrupt_regs(bde_ctrl_t *ctrl , int dev)
+{
+ int ind;
+ uint32_t val;
+
+ if (debug >= 2) {
+ gprintk("Interrupt timeout count = %d\n", ctrl->timeout_count);
+ gprintk("Interrupt count = %lu\n", intr_count);
+ for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) {
+ READ_INTC_INTR(dev, ctrl->intr_regs.intc_intr_status_base + 4 * ind, val);
+ gprintk("INTC_INTR_STATUS_REG_%d = 0x%x\n", ind, val);
+ READ_INTC_INTR(dev, ctrl->intr_regs.intc_intr_raw_status_base + 4 * ind, val);
+ gprintk("INTC_INTR_RAW_STATUS_REG_%d = 0x%x\n", ind, val);
+ READ_INTC_INTR(dev, ctrl->intr_regs.intc_intr_enable_base + 4 * ind, val);
+ gprintk("INTC_INTR_ENABLE_REG_%d = 0x%x\n", ind, val);
+ }
+ /* Dump PAXB Register */
+ READ_INTC_INTR(dev, ctrl->intr_regs.intc_intr_status, val);
+ gprintk("PAXB_0_PAXB_INTR_STATUS = 0x%x\n", val);
+ READ_INTC_INTR(dev, ctrl->intr_regs.intc_intr_pacing_ctrl, val);
+ gprintk("PAXB_0_PAXB_IC_INTR_PACING_CTRL = 0x%x\n", val);
+ READ_INTC_INTR(dev, ctrl->intr_regs.intc_intr_clear_delay_unit, val);
+ gprintk("PAXB_0_PAXB_INTRCLR_DELAY_UNIT = 0x%x\n", val);
+ READ_INTC_INTR(dev, ctrl->intr_regs.intc_intr_pcie_err_status, val);
+ gprintk("PAXB_0_PCIE_ERROR_STATUS = 0x%x\n", val);
+
+ for (ind = 0; ind < PAXB_INTRCLR_DELAY_REG_NUM; ind++) {
+ READ_INTC_INTR(dev, ctrl->intr_regs.intc_intr_clear_delay_base + 4 * ind, val);
+ gprintk("PAXB_0_PAXB_IC_INTRCLR_DELAY_REG_%d = 0x%x\n", ind, val);
+ }
+ }
+ /* Clear interrupt enable registers */
+ for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) {
+ WRITE_INTC_INTR(dev, ctrl->intr_regs.intc_intr_enable_base + 4 * ind, 0);
+ }
+}
+
+static int
+_cmicx_interrupt_prepare(bde_ctrl_t *ctrl)
+{
+ int d, ind;
+ uint32 stat, iena, mask, fmask;
+
+ d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
+
+ if (ctrl->dev_type & BDE_PCI_DEV_TYPE) {
+ READ_INTC_INTR(d, ctrl->intr_regs.intc_intr_clear_mode_0, stat);
+ /* Clear MSI interrupts immediately to prevent spurious interrupts */
+ if (stat == 0) {
+ WRITE_INTC_INTR(d, ctrl->intr_regs.intc_intr_clear_0, 0xFFFFFFFF);
+ WRITE_INTC_INTR(d, ctrl->intr_regs.intc_intr_clear_1, 0xFFFFFFFF);
+ }
+ }
+
+ lkbde_irq_mask_get(d, &mask, &fmask);
+
+ if (fmask) {
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ IHOST_READ_INTR(d, ihost_intr_status_base + INTC_PDMA_INTR_REG_IND, stat);
+ IHOST_READ_INTR(d, ihost_intr_enable_base + INTC_PDMA_INTR_REG_IND, iena);
+ } else {
+ READ_INTC_INTR(d, ctrl->intr_regs.intc_intr_status_base + 4 * INTC_PDMA_INTR_REG_IND, stat);
+ READ_INTC_INTR(d, ctrl->intr_regs.intc_intr_enable_base + 4 * INTC_PDMA_INTR_REG_IND, iena);
+ }
+ if (stat & iena) {
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ IHOST_WRITE_INTR(d, ihost_intr_enable_base + INTC_PDMA_INTR_REG_IND +
+ HX5_IHOST_IRQ_MASK_OFFSET, ~0);
+ } else {
+ WRITE_INTC_INTR(d, ctrl->intr_regs.intc_intr_enable_base + 4 * INTC_PDMA_INTR_REG_IND, 0);
+ }
+
+ for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) {
+ if (ind == INTC_PDMA_INTR_REG_IND) {
+ continue;
+ }
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ if (ind < INTC_SW_PROG_INTR_REG_IND) {
+ continue;
+ }
+ if (ind == INTC_SW_PROG_INTR_REG_IND) {
+ IHOST_READ_INTR(d, ihost_intr_enable_base + ind + HX5_IHOST_IRQ_PEND_OFFSET, stat);
+ stat &= INTR_SW_PROG_INTR_BITPOS;
+ } else {
+ IHOST_READ_INTR(d, ihost_intr_status_base + ind, stat);
+ if (ind == INTC_LOW_PRIORITY_INTR_REG_IND) {
+ stat &= INTR_LOW_PRIORITY_BITPOS;
+ }
+ }
+ } else {
+ READ_INTC_INTR(d, ctrl->intr_regs.intc_intr_status_base + 4 * ind, stat);
+ READ_INTC_INTR(d, ctrl->intr_regs.intc_intr_enable_base + 4 * ind, iena);
+ }
+ if (stat & iena) {
+ break;
+ }
+ }
+ /* No pending interrupts */
+ if (ind >= INTC_INTR_REG_NUM) {
+ return -1;
+ }
+ }
+ }
+
+ /* Disable all interrupts.. Re-enable unserviced interrupts later
+ * So as to avoid getting new interrupts until the user level driver
+ * enumerates the interrupts to be serviced
+ */
+ for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) {
+ if (fmask && ind == INTC_PDMA_INTR_REG_IND) {
+ continue;
+ }
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ if (ind < INTC_SW_PROG_INTR_REG_IND) {
+ continue;
+ }
+ if (ind == INTC_SW_PROG_INTR_REG_IND) {
+ IHOST_WRITE_INTR(d, ihost_intr_enable_base + INTC_SW_PROG_INTR_REG_IND +
+ HX5_IHOST_IRQ_MASK_OFFSET, INTR_SW_PROG_INTR_BITPOS);
+ } else if (ind == INTC_LOW_PRIORITY_INTR_REG_IND) {
+ IHOST_WRITE_INTR(d, ihost_intr_enable_base + INTC_LOW_PRIORITY_INTR_REG_IND +
+ HX5_IHOST_IRQ_MASK_OFFSET, INTR_LOW_PRIORITY_BITPOS);
+ } else {
+ IHOST_WRITE_INTR(d, ihost_intr_enable_base + ind +
+ HX5_IHOST_IRQ_MASK_OFFSET, ~0);
+ }
+ } else {
+ WRITE_INTC_INTR(d, ctrl->intr_regs.intc_intr_enable_base + 4*ind, 0);
+ }
+ }
+ return 0;
+}
+
+static void
+_cmicx_interrupt(bde_ctrl_t *ctrl)
+{
+ bde_inst_resource_t *res;
+
+ intr_count++;
+
+ res = &_bde_inst_resource[ctrl->inst];
+ if (_cmicx_interrupt_prepare(ctrl) < 0) {
+ return;
+ }
+
+ /* Notify */
+ atomic_set(&res->intr, 1);
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wake_up(&res->intr_wq);
+#else
+ wake_up_interruptible(&res->intr_wq);
+#endif
+}
+
+static void
+_cmicm_interrupt(bde_ctrl_t *ctrl)
+{
+ int d;
+ int cmc = BDE_CMICM_PCIE_CMC;
+ uint32 stat, mask = 0, fmask = 0, imask = 0;
+ bde_inst_resource_t *res;
+
+ d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
+ res = &_bde_inst_resource[ctrl->inst];
+
+ lkbde_irq_mask_get(d, &mask, &fmask);
+
+ while (fmask) {
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT0_OFFSET(cmc));
+ imask = mask & ~fmask;
+ if (stat & imask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT1_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT2_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT3_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT4_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ return;
+ }
+
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ lkbde_irq_mask_set(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(cmc), 0, 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(1), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(2), 0);
+ }
+ else {
+ lkbde_irq_mask_set(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(cmc), 0, 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(1), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(2), 0);
+ }
+ atomic_set(&res->intr, 1);
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wake_up(&res->intr_wq);
+#else
+ wake_up_interruptible(&res->intr_wq);
+#endif
+}
+
+/* some device has cmc0 only */
+static void
+_cmicd_cmc0_interrupt(bde_ctrl_t *ctrl)
+{
+ int d;
+ int cmc = 0;
+ uint32 stat, mask = 0, fmask = 0, imask = 0;
+ bde_inst_resource_t *res;
+
+ d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
+ res = &_bde_inst_resource[ctrl->inst];
+ lkbde_irq_mask_get(d, &mask, &fmask);
+
+ while (fmask) {
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT0_OFFSET(cmc));
+ imask = mask & ~fmask;
+ if (stat & imask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT1_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT2_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT3_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT4_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT5_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT6_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ return;
+ }
+
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ lkbde_irq_mask_set(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(cmc), 0, 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc), 0);
+ } else {
+ lkbde_irq_mask_set(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(cmc), 0, 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(cmc), 0);
+ }
+ atomic_set(&res->intr, 1);
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wake_up(&res->intr_wq);
+#else
+ wake_up_interruptible(&res->intr_wq);
+#endif
+}
+
+static void
+_cmicd_interrupt(bde_ctrl_t *ctrl)
+{
+ int d;
+ int cmc = BDE_CMICD_PCIE_CMC;
+ uint32 stat, mask = 0, fmask = 0, imask = 0;
+ bde_inst_resource_t *res;
+
+ d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
+ res = &_bde_inst_resource[ctrl->inst];
+ lkbde_irq_mask_get(d, &mask, &fmask);
+
+ while (fmask) {
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT0_OFFSET(cmc));
+ imask = mask & ~fmask;
+ if (stat & imask) {
+ break;
+ }
+ /** Check if there are interrupts other than PacketIO interrupts on CMC1 */
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT0_OFFSET(1));
+ imask = mask & ~fmask;
+ if (stat & imask) {
+ break;
+ }
+ /** Check if there are interrupts other than PacketIO interrupts on CMC2 */
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT0_OFFSET(2));
+ imask = mask & ~fmask;
+ if (stat & imask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT1_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT2_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT3_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT4_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT5_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT6_OFFSET(cmc));
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc));
+ } else {
+ mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(cmc));
+ }
+ if (stat & mask) {
+ break;
+ }
+ return;
+ }
+
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ lkbde_irq_mask_set(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(cmc), 0, 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(1), 0);
+ user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(2), 0);
+ } else {
+ lkbde_irq_mask_set(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(cmc), 0, 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(cmc), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(1), 0);
+ user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(2), 0);
+ }
+ atomic_set(&res->intr, 1);
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wake_up(&res->intr_wq);
+#else
+ wake_up_interruptible(&res->intr_wq);
+#endif
+}
+
+static void
+_bcm88750_interrupt(bde_ctrl_t *ctrl)
+{
+ int d;
+ bde_inst_resource_t *res;
+
+ d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
+ res = &_bde_inst_resource[ctrl->inst];
+ lkbde_irq_mask_set(d, CMIC_IRQ_MASK, 0, 0);
+
+ lkbde_irq_mask_set(d, CMIC_IRQ_MASK_1, 0, 0);
+ lkbde_irq_mask_set(d, CMIC_IRQ_MASK_2, 0, 0);
+ atomic_set(&res->intr, 1);
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wake_up(&res->intr_wq);
+#else
+ wake_up_interruptible(&res->intr_wq);
+#endif
+}
+
+/* The actual interrupt handler of ethernet devices */
+static void
+_ether_interrupt(bde_ctrl_t *ctrl)
+{
+ SSOC_WRITEL(0, ctrl->ba + 0x024/4);
+
+ atomic_set(&_ether_interrupt_has_taken_place, 1);
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wake_up(&_ether_interrupt_wq);
+#else
+ wake_up_interruptible(&_ether_interrupt_wq);
+#endif
+}
+
+
+static struct _intr_mode_s {
+ isr_f isr;
+ const char *name;
+} _intr_mode[] = {
+ { (isr_f)_cmic_interrupt, "CMIC/CMICe" },
+ { (isr_f)_cmicm_interrupt, "CMICm" },
+ { (isr_f)_cmicd_interrupt, "CMICd" },
+ { (isr_f)_cmicd_cmc0_interrupt, "CMICd CMC0" },
+ { (isr_f)_bcm88750_interrupt, "BCM88750" },
+ { (isr_f)_cmicx_interrupt, "CMICx" },
+ { NULL, NULL }
+};
+
+static const char *
+_intr_mode_str(void *isr)
+{
+ int imx;
+
+ imx = 0;
+ while (_intr_mode[imx].isr != NULL) {
+ if (isr == _intr_mode[imx].isr) {
+ return _intr_mode[imx].name;
+ }
+ imx++;
+ }
+ return NULL;
+}
+
+static void
+_intr_regs_init(bde_ctrl_t *ctrl, int hx5_intr)
+{
+ if (hx5_intr) {
+ ctrl->intr_regs.intc_intr_status_base = HX5_INTC_INTR_STATUS_BASE;
+ ctrl->intr_regs.intc_intr_enable_base = HX5_INTC_INTR_ENABLE_BASE;
+ ctrl->intr_regs.intc_intr_raw_status_base = HX5_INTC_INTR_RAW_STATUS_BASE;
+ ctrl->intr_regs.intc_intr_clear_0 = HX5_PAXB_0_PAXB_IC_INTRCLR_0;
+ ctrl->intr_regs.intc_intr_clear_1 = HX5_PAXB_0_PAXB_IC_INTRCLR_1;
+ ctrl->intr_regs.intc_intr_clear_mode_0 = HX5_PAXB_0_PAXB_IC_INTRCLR_MODE_0;
+ ctrl->intr_regs.intc_intr_clear_mode_1 = HX5_PAXB_0_PAXB_IC_INTRCLR_MODE_1;
+ ctrl->intr_regs.intc_intr_status = HX5_PAXB_0_PAXB_INTR_STATUS;
+ ctrl->intr_regs.intc_intr_pacing_ctrl = HX5_PAXB_0_PAXB_IC_INTR_PACING_CTRL;
+ ctrl->intr_regs.intc_intr_clear_delay_unit = HX5_PAXB_0_PAXB_INTRCLR_DELAY_UNIT;
+ ctrl->intr_regs.intc_intr_clear_delay_base = HX5_PAXB_0_PAXB_IC_INTRCLR_DELAY_BASE;
+ ctrl->intr_regs.intc_intr_pcie_err_status = HX5_PAXB_0_PCIE_ERROR_STATUS;
+
+ } else {
+ ctrl->intr_regs.intc_intr_status_base = INTC_INTR_STATUS_BASE;
+ ctrl->intr_regs.intc_intr_raw_status_base = INTC_INTR_RAW_STATUS_BASE;
+ ctrl->intr_regs.intc_intr_enable_base = INTC_INTR_ENABLE_BASE;
+ ctrl->intr_regs.intc_intr_clear_0 = PAXB_0_PAXB_IC_INTRCLR_0;
+ ctrl->intr_regs.intc_intr_clear_1 = PAXB_0_PAXB_IC_INTRCLR_1;
+ ctrl->intr_regs.intc_intr_clear_mode_0 = PAXB_0_PAXB_IC_INTRCLR_MODE_0;
+ ctrl->intr_regs.intc_intr_clear_mode_1 = PAXB_0_PAXB_IC_INTRCLR_MODE_1;
+ ctrl->intr_regs.intc_intr_status = PAXB_0_PAXB_INTR_STATUS;
+ ctrl->intr_regs.intc_intr_pacing_ctrl = PAXB_0_PAXB_IC_INTR_PACING_CTRL;
+ ctrl->intr_regs.intc_intr_clear_delay_unit = PAXB_0_PAXB_INTRCLR_DELAY_UNIT;
+ ctrl->intr_regs.intc_intr_clear_delay_base = PAXB_0_PAXB_IC_INTRCLR_DELAY_BASE;
+ ctrl->intr_regs.intc_intr_pcie_err_status = PAXB_0_PCIE_ERROR_STATUS;
+
+ }
+}
+
+static void
+_devices_init(int d)
+{
+ bde_ctrl_t *ctrl;
+ uint32 ver;
+ uint16 device_id_mask = 0xFFF0;
+ uint16 device_id;
+ uint32 state = 0;
+
+ (void)lkbde_dev_state_get(d, &state);
+ if (state == BDE_DEV_STATE_REMOVED) {
+ return;
+ }
+
+ ctrl = &_devices[d];
+ /* Initialize our control info */
+ ctrl->dev_type = user_bde->get_dev_type(d);
+ ctrl->devid = user_bde->get_dev(d)->device;
+ ctrl->inst = 0;
+
+ if (BDE_DEV_MEM_MAPPED(ctrl->dev_type)) {
+ ctrl->enabled = 0;
+ ctrl->ba = lkbde_get_dev_virt(d);
+ }
+ if (ctrl->dev_type & BDE_SWITCH_DEV_TYPE) {
+ switch (user_bde->get_dev(d)->device) {
+ case BCM88750_DEVICE_ID:
+ case BCM88753_DEVICE_ID:
+ case BCM88754_DEVICE_ID:
+ case BCM88755_DEVICE_ID:
+ case BCM88752_DEVICE_ID:
+ ctrl->isr = (isr_f)_bcm88750_interrupt;
+ break;
+ case BCM53540_DEVICE_ID:
+ case BCM53547_DEVICE_ID:
+ case BCM53548_DEVICE_ID:
+ case BCM53549_DEVICE_ID:
+ ctrl->isr = (isr_f)_cmicd_cmc0_interrupt;
+ break;
+ case BCM88670_DEVICE_ID:
+ case BCM88671_DEVICE_ID:
+ case BCM88671M_DEVICE_ID:
+ case BCM88672_DEVICE_ID:
+ case BCM88673_DEVICE_ID:
+ case BCM88674_DEVICE_ID:
+ case BCM88675_DEVICE_ID:
+ case BCM88675M_DEVICE_ID:
+ case BCM88676_DEVICE_ID:
+ case BCM88676M_DEVICE_ID:
+ case BCM88677_DEVICE_ID:
+ case BCM88678_DEVICE_ID:
+ case BCM88679_DEVICE_ID:
+ case BCM88370_DEVICE_ID:
+ case BCM88371_DEVICE_ID:
+ case BCM88371M_DEVICE_ID:
+ case BCM88375_DEVICE_ID:
+ case BCM88376_DEVICE_ID:
+ case BCM88376M_DEVICE_ID:
+ case BCM88377_DEVICE_ID:
+ case BCM88378_DEVICE_ID:
+ case BCM88379_DEVICE_ID:
+ case BCM88681_DEVICE_ID:
+ case BCM88682_DEVICE_ID:
+ case BCM88683_DEVICE_ID:
+ case BCM88684_DEVICE_ID:
+ case BCM88685_DEVICE_ID:
+ case BCM88687_DEVICE_ID:
+ case BCM88380_DEVICE_ID:
+ case BCM88381_DEVICE_ID:
+ case BCM88680_DEVICE_ID:
+ case BCM88770_DEVICE_ID:
+ case BCM88773_DEVICE_ID:
+ case BCM88774_DEVICE_ID:
+ case BCM88775_DEVICE_ID:
+ case BCM88776_DEVICE_ID:
+ case BCM88777_DEVICE_ID:
+ case BCM88470_DEVICE_ID:
+ case BCM88470P_DEVICE_ID:
+ case BCM88471_DEVICE_ID:
+ case BCM88473_DEVICE_ID:
+ case BCM88474_DEVICE_ID:
+ case BCM88474H_DEVICE_ID:
+ case BCM88476_DEVICE_ID:
+ case BCM88477_DEVICE_ID:
+ case BCM88270_DEVICE_ID:
+ case BCM88272_DEVICE_ID:
+ case BCM88273_DEVICE_ID:
+ case BCM88274_DEVICE_ID:
+ case BCM88278_DEVICE_ID:
+ case BCM88279_DEVICE_ID:
+ case BCM8206_DEVICE_ID:
+ case BCM88950_DEVICE_ID:
+ case BCM88953_DEVICE_ID:
+ case BCM88954_DEVICE_ID:
+ case BCM88955_DEVICE_ID:
+ case BCM88956_DEVICE_ID:
+ case BCM88772_DEVICE_ID:
+ case BCM88952_DEVICE_ID:
+ ctrl->isr = (isr_f)_cmicd_interrupt;
+ break;
+ case BCM56370_DEVICE_ID:
+ case BCM56371_DEVICE_ID:
+ case BCM56372_DEVICE_ID:
+ case BCM56374_DEVICE_ID:
+ case BCM56375_DEVICE_ID:
+ case BCM56376_DEVICE_ID:
+ case BCM56377_DEVICE_ID:
+ case BCM56577_DEVICE_ID:
+ case BCM56578_DEVICE_ID:
+ case BCM56579_DEVICE_ID:
+ case BCM56273_DEVICE_ID:
+ case BCM56274_DEVICE_ID:
+ case BCM56275_DEVICE_ID:
+ case BCM56276_DEVICE_ID:
+ case BCM56277_DEVICE_ID:
+ case BCM56278_DEVICE_ID:
+ case BCM56279_DEVICE_ID:
+ case BCM56575_DEVICE_ID:
+ ctrl->isr = (isr_f)_cmicx_interrupt;
+ if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
+ if (!ihost_intr_enable_base) {
+ ihost_intr_enable_base = (uint32_t *)IOREMAP(HX5_IHOST_GICD_ISENABLERN_1,
+ HX5_IHOST_INTR_MAP_NUM);
+ }
+ if (!ihost_intr_status_base) {
+ ihost_intr_status_base = (uint32_t *)IOREMAP(HX5_INTC_INTR_RAW_STATUS_REG0,
+ HX5_IHOST_INTR_STATUS_MAP_NUM);
+ }
+ }
+ _intr_regs_init(ctrl, 1);
+ break;
+ default:
+ /* Get CMIC version */
+ if (user_bde->get_cmic_ver(d, &ver) != 0) {
+ ver = -1;
+ }
+ device_id = ctrl->devid & device_id_mask;
+ /* TH/TH+/TH2 should use cmicd interrupt handler */
+ if (BCM56960_DEVICE_ID == device_id ||
+ BCM56930_DEVICE_ID == device_id ||
+ BCM56970_DEVICE_ID == device_id) {
+ ctrl->isr = (isr_f)_cmicd_interrupt;
+ }
+ /* check if version is CMICX */
+ else if (ver == 0x04) {
+ ctrl->isr = (isr_f)_cmicx_interrupt;
+ _intr_regs_init(ctrl, 0);
+ } else {
+ ctrl->isr = (isr_f)_cmic_interrupt;
+ if ((ctrl->dev_type & BDE_256K_REG_SPACE) &&
+#ifdef BCM_PETRA_SUPPORT /* FIXME remove code when hardware design is fixed */
+ ctrl->devid != 0x1234 &&
+#endif
+ readl(ctrl->ba + CMICE_DEV_REV_ID) == 0) {
+ ctrl->isr = (isr_f)_cmicm_interrupt;
+ }
+ }
+ break;
+ }
+
+ /* configure interrupts for DNX devices using iproc >=14 */
+#if defined(BCM_DNXF_SUPPORT) || defined(BCM_DNX_SUPPORT)
+ switch (user_bde->get_dev(d)->device & DNXC_DEVID_FAMILY_MASK) {
+#ifdef BCM_DNX_SUPPORT
+ case JERICHO2_DEVICE_ID:
+ case J2C_DEVICE_ID:
+ case J2C_2ND_DEVICE_ID:
+ case Q2A_DEVICE_ID:
+ case Q2U_DEVICE_ID:
+ case J2P_DEVICE_ID:
+#endif
+#ifdef BCM_DNXF_SUPPORT
+ case BCM88790_DEVICE_ID:
+#endif
+ ctrl->isr = (isr_f)_cmicx_interrupt;
+ _intr_regs_init(ctrl, 0);
+ break;
+ }
+#endif /* defined(BCM_DNXF_SUPPORT) || defined(BCM_DNX_SUPPORT) */
+
+ if (_intr_mode_str(ctrl->isr) == NULL) {
+ gprintk("Warning: Unknown interrupt mode\n");
+ }
+ }
+}
+/*
+ * Function: _init
+ *
+ * Purpose:
+ * Module initialization.
+ * Attaches to kernel BDE.
+ * Parameters:
+ * None
+ * Returns:
+ * Always 0
+ */
+static int
+_init(void)
+{
+ int i;
+ phys_addr_t cpu_pbase, dma_pbase;
+ ssize_t dmasize;
+ bde_inst_resource_t *res;
+
+ /* Connect to the kernel bde */
+ if ((linux_bde_create(NULL, &user_bde) < 0) || user_bde == NULL) {
+ return -ENODEV;
+ }
+
+ init_waitqueue_head(&_ether_interrupt_wq);
+
+ lkbde_get_dma_info(&cpu_pbase, &dma_pbase, &dmasize);
+
+ memset(&_dma_pool, 0, sizeof(_dma_pool));
+ _dma_pool.cpu_pbase = cpu_pbase;
+ _dma_pool.dma_pbase = dma_pbase;
+ _dma_pool.total_size = dmasize / ONE_MB;
+
+ memset(_devices, 0, sizeof(_devices));
+
+ /* Use _bde_inst_resource[0] as the default resource */
+ memset(_bde_inst_resource, 0, sizeof(_bde_inst_resource));
+ res = &_bde_inst_resource[0];
+ res->dma_offset = 0;
+ res->dma_size = _dma_pool.total_size;
+ init_waitqueue_head(&res->intr_wq);
+ atomic_set(&res->intr, 0);
+
+ ihost_intr_enable_base = NULL;
+ ihost_intr_status_base = NULL;
+
+ for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ res->inst_id |= (1 << i);
+ _devices_init(i);
+ }
+
+ if (intr_timeout > 0) {
+ gprintk("Interruptible wait timeout = %d msecs\n", intr_timeout);
+ }
+
+ return 0;
+}
+
+/*
+ * Function: _cleanup
+ *
+ * Purpose:
+ * Module cleanup function.
+ * Parameters:
+ * None
+ * Returns:
+ * Always 0
+ */
+static int
+_cleanup(void)
+{
+ int i;
+
+ if (user_bde) {
+ for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ if (_devices[i].enabled &&
+ BDE_DEV_MEM_MAPPED(_devices[i].dev_type)) {
+ user_bde->interrupt_disconnect(i);
+ }
+ lkbde_dev_instid_set(i, 0);
+ }
+ linux_bde_destroy(user_bde);
+ user_bde = NULL;
+ }
+
+ if (ihost_intr_enable_base) {
+ iounmap(ihost_intr_enable_base);
+ ihost_intr_enable_base = NULL;
+ }
+ if (ihost_intr_status_base) {
+ iounmap(ihost_intr_status_base);
+ ihost_intr_status_base = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * Function: _pprint
+ *
+ * Purpose:
+ * Print proc filesystem information.
+ * Parameters:
+ * None
+ * Returns:
+ * Always 0
+ */
+static int
+_pprint(void)
+{
+ int idx;
+ const char *name;
+ bde_inst_resource_t *res;
+ uint32 state, instid;
+
+ pprintf("Broadcom Device Enumerator (%s)\n", LINUX_USER_BDE_NAME);
+ for (idx = 0; idx < user_bde->num_devices(BDE_ALL_DEVICES); idx++) {
+ name = _intr_mode_str(_devices[idx].isr);
+ if (name == NULL) {
+ name = "unknown";
+ }
+ pprintf("\t%d: Interrupt mode %s ",idx, name);
+ (void)lkbde_dev_state_get(idx, &state);
+ if (state == BDE_DEV_STATE_REMOVED) {
+ pprintf(" Device REMOVED ! \n");
+ } else {
+ (void)lkbde_dev_instid_get(idx, &instid);
+ if (instid) {
+ pprintf("Inst id 0x%x\n",instid);
+ } else {
+ pprintf("\n");
+ }
+ }
+ }
+ pprintf("Instance resource \n");
+
+ for (idx = 0; idx < user_bde->num_devices(BDE_ALL_DEVICES); idx++) {
+ res = &_bde_inst_resource[idx];
+ if (res->inst_id) {
+ pprintf("\tDev mask 0x%x : "
+ "DMA offset %d size %d MB\n",
+ res->inst_id,
+ res->dma_offset,
+ res->dma_size);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Allocate the DMA resource from DMA pool
+ * Parameter :
+ * dma_size (IN): allocate dma_size in MB
+ * dma_offset (OUT): dma offset in MB
+ */
+static int
+_dma_resource_alloc(unsigned int dma_size, unsigned int *dma_offset)
+{
+ uint32 left;
+
+ left = _dma_pool.total_size - _dma_pool.offset;
+ if (dma_size > left) {
+ gprintk("ERROR: Run out the dma resource!\n");
+ return -1;
+ }
+ *dma_offset = _dma_pool.offset;
+ _dma_pool.offset += dma_size;
+ return 0;
+}
+
+static int
+_dma_resource_get(int inst_id, phys_addr_t *cpu_pbase, phys_addr_t *dma_pbase, ssize_t* size)
+{
+ int i;
+ unsigned int dma_size = 0, dma_offset = 0;
+ bde_inst_resource_t *res;
+
+ for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ res = &_bde_inst_resource[i];
+ if (res->inst_id == inst_id) {
+ dma_size = res->dma_size;
+ dma_offset = res->dma_offset;
+ break;
+ }
+ }
+
+ *cpu_pbase = _dma_pool.cpu_pbase + dma_offset * ONE_MB;
+ *dma_pbase = _dma_pool.dma_pbase + dma_offset * ONE_MB;
+ *size = dma_size * ONE_MB;
+
+ return 0;
+}
+
+static int
+_instance_validate(unsigned int inst_id, unsigned int dmasize)
+{
+ int i;
+ bde_inst_resource_t *res;
+
+ for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ res = &_bde_inst_resource[i];
+ if (res->inst_id == inst_id) {
+ if (res->dma_size != dmasize) {
+ if(_devices[i].inst == 0){
+ /* Skip _instance_validate (not init yet) */
+ return LUBDE_SUCCESS;
+ }
+ gprintk("ERROR: dma_size mismatch\n");
+ return LUBDE_FAIL;
+ }
+ return (1);
+ }
+ }
+ return LUBDE_SUCCESS;
+}
+
+static int
+_device_reprobe(void)
+{
+ int i;
+
+ for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ if (_devices[i].devid == 0) {
+ _devices_init(i);
+ }
+ }
+ return 0;
+}
+
+static int
+_instance_attach(unsigned int inst_id, unsigned int dma_size)
+{
+ unsigned int dma_offset;
+ int i, exist;
+ bde_inst_resource_t *res;
+ int inst_idx = -1;
+ uint32 instid;
+
+ /* Reprobe the system for hot-plugged device */
+ _device_reprobe();
+
+ /* Validate the resource with inst_id */
+ exist = _instance_validate(inst_id, dma_size);
+ if (exist < 0) {
+ return LUBDE_FAIL;
+ }
+ if (exist > 0) {
+ return LUBDE_SUCCESS;
+ }
+ if (_dma_resource_alloc(dma_size, &dma_offset) < 0) {
+ return LUBDE_FAIL;
+ }
+ for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ res = &_bde_inst_resource[i];
+ if ((_bde_multi_inst == 0) || (res->inst_id == 0)) {
+ res->inst_id = inst_id;
+ res->dma_offset = dma_offset;
+ res->dma_size = dma_size;
+ _bde_multi_inst++;
+ inst_idx = i;
+ init_waitqueue_head(&res->intr_wq);
+ atomic_set(&res->intr, 0);
+ break;
+ }
+ }
+
+ for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ if (inst_id & (1 << i)) {
+ _devices[i].inst = inst_idx;
+ /* Pass the instid to the kernel BDE */
+ if (lkbde_dev_instid_get(i, &instid) == 0) {
+ if (!instid) {
+ lkbde_dev_instid_set(i, inst_id);
+ }
+ }
+ }
+ }
+
+ return LUBDE_SUCCESS;
+}
+
+/*
+ * Function: _ioctl
+ *
+ * Purpose:
+ * Handle IOCTL commands from user mode.
+ * Parameters:
+ * cmd - IOCTL cmd
+ * arg - IOCTL parameters
+ * Returns:
+ * 0 on success, <0 on error
+ */
+static int
+_ioctl(unsigned int cmd, unsigned long arg)
+{
+ lubde_ioctl_t io;
+ phys_addr_t cpu_pbase, dma_pbase;
+ ssize_t size;
+ const ibde_dev_t *bde_dev;
+ int inst_id;
+ bde_inst_resource_t *res;
+ uint32_t *mapaddr;
+
+ if (copy_from_user(&io, (void *)arg, sizeof(io))) {
+ return -EFAULT;
+ }
+
+ io.rc = LUBDE_SUCCESS;
+
+ switch(cmd) {
+ case LUBDE_VERSION:
+ io.d0 = KBDE_VERSION;
+ break;
+ case LUBDE_GET_NUM_DEVICES:
+ io.d0 = user_bde->num_devices(io.dev);
+ break;
+ case LUBDE_GET_DEVICE:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ bde_dev = user_bde->get_dev(io.dev);
+ if (bde_dev) {
+ io.d0 = bde_dev->device;
+ io.d1 = bde_dev->rev;
+ io.dx.dw[0] = bde_dev->dev_unique_id;
+ if (BDE_DEV_MEM_MAPPED(_devices[io.dev].dev_type)) {
+ /* Get physical address to map */
+ io.d2 = lkbde_get_dev_phys(io.dev);
+ io.d3 = lkbde_get_dev_phys_hi(io.dev);
+ }
+ } else {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ case LUBDE_GET_DEVICE_TYPE:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ io.d0 = _devices[io.dev].dev_type;
+ break;
+ case LUBDE_GET_BUS_FEATURES:
+ user_bde->pci_bus_features(io.dev, (int *) &io.d0, (int *) &io.d1,
+ (int *) &io.d2);
+ break;
+ case LUBDE_PCI_CONFIG_PUT32:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ if (_devices[io.dev].dev_type & BDE_PCI_DEV_TYPE) {
+ user_bde->pci_conf_write(io.dev, io.d0, io.d1);
+ } else {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ case LUBDE_PCI_CONFIG_GET32:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ if (_devices[io.dev].dev_type & BDE_PCI_DEV_TYPE) {
+ io.d0 = user_bde->pci_conf_read(io.dev, io.d0);
+ } else {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ case LUBDE_GET_DMA_INFO:
+ inst_id = io.dev;
+ if (_bde_multi_inst){
+ _dma_resource_get(inst_id, &cpu_pbase, &dma_pbase, &size);
+ } else {
+ lkbde_get_dma_info(&cpu_pbase, &dma_pbase, &size);
+ }
+ io.d0 = dma_pbase;
+ io.d1 = size;
+ /* Optionally enable DMA mmap via /dev/linux-kernel-bde */
+ io.d2 = USE_LINUX_BDE_MMAP;
+ /* Get physical address for mmap */
+ io.dx.dw[0] = cpu_pbase;
+#ifdef PHYS_ADDRS_ARE_64BITS
+ io.dx.dw[1] = cpu_pbase >> 32;
+ io.d3 = dma_pbase >> 32;
+#else
+ io.dx.dw[1] = 0;
+ io.d3 = 0;
+#endif
+ break;
+ case LUBDE_ENABLE_INTERRUPTS:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ if (_devices[io.dev].dev_type & BDE_SWITCH_DEV_TYPE) {
+ if (_devices[io.dev].isr && !_devices[io.dev].enabled) {
+ user_bde->interrupt_connect(io.dev,
+ _devices[io.dev].isr,
+ _devices+io.dev);
+ _devices[io.dev].enabled = 1;
+ }
+ } else {
+ /* Process ethernet device interrupt */
+ /* FIXME: for multiple chips */
+ if (!_devices[io.dev].enabled) {
+ user_bde->interrupt_connect(io.dev,
+ (void(*)(void *))_ether_interrupt,
+ _devices+io.dev);
+ _devices[io.dev].enabled = 1;
+ }
+ }
+ break;
+ case LUBDE_DISABLE_INTERRUPTS:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ if (_devices[io.dev].enabled) {
+ user_bde->interrupt_disconnect(io.dev);
+ _devices[io.dev].enabled = 0;
+ }
+ break;
+ case LUBDE_WAIT_FOR_INTERRUPT:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ if (_devices[io.dev].dev_type & BDE_SWITCH_DEV_TYPE) {
+ res = &_bde_inst_resource[_devices[io.dev].inst];
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wait_event_timeout(res->intr_wq,
+ atomic_read(&res->intr) != 0, 100);
+
+#else
+ /* CMICX Devices */
+ if ((_devices[io.dev].dev_type & BDE_PCI_DEV_TYPE) &&
+ (_devices[io.dev].isr == (isr_f)_cmicx_interrupt) &&
+ (intr_timeout > 0)) {
+ unsigned long t_jiffies;
+ int err=0;
+ t_jiffies = msecs_to_jiffies(intr_timeout);
+ err = wait_event_interruptible_timeout(res->intr_wq,
+ atomic_read(&res->intr) != 0,
+ t_jiffies);
+ /* Timeout happend and condition not set */
+ if (err == 0) {
+ bde_ctrl_t *ctrl;
+ ctrl = &_devices[io.dev];
+ ctrl->timeout_count++;
+ if (debug >= 1) {
+ gprintk("Timeout happend and condition not set\n");
+ }
+ dump_interrupt_regs(ctrl, io.dev);
+ } else if (err == -ERESTARTSYS) {
+ if (debug >= 1) {
+ gprintk("Interrupted by Signal\n");
+ }
+ }
+ } else {
+ wait_event_interruptible(res->intr_wq,
+ atomic_read(&res->intr) != 0);
+ }
+#endif
+ /*
+ * Even if we get multiple interrupts, we
+ * only run the interrupt handler once.
+ */
+ atomic_set(&res->intr, 0);
+ } else {
+#ifdef BDE_LINUX_NON_INTERRUPTIBLE
+ wait_event_timeout(_ether_interrupt_wq,
+ atomic_read(&_ether_interrupt_has_taken_place) != 0, 100);
+#else
+ wait_event_interruptible(_ether_interrupt_wq,
+ atomic_read(&_ether_interrupt_has_taken_place) != 0);
+
+#endif
+ /*
+ * Even if we get multiple interrupts, we
+ * only run the interrupt handler once.
+ */
+ atomic_set(&_ether_interrupt_has_taken_place, 0);
+ }
+ break;
+ case LUBDE_USLEEP:
+ case LUBDE_UDELAY:
+ case LUBDE_SEM_OP:
+ return -EINVAL;
+ case LUBDE_WRITE_IRQ_MASK:
+ io.rc = lkbde_irq_mask_set(io.dev, io.d0, io.d1, 0);
+ break;
+ case LUBDE_SPI_READ_REG:
+ if (user_bde->spi_read(io.dev, io.d0, io.dx.buf, io.d1) == -1) {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ case LUBDE_SPI_WRITE_REG:
+ if (user_bde->spi_write(io.dev, io.d0, io.dx.buf, io.d1) == -1) {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ case LUBDE_READ_REG_16BIT_BUS:
+ io.d1 = user_bde->read(io.dev, io.d0);
+ break;
+ case LUBDE_WRITE_REG_16BIT_BUS:
+ io.rc = user_bde->write(io.dev, io.d0, io.d1);
+ break;
+#ifdef BCM_SAND_SUPPORT
+ case LUBDE_CPU_WRITE_REG:
+ {
+ if (lkbde_cpu_write(io.dev, io.d0, (uint32*)io.dx.buf) == -1) {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ }
+ case LUBDE_CPU_READ_REG:
+ {
+ if (lkbde_cpu_read(io.dev, io.d0, (uint32*)io.dx.buf) == -1) {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ }
+ case LUBDE_CPU_PCI_REGISTER:
+ {
+ if (lkbde_cpu_pci_register(io.dev) == -1) {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ }
+#endif
+ case LUBDE_DEV_RESOURCE:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ bde_dev = user_bde->get_dev(io.dev);
+ if (bde_dev) {
+ if (BDE_DEV_MEM_MAPPED(_devices[io.dev].dev_type)) {
+ /* Get physical address to map */
+ io.rc = lkbde_get_dev_resource(io.dev, io.d0,
+ &io.d1, &io.d2, &io.d3);
+ }
+ } else {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ case LUBDE_IPROC_READ_REG:
+ if (!VALID_DEVICE(io.dev)) {
+ return -EINVAL;
+ }
+ if (_devices[io.dev].dev_type & BDE_AXI_DEV_TYPE) {
+ mapaddr = IOREMAP(io.d0, sizeof(uint32_t));
+ if (mapaddr == NULL) {
+ io.rc = LUBDE_FAIL;
+ return -1;
+ }
+ io.d1 = readl(mapaddr);
+ iounmap(mapaddr);
+ } else {
+ io.d1 = user_bde->iproc_read(io.dev, io.d0);
+ if (io.d1 == -1) {
+ io.rc = LUBDE_FAIL;
+ }
+ }
+ break;
+ case LUBDE_IPROC_WRITE_REG:
+ if (user_bde->iproc_write(io.dev, io.d0, io.d1) == -1) {
+ io.rc = LUBDE_FAIL;
+ }
+ break;
+ case LUBDE_ATTACH_INSTANCE:
+ io.rc = _instance_attach(io.d0, io.d1);
+ break;
+ case LUBDE_GET_DEVICE_STATE:
+ io.rc = lkbde_dev_state_get(io.dev, &io.d0);
+ break;
+ case LUBDE_REPROBE:
+ io.rc = _device_reprobe();
+ break;
+ default:
+ gprintk("Error: Invalid ioctl (%08x)\n", cmd);
+ io.rc = LUBDE_FAIL;
+ break;
+ }
+
+ if (copy_to_user((void *)arg, &io, sizeof(io))) {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/* Workaround for broken Busybox/PPC insmod */
+static char _modname[] = LINUX_USER_BDE_NAME;
+
+static gmodule_t _gmodule =
+{
+ name: LINUX_USER_BDE_NAME,
+ major: LINUX_USER_BDE_MAJOR,
+ init: _init,
+ cleanup: _cleanup,
+ pprint: _pprint,
+ ioctl: _ioctl,
+};
+
+gmodule_t*
+gmodule_get(void)
+{
+ _gmodule.name = _modname;
+ return &_gmodule;
+}
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.h b/sdk-6.5.20/src/gpl-modules/systems/bde/linux/user/kernel/linux-user-bde.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: linux-user-bde.h,v 1.23 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#ifndef __LINUX_USER_BDE_H__
+#define __LINUX_USER_BDE_H__
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux-bde.h>
+#ifndef __KERNEL__
+#include <stdint.h>
+#endif
+
+#if defined(SAL_BDE_32BIT_USER_64BIT_KERNEL) || defined(PTRS_ARE_64BITS)
+typedef uint64_t bde_kernel_addr_t;
+#else
+typedef uint32_t bde_kernel_addr_t;
+#endif
+
+/* Ioctl control structure */
+typedef struct {
+ unsigned int dev; /* Device ID */
+ unsigned int rc; /* Operation Return Code */
+ unsigned int d0; /* Operation specific data */
+ unsigned int d1;
+ unsigned int d2;
+ unsigned int d3;
+ bde_kernel_addr_t p0;
+ union {
+ unsigned int dw[2];
+ unsigned char buf[64];
+ } dx;
+} lubde_ioctl_t;
+
+
+/* LUBDE ioctls */
+#define LUBDE_MAGIC 'L'
+
+#define LUBDE_VERSION _IO(LUBDE_MAGIC, 0)
+#define LUBDE_GET_NUM_DEVICES _IO(LUBDE_MAGIC, 1)
+#define LUBDE_GET_DEVICE _IO(LUBDE_MAGIC, 2)
+#define LUBDE_PCI_CONFIG_PUT32 _IO(LUBDE_MAGIC, 3)
+#define LUBDE_PCI_CONFIG_GET32 _IO(LUBDE_MAGIC, 4)
+#define LUBDE_GET_DMA_INFO _IO(LUBDE_MAGIC, 5)
+#define LUBDE_ENABLE_INTERRUPTS _IO(LUBDE_MAGIC, 6)
+#define LUBDE_DISABLE_INTERRUPTS _IO(LUBDE_MAGIC, 7)
+#define LUBDE_USLEEP _IO(LUBDE_MAGIC, 8)
+#define LUBDE_WAIT_FOR_INTERRUPT _IO(LUBDE_MAGIC, 9)
+#define LUBDE_SEM_OP _IO(LUBDE_MAGIC, 10)
+#define LUBDE_UDELAY _IO(LUBDE_MAGIC, 11)
+#define LUBDE_GET_DEVICE_TYPE _IO(LUBDE_MAGIC, 12)
+#define LUBDE_SPI_READ_REG _IO(LUBDE_MAGIC, 13)
+#define LUBDE_SPI_WRITE_REG _IO(LUBDE_MAGIC, 14)
+#define LUBDE_READ_REG_16BIT_BUS _IO(LUBDE_MAGIC, 19)
+#define LUBDE_WRITE_REG_16BIT_BUS _IO(LUBDE_MAGIC, 20)
+#define LUBDE_GET_BUS_FEATURES _IO(LUBDE_MAGIC, 21)
+#define LUBDE_WRITE_IRQ_MASK _IO(LUBDE_MAGIC, 22)
+#define LUBDE_CPU_WRITE_REG _IO(LUBDE_MAGIC, 23)
+#define LUBDE_CPU_READ_REG _IO(LUBDE_MAGIC, 24)
+#define LUBDE_CPU_PCI_REGISTER _IO(LUBDE_MAGIC, 25)
+#define LUBDE_DEV_RESOURCE _IO(LUBDE_MAGIC, 26)
+#define LUBDE_IPROC_READ_REG _IO(LUBDE_MAGIC, 27)
+#define LUBDE_IPROC_WRITE_REG _IO(LUBDE_MAGIC, 28)
+#define LUBDE_ATTACH_INSTANCE _IO(LUBDE_MAGIC, 29)
+#define LUBDE_GET_DEVICE_STATE _IO(LUBDE_MAGIC, 30)
+#define LUBDE_REPROBE _IO(LUBDE_MAGIC, 31)
+
+#define LUBDE_SEM_OP_CREATE 1
+#define LUBDE_SEM_OP_DESTROY 2
+#define LUBDE_SEM_OP_TAKE 3
+#define LUBDE_SEM_OP_GIVE 4
+
+#define LUBDE_SUCCESS 0
+#define LUBDE_FAIL ((unsigned int)-1)
+
+
+/*
+ * Version history
+ * 1: add LUBDE_GET_DEVICE_STATE to support PCI hot plug
+ * 2: add LUBDE_REPROBE to support reprobe available devices
+ */
+#define KBDE_VERSION 2
+
+
+/* This is the signal that will be used
+ * when an interrupt occurs
+ */
+
+#ifndef __KERNEL__
+#include <signal.h>
+#endif
+
+#define LUBDE_INTERRUPT_SIGNAL SIGUSR1
+#define LUBDE_ETHER_INTERRUPT_SIGNAL SIGUSR2
+
+#endif /* __LUBDE_H__ */
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde.h b/sdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2014 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#ifndef __SHBDE_H__
+#define __SHBDE_H__
+
+typedef void (*shbde_log_func_t)(int level, const char *str, int param);
+
+#define SHBDE_ERR 0
+#define SHBDE_WARN 1
+#define SHBDE_DBG 2
+
+/* iProc configuration (primarily used for PCI-AXI bridge) */
+typedef struct shbde_iproc_config_s {
+ unsigned int dev_id;
+ unsigned int dev_rev;
+ unsigned int use_msi;
+ unsigned int iproc_ver;
+ unsigned int cmic_ver;
+ unsigned int cmic_rev;
+ unsigned int dma_hi_bits;
+ unsigned int mdio_base_addr;
+ unsigned int pcie_phy_addr;
+ unsigned int adjust_pcie_preemphasis;
+} shbde_iproc_config_t;
+
+/* Hardware abstraction functions */
+typedef struct shbde_hal_s {
+
+ /* Optional log output interface */
+ shbde_log_func_t log_func;
+
+ /* PCI configuration access */
+ unsigned char (*pcic8_read)(void *pci_dev, unsigned int reg);
+ void (*pcic8_write)(void *pci_dev, unsigned int reg, unsigned char data);
+ unsigned short (*pcic16_read)(void *pci_dev, unsigned int reg);
+ void (*pcic16_write)(void *pci_dev, unsigned int reg, unsigned short data);
+ unsigned int (*pcic32_read)(void *pci_dev, unsigned int reg);
+ void (*pcic32_write)(void *pci_dev, unsigned int reg, unsigned int data);
+
+ /* iProc register access */
+ unsigned int (*io32_read)(void *addr);
+ void (*io32_write)(void *addr, unsigned int);
+
+ /* usleep function (optional) */
+ void (*usleep)(int usec);
+
+ /* PCI parent device access */
+ void *(*pci_parent_device_get)(void *pci_dev);
+
+ /* iProc configuration */
+ shbde_iproc_config_t icfg;
+
+} shbde_hal_t;
+
+
+#endif /* __SHBDE_H__ */
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde_iproc.h b/sdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde_iproc.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2014 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#ifndef __SHBDE_IPROC_H__
+#define __SHBDE_IPROC_H__
+
+#include <shbde.h>
+
+extern int
+shbde_iproc_config_init(shbde_iproc_config_t *icfg,
+ unsigned int dev_id, unsigned int dev_rev);
+
+extern int
+shbde_iproc_paxb_init(shbde_hal_t *shbde, void *iproc_regs,
+ shbde_iproc_config_t *icfg);
+
+extern unsigned int
+shbde_iproc_pci_read(shbde_hal_t *shbde, void *iproc_regs,
+ unsigned int addr);
+
+extern void
+shbde_iproc_pci_write(shbde_hal_t *shbde, void *iproc_regs,
+ unsigned int addr, unsigned int data);
+
+extern int
+shbde_iproc_pcie_preemphasis_set(shbde_hal_t *shbde, void *iproc_regs,
+ shbde_iproc_config_t *icfg, void *pci_dev);
+
+#endif /* __SHBDE_IPROC_H__ */
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde_mdio.h b/sdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde_mdio.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2015 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#ifndef __SHBDE_MDIO_H__
+#define __SHBDE_MDIO_H__
+
+#include <shbde.h>
+
+typedef struct shbde_mdio_ctrl_s {
+
+ /* Primary HAL*/
+ shbde_hal_t *shbde;
+
+ /* Context for iProc MDIO register access */
+ void *regs;
+
+ /* Base address for MDIO registers */
+ unsigned int base_addr;
+
+ /* iProc MDIO register access */
+ unsigned int (*io32_read)(shbde_hal_t *shbde, void *iproc_regs,
+ unsigned int addr);
+ void (*io32_write)(shbde_hal_t *shbde, void *iproc_regs,
+ unsigned int addr, unsigned int data);
+
+} shbde_mdio_ctrl_t;
+
+
+extern int
+shbde_iproc_mdio_init(shbde_mdio_ctrl_t *smc);
+
+extern int
+shbde_iproc_mdio_read(shbde_mdio_ctrl_t *smc, unsigned int phy_addr,
+ unsigned int reg, unsigned int *val);
+
+extern int
+shbde_iproc_mdio_write(shbde_mdio_ctrl_t *smc, unsigned int phy_addr,
+ unsigned int reg, unsigned int val);
+
+#endif /* __SHBDE_MDIO_H__ */
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde_pci.h b/sdk-6.5.20/src/gpl-modules/systems/bde/shared/include/shbde_pci.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2014 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#ifndef __SHBDE_PCI_H__
+#define __SHBDE_PCI_H__
+
+#include <shbde.h>
+
+extern unsigned int
+shbde_pci_pcie_cap(shbde_hal_t *shbde, void *pci_dev);
+
+extern int
+shbde_pci_is_pcie(shbde_hal_t *shbde, void *pci_dev);
+
+extern int
+shbde_pci_is_iproc(shbde_hal_t *shbde, void *pci_dev, int *cmic_bar);
+
+extern int
+shbde_pci_max_payload_set(shbde_hal_t *shbde, void *pci_dev, int maxpayload);
+
+extern int
+shbde_pci_iproc_version_get(shbde_hal_t *shbde, void *pci_dev,
+ unsigned int *iproc_ver,
+ unsigned int *cmic_ver,
+ unsigned int *cmic_rev);
+
+#endif /* __SHBDE_PCI_H__ */
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/shared/shbde_iproc.c b/sdk-6.5.20/src/gpl-modules/systems/bde/shared/shbde_iproc.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2014 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#include <shbde_iproc.h>
+#include <shbde_mdio.h>
+#include <shbde_pci.h>
+
+/* PAXB register offsets within PCI BAR0 window */
+#define BAR0_PAXB_ENDIANESS 0x2030
+#define BAR0_PAXB_PCIE_EP_AXI_CONFIG 0x2104
+#define BAR0_PAXB_CONFIG_IND_ADDR 0x2120
+#define BAR0_PAXB_CONFIG_IND_DATA 0x2124
+
+#define PAXB_0_CMICD_TO_PCIE_INTR_EN 0x2380
+
+#define BAR0_PAXB_IMAP0_0 (0x2c00)
+#define BAR0_PAXB_IMAP0_1 (0x2c04)
+#define BAR0_PAXB_IMAP0_2 (0x2c08)
+#define BAR0_PAXB_IMAP0_7 (0x2c1c)
+
+#define BAR0_PAXB_OARR_FUNC0_MSI_PAGE 0x2d34
+#define BAR0_PAXB_OARR_2 0x2d60
+#define BAR0_PAXB_OARR_2_UPPER 0x2d64
+#define BAR0_DMU_PCU_PCIE_SLAVE_RESET_MODE 0x7024
+
+#define PAXB_0_FUNC0_IMAP1_3 0x2d88
+
+/* Force byte pointer for offset adjustments */
+#define ROFFS(_ptr, _offset) ((unsigned char*)(_ptr) + (_offset))
+
+#define PAXB_CONFIG_IND_ADDRr_PROTOCOL_LAYERf_SHFT 11
+#define PAXB_CONFIG_IND_ADDRr_PROTOCOL_LAYERf_MASK 0x3
+#define PAXB_CONFIG_IND_ADDRr_ADDRESSf_SHFT 0
+#define PAXB_CONFIG_IND_ADDRr_ADDRESSf_MASK 0x7ff
+#define PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT 20
+
+/* Register value set/get by field */
+#define REG_FIELD_SET(_r, _f, _r_val, _f_val) \
+ _r_val = ((_r_val) & ~(_r##_##_f##_MASK << _r##_##_f##_SHFT)) | \
+ (((_f_val) & _r##_##_f##_MASK) << _r##_##_f##_SHFT)
+#define REG_FIELD_GET(_r, _f, _r_val) \
+ (((_r_val) >> _r##_##_f##_SHFT) & _r##_##_f##_MASK)
+
+/* PCIe capabilities definition */
+#ifndef PCI_EXP_LNKSTA
+#define PCI_EXP_LNKSTA 0x12
+#endif
+/* Current Link Speed 5.0GT/s */
+#ifndef PCI_EXP_LNKSTA_CLS_5_0GB
+#define PCI_EXP_LNKSTA_CLS_5_0GB 2
+#endif
+#ifndef PCI_EXP_LNKSTA2
+#define PCI_EXP_LNKSTA2 0x32
+#endif
+/* Current Deemphasis Level -3.5 dB */
+#ifndef PCI_EXP_LNKSTA2_CDL_3_5DB
+#define PCI_EXP_LNKSTA2_CDL_3_5DB 0x1
+#endif
+
+static unsigned int
+iproc32_read(shbde_hal_t *shbde, void *addr)
+{
+ if (!shbde || !shbde->io32_read) {
+ return 0;
+ }
+ return shbde->io32_read(addr);
+}
+
+static void
+iproc32_write(shbde_hal_t *shbde, void *addr, unsigned int data)
+{
+ if (!shbde || !shbde->io32_write) {
+ return;
+ }
+ shbde->io32_write(addr, data);
+}
+
+static void
+wait_usec(shbde_hal_t *shbde, int usec)
+{
+ if (shbde && shbde->usleep) {
+ shbde->usleep(usec);
+ } else {
+ int idx;
+ volatile int count;
+ for (idx = 0; idx < usec; idx++) {
+ for (count = 0; count < 100; count++);
+ }
+ }
+}
+
+/*
+ * Function:
+ * shbde_iproc_config_init
+ * Purpose:
+ * Initialize iProc configuration parameters
+ * Parameters:
+ * icfg - pointer to empty iProc configuration structure
+ * Returns:
+ * -1 if error, otherwise 0
+ */
+int
+shbde_iproc_config_init(shbde_iproc_config_t *icfg,
+ unsigned int dev_id, unsigned int dev_rev)
+{
+ if (!icfg) {
+ return -1;
+ }
+
+ /* Save device ID and revision */
+ icfg->dev_id = dev_id;
+ icfg->dev_rev = dev_rev;
+
+ /* Check device families first */
+ switch (icfg->dev_id & 0xfff0) {
+ case 0x8400: /* Greyhound Lite */
+ case 0x8410: /* Greyhound */
+ case 0x8420: /* Bloodhound */
+ case 0x8450: /* Elkhound */
+ case 0xb060: /* Ranger2(Greyhound) */
+ case 0x8360: /* Greyhound 53365 & 53369 */
+ case 0xb260: /* saber2 */
+ case 0xb460: /* saber2+ */
+ case 0xb170: /* Hurricane3-MG */
+ case 0x8570: /* Greyhound2 */
+ case 0xb070: /* Greyhound2(emulation) */
+ case 0x8580: /* Greyhound2(emulation) */
+ case 0xb230: /* Dagger2 */
+ icfg->iproc_ver = 7;
+ icfg->dma_hi_bits = 0x2;
+ break;
+ case 0xb560: /* Apache */
+ case 0xb670: /* MO */
+ case 0xb760: /* Maverick */
+ icfg->iproc_ver = 0xB;
+ break;
+ case 0xb160: /* Hurricane3 */
+ case 0x8440: /* Buckhound2 */
+ case 0x8430: /* Foxhound2 */
+ case 0x8540: /* Wolfhound2 */
+ icfg->iproc_ver = 10;
+ icfg->dma_hi_bits = 0x2;
+ break;
+ default:
+ break;
+ }
+
+ /* Check for exceptions */
+ switch (icfg->dev_id) {
+ case 0xb069:
+ case 0xb068:
+ icfg->iproc_ver = 0xB; /*Ranger2+ Apache Family */
+ icfg->dma_hi_bits = 0;
+ break;
+ case 0xb168: /* Ranger3+ */
+ case 0xb169:
+ icfg->iproc_ver = 0;
+ icfg->dma_hi_bits = 0;
+ break;
+ default:
+ break;
+ }
+ /* Check for PCIe PHY address that needs PCIe preemphasis and
+ * assign the MDIO base address
+ */
+ switch (icfg->dev_id & 0xfff0) {
+ case 0xb150: /* Hurricane2 */
+ case 0x8340: /* Wolfhound */
+ case 0x8330: /* Foxhound */
+ case 0x8390: /* Dearhound */
+ icfg->mdio_base_addr = 0x18032000;
+ icfg->pcie_phy_addr = 0x2;
+ break;
+ case 0xb340: /* Helilx4 */
+ case 0xb540: /* FireScout */
+ case 0xb040: /* Spiral, Ranger */
+ icfg->mdio_base_addr = 0x18032000;
+ icfg->pcie_phy_addr = 0x5;
+ icfg->adjust_pcie_preemphasis = 1;
+ break;
+ case 0xa450: /* Katana2 */
+ case 0xb240:
+ case 0xb450:
+ icfg->mdio_base_addr = 0x18032000;
+ icfg->pcie_phy_addr = 0x5;
+ icfg->adjust_pcie_preemphasis = 1;
+ break;
+ default:
+ break;
+ }
+
+ /* Check for exceptions */
+ switch (icfg->dev_id) {
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Function:
+ * shbde_iproc_paxb_init
+ * Purpose:
+ * Initialize iProc PCI-AXI bridge for CMIC access
+ * Parameters:
+ * shbde - pointer to initialized hardware abstraction module
+ * iproc_regs - memory mapped iProc registers in PCI BAR
+ * icfg - iProc configuration parameters
+ * Returns:
+ * -1 if error, otherwise 0
+ */
+int
+shbde_iproc_paxb_init(shbde_hal_t *shbde, void *iproc_regs,
+ shbde_iproc_config_t *icfg)
+{
+ void *reg;
+ unsigned int data;
+ int pci_num;
+
+ if (!iproc_regs || !icfg) {
+ return -1;
+ }
+
+ /*
+ * The following code attempts to auto-detect the correct
+ * iProc PCI endianess configuration by reading a well-known
+ * register (the endianess configuration register itself).
+ * Note that the PCI endianess may be different for different
+ * big endian host processors.
+ */
+ reg = ROFFS(iproc_regs, BAR0_PAXB_ENDIANESS);
+ /* Select big endian */
+ iproc32_write(shbde, reg, 0x01010101);
+ /* Check if endianess register itself is correct endian */
+ if (iproc32_read(shbde, reg) != 1) {
+ /* If not, then assume little endian */
+ iproc32_write(shbde, reg, 0x0);
+ }
+
+ /* Select which PCI core to use */
+ pci_num = 0;
+ reg = ROFFS(iproc_regs, BAR0_PAXB_IMAP0_2);
+ data = iproc32_read(shbde, reg);
+ if (data & 0x1000) {
+ /* PAXB_1 is mapped to sub-window 2 */
+ pci_num = 1;
+ }
+
+ /* Default DMA mapping if uninitialized */
+ if (icfg->dma_hi_bits == 0) {
+ icfg->dma_hi_bits = 0x1;
+ if (pci_num == 1) {
+ icfg->dma_hi_bits = 0x2;
+ }
+ }
+
+ /* Enable iProc DMA to external host memory */
+ reg = ROFFS(iproc_regs, BAR0_PAXB_PCIE_EP_AXI_CONFIG);
+ iproc32_write(shbde, reg, 0x0);
+ if(icfg->cmic_ver < 4) { /* Non-CMICX */
+ reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_2);
+ iproc32_write(shbde, reg, 0x1);
+ reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_2_UPPER);
+ iproc32_write(shbde, reg, icfg->dma_hi_bits);
+ /* Configure MSI interrupt page */
+ if (icfg->use_msi) {
+ reg = ROFFS(iproc_regs, BAR0_PAXB_OARR_FUNC0_MSI_PAGE);
+ data = iproc32_read(shbde, reg);
+ iproc32_write(shbde, reg, data | 0x1);
+ }
+ }
+
+ /* Configure MSIX interrupt page, need for iproc ver 0x10 and 0x12 */
+ if ((icfg->use_msi == 2) &&
+ ((icfg->iproc_ver == 0x10) || (icfg->iproc_ver == 0x12))){
+ unsigned int mask = (0x1 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT) - 1;
+ reg = ROFFS(iproc_regs, PAXB_0_FUNC0_IMAP1_3);
+ data = iproc32_read(shbde, reg);
+ data &= mask;
+ data |= 0x410 << PAXB_0_FUNC0_IMAP1_3_ADDR_SHIFT;
+ iproc32_write(shbde, reg, data);
+ }
+
+ /* Disable INTx interrupt if MSI/MSIX is selected */
+ reg = ROFFS(iproc_regs, PAXB_0_CMICD_TO_PCIE_INTR_EN);
+ data = iproc32_read(shbde, reg);
+ if (icfg->use_msi) {
+ data &= ~0x1;
+ } else {
+ data |= 0x1;
+ }
+ iproc32_write(shbde, reg, data);
+
+ return pci_num;
+}
+
+/*
+ * Function:
+ * shbde_iproc_pci_read
+ * Purpose:
+ * Read iProc register through PCI BAR 0
+ * Parameters:
+ * shbde - pointer to initialized hardware abstraction module
+ * iproc_regs - memory mapped iProc registers in PCI BAR
+ * addr - iProc register address in AXI memory space
+ * Returns:
+ * Register value
+ */
+unsigned int
+shbde_iproc_pci_read(shbde_hal_t *shbde, void *iproc_regs,
+ unsigned int addr)
+{
+ unsigned int subwin_base;
+ void *reg;
+ shbde_iproc_config_t *icfg = &shbde->icfg;
+
+ if (!iproc_regs) {
+ return -1;
+ }
+
+ /* Sub-window size is 0x1000 (4K) */
+ subwin_base = (addr & ~0xfff);
+
+ if((icfg->cmic_ver >= 4) &&
+ ((subwin_base == 0x10230000) || (subwin_base == 0x18012000))) {
+ /* Route the PAXB register through IMAP0_2 */
+ reg = ROFFS(iproc_regs, 0x2000 + (addr & 0xfff));
+ } else if((icfg->cmic_ver >= 4) &&
+ ((subwin_base == 0x10231000) || (subwin_base == 0x18013000))) {
+ /* Route the INTC block access through IMAP0_6 */
+ reg = ROFFS(iproc_regs, 0x6000 + (addr & 0xfff));
+ } else {
+ /* Update base address for sub-window 7 */
+ subwin_base |= 1; /* Valid bit */
+ reg = ROFFS(iproc_regs, BAR0_PAXB_IMAP0_7);
+ iproc32_write(shbde, reg, subwin_base);
+ /* Read it to make sure the write actually goes through */
+ subwin_base = iproc32_read(shbde, reg);
+
+ /* Read register through sub-window 7 */
+ reg = ROFFS(iproc_regs, 0x7000 + (addr & 0xfff));
+ }
+
+ return iproc32_read(shbde, reg);
+}
+
+/*
+ * Function:
+ * shbde_iproc_pci_write
+ * Purpose:
+ * Write iProc register through PCI BAR 0
+ * Parameters:
+ * shbde - pointer to initialized hardware abstraction module
+ * iproc_regs - memory mapped iProc registers in PCI BAR
+ * addr - iProc register address in AXI memory space
+ * data - data to write to iProc register
+ * Returns:
+ * Register value
+ */
+void
+shbde_iproc_pci_write(shbde_hal_t *shbde, void *iproc_regs,
+ unsigned int addr, unsigned int data)
+{
+ unsigned int subwin_base;
+ void *reg;
+ shbde_iproc_config_t *icfg = &shbde->icfg;
+
+ if (!iproc_regs) {
+ return;
+ }
+
+ /* Sub-window size is 0x1000 (4K) */
+ subwin_base = (addr & ~0xfff);
+
+ if((icfg->cmic_ver >= 4) &&
+ ((subwin_base == 0x10230000) || (subwin_base == 0x18012000))) {
+ /* Route the PAXB register through IMAP0_2 */
+ reg = ROFFS(iproc_regs, 0x2000 + (addr & 0xfff));
+ } else if((icfg->cmic_ver >= 4) &&
+ ((subwin_base == 0x10231000) || (subwin_base == 0x18013000))) {
+ /* Route the INTC block access through IMAP0_6 */
+ reg = ROFFS(iproc_regs, 0x6000 + (addr & 0xfff));
+ } else {
+ /* Update base address for sub-window 7 */
+ subwin_base |= 1; /* Valid bit */
+ reg = ROFFS(iproc_regs, BAR0_PAXB_IMAP0_7);
+ iproc32_write(shbde, reg, subwin_base);
+ /* Read it to make sure the write actually goes through */
+ subwin_base = iproc32_read(shbde, reg);
+
+ /* Read register through sub-window 7 */
+ reg = ROFFS(iproc_regs, 0x7000 + (addr & 0xfff));
+ }
+
+ iproc32_write(shbde, reg, data);
+}
+
+int
+shbde_iproc_pcie_preemphasis_set(shbde_hal_t *shbde, void *iproc_regs,
+ shbde_iproc_config_t *icfg, void *pci_dev)
+{
+ shbde_mdio_ctrl_t mdio_ctrl, *smc = &mdio_ctrl;
+ unsigned int phy_addr, data;
+ void *reg;
+ unsigned int pcie_cap_base;
+ unsigned short link_stat, link_stat2;
+
+ if (!icfg) {
+ return -1;
+ }
+
+ /* PHY address for PCIe link */
+ phy_addr = icfg->pcie_phy_addr;
+ if (phy_addr == 0 || icfg->mdio_base_addr == 0) {
+ return 0;
+ }
+
+ /* Initialize MDIO control */
+ smc->shbde = shbde;
+ smc->regs = iproc_regs;
+ smc->base_addr = icfg->mdio_base_addr;
+ smc->io32_read = shbde_iproc_pci_read;
+ smc->io32_write = shbde_iproc_pci_write;
+ shbde_iproc_mdio_init(smc);
+
+ /* PCIe SerDes Gen1/Gen2 CDR Track Bandwidth Adjustment
+ * for Better Jitter Tolerance
+ */
+ shbde_iproc_mdio_write(smc, phy_addr, 0x1f, 0x8630);
+ shbde_iproc_mdio_write(smc, phy_addr, 0x13, 0x190);
+ shbde_iproc_mdio_write(smc, phy_addr, 0x19, 0x191);
+
+ if (!icfg->adjust_pcie_preemphasis) {
+ return 0;
+ }
+
+ /* Check to see if the PCIe SerDes deemphasis needs to be changed
+ * based on the advertisement from the root complex
+ */
+ /* Find PCIe capability base */
+ if (!shbde || !shbde->pcic16_read || !pci_dev) {
+ return -1;
+ }
+ pcie_cap_base = shbde_pci_pcie_cap(shbde, pci_dev);
+ if (pcie_cap_base) {
+ link_stat = shbde->pcic16_read(pci_dev,
+ pcie_cap_base + PCI_EXP_LNKSTA);
+ link_stat2 = shbde->pcic16_read(pci_dev,
+ pcie_cap_base + PCI_EXP_LNKSTA2);
+ if (((link_stat & 0xf) == PCI_EXP_LNKSTA_CLS_5_0GB) &&
+ (link_stat2 & PCI_EXP_LNKSTA2_CDL_3_5DB)) {
+ /* Device is operating at Gen2 speeds and RC requested -3.5dB */
+ /* Change the transmitter setting */
+ shbde_iproc_mdio_write(smc, phy_addr, 0x1f, 0x8610);
+ shbde_iproc_mdio_read(smc, phy_addr, 0x17, &data);
+ data &= ~0xf00;
+ data |= 0x700;
+ shbde_iproc_mdio_write(smc, phy_addr, 0x17, data);
+
+ /* Force the PCIe link to retrain */
+ data = 0;
+ REG_FIELD_SET(PAXB_CONFIG_IND_ADDRr, PROTOCOL_LAYERf, data, 0x2);
+ REG_FIELD_SET(PAXB_CONFIG_IND_ADDRr, ADDRESSf, data, 0x4);
+ reg = ROFFS(iproc_regs, BAR0_PAXB_CONFIG_IND_ADDR);
+ iproc32_write(shbde, reg, data);
+
+ reg = ROFFS(iproc_regs, BAR0_PAXB_CONFIG_IND_DATA);
+ data = iproc32_read(shbde, reg);
+ data &= ~0x4000;
+ iproc32_write(shbde, reg, data);
+ data |= 0x4000;
+ iproc32_write(shbde, reg, data);
+ data &= ~0x4000;
+ iproc32_write(shbde, reg, data);
+
+ /* Wait a short while for the retraining to complete */
+ wait_usec(shbde, 1000);
+ }
+ }
+
+ return 0;
+}
+
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/shared/shbde_mdio.c b/sdk-6.5.20/src/gpl-modules/systems/bde/shared/shbde_mdio.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2015 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#include <shbde_mdio.h>
+
+/* iProc MDIO register offset */
+#define MII_MGMT_CTRL 0x0
+#define MII_MGMT_CMD_DATA 0x4
+
+/* iProc MII register with fields definition */
+#define MII_MGMT_CTRLr_MDCDIVf_SHFT 0
+#define MII_MGMT_CTRLr_MDCDIVf_MASK 0x7f
+#define MII_MGMT_CTRLr_BSYf_SHFT 8
+#define MII_MGMT_CTRLr_BSYf_MASK 0x1
+
+#define MII_MGMT_CMD_DATAr_DATAf_SHFT 0
+#define MII_MGMT_CMD_DATAr_DATAf_MASK 0xffff
+#define MII_MGMT_CMD_DATAr_TAf_SHFT 16
+#define MII_MGMT_CMD_DATAr_TAf_MASK 0x3
+#define MII_MGMT_CMD_DATAr_RAf_SHFT 18
+#define MII_MGMT_CMD_DATAr_RAf_MASK 0x1f
+#define MII_MGMT_CMD_DATAr_PAf_SHFT 23
+#define MII_MGMT_CMD_DATAr_PAf_MASK 0x1f
+#define MII_MGMT_CMD_DATAr_OPf_SHFT 28
+#define MII_MGMT_CMD_DATAr_OPf_MASK 0x3
+#define MII_MGMT_CMD_DATAr_SBf_SHFT 30
+#define MII_MGMT_CMD_DATAr_SBf_MASK 0x3
+
+/* Register field value set/get */
+#define REG_FIELD_SET(_r, _f, _r_val, _f_val) \
+ _r_val = ((_r_val) & ~(_r##_##_f##_MASK << _r##_##_f##_SHFT)) | \
+ (((_f_val) & _r##_##_f##_MASK) << _r##_##_f##_SHFT)
+#define REG_FIELD_GET(_r, _f, _r_val) \
+ (((_r_val) >> _r##_##_f##_SHFT) & _r##_##_f##_MASK)
+
+#define LOG_OUT(_shbde, _lvl, _str, _prm) \
+ if ((_shbde)->log_func) { \
+ (_shbde)->log_func(_lvl, _str, _prm); \
+ }
+#define LOG_ERR(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_ERR, _str, _prm)
+#define LOG_WARN(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_WARN, _str, _prm)
+#define LOG_DBG(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_DBG, _str, _prm)
+
+static unsigned int
+mdio32_read(shbde_mdio_ctrl_t *smc, unsigned int offset)
+{
+ if (!smc || !smc->io32_read) {
+ return 0;
+ }
+ return smc->io32_read(smc->shbde, smc->regs, smc->base_addr + offset);
+}
+
+static void
+mdio32_write(shbde_mdio_ctrl_t *smc, unsigned int offset, unsigned int data)
+{
+ if (!smc || !smc->io32_read) {
+ return;
+ }
+ smc->io32_write(smc->shbde, smc->regs, smc->base_addr + offset, data);
+}
+
+static void
+wait_usec(shbde_mdio_ctrl_t *smc, int usec)
+{
+ shbde_hal_t *shbde = smc->shbde;
+
+ if (shbde && shbde->usleep) {
+ shbde->usleep(usec);
+ } else {
+ int idx;
+ volatile int count;
+ for (idx = 0; idx < usec; idx++) {
+ for (count = 0; count < 100; count++);
+ }
+ }
+}
+
+static int
+iproc_mdio_wait_for_busy(shbde_mdio_ctrl_t *smc)
+{
+ int mii_busy;
+ unsigned int reg_val;
+ int count = 1000;
+
+ /* Wait until MII is not busy */
+ do {
+ reg_val = mdio32_read(smc, MII_MGMT_CTRL);
+ mii_busy = REG_FIELD_GET(MII_MGMT_CTRLr, BSYf, reg_val);
+ if (!mii_busy) {
+ break;
+ }
+ wait_usec(smc, 10);
+ count --;
+ } while (count > 0);
+
+ return mii_busy;
+}
+
+int
+shbde_iproc_mdio_init(shbde_mdio_ctrl_t *smc)
+{
+ shbde_hal_t *shbde = smc->shbde;
+ unsigned int reg_val = 0;
+
+ /* Enable the iProc internal MDIO interface */
+ REG_FIELD_SET(MII_MGMT_CTRLr, MDCDIVf, reg_val, 0x7f);
+ mdio32_write(smc, MII_MGMT_CTRL, reg_val);
+
+ if (shbde && !shbde->usleep) {
+ LOG_DBG(shbde, "shbde_mdio: no registration of usleep vector", 0);
+ }
+
+ wait_usec(smc, 100);
+
+ return 0;
+}
+
+int
+shbde_iproc_mdio_read(shbde_mdio_ctrl_t *smc, unsigned int phy_addr,
+ unsigned int reg, unsigned int *val)
+{
+ unsigned int reg_val = 0;
+
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, SBf, reg_val, 0x1);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, TAf, reg_val, 0x2);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, OPf, reg_val, 0x2);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, PAf, reg_val, phy_addr);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, RAf, reg_val, reg);
+ mdio32_write(smc, MII_MGMT_CMD_DATA, reg_val);
+
+ if (iproc_mdio_wait_for_busy(smc)) {
+ *val = 0;
+ LOG_DBG(smc->shbde, "shbde_iproc_mdio_read busy", reg);
+ return -1;
+ }
+
+ reg_val = mdio32_read(smc, MII_MGMT_CMD_DATA);
+ *val = REG_FIELD_GET(MII_MGMT_CMD_DATAr, DATAf, reg_val);
+
+ return 0;
+}
+
+int
+shbde_iproc_mdio_write(shbde_mdio_ctrl_t *smc, unsigned int phy_addr,
+ unsigned int reg, unsigned int val)
+{
+ unsigned int reg_val = 0;
+
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, SBf, reg_val, 0x1);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, TAf, reg_val, 0x2);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, OPf, reg_val, 0x1);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, PAf, reg_val, phy_addr);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, RAf, reg_val, reg);
+ REG_FIELD_SET(MII_MGMT_CMD_DATAr, DATAf, reg_val, val);
+ mdio32_write(smc, MII_MGMT_CMD_DATA, reg_val);
+
+ if (iproc_mdio_wait_for_busy(smc)) {
+ LOG_DBG(smc->shbde, "shbde_iproc_mdio_write busy", reg);
+ return -1;
+ }
+
+ /* Wait for some time for the write to take effect */
+ wait_usec(smc, 100);
+
+ return 0;
+}
+
diff --git a/sdk-6.5.20/src/gpl-modules/systems/bde/shared/shbde_pci.c b/sdk-6.5.20/src/gpl-modules/systems/bde/shared/shbde_pci.c
@@ -0,0 +1,392 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: $
+ * $Copyright: (c) 2014 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ */
+
+#include <shbde_pci.h>
+
+/* PCIe capabilities */
+#ifndef PCI_CAPABILITY_LIST
+#define PCI_CAPABILITY_LIST 0x34
+#endif
+#ifndef PCI_CAP_ID_EXP
+#define PCI_CAP_ID_EXP 0x10
+#endif
+#ifndef PCI_EXP_DEVCAP
+#define PCI_EXP_DEVCAP 4
+#endif
+#ifndef PCI_EXP_DEVCTL
+#define PCI_EXP_DEVCTL 8
+#endif
+#ifndef PCI_EXT_CAP_START
+#define PCI_EXT_CAP_START 0x100
+#endif
+#ifndef PCI_EXT_CAP_ID
+#define PCI_EXT_CAP_ID(_hdr) (_hdr & 0x0000ffff)
+#endif
+#ifndef PCI_EXT_CAP_VER
+#define PCI_EXT_CAP_VER(_hdr) ((_hdr >> 16) & 0xf)
+#endif
+#ifndef PCI_EXT_CAP_NEXT
+#define PCI_EXT_CAP_NEXT(_hdr) ((_hdr >> 20) & 0xffc)
+#endif
+#ifndef PCI_EXT_CAP_ID_VNDR
+#define PCI_EXT_CAP_ID_VNDR 0x0b
+#endif
+
+#define LOG_OUT(_shbde, _lvl, _str, _prm) \
+ if ((_shbde)->log_func) { \
+ (_shbde)->log_func(_lvl, _str, _prm); \
+ }
+#define LOG_ERR(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_ERR, _str, _prm)
+#define LOG_WARN(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_WARN, _str, _prm)
+#define LOG_DBG(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_DBG, _str, _prm)
+
+#ifndef NULL
+#define NULL (void *)0
+#endif
+
+/*
+ * Warpper functions with null-pointer checks.
+ */
+static unsigned int
+pcic16_read(shbde_hal_t *shbde, void *pci_dev,
+ unsigned int addr)
+{
+ if (!shbde || !shbde->pcic16_read) {
+ return 0;
+ }
+ return shbde->pcic16_read(pci_dev, addr);
+}
+
+static void
+pcic16_write(shbde_hal_t *shbde, void *pci_dev,
+ unsigned int addr, unsigned int data)
+{
+ if (!shbde || !shbde->pcic16_write) {
+ return;
+ }
+ shbde->pcic16_write(pci_dev, addr, data);
+}
+
+static unsigned int
+pcic32_read(shbde_hal_t *shbde, void *pci_dev,
+ unsigned int addr)
+{
+ if (!shbde || !shbde->pcic32_read) {
+ return 0;
+ }
+ return shbde->pcic32_read(pci_dev, addr);
+}
+
+static void *
+pci_parent_device_get(shbde_hal_t *shbde, void *pci_dev)
+{
+ if (!shbde || !shbde->pci_parent_device_get) {
+ return NULL;
+ }
+ return shbde->pci_parent_device_get(pci_dev);
+}
+
+/*
+ * Function:
+ * shbde_pci_pcie_cap
+ * Purpose:
+ * Return offset of PCIe capabilities in PCI configuration space
+ * Parameters:
+ * shbde - pointer to initialized hardware abstraction module
+ * dev - PCI device handle (passed back to PCI HAL functions)
+ * Returns:
+ * PCI_CAP_ID_EXP offset in PCI configuration space if PCIe, otherwise 0
+ */
+unsigned int
+shbde_pci_pcie_cap(shbde_hal_t *shbde, void *pci_dev)
+{
+ unsigned int cap_base, rval;
+
+ cap_base = pcic16_read(shbde, pci_dev, PCI_CAPABILITY_LIST);
+ while (cap_base) {
+ rval = pcic16_read(shbde, pci_dev, cap_base);
+ if ((rval & 0xff) == PCI_CAP_ID_EXP) {
+ break;
+ }
+ cap_base = (rval >> 8) & 0xff;
+ }
+
+ return cap_base;
+}
+
+/*
+ * Function:
+ * shbde_pci_is_pcie
+ * Purpose:
+ * Check if PCI device is PCIe device
+ * Parameters:
+ * shbde - pointer to initialized hardware abstraction module
+ * dev - PCI device handle (passed back to PCI HAL functions)
+ * Returns:
+ * 1 if PCIe, otherwise 0
+ */
+int
+shbde_pci_is_pcie(shbde_hal_t *shbde, void *pci_dev)
+{
+ return shbde_pci_pcie_cap(shbde, pci_dev) ? 1 : 0;
+}
+
+/*
+ * Function:
+ * shbde_pci_is_iproc
+ * Purpose:
+ * Check if PCI device is iProc-based
+ * Parameters:
+ * shbde - pointer to initialized hardware abstraction module
+ * dev - PCI device handle (passed back to PCI HAL functions)
+ * cmic_bar - (OUT) PCI BAR which contains switch CMIC registers
+ * Returns:
+ * 1 if iProc-based, otherwise 0
+ */
+int
+shbde_pci_is_iproc(shbde_hal_t *shbde, void *pci_dev, int *cmic_bar)
+{
+ unsigned int cap_base, rval;
+
+ if (!shbde_pci_is_pcie(shbde, pci_dev)) {
+ return 0;
+ }
+
+ /* Look for PCIe vendor-specific extended capability (VSEC) */
+ cap_base = PCI_EXT_CAP_START;
+ while (cap_base) {
+ rval = pcic32_read(shbde, pci_dev, cap_base);
+ if (rval == 0xffffffff) {
+ /* Assume PCI HW read error */
+ return 0;
+ }
+
+ if (PCI_EXT_CAP_ID(rval) == PCI_EXT_CAP_ID_VNDR) {
+ break;
+ }
+ cap_base = PCI_EXT_CAP_NEXT(rval);
+ }
+ if (cap_base) {
+ /*
+ * VSEC layout:
+ *
+ * 0x00: PCI Express Extended Capability Header
+ * 0x04: Vendor-Specific Header
+ * 0x08: Vendor-Specific Register 1
+ * 0x0c: Vendor-Specific Register 2
+ * ...
+ * 0x24: Vendor-Specific Register 8
+ */
+ /* 32'b // 31:12=0 Reserved; 11:08=CMIC BAR; 07:00=iProc Configuration ID */
+ rval = pcic32_read(shbde, pci_dev, cap_base + 8);
+ LOG_DBG(shbde, "Found VSEC", rval);
+
+ /* Determine PCI BAR of CMIC */
+ *cmic_bar = 0;
+ if ((rval & 0x100) == 0x100) {
+ *cmic_bar = 2;
+ }
+ /* Assume iProc device */
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Function:
+ * shbde_pci_iproc_version_get
+ * Purpose:
+ * Get iproc, cmic versions and revisions
+ * Parameters:
+ * shbde - pointer to initialized hardware abstraction module
+ * dev - PCI device handle (passed back to PCI HAL functions)
+ * iproc_ver - (OUT) iProc version
+ * cmic_ver - (OUT) CMIC version
+ * cmic_rev - (OUT) CMIC revision
+ * Returns:
+ * 1 for no error, otherwise 0
+ */
+int
+shbde_pci_iproc_version_get(shbde_hal_t *shbde, void *pci_dev,
+ unsigned int *iproc_ver,
+ unsigned int *cmic_ver,
+ unsigned int *cmic_rev)
+{
+ unsigned int cap_base, rval;
+
+ if (!shbde_pci_is_pcie(shbde, pci_dev)) {
+ return 0;
+ }
+
+ /* Look for PCIe vendor-specific extended capability (VSEC) */
+ cap_base = PCI_EXT_CAP_START;
+ while (cap_base) {
+ rval = pcic32_read(shbde, pci_dev, cap_base);
+ if (rval == 0xffffffff) {
+ /* Assume PCI HW read error */
+ return 0;
+ }
+
+ if (PCI_EXT_CAP_ID(rval) == PCI_EXT_CAP_ID_VNDR) {
+ break;
+ }
+ cap_base = PCI_EXT_CAP_NEXT(rval);
+ }
+ if (cap_base) {
+ /*
+ * VSEC layout:
+ *
+ * 0x00: PCI Express Extended Capability Header
+ * 0x04: Vendor-Specific Header
+ * 0x08: Vendor-Specific Register 1
+ * 0x0c: Vendor-Specific Register 2
+ * ...
+ * 0x24: Vendor-Specific Register 8
+ */
+
+ /* Read PCIe Vendor Specific Register 1 */
+ /* VENODR REG FORMAT
+ * [7:0] iProc Rev = 8'h0E (for P14)
+ * [11:8] CMIC BAR = 4'h1 (BAR64-1)
+ * [15:12] CMIC Version = 4'h4
+ * [19:16] CMIC Rev = 4'h1
+ * [22:20] SBUS Version = 4'h4
+ */
+
+ rval = pcic32_read(shbde, pci_dev, cap_base + 8);
+ LOG_DBG(shbde, "Found VSEC", rval);
+
+ /* Determine PCI BAR of CMIC */
+ *iproc_ver = rval & 0xff;
+ *cmic_ver = (rval >> 12) & 0xf;
+ *cmic_rev = (rval >> 16) & 0xf;
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Function:
+ * shbde_pci_max_payload_set
+ * Purpose:
+ * Set PCIe maximum payload
+ * Parameters:
+ * shbde - pointer to initialized hardware abstraction module
+ * dev - PCI device handle (passed back to PCI HAL functions)
+ * maxpayload - maximum payload (in byte)
+ * Returns:
+ * -1 if error, otherwise 0
+ * Notes:
+ * If not PCIe device, set the PCI retry count to infinte instead.
+ */
+int
+shbde_pci_max_payload_set(shbde_hal_t *shbde, void *pci_dev, int maxpayload)
+{
+ unsigned int cap_base, parent_cap_base;
+ unsigned int devcap, devctl, parent_devctl;
+ int max_val, max_cap, parent_max_val;
+ void *parent_pci_dev;
+
+ cap_base = shbde_pci_pcie_cap(shbde, pci_dev);
+
+ if (cap_base == 0) {
+ /* Not PCIe */
+ return 0;
+ }
+
+ /* Get current device control settings */
+ devctl = pcic16_read(shbde, pci_dev, cap_base + PCI_EXP_DEVCTL);
+
+ /* Get current max payload setting */
+ max_val = (devctl >> 5) & 0x7;
+
+ if (maxpayload) {
+ /* Get encoding from byte value */
+ max_val = 0;
+ while ((1 << (max_val + 7)) < maxpayload) {
+ max_val++;
+ }
+ LOG_DBG(shbde, "Set max payload size", maxpayload);
+ LOG_DBG(shbde, "Set max payload val", max_val);
+
+ /* Get max supported payload size */
+ devcap = pcic16_read(shbde, pci_dev, cap_base + PCI_EXP_DEVCAP);
+ max_cap = (devcap & 0x7);
+
+ /* Do not exceed device capabilities */
+ if (max_val > max_cap) {
+ max_val = max_cap;
+ LOG_DBG(shbde,
+ "Payload size exceeds device capability",
+ maxpayload);
+ }
+
+ /* Get currently set max payload size for the parent device
+ * in the PCI tree (if it exists).
+ */
+ parent_pci_dev = pci_parent_device_get(shbde, pci_dev);
+ if (parent_pci_dev != NULL) {
+ parent_cap_base = shbde_pci_pcie_cap(shbde, parent_pci_dev);
+ parent_devctl = pcic16_read(shbde,
+ parent_pci_dev,
+ parent_cap_base + PCI_EXP_DEVCTL);
+ parent_max_val = (parent_devctl >> 5) & 0x7;
+
+ /* Do not exceed current parent max payload setting (our device
+ * should have an MPS setting <= current parent MPS setting in
+ * the tree of PCIe devices).
+ */
+ if (max_val > parent_max_val) {
+ max_val = parent_max_val;
+ LOG_DBG(shbde,
+ "Payload size exceeds current parent device setting",
+ maxpayload);
+ }
+ }
+
+ /* Update max payload size */
+ devctl &= ~(0x7 << 5);
+ devctl |= (max_val) << 5;
+
+ /* Update max request size */
+ devctl &= ~(0x7 << 12);
+ devctl |= (max_val << 12);
+ }
+
+ /* Always disable relaxed ordering */
+ devctl &= ~(1 << 4);
+
+ /* Update device control settings */
+ pcic16_write(shbde, pci_dev, cap_base + PCI_EXP_DEVCTL, devctl);
+
+ /* Warn if non-default setting is used */
+ if (max_val > 0) {
+ LOG_WARN(shbde,
+ "Selected payload size may not be supported by all "
+ "PCIe bridges by default.",
+ (1 << (max_val + 7)));
+ }
+
+ return 0;
+}
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/Makefile
@@ -0,0 +1,31 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.10 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+# Makefile for SOC SAL support
+#
+LOCALDIR = systems/linux/kernel/modules
+
+include ${SDK}/make/Make.config
+
+subdirs=
+
+include ${SDK}/make/Make.subdirs
+
+include ${SDK}/make/Make.depend
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/Makefile
@@ -0,0 +1,64 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.3 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+LOCALDIR = systems/linux/kernel/modules/bcm-knet
+
+include ${SDK}/make/Make.config
+
+LIBS = $(LIBDIR)/libkern.a
+
+ifeq ($(kernel_version),2_4)
+MODULE = $(LIBDIR)/linux-bcm-knet.o
+else
+KERNEL_MODULE_DIR = kernel_module
+
+THIS_MOD_NAME := linux-bcm-knet
+MODULE = $(LIBDIR)/$(THIS_MOD_NAME).o
+KMODULE = $(LIBDIR)/$(THIS_MOD_NAME).ko
+
+build: $(MODULE) $(KMODULE)
+endif
+
+KBUILD_EXTRA_SYMBOLS := ${BLDDIR}/../../../../bde/linux/kernel/kernel_module/Module.symvers
+
+# BCM Network Device
+
+$(MODULE): $(BLDDIR)/.tree $(BOBJS) $(LIBS)
+ $(LD) $(MODULE_LDFLAGS) -r -d $(BOBJS) $(LIBS) -o $@
+ifneq ($(kernel_version),2_4)
+$(KMODULE): $(MODULE)
+ rm -fr $(BLDDIR)/$(KERNEL_MODULE_DIR)
+ mkdir $(BLDDIR)/$(KERNEL_MODULE_DIR)
+ cp ${SDK}/make/Makefile.linux-kmodule $(BLDDIR)/$(KERNEL_MODULE_DIR)/Makefile
+ cat ${KBUILD_EXTRA_SYMBOLS} > $(BLDDIR)/$(KERNEL_MODULE_DIR)/Module.symvers
+ MOD_NAME=$(THIS_MOD_NAME) $(MAKE) -C $(BLDDIR)/$(KERNEL_MODULE_DIR) $(THIS_MOD_NAME).ko
+endif
+
+# Make.depend is before clean:: so that Make.depend's clean:: runs first.
+
+include ${SDK}/make/Make.depend
+
+clean::
+ $(RM) $(BLDDIR)/version.c $(BLDDIR)/version.o
+ $(RM) $(BOBJS) $(MODULE)
+
+ifneq ($(kernel_version),2_4)
+.PHONY: build
+endif
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/bcm-knet/bcm-knet.c
@@ -0,0 +1,9034 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+
+/*
+ * This module implements a Linux network driver for Broadcom
+ * XGS switch devices. The driver simultaneously serves a
+ * number of vitual Linux network devices and a Tx/Rx API
+ * implemented in user space.
+ *
+ * Packets received from the switch device are sent to either
+ * a virtual Linux network device or the user mode Rx API
+ * based on a set of packet filters.susp
+ *
+ * Packets from the virtual Linux network devices and the user
+ * mode Tx API are multiplexed with priority given to the Tx API.
+ *
+ * A message-based IOCTL interface is used for managing packet
+ * filters and virtual Linux network interfaces.
+ *
+ * A virtual network interface can be configured to work in RCPU
+ * mode, which means that packets from the switch device will
+ * be encasulated with a RCPU header and a block of meta data
+ * that basically contains the core DCB information. Likewise,
+ * packets received from the Linux network stack are assumed to
+ * be RCPU encapsulated when going out on an interface in RCPU
+ * mode.
+ *
+ * The module implements basic Rx DMA rate control. The rate is
+ * specified in packets per second, and different Rx DMA channels
+ * can be configured to use different maximum packet rates.
+ * The packet rate can be configure as a module parameter, and
+ * it can also be changed dynamically through the proc file
+ * system (syntax is described in function header comment).
+ *
+ * To support multiple instance, each instance has its event queue.
+ *
+ * To support pci hot-plug in this module, the resource update
+ * should be handled when the PCI device is re-plugged.
+ * NOTE: the KNET detach should be invoked before removing the
+ * device.
+ *
+ * For a list of supported module parameters, please see below.
+ */
+
+#include <gmodule.h> /* Must be included first */
+#include <linux-bde.h>
+#include <kcom.h>
+#include <bcm-knet.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/random.h>
+#include <linux/seq_file.h>
+#include <linux/if_vlan.h>
+#include <linux/nsproxy.h>
+
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Network Device Driver for Broadcom BCM TxRx API");
+MODULE_LICENSE("GPL");
+
+static int debug;
+LKM_MOD_PARAM(debug, "i", int, 0);
+MODULE_PARM_DESC(debug,
+"Debug level (default 0)");
+
+static char *mac_addr = NULL;
+LKM_MOD_PARAM(mac_addr, "s", charp, 0);
+MODULE_PARM_DESC(mac_addr,
+"Ethernet MAC address (default 02:10:18:xx:xx:xx)");
+
+static int rx_buffer_size = 9216;
+LKM_MOD_PARAM(rx_buffer_size, "i", int, 0);
+MODULE_PARM_DESC(rx_buffer_size,
+"Size of RX packet buffers (default 9216)");
+
+static int default_mtu = 1500;
+LKM_MOD_PARAM(default_mtu, "i", int, 0);
+MODULE_PARM_DESC(default_mtu,
+"Default MTU for KNET network interfaces (default 1500)");
+
+static int rx_sync_retry = 1000;
+LKM_MOD_PARAM(rx_sync_retry, "i", int, 0);
+MODULE_PARM_DESC(rx_sync_retry,
+"Retries if chain is incomplete on interrupt (default 10)");
+
+static char *base_dev_name = NULL;
+LKM_MOD_PARAM(base_dev_name, "s", charp, 0);
+MODULE_PARM_DESC(base_dev_name,
+"Base device name (default bcm0, bcm1, etc.)");
+
+static int rcpu_mode = 0;
+LKM_MOD_PARAM(rcpu_mode, "i", int, 0);
+MODULE_PARM_DESC(rcpu_mode,
+"Enable RCPU encapsulation (default 0)");
+
+static char *rcpu_dmac = NULL;
+LKM_MOD_PARAM(rcpu_dmac, "s", charp, 0);
+MODULE_PARM_DESC(rcpu_dmac,
+"RCPU destination MAC address (by default use L2 destination MAC address)");
+
+static char *rcpu_smac = NULL;
+LKM_MOD_PARAM(rcpu_smac, "s", charp, 0);
+MODULE_PARM_DESC(rcpu_smac,
+"RCPU source MAC address (by default use L2 source MAC address)");
+
+static int rcpu_ethertype = 0xde08;
+LKM_MOD_PARAM(rcpu_ethertype, "i", int, 0);
+MODULE_PARM_DESC(rcpu_ethertype,
+"RCPU EtherType (default DE08h)");
+
+static int rcpu_signature = 0;
+LKM_MOD_PARAM(rcpu_signature, "i", int, 0);
+MODULE_PARM_DESC(rcpu_signature,
+"RCPU Signature (default is PCI device ID)");
+
+static int rcpu_vlan = 1;
+LKM_MOD_PARAM(rcpu_vlan, "i", int, 0);
+MODULE_PARM_DESC(rcpu_vlan,
+"RCPU VLAN ID (default 1)");
+
+static int use_rx_skb = 0;
+LKM_MOD_PARAM(use_rx_skb, "i", int, 0);
+MODULE_PARM_DESC(use_rx_skb,
+"Use socket buffers for receive operation (default 0)");
+
+static int num_rx_prio = 1;
+LKM_MOD_PARAM(num_rx_prio, "i", int, 0);
+MODULE_PARM_DESC(num_rx_prio,
+"Number of filter priorities per Rx DMA channel");
+
+static int rx_rate[8] = { 100000, 100000, 100000, 100000, 100000, 100000, 100000, 0 };
+LKM_MOD_PARAM_ARRAY(rx_rate, "1-4i", int, NULL, 0);
+MODULE_PARM_DESC(rx_rate,
+"Rx rate in packets per second (default 100000)");
+
+static int rx_burst[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+LKM_MOD_PARAM_ARRAY(rx_burst, "1-4i", int, NULL, 0);
+MODULE_PARM_DESC(rx_burst,
+"Rx rate burst maximum in packets (default rx_rate/10)");
+
+static int check_rcpu_signature = 0;
+LKM_MOD_PARAM(check_rcpu_signature, "i", int, 0);
+MODULE_PARM_DESC(check_rcpu_signature,
+"Check RCPU Signature for Tx packets from RCPU interfaces");
+
+static int basedev_suspend = 0;
+LKM_MOD_PARAM(basedev_suspend, "i", int, 0);
+MODULE_PARM_DESC(basedev_suspend,
+"Pause traffic till base device is up (enabled by default in NAPI mode)");
+
+/*
+ * Force to add one layer of VLAN tag to untagged packets on Dune devices
+ */
+static int force_tagged = 1;
+LKM_MOD_PARAM(force_tagged, "i", int, 0);
+MODULE_PARM_DESC(force_tagged,
+"Always tagged with VLAN tag with spceified VID or VSI(default 1)");
+
+static int ft_tpid=0x8100;
+LKM_MOD_PARAM(ft_tpid, "i", int, 0);
+MODULE_PARM_DESC(ft_tpid,
+"Tag Protocol Identifier (TPID) indicates the frame type (default 0x8100)");
+
+static int ft_pri=0;
+LKM_MOD_PARAM(ft_pri, "i", int, 0);
+MODULE_PARM_DESC(ft_cfi,
+"Priority (PRI) indicates the frame priority (default 0)");
+
+static int ft_cfi=0;
+LKM_MOD_PARAM(ft_cfi, "i", int, 0);
+MODULE_PARM_DESC(ft_cfi,
+"Canonical Format Indicator (CFI) indicates whether a MAC address is encapsulated in canonical format over different transmission media (default 0)");
+
+static int ft_vid=0;
+LKM_MOD_PARAM(ft_vid, "i", int, 0);
+MODULE_PARM_DESC(ft_vid,
+"VLAN ID (VID) indicates the VLAN to which a frame belongs (default 0)");
+
+
+/* Debug levels */
+#define DBG_LVL_VERB 0x1
+#define DBG_LVL_DCB 0x2
+#define DBG_LVL_PKT 0x4
+#define DBG_LVL_SKB 0x8
+#define DBG_LVL_CMD 0x10
+#define DBG_LVL_EVT 0x20
+#define DBG_LVL_IRQ 0x40
+#define DBG_LVL_NAPI 0x80
+#define DBG_LVL_PDMP 0x100
+#define DBG_LVL_FLTR 0x200
+#define DBG_LVL_KCOM 0x400
+#define DBG_LVL_RCPU 0x800
+#define DBG_LVL_WARN 0x1000
+#define DBG_LVL_NDEV 0x2000
+#define DBG_LVL_INST 0x4000
+/* Level to output Dune internal headers Parsing */
+#define DBG_LVL_DUNE 0x8000
+#define DBG_LVL_DCB_TX 0x10000
+#define DBG_LVL_DCB_RX 0x20000
+#define DBG_LVL_PDMP_TX 0x40000
+#define DBG_LVL_PDMP_RX 0x80000
+
+#define DBG_VERB(_s) do { if (debug & DBG_LVL_VERB) gprintk _s; } while (0)
+#define DBG_PKT(_s) do { if (debug & DBG_LVL_PKT) gprintk _s; } while (0)
+#define DBG_SKB(_s) do { if (debug & DBG_LVL_SKB) gprintk _s; } while (0)
+#define DBG_CMD(_s) do { if (debug & DBG_LVL_CMD) gprintk _s; } while (0)
+#define DBG_EVT(_s) do { if (debug & DBG_LVL_EVT) gprintk _s; } while (0)
+#define DBG_IRQ(_s) do { if (debug & DBG_LVL_IRQ) gprintk _s; } while (0)
+#define DBG_NAPI(_s) do { if (debug & DBG_LVL_NAPI) gprintk _s; } while (0)
+#define DBG_PDMP(_s) do { if (debug & DBG_LVL_PDMP) gprintk _s; } while (0)
+#define DBG_FLTR(_s) do { if (debug & DBG_LVL_FLTR) gprintk _s; } while (0)
+#define DBG_KCOM(_s) do { if (debug & DBG_LVL_KCOM) gprintk _s; } while (0)
+#define DBG_RCPU(_s) do { if (debug & DBG_LVL_RCPU) gprintk _s; } while (0)
+#define DBG_WARN(_s) do { if (debug & DBG_LVL_WARN) gprintk _s; } while (0)
+#define DBG_NDEV(_s) do { if (debug & DBG_LVL_NDEV) gprintk _s; } while (0)
+#define DBG_INST(_s) do { if (debug & DBG_LVL_INST) gprintk _s; } while (0)
+#define DBG_DUNE(_s) do { if (debug & DBG_LVL_DUNE) gprintk _s; } while (0)
+#define DBG_DCB_TX(_s) do { if (debug & (DBG_LVL_DCB|DBG_LVL_DCB_TX)) \
+ gprintk _s; } while (0)
+#define DBG_DCB_RX(_s) do { if (debug & (DBG_LVL_DCB|DBG_LVL_DCB_RX)) \
+ gprintk _s; } while (0)
+#define DBG_DCB(_s) do { if (debug & (DBG_LVL_DCB|DBG_LVL_DCB_TX| \
+ DBG_LVL_DCB_RX)) \
+ gprintk _s; } while (0)
+
+
+/* This flag is used to indicate if debugging packet function is open or closed */
+static int dbg_pkt_enable = 0;
+
+/* Module Information */
+#define MODULE_MAJOR 122
+#define MODULE_NAME "linux-bcm-knet"
+
+#ifndef NAPI_SUPPORT
+#define NAPI_SUPPORT 1
+#endif
+
+#if NAPI_SUPPORT
+
+static int use_napi = 0;
+LKM_MOD_PARAM(use_napi, "i", int, 0);
+MODULE_PARM_DESC(use_napi,
+"Use NAPI interface (default 0)");
+
+static int napi_weight = 64;
+LKM_MOD_PARAM(napi_weight, "i", int, 0);
+MODULE_PARM_DESC(napi_weight,
+"Weight of NAPI interfaces (default 64)");
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+#define bkn_napi_enable(_dev, _napi) netif_poll_enable(_dev)
+#define bkn_napi_disable(_dev, _napi) netif_poll_disable(_dev)
+#define bkn_napi_schedule(_dev, _napi) netif_rx_schedule(_dev)
+#define bkn_napi_schedule_prep(_dev, _napi) netif_rx_schedule_prep(_dev)
+#define __bkn_napi_schedule(_dev, _napi) __netif_rx_schedule(_dev)
+#define bkn_napi_complete(_dev, _napi) netif_rx_complete(_dev)
+#else
+#define bkn_napi_enable(_dev, _napi) napi_enable(_napi)
+#define bkn_napi_disable(_dev, _napi) napi_disable(_napi)
+#define bkn_napi_schedule(_dev, _napi) napi_schedule(_napi)
+#define bkn_napi_schedule_prep(_dev, _napi) napi_schedule_prep(_napi)
+#define __bkn_napi_schedule(_dev, _napi) __napi_schedule(_napi)
+#define bkn_napi_complete(_dev, _napi) napi_complete(_napi)
+#endif
+
+#else
+
+static int use_napi = 0;
+static int napi_weight = 0;
+
+#define bkn_napi_enable(_dev, _napi)
+#define bkn_napi_disable(_dev, _napi)
+#define bkn_napi_schedule(_dev, _napi)
+#define bkn_napi_schedule_prep(_dev, _napi) (0)
+#define __bkn_napi_schedule(_dev, _napi)
+#define bkn_napi_complete(_dev, _napi)
+
+#endif
+
+/* Compatibility */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0))
+#define NETDEV_UPDATE_TRANS_START_TIME(dev) dev->trans_start = jiffies
+#else
+#define NETDEV_UPDATE_TRANS_START_TIME(dev) netif_trans_update(dev)
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
+#define skb_copy_to_linear_data(_skb, _pkt, _len) \
+ eth_copy_and_sum(_skb, _pkt, _len, 0)
+struct napi_struct { int not_used; };
+#define netif_napi_add(_dev, _napi, _poll, _weight) do { \
+ (_dev)->poll = _poll; \
+ (_dev)->weight = _weight; \
+} while(0)
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
+#define SKB_PADTO(_skb,_len) (((_skb = skb_padto(_skb,_len)) == NULL) ? -1 : 0)
+#else
+#define SKB_PADTO(_skb,_len) skb_padto(_skb,_len)
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12))
+#define skb_header_cloned(_skb) \
+ skb_cloned(_skb)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27)
+static inline void *netdev_priv(struct net_device *dev)
+{
+ return dev->priv;
+}
+#endif /* KERNEL_VERSION(2,4,27) */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23)
+/* Special check for MontaVista 2.4.20 MIPS */
+#if !(defined(MAX_USER_RT_PRIO) && defined(CONFIG_MIPS))
+static inline void free_netdev(struct net_device *dev)
+{
+ kfree(dev);
+}
+#endif
+static inline void netif_poll_disable(struct net_device *dev)
+{
+ while (test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state)) {
+ /* No hurry. */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+}
+static inline void netif_poll_enable(struct net_device *dev)
+{
+ clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
+}
+#endif /* KERNEL_VERSION(2,4,23) */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21)
+static struct sk_buff *skb_pad(struct sk_buff *skb, int pad)
+{
+ struct sk_buff *nskb;
+
+ /* If the skbuff is non linear tailroom is always zero.. */
+ if(skb_tailroom(skb) >= pad)
+ {
+ memset(skb->data+skb->len, 0, pad);
+ return skb;
+ }
+
+ nskb = skb_copy_expand(skb, skb_headroom(skb), skb_tailroom(skb) + pad, GFP_ATOMIC);
+ kfree_skb(skb);
+ if(nskb)
+ memset(nskb->data+nskb->len, 0, pad);
+ return nskb;
+}
+static inline struct sk_buff *skb_padto(struct sk_buff *skb, unsigned int len)
+{
+ unsigned int size = skb->len;
+ if(likely(size >= len))
+ return skb;
+ return skb_pad(skb, len-size);
+}
+#endif /* KERNEL_VERSION(2,4,21) */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
+#define bkn_vlan_hwaccel_put_tag(_skb, _proto, _tci) \
+ __vlan_hwaccel_put_tag(_skb, _tci)
+#else
+#define bkn_vlan_hwaccel_put_tag(_skb, _proto, _tci) \
+ __vlan_hwaccel_put_tag(_skb, htons(_proto), _tci)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)
+#define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
+#define bkn_dma_mapping_error(d, a) \
+ dma_mapping_error(a)
+#define bkn_pci_dma_mapping_error(d, a) \
+ pci_dma_mapping_error(a)
+#else
+#define bkn_dma_mapping_error(d, a) \
+ dma_mapping_error(d, a)
+#define bkn_pci_dma_mapping_error(d, a) \
+ pci_dma_mapping_error(d, a)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+enum hwtstamp_tx_types {
+ HWTSTAMP_TX_OFF,
+ HWTSTAMP_TX_ON,
+ HWTSTAMP_TX_ONESTEP_SYNC
+};
+enum {
+ SKBTX_HW_TSTAMP = 1 << 0,
+ SKBTX_SW_TSTAMP = 1 << 1,
+ SKBTX_IN_PROGRESS = 1 << 2,
+};
+struct skb_shared_hwtstamps {
+ ktime_t hwtstamp;
+ ktime_t syststamp;
+};
+struct bkn_skb_shared_info {
+ uint8_t tx_flags;
+ struct skb_shared_hwtstamps hwtstamps;
+};
+#define bkn_skb_shinfo(_skb) ((struct bkn_skb_shared_info *)(unsigned char *)_skb->end)
+#define bkn_skb_tx_flags(_skb) bkn_skb_shinfo(_skb)->tx_flags
+static inline struct skb_shared_hwtstamps *skb_hwtstamps(struct sk_buff *skb)
+{
+ return &bkn_skb_shinfo(skb)->hwtstamps;
+}
+void skb_tstamp_tx(struct sk_buff *orig_skb, struct skb_shared_hwtstamps *hwtstamps)
+{
+}
+static inline void bkn_skb_tx_timestamp(struct sk_buff *skb)
+{
+}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+static inline ktime_t ns_to_ktime(u64 ns)
+{
+ static const ktime_t ktime;
+ return ktime;
+}
+#endif
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+#include <linux/net_tstamp.h>
+#define HWTSTAMP_TX_ONESTEP_SYNC 2
+enum {
+ SKBTX_HW_TSTAMP = 1 << 0,
+ SKBTX_SW_TSTAMP = 1 << 1,
+ SKBTX_IN_PROGRESS = 1 << 2,
+};
+#define bkn_skb_tx_flags(_skb) skb_shinfo(_skb)->tx_flags.flags
+static inline void bkn_skb_tx_timestamp(struct sk_buff *skb)
+{
+}
+#else
+#include <linux/net_tstamp.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0)
+#define HWTSTAMP_TX_ONESTEP_SYNC 2
+#endif
+
+#define bkn_skb_tx_flags(_skb) skb_shinfo(_skb)->tx_flags
+static inline void bkn_skb_tx_timestamp(struct sk_buff *skb)
+{
+ return skb_tx_timestamp(skb);
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+#define bkn_dev_net_set(dev, net)
+#else
+#define bkn_dev_net_set(dev, net) dev_net_set(dev, net)
+#endif
+
+#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT
+#define BKN_DMA_DEV device
+#define BKN_DMA_FROMDEV DMA_FROM_DEVICE
+#define BKN_DMA_TODEV DMA_TO_DEVICE
+#define BKN_DMA_MAP_SINGLE(d,p,s,r) dma_map_single(d,p,s,r)
+#define BKN_DMA_UNMAP_SINGLE(d,a,s,r) dma_unmap_single(d,a,s,r)
+#define BKN_DMA_ALLOC_COHERENT(d,s,h) dma_alloc_coherent(d,s,h,GFP_ATOMIC|GFP_DMA32)
+#define BKN_DMA_FREE_COHERENT(d,s,a,h) dma_free_coherent(d,s,a,h)
+#define BKN_DMA_MAPPING_ERROR(d,a) bkn_dma_mapping_error(d,a)
+#else
+#define BKN_DMA_DEV pci_dev
+#define BKN_DMA_FROMDEV PCI_DMA_FROMDEVICE
+#define BKN_DMA_TODEV PCI_DMA_TODEVICE
+#define BKN_DMA_MAP_SINGLE(d,p,s,r) pci_map_single(d,p,s,r)
+#define BKN_DMA_UNMAP_SINGLE(d,a,s,r) pci_unmap_single(d,a,s,r)
+#define BKN_DMA_ALLOC_COHERENT(d,s,h) pci_alloc_consistent(d,s,h)
+#define BKN_DMA_FREE_COHERENT(d,s,a,h) pci_free_consistent(d,s,a,h)
+#define BKN_DMA_MAPPING_ERROR(d,a) bkn_pci_dma_mapping_error(d,a)
+#endif
+
+/*
+ * Get a 16-bit value from packet offset
+ * _data Pointer to packet
+ * _offset Offset
+ */
+#define PKT_U16_GET(_data, _offset) \
+ (uint16_t)(_data[_offset] << 8 | _data[_offset + 1])
+
+
+/* RCPU operations */
+#define RCPU_OPCODE_RX 0x10
+#define RCPU_OPCODE_TX 0x20
+
+/* RCPU flags */
+#define RCPU_F_MODHDR 0x4
+
+/* RCPU encapsulation */
+#define RCPU_HDR_SIZE 32
+#define RCPU_TX_META_SIZE 32
+#define RCPU_TX_ENCAP_SIZE (RCPU_HDR_SIZE + RCPU_TX_META_SIZE)
+#define RCPU_RX_META_SIZE 64
+#define RCPU_RX_ENCAP_SIZE (RCPU_HDR_SIZE + RCPU_RX_META_SIZE)
+
+#define PKT_TX_HDR_SIZE 16
+
+static volatile int module_initialized;
+
+static ibde_t *kernel_bde = NULL;
+
+/* Descriptor info */
+typedef struct bkn_desc_info_s {
+ uint32_t *dcb_mem;
+ uint64_t dcb_dma;
+ struct sk_buff *skb;
+ uint64_t skb_dma;
+ uint32_t dma_size;
+} bkn_desc_info_t;
+
+/* DCB chain info */
+typedef struct bkn_dcb_chain_s {
+ struct list_head list;
+ int dcb_cnt;
+ int dcb_cur;
+ uint32_t *dcb_mem;
+ uint64_t dcb_dma;
+} bkn_dcb_chain_t;
+
+#define MAX_TX_DCBS 64
+#define MAX_RX_DCBS 64
+
+#define NUM_DMA_CHAN 8
+#define NUM_RX_CHAN 7
+#define NUM_CMICX_RX_CHAN 7
+#define NUM_CMICM_RX_CHAN 3
+
+#define FCS_SZ 4
+#define TAG_SZ 4
+
+/* Device control info */
+typedef struct bkn_switch_info_s {
+ struct list_head list;
+ struct list_head ndev_list; /* Associated virtual Ethernet interfaces */
+ struct net_device **ndevs; /* Indexed array of ndev_list */
+ int ndev_max; /* Size of indexed array */
+ struct list_head rxpf_list; /* Associated Rx packet filters */
+ volatile void *base_addr; /* Base address for PCI register access */
+ struct BKN_DMA_DEV *dma_dev; /* Required for DMA memory control */
+ struct pci_dev *pdev; /* Required for DMA memory control */
+ struct net_device *dev; /* Base network device */
+ struct napi_struct napi; /* New NAPI */
+ struct timer_list timer; /* Retry/resource timer */
+ int timer_queued; /* Flag indicating queued timer function */
+ uint32_t timer_runs; /* Timer function runs (debug only) */
+ struct timer_list rxtick; /* Rx rate control timer */
+ uint32_t rxticks_per_sec; /* Rx rate control update frequency */
+ uint32_t rxtick_jiffies; /* Time between updates (in jiffies) */
+ uint32_t rxticks; /* Rx rate control debug counter */
+ uint32_t interrupts; /* Total number of interrupts */
+ spinlock_t lock; /* Main lock for device */
+ int dev_no; /* Device number (from BDE) */
+ int cpu_no; /* Cpu number. 1 for iHost(AXI),0 for others */
+ int dcb_type; /* DCB type */
+ int dcb_wsize; /* DCB size (in 32-bit words) */
+ int pkt_hdr_size; /* Packet header size */
+ uint32_t ftmh_lb_key_ext_size; /* FTMH LB-Key Extension existence/size */
+ uint32_t ftmh_stacking_ext_size; /* FTMH Stacking extension existence/size */
+ uint32_t pph_base_size; /* Size of PPH base */
+ uint32_t pph_lif_ext_size[8]; /* Size of PPH Lif extension header */
+ uint32_t udh_length_type[4]; /* Size of UDH header per type */
+ uint32_t udh_size; /* Size of UDH header on legacy devices */
+ uint32_t oamp_punt; /* OAMP port if nonzero */
+ uint8_t no_skip_udh_check; /* Indicates UDH won't be skipped */
+ uint8_t system_headers_mode; /* Indicates system header mode */
+ uint8_t udh_enable; /* Indicates UDH existence */
+ int rx_chans; /* Number of Rx channels */
+ uint32_t dma_hi; /* DMA higher address */
+ uint32_t cmic_type; /* CMIC type (CMICe or CMICm) */
+ uint32_t irq_mask; /* Active IRQs for DMA control */
+ uint32_t napi_poll_mode; /* NAPI is in polling mode */
+ uint32_t napi_not_done; /* NAPI poll did not process all packets */
+ uint32_t napi_poll_again; /* Used if DCB chain is restarted */
+ uint32_t tx_yield; /* Tx schedule for Continuous DMA and Non-NAPI mode */
+ void *dcb_mem; /* Logical pointer to DCB memory */
+ uint64_t dcb_dma; /* Physical bus address for DCB memory */
+ int dcb_mem_size; /* Total size of allocated DCB memory */
+ uint32_t dma_events; /* DMA events pending for BCM API */
+ uint32_t rcpu_sig; /* RCPU signature */
+ uint64_t halt_addr[NUM_DMA_CHAN]; /* DMA halt address */
+ uint32_t cdma_channels; /* Active channels for Continuous DMA mode */
+ uint32_t poll_channels; /* Channels for polling */
+ uint32_t inst_id; /* Instance id of this device */
+ int evt_idx; /* Event queue index for this device*/
+ int basedev_suspended; /* Base device suspended */
+ struct sk_buff_head tx_ptp_queue; /* Tx PTP skb queue */
+ struct work_struct tx_ptp_work; /* Tx PTP work */
+ struct {
+ bkn_desc_info_t desc[MAX_TX_DCBS+1];
+ int free; /* Number of free Tx DCBs */
+ int cur; /* Index of current Tx DCB */
+ int dirty; /* Index of next Tx DCB to complete */
+ int api_active; /* BCM Tx API is in progress */
+ int suspends; /* Calls to netif_stop_queue (debug only) */
+ struct list_head api_dcb_list; /* Tx DCB chains from BCM Tx API */
+ bkn_dcb_chain_t *api_dcb_chain; /* Current Tx DCB chain */
+ bkn_dcb_chain_t *api_dcb_chain_end; /* Tx DCB chain end */
+ uint32_t pkts; /* Tx packet counter */
+ uint32_t pkts_d_no_skb; /* Tx drop - skb allocation failed */
+ uint32_t pkts_d_rcpu_encap; /* Tx drop - bad RCPU encapsulation */
+ uint32_t pkts_d_rcpu_sig; /* Tx drop - bad RCPU signature */
+ uint32_t pkts_d_rcpu_meta; /* Tx drop - bad RCPU meta data */
+ uint32_t pkts_d_pad_fail; /* Tx drop - pad to minimum size failed */
+ uint32_t pkts_d_dma_resrc; /* Tx drop - no DMA resources */
+ uint32_t pkts_d_callback; /* Tx drop - consumed by call-back */
+ uint32_t pkts_d_no_link; /* Tx drop - software link down */
+ uint32_t pkts_d_over_limit; /* Tx drop - length is out of range */
+ } tx;
+ struct {
+ bkn_desc_info_t desc[MAX_RX_DCBS+1];
+ int free; /* Number of free Rx DCBs */
+ int cur; /* Index of current Rx DCB */
+ int dirty; /* Index of next Rx DCB to complete */
+ int running; /* Rx DMA is active */
+ int api_active; /* BCM Rx API is active */
+ int chain_complete; /* All DCBs in chain processed */
+ int sync_err; /* Chain done with incomplete DCBs (debug) */
+ int sync_retry; /* Total retry times for sync error (debug) */
+ int sync_maxloop; /* Max loop times once in recovering sync (debug) */
+ int use_rx_skb; /* Use SKBs for DMA */
+ uint32_t rate_max; /* Rx rate in packets/sec */
+ uint32_t burst_max; /* Rx burst size in number of packets */
+ uint32_t tokens; /* Tokens for Rx rate control */
+ uint32_t rate; /* Current packet rate */
+ unsigned long tok_jif; /* Jiffies at last token update */
+ unsigned long rate_jif; /* Jiffies at last rate update */
+ struct list_head api_dcb_list; /* Rx DCB chains from BCM Rx API */
+ bkn_dcb_chain_t *api_dcb_chain; /* Current Rx DCB chain */
+ bkn_dcb_chain_t *api_dcb_chain_end; /* Rx DCB chain end */
+ uint32_t pkts; /* Rx packet counter */
+ uint32_t pkts_ref; /* Rx packet count for rate calculation */
+ uint32_t pkts_f_api; /* Rx packets filtered to API */
+ uint32_t pkts_f_netif; /* Rx packets filtered to net interface */
+ uint32_t pkts_m_api; /* Rx packets mirrored to API */
+ uint32_t pkts_m_netif; /* Rx packets mirrored to net interface */
+ uint32_t pkts_d_no_skb; /* Rx drop - skb allocation failed */
+ uint32_t pkts_d_no_match; /* Rx drop - no matching filters */
+ uint32_t pkts_d_unkn_netif; /* Rx drop - unknown net interface ID */
+ uint32_t pkts_d_unkn_dest; /* Rx drop - unknown destination type */
+ uint32_t pkts_d_callback; /* Rx drop - consumed by call-back */
+ uint32_t pkts_d_no_link; /* Rx drop - software link down */
+ uint32_t pkts_d_no_api_buf; /* Rx drop - no API buffers */
+ } rx[NUM_RX_CHAN];
+} bkn_switch_info_t;
+
+/* 0x1 - Jericho 2 mode */
+#define BKN_DNX_JR2_MODE 1
+/* PTCH_2 */
+#define BKN_DNX_PTCH_2_SIZE 2
+/* ITMH */
+#define BKN_DNX_ITMH_SIZE 5
+/* Modlue Header */
+#define BKN_DNX_MODULE_HEADER_SIZE 20
+/* FTMH */
+#define BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_MSB 17
+#define BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_NOF_BITS 16
+#define BKN_DNX_FTMH_PP_DSP_MSB 33
+#define BKN_DNX_FTMH_PP_DSP_NOF_BITS 8
+#define BKN_DNX_FTMH_ACTION_TYPE_MSB 43
+#define BKN_DNX_FTMH_ACTION_TYPE_NOF_BITS 2
+#define BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_MSB 73
+#define BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_NOF_BITS 1
+#define BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_MSB 74
+#define BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_NOF_BITS 1
+#define BKN_DNX_FTMH_TM_DST_EXT_PRESENT_MSB 75
+#define BKN_DNX_FTMH_TM_DST_EXT_PRESENT_NOF_BITS 1
+#define BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_MSB 76
+#define BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_NOF_BITS 1
+#define BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_MSB 77
+#define BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_NOF_BITS 1
+#define BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_MSB 78
+#define BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_NOF_BITS 1
+/* Fix Length for FTMH and Extension headers */
+#define BKN_DNX_FTMH_BASE_SIZE 10
+#define BKN_DNX_FTMH_BIER_BFR_EXT_SIZE 2
+#define BKN_DNX_FTMH_TM_DST_EXT_SIZE 3
+#define BKN_DNX_FTMH_FLOW_ID_EXT_SIZE 3
+#define BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE 6
+/* TSH */
+#define BKN_DNX_TSH_SIZE 4
+/* PPH */
+#define BKN_DNX_INTERNAL_BASE_TYPE_9 9
+#define BKN_DNX_INTERNAL_BASE_TYPE_10 10
+#define BKN_DNX_INTERNAL_BASE_TYPE_12 12
+#define BKN_DNX_INTERNAL_9_FORWARD_DOMAIN_MSB 5
+#define BKN_DNX_INTERNAL_9_FORWARD_DOMAIN_NOF_BITS 16
+#define BKN_DNX_INTERNAL_9_LEARN_EXT_PRESENT_MSB 53
+#define BKN_DNX_INTERNAL_9_LEARN_EXT_PRESENT_NOF_BITS 1
+#define BKN_DNX_INTERNAL_9_FHEI_SIZE_MSB 54
+#define BKN_DNX_INTERNAL_9_FHEI_SIZE_NOF_BITS 2
+#define BKN_DNX_INTERNAL_9_LIF_EXT_TYPE_MSB 56
+#define BKN_DNX_INTERNAL_9_LIF_EXT_TYPE_NOF_BITS 3
+#define BKN_DNX_INTERNAL_10_FORWARD_DOMAIN_MSB 9
+#define BKN_DNX_INTERNAL_10_FORWARD_DOMAIN_NOF_BITS 16
+#define BKN_DNX_INTERNAL_10_LEARN_EXT_PRESENT_MSB 61
+#define BKN_DNX_INTERNAL_10_LEARN_EXT_PRESENT_NOF_BITS 1
+#define BKN_DNX_INTERNAL_10_FHEI_SIZE_MSB 62
+#define BKN_DNX_INTERNAL_10_FHEI_SIZE_NOF_BITS 2
+#define BKN_DNX_INTERNAL_10_LIF_EXT_TYPE_MSB 64
+#define BKN_DNX_INTERNAL_10_LIF_EXT_TYPE_NOF_BITS 3
+#define BKN_DNX_INTERNAL_12_FORWARD_DOMAIN_MSB 21
+#define BKN_DNX_INTERNAL_12_FORWARD_DOMAIN_NOF_BITS 18
+#define BKN_DNX_INTERNAL_12_LEARN_EXT_PRESENT_MSB 77
+#define BKN_DNX_INTERNAL_12_LEARN_EXT_PRESENT_NOF_BITS 1
+#define BKN_DNX_INTERNAL_12_FHEI_SIZE_MSB 78
+#define BKN_DNX_INTERNAL_12_FHEI_SIZE_NOF_BITS 2
+#define BKN_DNX_INTERNAL_12_LIF_EXT_TYPE_MSB 80
+#define BKN_DNX_INTERNAL_12_LIF_EXT_TYPE_NOF_BITS 3
+/* PPH.FHEI_TYPE */
+#define BKN_DNX_INTERNAL_FHEI_TYPE_SZ0 1
+#define BKN_DNX_INTERNAL_FHEI_TYPE_SZ1 2
+#define BKN_DNX_INTERNAL_FHEI_TYPE_SZ2 3
+/* FHEI */
+#define BKN_DNX_INTERNAL_FHEI_SZ0_SIZE 3
+#define BKN_DNX_INTERNAL_FHEI_SZ1_SIZE 5
+#define BKN_DNX_INTERNAL_FHEI_SZ2_SIZE 8
+#define BKN_DNX_INTERNAL_FHEI_TRAP_5B_QUALIFIER_MSB 0
+#define BKN_DNX_INTERNAL_FHEI_TRAP_5B_QUALIFIER_NOF_BITS 27
+#define BKN_DNX_INTERNAL_FHEI_TRAP_5B_CODE_MSB 27
+#define BKN_DNX_INTERNAL_FHEI_TRAP_5B_CODE_NOF_BITS 9
+#define BKN_DNX_INTERNAL_FHEI_TRAP_5B_TYPE_MSB 36
+#define BKN_DNX_INTERNAL_FHEI_TRAP_5B_TYPE_NOF_BITS 4
+/* PPH Extension */
+#define BKN_DNX_INTERNAL_LEARN_EXT_SIZE 19
+/* UDH */
+#define BKN_DNX_UDH_DATA_TYPE_0_MSB 0
+#define BKN_DNX_UDH_DATA_TYPE_0_NOF_BITS 2
+#define BKN_DNX_UDH_DATA_TYPE_1_MSB 2
+#define BKN_DNX_UDH_DATA_TYPE_1_NOF_BITS 2
+#define BKN_DNX_UDH_DATA_TYPE_2_MSB 4
+#define BKN_DNX_UDH_DATA_TYPE_2_NOF_BITS 2
+#define BKN_DNX_UDH_DATA_TYPE_3_MSB 6
+#define BKN_DNX_UDH_DATA_TYPE_3_NOF_BITS 2
+#define BKN_DNX_UDH_BASE_SIZE 1
+
+#define BKN_DPP_HDR_MAX_SIZE 40
+/* PTCH_2 */
+#define BKN_DPP_PTCH_2_SIZE 2
+/* ITMH */
+#define BKN_DPP_ITMH_SIZE 4
+/* FTMH */
+#define BKN_DPP_FTMH_LB_EXT_EN 0x1
+#define BKN_DPP_FTMH_STACKING_EXT_EN 0x2
+#define BKN_DPP_FTMH_SIZE_BYTE 9
+#define BKN_DPP_FTMH_LB_EXT_SIZE_BYTE 1
+#define BKN_DPP_FTMH_STACKING_SIZE_BYTE 2
+#define BKN_DPP_FTMH_DEST_EXT_SIZE_BYTE 2
+#define BKN_DPP_FTMH_LB_EXT_SIZE_BYTE 1
+#define BKN_DPP_FTMH_PKT_SIZE_MSB 0
+#define BKN_DPP_FTMH_PKT_SIZE_NOF_BITS 14
+#define BKN_DPP_FTMH_TC_MSB 14
+#define BKN_DPP_FTMH_TC_NOF_BITS 3
+#define BKN_DPP_FTMH_SRC_SYS_PORT_MSB 17
+#define BKN_DPP_FTMH_SRC_SYS_PORT_NOF_BITS 16
+#define BKN_DPP_FTMH_EXT_DSP_EXIST_MSB 68
+#define BKN_DPP_FTMH_EXT_DSP_EXIST_NOF_BITS 1
+#define BKN_DPP_FTMH_EXT_MSB 45
+#define BKN_DPP_FTMH_EXT_NOF_BITS 2
+#define BKN_DPP_FTMH_FIRST_EXT_MSB 72
+#define BKN_DPP_FTMH_ACTION_TYPE_MSB 43
+#define BKN_DPP_FTMH_ACTION_TYPE_NOF_BITS 2
+#define BKN_DPP_FTMH_PPH_TYPE_MSB 45
+#define BKN_DPP_FTMH_PPH_TYPE_NOF_BITS 2
+
+/* OTSH */
+#define BKN_DPP_OTSH_SIZE_BYTE 6
+#define BKN_DPP_OTSH_TYPE_MSB 0
+#define BKN_DPP_OTSH_TYPE_NOF_BITS 2
+#define BKN_DPP_OTSH_OAM_SUB_TYPE_MSB 2
+#define BKN_DPP_OTSH_OAM_SUB_TYPE_NOF_BITS 3
+
+#define BKN_DPP_OTSH_TYPE_OAM 0
+#define BKN_DPP_OTSH_OAM_SUB_TYPE_DM_1588 2
+#define BKN_DPP_OTSH_OAM_SUB_TYPE_DM_NTP 3
+
+#define BKN_DPP_OAM_DM_TOD_SIZE_BYTE 4
+
+/* PPH */
+#define BKN_DPP_INTERNAL_SIZE_BYTE 7
+#define BKN_DPP_INTERNAL_EEI_EXTENSION_PRESENT_MSB 0
+#define BKN_DPP_INTERNAL_EEI_EXTENSION_PRESENT_NOF_BITS 1
+#define BKN_DPP_INTERNAL_LEARN_EXENSION_PRESENT_MSB 1
+#define BKN_DPP_INTERNAL_LEARN_EXENSION_PRESENT_NOF_BITS 1
+#define BKN_DPP_INTERNAL_FHEI_SIZE_MSB 2
+#define BKN_DPP_INTERNAL_FHEI_SIZE_NOF_BITS 2
+#define BKN_DPP_INTERNAL_FORWARD_CODE_MSB 4
+#define BKN_DPP_INTERNAL_FORWARD_CODE_NOF_BITS 4
+#define BKN_DPP_INTERNAL_FORWARD_CODE_CPU_TRAP 7
+#define BKN_DPP_INTERNAL_FORWARDING_HEADER_OFFSET_MSB 8
+#define BKN_DPP_INTERNAL_FORWARDING_HEADER_OFFSET_NOF_BITS 7
+#define BKN_DPP_INTERNAL_VSI_MSB 22
+#define BKN_DPP_INTERNAL_VSI_NOF_BITS 16
+
+/* FHEI TRAP/SNOOP 3B */
+#define BKN_DPP_INTERNAL_FHEI_3B_SIZE_BYTE 3
+#define BKN_DPP_INTERNAL_FHEI_5B_SIZE_BYTE 5
+#define BKN_DPP_INTERNAL_FHEI_8B_SIZE_BYTE 8
+#define BKN_DPP_INTERNAL_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_MSB 0
+#define BKN_DPP_INTERNAL_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_NOF_BITS 16
+#define BKN_DPP_INTERNAL_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_MSB 16
+#define BKN_DPP_INTERNAL_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_NOF_BITS 8
+/* PPH extension */
+#define BKN_DPP_INTERNAL_EXPLICIT_EDITING_INFOMATION_EXTENSION_SIZE_BYTE 3
+#define BKN_DPP_INTERNAL_LEARN_EXTENSION_SIZE_BYTE 5
+
+#define BKN_SAND_SCRATCH_DATA_SIZE 4
+
+/* ftmh action type. */
+typedef enum bkn_dpp_ftmh_action_type_e {
+ BKN_DPP_FTMH_ACTION_TYPE_FORWARD = 0, /* TM action is forward */
+ BKN_DPP_FTMH_ACTION_TYPE_SNOOP = 1, /* TM action is snoop */
+ BKN_DPP_FTMH_ACTION_TYPE_INBOUND_MIRROR = 2, /* TM action is inbound mirror. */
+ BKN_DPP_FTMH_ACTION_TYPE_OUTBOUND_MIRROR = 3 /* TM action is outbound mirror. */
+}bkn_dpp_ftmh_action_type_t;
+
+/* ftmh dest extension. */
+typedef struct bkn_dpp_ftmh_dest_extension_s {
+ uint8_t valid; /* Set if the extension is present */
+ uint32_t dst_sys_port; /* Destination System Port */
+} bkn_dpp_ftmh_dest_extension_t;
+
+/* dnx packet */
+typedef struct bkn_dune_system_header_info_s {
+ uint32_t system_header_size;
+ struct {
+ uint32_t action_type; /* Indicates if the copy is one of the Forward Snoop or Mirror packet copies */
+ uint32_t source_sys_port_aggregate; /* Source System port*/
+ } ftmh;
+ struct {
+ uint32_t forward_domain;
+ uint32_t trap_qualifier;
+ uint32_t trap_id;
+ } internal;
+} bkn_dune_system_header_info_t;
+
+#define PREV_IDX(_cur, _max) (((_cur) == 0) ? (_max) - 1 : (_cur) - 1)
+
+#if defined(CMIC_SOFT_BYTE_SWAP)
+
+#define CMIC_SWAP32(_x) ((((_x) & 0xff000000) >> 24) \
+ | (((_x) & 0x00ff0000) >> 8) \
+ | (((_x) & 0x0000ff00) << 8) \
+ | (((_x) & 0x000000ff) << 24))
+
+#define DEV_READ32(_d, _a, _p) \
+ do { \
+ uint32_t _data; \
+ _data = (((volatile uint32_t *)(_d)->base_addr)[(_a)/4]); \
+ *(_p) = CMIC_SWAP32(_data); \
+ } while(0)
+
+#define DEV_WRITE32(_d, _a, _v) \
+ do { \
+ uint32_t _data = CMIC_SWAP32(_v); \
+ ((volatile uint32_t *)(_d)->base_addr)[(_a)/4] = (_data); \
+ } while(0)
+
+#else
+
+#define DEV_READ32(_d, _a, _p) \
+ do { \
+ *(_p) = (((volatile uint32_t *)(_d)->base_addr)[(_a)/4]); \
+ } while(0)
+
+#define DEV_WRITE32(_d, _a, _v) \
+ do { \
+ ((volatile uint32_t *)(_d)->base_addr)[(_a)/4] = (_v); \
+ } while(0)
+
+#endif /* defined(CMIC_SOFT_BYTE_SWAP) */
+
+#define MEMORY_BARRIER smp_mb()
+
+/* Default random MAC address has Broadcom OUI with local admin bit set */
+static u8 bkn_dev_mac[6] = { 0x02, 0x10, 0x18, 0x00, 0x00, 0x00 };
+
+static u8 bkn_rcpu_dmac[6];
+static u8 bkn_rcpu_smac[6];
+
+/* Driver Proc Entry root */
+static struct proc_dir_entry *bkn_proc_root = NULL;
+
+typedef struct bkn_priv_s {
+ struct list_head list;
+ struct net_device_stats stats;
+ struct net_device *dev;
+ bkn_switch_info_t *sinfo;
+ int id;
+ int type;
+ int port;
+ int qnum;
+ uint32_t vlan;
+ uint32_t flags;
+ uint32_t cb_user_data;
+ uint8_t system_headers[27];
+ uint32_t system_headers_size;
+ int tx_hwts; /* HW timestamp for Tx */
+ int rx_hwts; /* HW timestamp for Rx */
+ int phys_port;
+} bkn_priv_t;
+
+typedef struct bkn_filter_s {
+ struct list_head list;
+ int dev_no;
+ unsigned long hits;
+ kcom_filter_t kf;
+} bkn_filter_t;
+
+
+/*
+ * Multiple instance support in KNET
+ */
+static int _bkn_multi_inst = 0;
+typedef struct {
+ wait_queue_head_t evt_wq;
+ int evt_wq_put;
+ int evt_wq_get;
+ uint32_t inst_id;
+} bkn_evt_resource_t;
+
+static bkn_evt_resource_t _bkn_evt[LINUX_BDE_MAX_DEVICES];
+
+static int bkn_knet_dev_init(int d);
+static int bkn_knet_dev_reinit(int d);
+
+/* IOCTL debug counters */
+static int ioctl_cmd;
+static int ioctl_evt;
+
+/* Switch devices */
+LIST_HEAD(_sinfo_list);
+
+/* Reallocation chunk size for netif array */
+#define NDEVS_CHUNK 64
+
+/* User call-backs */
+static knet_skb_cb_f knet_rx_cb = NULL;
+static knet_skb_cb_f knet_tx_cb = NULL;
+static knet_filter_cb_f knet_filter_cb = NULL;
+static knet_hw_tstamp_enable_cb_f knet_hw_tstamp_enable_cb = NULL;
+static knet_hw_tstamp_enable_cb_f knet_hw_tstamp_disable_cb = NULL;
+static knet_hw_tstamp_tx_time_get_cb_f knet_hw_tstamp_tx_time_get_cb = NULL;
+static knet_hw_tstamp_tx_meta_get_cb_f knet_hw_tstamp_tx_meta_get_cb = NULL;
+static knet_hw_tstamp_ptp_clock_index_cb_f knet_hw_tstamp_ptp_clock_index_cb = NULL;
+static knet_hw_tstamp_rx_time_upscale_cb_f knet_hw_tstamp_rx_time_upscale_cb = NULL;
+static knet_hw_tstamp_ioctl_cmd_cb_f knet_hw_tstamp_ioctl_cmd_cb = NULL;
+
+/*
+ * Thread management
+ */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10))
+static void
+bkn_sleep(int clicks)
+{
+ wait_queue_head_t wq;
+
+ init_waitqueue_head(&wq);
+ sleep_on_timeout(&wq, clicks);
+}
+#else
+static void
+bkn_sleep(int clicks)
+{
+ wait_queue_head_t wq;
+
+ init_waitqueue_head(&wq);
+ wait_event_timeout(wq, 0, clicks);
+}
+#endif
+
+/*
+ * On XGS devices bit 15 fo the Transferred Bytes field in
+ * the DCBs is used to indicate that kernel processing is
+ * complete. Using this bit reduces the theoretically maximum
+ * supported packet size from 64K to 32K, but this is still
+ * adequate for 16K jumbo packets.
+ */
+#define SOC_DCB_KNET_DONE 0x8000
+#define SOC_DCB_KNET_COUNT_MASK 0x7fff
+#define SOC_DCB_META_OFFSET 2
+
+/* Default channel configuration */
+#define XGS_DMA_TX_CHAN 0
+#define XGS_DMA_RX_CHAN 1
+
+/* CMIC registers */
+#define CMIC_DMA_CTRLr 0x00000100
+#define CMIC_DMA_STATr 0x00000104
+#define CMIC_DMA_DESC0r 0x00000110
+#define CMIC_IRQ_STATr 0x00000144
+#define CMIC_IRQ_MASKr 0x00000148
+#define CMIC_DEV_REV_IDr 0x00000178
+
+/* CMIC interrupts reserved for kernel handler */
+#define CMIC_TXRX_IRQ_MASK 0x7f80
+
+/* CMICm registers */
+#define CMICM_CMC_BASE 0x00031000
+#define CMICM_DMA_CTRLr (CMICM_CMC_BASE + 0x00000140)
+#define CMICM_DMA_STATr (CMICM_CMC_BASE + 0x00000150)
+#define CMICM_DMA_STAT_CLRr (CMICM_CMC_BASE + 0x000001a4)
+#define CMICM_DMA_DESC0r (CMICM_CMC_BASE + 0x00000158)
+#define CMICM_DMA_HALT_ADDRr (CMICM_CMC_BASE + 0x00000120)
+#define CMICM_IRQ_STATr (CMICM_CMC_BASE + 0x00000400)
+#define CMICM_IRQ_PCI_MASKr (CMICM_CMC_BASE + 0x00000414)
+#define CMICM_IRQ_UC0_MASKr (CMICM_CMC_BASE + 0x00000428)
+#define CMICM_DEV_REV_IDr 0x00010224
+
+/* CMICm interrupts reserved for kernel handler */
+#define CMICM_TXRX_IRQ_MASK 0xff00
+
+/* CMICd increased interrupts reserved for kernel handler */
+#define CMICD_CTRLD_IRQ_MASK 0x78000000
+
+/* CMICx registers */
+#define CMICX_CMC_BASE 0x00000000
+#define CMICX_DMA_CTRLr (CMICX_CMC_BASE + 0x00002100)
+#define CMICX_DMA_STATr (CMICX_CMC_BASE + 0x00002114)
+#define CMICX_DMA_DESC_HIr (CMICX_CMC_BASE + 0x00002108)
+#define CMICX_DMA_DESC_LOr (CMICX_CMC_BASE + 0x00002104)
+#define CMICX_DMA_HALT_HIr (CMICX_CMC_BASE + 0x00002110)
+#define CMICX_DMA_HALT_LOr (CMICX_CMC_BASE + 0x0000210c)
+#define CMICX_IRQ_STATr (CMICX_CMC_BASE + 0x0000106c)
+#define CMICX_IRQ_STAT_CLRr (CMICX_CMC_BASE + 0x00001074)
+#define CMICX_IRQ_ENABr 0x18013100
+#define IHOST_GIC_GIC400_GICD_ISENABLERN_5r 0x10781114
+#define IHOST_GIC_GIC400_GICD_ICENABLERN_5r 0x10781194
+
+/* CMICx interrupts reserved for kernel handler */
+#define CMICX_TXRX_IRQ_MASK 0xffffffff
+
+#define DEV_IS_CMICX(_sinfo) ((_sinfo)->cmic_type == 'x')
+#define DEV_IS_CMICM(_sinfo) ((_sinfo)->cmic_type == 'm')
+#define CDMA_CH(_d, _ch) ((_d)->cdma_channels & (1 << (_ch)))
+
+/*
+ * DMA_STAT: control bits
+ *
+ * xxx_SET and xxx_CLR can be WRITTEN to CMIC_DMA_STAT
+ * xxx_TST can be masked against values read from CMIC_DMA_STAT.
+ * Argument required: 0 <= ch <= 3
+ */
+#define DS_DMA_ACTIVE(ch) (0x00040000 << (ch))
+#define DS_DMA_EN_SET(ch) (0x80|(ch))
+#define DS_DMA_EN_CLR(ch) (0x00|(ch))
+#define DS_DMA_EN_TST(ch) (0x00000001 << (ch))
+
+#define DS_CHAIN_DONE_SET(ch) (0x80|(4+(ch)))
+#define DS_CHAIN_DONE_CLR(ch) (0x00|(4+(ch)))
+#define DS_CHAIN_DONE_TST(ch) (0x00000010 << (ch))
+
+#define DS_DESC_DONE_SET(ch) (0x80|(8+(ch)))
+#define DS_DESC_DONE_CLR(ch) (0x00|(8+(ch)))
+#define DS_DESC_DONE_TST(ch) (0x00000100 << (ch))
+
+#define DC_ABORT_DMA(ch) (0x04 << (8 * (ch)))
+
+#define DS_CMC_DESCRD_CMPLT_CLR(ch) (0x00000001 << (ch))
+#define DS_CMC_CTRLD_INT_CLR(ch) (0x00000100 << (ch))
+#define DS_CMC_DMA_ACTIVE(ch) (0x00000100 << (ch))
+
+#define CMICX_DS_CMC_DESC_DONE(ch) (0x00000001 << ((ch) * 4))
+#define CMICX_DS_CMC_CHAIN_DONE(ch) (0x00000002 << ((ch) * 4))
+#define CMICX_DS_CMC_CTRLD_INT(ch) (0x00000008 << ((ch) * 4))
+#define CMICX_DS_CMC_DMA_CHAIN_DONE (0x00000001)
+#define CMICX_DS_CMC_DMA_ACTIVE (0x00000002)
+
+#define DMA_TO_BUS_HI(dma) ((dma) | sinfo->dma_hi)
+#define BUS_TO_DMA_HI(bus) ((bus) & ~sinfo->dma_hi)
+
+/*
+ * DMA_CTRL: control bits
+ */
+#define DC_CMC_DIRECTION (0x00000001)
+#define DC_CMC_ENABLE (0x00000002)
+#define DC_CMC_ABORT (0x00000004)
+#define DC_CMC_CTRLD_INT (0x00000100)
+#define DC_CMC_CONTINUOUS (0x00000200)
+
+#define CMICX_DC_CMC_DIRECTION (0x00000001)
+#define CMICX_DC_CMC_ENABLE (0x00000002)
+#define CMICX_DC_CMC_ABORT (0x00000004)
+#define CMICX_DC_CMC_CTRLD_INT (0x00000080)
+#define CMICX_DC_CMC_CONTINUOUS (0x00000100)
+
+/*
+ * Per-channel operations.
+ * These are the basis for the TX/RX functions
+ */
+
+static inline void
+xgs_dma_chain_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ DBG_IRQ(("Clear chain on device %d chan %d\n",
+ sinfo->dev_no, chan));
+ DEV_WRITE32(sinfo, CMIC_DMA_STATr, DS_DMA_EN_CLR(chan));
+ DEV_WRITE32(sinfo, CMIC_DMA_STATr, DS_CHAIN_DONE_CLR(chan));
+
+ MEMORY_BARRIER;
+}
+
+static inline void
+xgs_dma_desc_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ uint32_t val;
+
+ DBG_IRQ(("Clear desc on device %d chan %d\n",
+ sinfo->dev_no, chan));
+ DEV_WRITE32(sinfo, CMIC_DMA_STATr, DS_DESC_DONE_CLR(chan));
+
+ MEMORY_BARRIER;
+
+ /* Flush write buffer */
+ DEV_READ32(sinfo, CMIC_DMA_STATr, &val);
+
+ MEMORY_BARRIER;
+}
+
+static int
+xgs_dma_chan_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ xgs_dma_chain_clear(sinfo, chan);
+ xgs_dma_desc_clear(sinfo, chan);
+
+ return 0;
+}
+
+static int
+xgs_dma_chan_init(bkn_switch_info_t *sinfo, int chan, int dir)
+{
+ uint32_t cdc;
+
+ DEV_READ32(sinfo, CMIC_DMA_CTRLr, &cdc);
+
+ cdc &= ~(0x9 << (8 * chan));
+ if (dir) {
+ cdc |= 0x1 << (8 * chan);
+ } else {
+ cdc |= 0x8 << (8 * chan);
+ }
+
+ DEV_WRITE32(sinfo, CMIC_DMA_CTRLr, cdc);
+
+ return 0;
+}
+
+static int
+xgs_dma_chan_start(bkn_switch_info_t *sinfo, int chan, uint64_t dcb)
+{
+ /* Write the DCB address to the DESC address for this channel */
+ DEV_WRITE32(sinfo, CMIC_DMA_DESC0r + 4 * chan, dcb);
+
+ MEMORY_BARRIER;
+
+ /* Kick it off */
+ DEV_WRITE32(sinfo, CMIC_DMA_STATr, DS_DMA_EN_SET(chan));
+
+ MEMORY_BARRIER;
+
+ return 0;
+}
+
+static int
+xgs_dma_chan_abort(bkn_switch_info_t *sinfo, int chan, int polls)
+{
+ uint32_t ctrl, dma_stat;
+ int p;
+
+ /* Clear enable */
+ DEV_WRITE32(sinfo, CMIC_DMA_STATr, DS_DMA_EN_CLR(chan));
+
+ MEMORY_BARRIER;
+
+ /* Abort the channel */
+ DEV_READ32(sinfo, CMIC_DMA_CTRLr, &ctrl);
+ DEV_WRITE32(sinfo, CMIC_DMA_CTRLr, ctrl | DC_ABORT_DMA(chan));
+
+ MEMORY_BARRIER;
+
+ /* Poll for abort completion */
+ for (p = 0; p < polls; p++) {
+ DEV_READ32(sinfo, CMIC_DMA_STATr, &dma_stat);
+ if (!(dma_stat & DS_DMA_ACTIVE(chan))) {
+ /* Restore previous control value */
+ DEV_WRITE32(sinfo, CMIC_DMA_CTRLr, ctrl);
+
+ MEMORY_BARRIER;
+
+ /* Clear up channel */
+ xgs_dma_chan_clear(sinfo, chan);
+
+ return polls;
+ }
+ }
+ DBG_WARN(("DMA channel %d abort failed\n", chan));
+
+ return -1;
+}
+
+static inline void
+xgs_irq_mask_set(bkn_switch_info_t *sinfo, uint32_t mask)
+{
+ if (sinfo->napi_poll_mode) {
+ mask = 0;
+ }
+ lkbde_irq_mask_set(sinfo->dev_no | LKBDE_ISR2_DEV, CMIC_IRQ_MASKr,
+ mask, CMIC_TXRX_IRQ_MASK);
+}
+
+static inline void
+xgs_irq_mask_enable(bkn_switch_info_t *sinfo, int chan, int update_hw)
+{
+ uint32_t mask;
+
+ if (chan == XGS_DMA_TX_CHAN) {
+ mask = 0x100;
+ } else {
+ mask = 0x180 << (2 * chan);
+ }
+
+ sinfo->irq_mask |= mask;
+
+ if (update_hw) {
+ xgs_irq_mask_set(sinfo, sinfo->irq_mask);
+ }
+}
+
+static inline void
+xgs_irq_mask_disable(bkn_switch_info_t *sinfo, int chan, int update_hw)
+{
+ uint32_t mask;
+
+ if (chan == XGS_DMA_TX_CHAN) {
+ mask = 0x100;
+ } else {
+ mask = 0x180 << (2 * chan);
+ }
+
+ sinfo->irq_mask &= ~mask;
+
+ if (update_hw) {
+ xgs_irq_mask_set(sinfo, sinfo->irq_mask);
+ }
+}
+
+static inline void
+xgsm_dma_chain_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ uint32_t cdc;
+
+ /* Disabing DMA clears chain done */
+ DEV_READ32(sinfo, CMICM_DMA_CTRLr + 4 * chan, &cdc);
+ cdc &= ~(DC_CMC_ENABLE | DC_CMC_ABORT);
+ DEV_WRITE32(sinfo, CMICM_DMA_CTRLr + 4 * chan, cdc);
+
+ MEMORY_BARRIER;
+}
+
+static inline void
+xgsm_dma_desc_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ uint32_t val;
+
+ val = DS_CMC_DESCRD_CMPLT_CLR(chan);
+ if (CDMA_CH(sinfo, chan)) {
+ val |= DS_CMC_CTRLD_INT_CLR(chan);
+ }
+ DEV_WRITE32(sinfo, CMICM_DMA_STAT_CLRr, val);
+
+ MEMORY_BARRIER;
+
+ /* Flush write buffer */
+ DEV_READ32(sinfo, CMICM_DMA_STAT_CLRr, &val);
+
+ MEMORY_BARRIER;
+}
+
+static int
+xgsm_dma_chan_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ xgsm_dma_chain_clear(sinfo, chan);
+ xgsm_dma_desc_clear(sinfo, chan);
+
+ return 0;
+}
+
+static inline void
+xgsm_cdma_halt_set(bkn_switch_info_t *sinfo, int chan)
+{
+ DEV_WRITE32(sinfo, CMICM_DMA_HALT_ADDRr + 4 * chan,
+ sinfo->halt_addr[chan]);
+
+ MEMORY_BARRIER;
+}
+
+static int
+xgsm_dma_chan_init(bkn_switch_info_t *sinfo, int chan, int dir)
+{
+ uint32_t cdc;
+
+ DEV_READ32(sinfo, CMICM_DMA_CTRLr + 4 * chan, &cdc);
+ cdc &= ~DC_CMC_DIRECTION;
+ if (dir) {
+ cdc |= DC_CMC_DIRECTION;
+ }
+ if (CDMA_CH(sinfo, chan)) {
+ cdc |= DC_CMC_CONTINUOUS | DC_CMC_CTRLD_INT;
+ xgsm_cdma_halt_set(sinfo, chan);
+ }
+ DEV_WRITE32(sinfo, CMICM_DMA_CTRLr + 4 * chan, cdc);
+
+ return 0;
+}
+
+static int
+xgsm_dma_chan_start(bkn_switch_info_t *sinfo, int chan, uint64_t dcb)
+{
+ uint32_t cdc;
+
+ /* Write the DCB address to the DESC address for this channel */
+ DEV_WRITE32(sinfo, CMICM_DMA_DESC0r + 4 * chan, dcb);
+
+ MEMORY_BARRIER;
+
+ /* Kick it off */
+ DEV_READ32(sinfo, CMICM_DMA_CTRLr + 4 * chan, &cdc);
+ cdc |= DC_CMC_ENABLE;
+ DEV_WRITE32(sinfo, CMICM_DMA_CTRLr + 4 * chan, cdc);
+
+ MEMORY_BARRIER;
+
+ return 0;
+}
+
+static int
+xgsm_dma_chan_abort(bkn_switch_info_t *sinfo, int chan, int polls)
+{
+ uint32_t ctrl, dma_stat;
+ int p;
+
+ /* Skip abort sequence if channel is not active */
+ DEV_READ32(sinfo, CMICM_DMA_STATr, &dma_stat);
+ if (!(dma_stat & DS_CMC_DMA_ACTIVE(chan))) {
+ return 0;
+ }
+
+ /* Abort the channel */
+ DEV_READ32(sinfo, CMICM_DMA_CTRLr + 4 * chan, &ctrl);
+ ctrl |= (DC_CMC_ENABLE | DC_CMC_ABORT);
+ DEV_WRITE32(sinfo, CMICM_DMA_CTRLr + 4 * chan, ctrl);
+
+ MEMORY_BARRIER;
+
+ /* Poll for abort completion */
+ for (p = 0; p < polls; p++) {
+ DEV_READ32(sinfo, CMICM_DMA_STATr, &dma_stat);
+ if (!(dma_stat & DS_CMC_DMA_ACTIVE(chan))) {
+ /* Clear up channel */
+ xgsm_dma_chan_clear(sinfo, chan);
+ return polls;
+ }
+ }
+ DBG_WARN(("DMA channel %d abort failed\n", chan));
+
+ return -1;
+}
+
+static inline void
+xgsm_irq_mask_set(bkn_switch_info_t *sinfo, uint32_t mask)
+{
+ uint32_t irq_mask_reg = CMICM_IRQ_PCI_MASKr;
+ uint32_t ctrld_mask = 0;
+
+ if (sinfo->napi_poll_mode) {
+ mask = 0;
+ }
+ if (sinfo->cpu_no == 1) {
+ irq_mask_reg = CMICM_IRQ_UC0_MASKr;
+ }
+
+ /* Get the Controlled Interrupts mask for Continuous DMA mode */
+ ctrld_mask |= (sinfo->cdma_channels << 27) & CMICD_CTRLD_IRQ_MASK;
+
+ lkbde_irq_mask_set(sinfo->dev_no | LKBDE_ISR2_DEV, irq_mask_reg,
+ mask, CMICM_TXRX_IRQ_MASK | ctrld_mask);
+}
+
+static inline void
+xgsm_irq_mask_enable(bkn_switch_info_t *sinfo, int chan, int update_hw)
+{
+ uint32_t mask;
+
+ if (CDMA_CH(sinfo, chan)) {
+ mask = 0x08000000 << chan;
+ } else {
+ if (chan == XGS_DMA_TX_CHAN) {
+ mask = 0x8000;
+ } else {
+ mask = 0xc000 >> (2 * chan);
+ }
+ }
+
+ sinfo->irq_mask |= mask;
+
+ if (update_hw) {
+ xgsm_irq_mask_set(sinfo, sinfo->irq_mask);
+ }
+}
+
+static inline void
+xgsm_irq_mask_disable(bkn_switch_info_t *sinfo, int chan, int update_hw)
+{
+ uint32_t mask;
+
+ if (CDMA_CH(sinfo, chan)) {
+ mask = 0x08000000 << chan;
+ } else {
+ if (chan == XGS_DMA_TX_CHAN) {
+ mask = 0x8000;
+ } else {
+ mask = 0xc000 >> (2 * chan);
+ }
+ }
+
+ sinfo->irq_mask &= ~mask;
+
+ if (update_hw) {
+ xgsm_irq_mask_set(sinfo, sinfo->irq_mask);
+ }
+}
+
+static inline void
+xgsx_dma_chain_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ uint32_t ctrl, stat;
+
+ /* Disabing DMA clears chain done */
+ DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl);
+ ctrl &= ~(CMICX_DC_CMC_ENABLE | CMICX_DC_CMC_ABORT);
+ DEV_WRITE32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, ctrl);
+
+ stat = CMICX_DS_CMC_CHAIN_DONE(chan);
+ DEV_WRITE32(sinfo, CMICX_IRQ_STAT_CLRr, stat);
+
+ MEMORY_BARRIER;
+
+ /* Flush write buffer */
+ DEV_READ32(sinfo, CMICX_IRQ_STAT_CLRr, &stat);
+
+ MEMORY_BARRIER;
+}
+
+static inline void
+xgsx_dma_desc_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ uint32_t stat;
+
+ if (CDMA_CH(sinfo, chan)) {
+ stat = CMICX_DS_CMC_CTRLD_INT(chan);
+ } else {
+ stat = CMICX_DS_CMC_DESC_DONE(chan);
+ }
+ DEV_WRITE32(sinfo, CMICX_IRQ_STAT_CLRr, stat);
+
+ MEMORY_BARRIER;
+
+ /* Flush write buffer */
+ DEV_READ32(sinfo, CMICX_IRQ_STAT_CLRr, &stat);
+
+ MEMORY_BARRIER;
+}
+
+static int
+xgsx_dma_chan_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ xgsx_dma_chain_clear(sinfo, chan);
+ xgsx_dma_desc_clear(sinfo, chan);
+
+ return 0;
+}
+
+static inline void
+xgsx_cdma_halt_set(bkn_switch_info_t *sinfo, int chan)
+{
+ DEV_WRITE32(sinfo, CMICX_DMA_HALT_LOr + 0x80 * chan,
+ sinfo->halt_addr[chan]);
+ DEV_WRITE32(sinfo, CMICX_DMA_HALT_HIr + 0x80 * chan,
+ DMA_TO_BUS_HI(sinfo->halt_addr[chan] >> 32));
+
+ MEMORY_BARRIER;
+}
+
+static int
+xgsx_dma_chan_init(bkn_switch_info_t *sinfo, int chan, int dir)
+{
+ uint32_t ctrl;
+
+ DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl);
+ ctrl &= ~CMICX_DC_CMC_DIRECTION;
+ if (dir) {
+ ctrl |= CMICX_DC_CMC_DIRECTION;
+ }
+ if (CDMA_CH(sinfo, chan)) {
+ ctrl |= CMICX_DC_CMC_CONTINUOUS | CMICX_DC_CMC_CTRLD_INT;
+ xgsx_cdma_halt_set(sinfo, chan);
+ }
+ DEV_WRITE32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, ctrl);
+
+ MEMORY_BARRIER;
+
+ return 0;
+}
+
+static int
+xgsx_dma_chan_start(bkn_switch_info_t *sinfo, int chan, uint64_t dcb)
+{
+ uint32_t ctrl;
+
+ /* Write the DCB address to the DESC address for this channel */
+ DEV_WRITE32(sinfo, CMICX_DMA_DESC_LOr + 0x80 * chan, dcb);
+ DEV_WRITE32(sinfo, CMICX_DMA_DESC_HIr + 0x80 * chan, DMA_TO_BUS_HI(dcb >> 32));
+
+ MEMORY_BARRIER;
+
+ /* Kick it off */
+ DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl);
+ ctrl |= CMICX_DC_CMC_ENABLE;
+ DEV_WRITE32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, ctrl);
+
+ MEMORY_BARRIER;
+
+ return 0;
+}
+
+static int
+xgsx_dma_chan_abort(bkn_switch_info_t *sinfo, int chan, int polls)
+{
+ uint32_t ctrl, stat;
+ int p;
+
+ /* Skip abort sequence if channel is not active */
+ DEV_READ32(sinfo, CMICX_DMA_STATr + 0x80 * chan, &stat);
+ if (!(stat & CMICX_DS_CMC_DMA_ACTIVE)) {
+ return 0;
+ }
+
+ /* Abort the channel */
+ DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl);
+ ctrl |= CMICX_DC_CMC_ENABLE | CMICX_DC_CMC_ABORT;
+ DEV_WRITE32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, ctrl);
+
+ MEMORY_BARRIER;
+
+ /* Poll for abort completion */
+ for (p = 0; p < polls; p++) {
+ DEV_READ32(sinfo, CMICX_DMA_STATr + 0x80 * chan, &stat);
+ if (!(stat & CMICX_DS_CMC_DMA_ACTIVE)) {
+ /* Clear up channel */
+ xgsx_dma_chan_clear(sinfo, chan);
+ return polls;
+ }
+ }
+
+ DBG_WARN(("DMA channel %d abort failed\n", chan));
+
+ return -1;
+}
+
+static inline void
+xgsx_irq_mask_set(bkn_switch_info_t *sinfo, uint32_t mask)
+{
+ uint32_t irq_mask_reg = CMICX_IRQ_ENABr;
+ uint32_t irq_mask, irq_fmask, disable_mask;
+
+ if (sinfo->napi_poll_mode) {
+ mask = 0;
+ }
+
+ if (sinfo->cpu_no == 1) {
+ lkbde_irq_mask_get(sinfo->dev_no, &irq_mask, &irq_fmask);
+ disable_mask = ~mask & (irq_mask & irq_fmask);
+ if (disable_mask) {
+ lkbde_irq_mask_set(sinfo->dev_no | LKBDE_ISR2_DEV | LKBDE_IPROC_REG,
+ IHOST_GIC_GIC400_GICD_ICENABLERN_5r, disable_mask, CMICX_TXRX_IRQ_MASK);
+ }
+ irq_mask_reg = IHOST_GIC_GIC400_GICD_ISENABLERN_5r;
+ }
+
+ lkbde_irq_mask_set(sinfo->dev_no | LKBDE_ISR2_DEV | LKBDE_IPROC_REG,
+ irq_mask_reg, mask, CMICX_TXRX_IRQ_MASK);
+}
+
+static inline void
+xgsx_irq_mask_enable(bkn_switch_info_t *sinfo, int chan, int update_hw)
+{
+ uint32_t mask;
+
+ if (CDMA_CH(sinfo, chan)) {
+ mask = CMICX_DS_CMC_CTRLD_INT(chan);
+ } else {
+ if (chan == XGS_DMA_TX_CHAN) {
+ mask = CMICX_DS_CMC_CHAIN_DONE(chan);
+ } else {
+ mask = CMICX_DS_CMC_DESC_DONE(chan) |
+ CMICX_DS_CMC_CHAIN_DONE(chan);
+ }
+ }
+
+ sinfo->irq_mask |= mask;
+
+ if (update_hw) {
+ xgsx_irq_mask_set(sinfo, sinfo->irq_mask);
+ }
+}
+
+static inline void
+xgsx_irq_mask_disable(bkn_switch_info_t *sinfo, int chan, int update_hw)
+{
+ uint32_t mask;
+
+ if (CDMA_CH(sinfo, chan)) {
+ mask = CMICX_DS_CMC_CTRLD_INT(chan);
+ } else {
+ if (chan == XGS_DMA_TX_CHAN) {
+ mask = CMICX_DS_CMC_CHAIN_DONE(chan);
+ } else {
+ mask = CMICX_DS_CMC_DESC_DONE(chan) |
+ CMICX_DS_CMC_CHAIN_DONE(chan);
+ }
+ }
+
+ sinfo->irq_mask &= ~mask;
+
+ if (update_hw) {
+ xgsx_irq_mask_set(sinfo, sinfo->irq_mask);
+ }
+}
+
+static inline void
+dev_dma_chain_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ xgsx_dma_chain_clear(sinfo, chan);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ xgsm_dma_chain_clear(sinfo, chan);
+ } else {
+ xgs_dma_chain_clear(sinfo, chan);
+ }
+}
+
+static inline void
+dev_dma_desc_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ xgsx_dma_desc_clear(sinfo, chan);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ xgsm_dma_desc_clear(sinfo, chan);
+ } else {
+ xgs_dma_desc_clear(sinfo, chan);
+ }
+}
+
+static int
+dev_dma_chan_clear(bkn_switch_info_t *sinfo, int chan)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ return xgsx_dma_chan_clear(sinfo, chan);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ return xgsm_dma_chan_clear(sinfo, chan);
+ } else {
+ return xgs_dma_chan_clear(sinfo, chan);
+ }
+}
+
+static void
+dev_cdma_halt_set(bkn_switch_info_t *sinfo, int chan)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ xgsx_cdma_halt_set(sinfo, chan);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ xgsm_cdma_halt_set(sinfo, chan);
+ }
+}
+
+static int
+dev_dma_chan_init(bkn_switch_info_t *sinfo, int chan, int dir)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ return xgsx_dma_chan_init(sinfo, chan, dir);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ return xgsm_dma_chan_init(sinfo, chan, dir);
+ } else {
+ return xgs_dma_chan_init(sinfo, chan, dir);
+ }
+}
+
+static int
+dev_dma_chan_start(bkn_switch_info_t *sinfo, int chan, uint64_t dcb)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ return xgsx_dma_chan_start(sinfo, chan, dcb);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ return xgsm_dma_chan_start(sinfo, chan, dcb);
+ } else {
+ return xgs_dma_chan_start(sinfo, chan, dcb);
+ }
+}
+
+static int
+dev_dma_chan_abort(bkn_switch_info_t *sinfo, int chan, int polls)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ return xgsx_dma_chan_abort(sinfo, chan, polls);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ return xgsm_dma_chan_abort(sinfo, chan, polls);
+ } else {
+ return xgs_dma_chan_abort(sinfo, chan, polls);
+ }
+}
+
+static inline void
+dev_irq_mask_set(bkn_switch_info_t *sinfo, uint32_t mask)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ xgsx_irq_mask_set(sinfo, mask);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ xgsm_irq_mask_set(sinfo, mask);
+ } else {
+ xgs_irq_mask_set(sinfo, mask);
+ }
+}
+
+static inline void
+dev_irq_mask_enable(bkn_switch_info_t *sinfo, int chan, int update_hw)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ xgsx_irq_mask_enable(sinfo, chan, update_hw);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ xgsm_irq_mask_enable(sinfo, chan, update_hw);
+ } else {
+ xgs_irq_mask_enable(sinfo, chan, update_hw);
+ }
+}
+
+static void
+dev_irq_mask_disable(bkn_switch_info_t *sinfo, int chan, int update_hw)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ xgsx_irq_mask_disable(sinfo, chan, update_hw);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ xgsm_irq_mask_disable(sinfo, chan, update_hw);
+ } else {
+ xgs_irq_mask_disable(sinfo, chan, update_hw);
+ }
+}
+
+static int
+bkn_alloc_dcbs(bkn_switch_info_t *sinfo)
+{
+ int dcb_size;
+ int tx_ring_size, rx_ring_size;
+ dma_addr_t dcb_dma = 0;
+
+ dcb_size = sinfo->dcb_wsize * sizeof(uint32_t);
+ tx_ring_size = dcb_size * (MAX_TX_DCBS + 1);
+ rx_ring_size = dcb_size * (MAX_RX_DCBS + 1);
+ sinfo->dcb_mem_size = tx_ring_size + rx_ring_size * sinfo->rx_chans;
+
+ sinfo->dcb_mem = BKN_DMA_ALLOC_COHERENT(sinfo->dma_dev,
+ sinfo->dcb_mem_size,
+ &dcb_dma);
+ if (sinfo->dcb_mem == NULL) {
+ gprintk("DCB memory allocation (%d bytes) failed.\n",
+ sinfo->dcb_mem_size);
+ return -ENOMEM;
+ }
+ sinfo->dcb_dma = (uint64_t)dcb_dma;
+
+ return 0;
+}
+
+static void
+bkn_free_dcbs(bkn_switch_info_t *sinfo)
+{
+ if (sinfo->dcb_mem != NULL) {
+ BKN_DMA_FREE_COHERENT(sinfo->dma_dev, sinfo->dcb_mem_size,
+ sinfo->dcb_mem, (dma_addr_t)sinfo->dcb_dma);
+ sinfo->dcb_mem = NULL;
+ }
+}
+
+static void
+bkn_clean_tx_dcbs(bkn_switch_info_t *sinfo)
+{
+ bkn_desc_info_t *desc;
+
+ DBG_DCB_TX(("Cleaning Tx DCBs (%d %d).\n",
+ sinfo->tx.cur, sinfo->tx.dirty));
+ while (sinfo->tx.free < MAX_TX_DCBS) {
+ desc = &sinfo->tx.desc[sinfo->tx.dirty];
+ if (desc->skb != NULL) {
+ DBG_SKB(("Cleaning Tx SKB from DCB %d.\n",
+ sinfo->tx.dirty));
+ BKN_DMA_UNMAP_SINGLE(sinfo->dma_dev,
+ desc->skb_dma, desc->dma_size,
+ BKN_DMA_TODEV);
+ desc->skb_dma = 0;
+ dev_kfree_skb_any(desc->skb);
+ desc->skb = NULL;
+ }
+ if (++sinfo->tx.dirty >= MAX_TX_DCBS) {
+ sinfo->tx.dirty = 0;
+ }
+ sinfo->tx.free++;
+ }
+ sinfo->tx.api_active = 0;
+ DBG_DCB_TX(("Cleaned Tx DCBs (%d %d).\n",
+ sinfo->tx.cur, sinfo->tx.dirty));
+}
+
+static void
+bkn_clean_rx_dcbs(bkn_switch_info_t *sinfo, int chan)
+{
+ bkn_desc_info_t *desc;
+
+ DBG_DCB_RX(("Cleaning Rx%d DCBs (%d %d).\n",
+ chan, sinfo->rx[chan].cur, sinfo->rx[chan].dirty));
+ while (sinfo->rx[chan].free) {
+ desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty];
+ if (desc->skb != NULL) {
+ DBG_SKB(("Cleaning Rx%d SKB from DCB %d.\n",
+ chan, sinfo->rx[chan].dirty));
+ BKN_DMA_UNMAP_SINGLE(sinfo->dma_dev,
+ desc->skb_dma, desc->dma_size,
+ BKN_DMA_FROMDEV);
+ desc->skb_dma = 0;
+ dev_kfree_skb_any(desc->skb);
+ desc->skb = NULL;
+ }
+ if (++sinfo->rx[chan].dirty >= MAX_RX_DCBS) {
+ sinfo->rx[chan].dirty = 0;
+ }
+ sinfo->rx[chan].free--;
+ }
+ sinfo->rx[chan].running = 0;
+ sinfo->rx[chan].api_active = 0;
+ DBG_DCB_RX(("Cleaned Rx%d DCBs (%d %d).\n",
+ chan, sinfo->rx[chan].cur, sinfo->rx[chan].dirty));
+}
+
+static void
+bkn_clean_dcbs(bkn_switch_info_t *sinfo)
+{
+ int chan;
+
+ bkn_clean_tx_dcbs(sinfo);
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ bkn_clean_rx_dcbs(sinfo, chan);
+ }
+}
+
+static void
+bkn_init_dcbs(bkn_switch_info_t *sinfo)
+{
+ int dcb_size;
+ uint32_t *dcb_mem;
+ uint64_t dcb_dma;
+ bkn_desc_info_t *desc;
+ int idx;
+ int chan;
+
+ memset(sinfo->dcb_mem, 0, sinfo->dcb_mem_size);
+
+ dcb_size = sinfo->dcb_wsize * sizeof(uint32_t);
+ dcb_mem = sinfo->dcb_mem;
+ dcb_dma = sinfo->dcb_dma;
+
+ for (idx = 0; idx < (MAX_TX_DCBS + 1); idx++) {
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ if (sinfo->cmic_type == 'x') {
+ dcb_mem[2] |= 1 << 24 | 1 << 16;
+ } else {
+ dcb_mem[1] |= 1 << 24 | 1 << 16;
+ }
+ if (idx == MAX_TX_DCBS) {
+ if (sinfo->cmic_type == 'x') {
+ dcb_mem[0] = sinfo->tx.desc[0].dcb_dma;
+ dcb_mem[1] = DMA_TO_BUS_HI(sinfo->tx.desc[0].dcb_dma >> 32);
+ dcb_mem[2] |= 1 << 18;
+ } else {
+ dcb_mem[0] = sinfo->tx.desc[0].dcb_dma;
+ dcb_mem[1] |= 1 << 18;
+ }
+ }
+ }
+ desc = &sinfo->tx.desc[idx];
+ desc->dcb_mem = dcb_mem;
+ desc->dcb_dma = dcb_dma;
+ dcb_mem += sinfo->dcb_wsize;
+ dcb_dma += dcb_size;
+ }
+ sinfo->halt_addr[XGS_DMA_TX_CHAN] = sinfo->tx.desc[0].dcb_dma;
+ sinfo->tx.free = MAX_TX_DCBS;
+ sinfo->tx.cur = 0;
+ sinfo->tx.dirty = 0;
+
+ DBG_DCB_TX(("Tx DCBs @ 0x%08x.\n",
+ (uint32_t)sinfo->tx.desc[0].dcb_dma));
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ for (idx = 0; idx < (MAX_RX_DCBS + 1); idx++) {
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ if (sinfo->cmic_type == 'x') {
+ dcb_mem[2] |= 1 << 24 | 1 << 16;
+ } else {
+ dcb_mem[1] |= 1 << 24 | 1 << 16;
+ }
+ if (idx == MAX_RX_DCBS) {
+ if (sinfo->cmic_type == 'x') {
+ dcb_mem[0] = sinfo->rx[chan].desc[0].dcb_dma;
+ dcb_mem[1] = DMA_TO_BUS_HI(sinfo->rx[chan].desc[0].dcb_dma >> 32);
+ dcb_mem[2] |= 1 << 18;
+ } else {
+ dcb_mem[0] = sinfo->rx[chan].desc[0].dcb_dma;
+ dcb_mem[1] |= 1 << 18;
+ }
+ }
+ }
+ desc = &sinfo->rx[chan].desc[idx];
+ desc->dcb_mem = dcb_mem;
+ desc->dcb_dma = dcb_dma;
+ dcb_mem += sinfo->dcb_wsize;
+ dcb_dma += dcb_size;
+ }
+ sinfo->halt_addr[XGS_DMA_RX_CHAN + chan] = sinfo->rx[chan].desc[MAX_RX_DCBS].dcb_dma;
+ sinfo->rx[chan].free = 0;
+ sinfo->rx[chan].cur = 0;
+ sinfo->rx[chan].dirty = 0;
+
+ DBG_DCB_RX(("Rx%d DCBs @ 0x%08x.\n",
+ chan, (uint32_t)sinfo->rx[chan].desc[0].dcb_dma));
+ }
+}
+
+static void
+bkn_dump_dcb(char *prefix, uint32_t *dcb, int wsize, int txrx)
+{
+ if (XGS_DMA_TX_CHAN == txrx) {
+ if (wsize > 4) {
+ DBG_DCB_TX(("%s: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x ... 0x%08x\n",
+ prefix, dcb[0], dcb[1], dcb[2], dcb[3], dcb[4], dcb[5],
+ dcb[wsize - 1]));
+ } else {
+ DBG_DCB_TX(("%s: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ prefix, dcb[0], dcb[1], dcb[2], dcb[3]));
+ }
+ } else {
+ if (wsize > 4) {
+ DBG_DCB_RX(("%s: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x ... 0x%08x\n",
+ prefix, dcb[0], dcb[1], dcb[2], dcb[3], dcb[4], dcb[5],
+ dcb[wsize - 1]));
+ } else {
+ DBG_DCB_RX(("%s: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ prefix, dcb[0], dcb[1], dcb[2], dcb[3]));
+ }
+ }
+}
+
+static void
+bkn_dump_pkt(uint8_t *data, int size, int txrx)
+{
+ int idx;
+ char str[128];
+
+ if (!(debug & DBG_LVL_PDMP) &&
+ !(txrx == XGS_DMA_TX_CHAN && debug & DBG_LVL_PDMP_TX) &&
+ !(txrx == XGS_DMA_RX_CHAN && debug & DBG_LVL_PDMP_RX)) {
+ return;
+ }
+
+ for (idx = 0; idx < size; idx++) {
+ if ((idx & 0xf) == 0) {
+ sprintf(str, "%04x: ", idx);
+ }
+ if ((idx & 0xf) == 8) {
+ sprintf(&str[strlen(str)], "- ");
+ }
+ sprintf(&str[strlen(str)], "%02x ", data[idx]);
+ if ((idx & 0xf) == 0xf) {
+ sprintf(&str[strlen(str)], "\n");
+ gprintk(str);
+ }
+ }
+ if ((idx & 0xf) != 0) {
+ sprintf(&str[strlen(str)], "\n");
+ gprintk(str);
+ }
+}
+
+static bkn_switch_info_t *
+bkn_sinfo_from_unit(int unit)
+{
+ struct list_head *list;
+ bkn_switch_info_t *sinfo;
+
+ list_for_each(list, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)list;
+ if (sinfo->dev_no == unit || unit == -1) {
+ return sinfo;
+ }
+ }
+ return NULL;
+}
+
+static void
+bkn_cdma_goto(bkn_switch_info_t *sinfo, int chan, uint64_t dcb)
+{
+ if (sinfo->basedev_suspended) {
+ return;
+ }
+
+ /* Set the new halt location */
+ sinfo->halt_addr[chan] = dcb;
+ dev_cdma_halt_set(sinfo, chan);
+}
+
+static void
+bkn_api_rx_restart(bkn_switch_info_t *sinfo, int chan)
+{
+ bkn_dcb_chain_t *dcb_chain;
+ int start_dma;
+
+ if (sinfo->basedev_suspended) {
+ return;
+ }
+
+ /* If resume from basedev suspended, there could be a suspended chain */
+ if (sinfo->rx[chan].api_dcb_chain) {
+ return;
+ }
+
+ /* Assume that driver lock is held */
+ if (!list_empty(&sinfo->rx[chan].api_dcb_list)) {
+ dcb_chain = list_entry(sinfo->rx[chan].api_dcb_list.next,
+ bkn_dcb_chain_t, list);
+ start_dma = 0;
+ if (sinfo->rx[chan].use_rx_skb == 0) {
+ sinfo->rx[chan].chain_complete = 0;
+ start_dma = 1;
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) &&
+ sinfo->rx[chan].api_active) {
+ /* HW is running already, so we just move to the next chain */
+ start_dma = 0;
+ }
+ }
+ sinfo->rx[chan].api_dcb_chain = dcb_chain;
+ sinfo->rx[chan].api_active = 1;
+ if (start_dma) {
+ DBG_DCB_RX(("Start API Rx DMA, first DCB @ 0x%08x (%d DCBs).\n",
+ (uint32_t)dcb_chain->dcb_dma, dcb_chain->dcb_cnt));
+ dev_dma_chan_clear(sinfo, XGS_DMA_RX_CHAN + chan);
+ dev_irq_mask_enable(sinfo, XGS_DMA_RX_CHAN + chan, 1);
+ dev_dma_chan_start(sinfo, XGS_DMA_RX_CHAN + chan, dcb_chain->dcb_dma);
+ }
+
+ list_del(&dcb_chain->list);
+ }
+}
+
+static void
+bkn_api_rx_chain_done(bkn_switch_info_t *sinfo, int chan)
+{
+ DBG_DCB_RX(("API Rx DMA chain done\n"));
+
+ if (!CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ sinfo->rx[chan].api_active = 0;
+ }
+ if (sinfo->rx[chan].api_dcb_chain) {
+ kfree(sinfo->rx[chan].api_dcb_chain);
+ sinfo->rx[chan].api_dcb_chain = NULL;
+ }
+ bkn_api_rx_restart(sinfo, chan);
+}
+
+static int
+bkn_api_rx_copy_from_skb(bkn_switch_info_t *sinfo,
+ int chan, bkn_desc_info_t *desc)
+{
+ bkn_dcb_chain_t *dcb_chain;
+ uint32_t *dcb;
+ uint32_t dcb_stat;
+ uint8_t *pkt;
+ uint64_t pkt_dma;
+ int pktlen;
+ int i;
+ bkn_evt_resource_t *evt;
+
+ dcb_stat = desc->dcb_mem[sinfo->dcb_wsize-1];
+ pktlen = dcb_stat & SOC_DCB_KNET_COUNT_MASK;
+
+ dcb_chain = sinfo->rx[chan].api_dcb_chain;
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) && dcb_chain == NULL) {
+ /* Last chain done, try to get a new one */
+ bkn_api_rx_chain_done(sinfo, chan);
+ dcb_chain = sinfo->rx[chan].api_dcb_chain;
+ }
+ if (dcb_chain == NULL) {
+ DBG_WARN(("No Rx API buffers\n"));
+ sinfo->rx[chan].pkts_d_no_api_buf++;
+ return -1;
+ }
+ dcb = &dcb_chain->dcb_mem[dcb_chain->dcb_cur * sinfo->dcb_wsize];
+ if ((sinfo->cmic_type == 'x' && (dcb[2] & 0xffff) < pktlen) ||
+ (sinfo->cmic_type != 'x' && (dcb[1] & 0xffff) < pktlen)) {
+ DBG_WARN(("Rx API buffer too small\n"));
+ return -1;
+ }
+ if (sinfo->cmic_type == 'x') {
+ pkt_dma = BUS_TO_DMA_HI(dcb[1]);
+ pkt_dma = pkt_dma << 32 | dcb[0];
+ } else {
+ pkt_dma = dcb[0];
+ }
+ pkt = (uint8_t *)kernel_bde->p2l(sinfo->dev_no, (sal_paddr_t)pkt_dma);
+ if (pkt == NULL) {
+ DBG_WARN(("Invalid Rx API buffer\n"));
+ return -1;
+ }
+
+ /* Copy packet data */
+ memcpy(pkt, desc->skb->data, pktlen);
+
+ /* Copy packet metadata and mark as done */
+ if (sinfo->cmic_type != 'x') {
+ for (i = SOC_DCB_META_OFFSET; i < sinfo->dcb_wsize; i++) {
+ dcb[i] = desc->dcb_mem[i];
+ }
+ }
+ dcb[sinfo->dcb_wsize-1] = dcb_stat | SOC_DCB_KNET_DONE;
+ MEMORY_BARRIER;
+
+ dcb_chain->dcb_cur++;
+
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ dcb = &dcb_chain->dcb_mem[dcb_chain->dcb_cur * sinfo->dcb_wsize];
+ if ((sinfo->cmic_type == 'x' && dcb[2] & (1 << 18)) ||
+ (sinfo->cmic_type != 'x' && dcb[1] & (1 << 18))) {
+ /* Get the next chain if reload done */
+ dcb[sinfo->dcb_wsize-1] |= 1 << 31 | SOC_DCB_KNET_DONE;
+ MEMORY_BARRIER;
+ bkn_api_rx_chain_done(sinfo, chan);
+ dcb_chain = sinfo->rx[chan].api_dcb_chain;
+ if (dcb_chain == NULL) {
+ sinfo->rx[chan].api_dcb_chain_end = NULL;
+ }
+ }
+ } else {
+ if ((sinfo->cmic_type == 'x' && (dcb[2] & (1 << 16)) == 0) ||
+ (sinfo->cmic_type != 'x' && (dcb[1] & (1 << 16)) == 0)) {
+ bkn_api_rx_chain_done(sinfo, chan);
+ }
+ }
+
+ sinfo->dma_events |= KCOM_DMA_INFO_F_RX_DONE;
+
+ evt = &_bkn_evt[sinfo->evt_idx];
+ evt->evt_wq_put++;
+ wake_up_interruptible(&evt->evt_wq);
+
+ return 0;
+}
+
+static void
+bkn_rx_refill(bkn_switch_info_t *sinfo, int chan)
+{
+ struct sk_buff *skb;
+ bkn_desc_info_t *desc;
+ uint32_t *dcb;
+ uint32_t resv_size = sinfo->cmic_type == 'x' ? RCPU_HDR_SIZE : RCPU_RX_ENCAP_SIZE;
+ uint32_t meta_size = sinfo->cmic_type == 'x' ? RCPU_RX_META_SIZE : 0;
+ int prev;
+
+ if (sinfo->rx[chan].use_rx_skb == 0) {
+ /* Rx buffers are provided by BCM Rx API */
+ return;
+ }
+
+ if (!CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) &&
+ sinfo->rx[chan].tokens < MAX_RX_DCBS) {
+ /* Pause DMA for now */
+ return;
+ }
+
+ while (sinfo->rx[chan].free < MAX_RX_DCBS) {
+ desc = &sinfo->rx[chan].desc[sinfo->rx[chan].cur];
+ if (desc->skb == NULL) {
+ skb = dev_alloc_skb(rx_buffer_size + RCPU_RX_ENCAP_SIZE);
+ if (skb == NULL) {
+ break;
+ }
+ skb_reserve(skb, resv_size);
+ desc->skb = skb;
+ } else {
+ DBG_DCB_RX(("Refill Rx%d SKB in DCB %d recycled.\n",
+ chan, sinfo->rx[chan].cur));
+ }
+ skb = desc->skb;
+ desc->dma_size = rx_buffer_size + meta_size;
+#ifdef KNET_NO_AXI_DMA_INVAL
+ /*
+ * FIXME: Need to retain this code until iProc customers have been
+ * migrated to updated u-boot. Old u-boot versions are unable to load
+ * the kernel into non-ACP memory.
+ */
+ /*
+ * Cache invalidate may corrupt DMA memory on some iProc-based devices
+ * if the kernel is mapped to ACP memory.
+ */
+ if (sinfo->pdev == NULL) {
+ desc->dma_size = 0;
+ }
+#endif
+ desc->skb_dma = BKN_DMA_MAP_SINGLE(sinfo->dma_dev,
+ skb->data, desc->dma_size,
+ BKN_DMA_FROMDEV);
+ if (BKN_DMA_MAPPING_ERROR(sinfo->dma_dev, desc->skb_dma)) {
+ dev_kfree_skb_any(skb);
+ desc->skb = NULL;
+ break;
+ }
+ DBG_DCB_RX(("Refill Rx%d DCB %d (0x%08x).\n",
+ chan, sinfo->rx[chan].cur, (uint32_t)desc->skb_dma));
+ dcb = desc->dcb_mem;
+ dcb[0] = desc->skb_dma;
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ if (sinfo->cmic_type == 'x') {
+ dcb[2] |= 1 << 24 | 1 << 16;
+ } else {
+ dcb[1] |= 1 << 24 | 1 << 16;
+ }
+ } else {
+ prev = PREV_IDX(sinfo->rx[chan].cur, MAX_RX_DCBS);
+ if (prev < (MAX_RX_DCBS - 1)) {
+ if (sinfo->cmic_type == 'x') {
+ sinfo->rx[chan].desc[prev].dcb_mem[2] |= 1 << 16;
+ } else {
+ sinfo->rx[chan].desc[prev].dcb_mem[1] |= 1 << 16;
+ }
+ }
+ }
+ if (sinfo->cmic_type == 'x') {
+ dcb[1] = DMA_TO_BUS_HI(desc->skb_dma >> 32);
+ dcb[2] |= rx_buffer_size + meta_size;
+ } else {
+ dcb[1] |= rx_buffer_size;
+ }
+
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) &&
+ sinfo->rx[chan].tokens > MAX_RX_DCBS) {
+ /* DMA run to the new halt location */
+ bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, desc->dcb_dma);
+ }
+
+ if (++sinfo->rx[chan].cur >= MAX_RX_DCBS) {
+ sinfo->rx[chan].cur = 0;
+ }
+ sinfo->rx[chan].free++;
+ sinfo->rx[chan].tokens--;
+ }
+}
+
+static int
+bkn_rx_restart(bkn_switch_info_t *sinfo, int chan)
+{
+ bkn_desc_info_t *desc;
+
+ if (sinfo->basedev_suspended) {
+ return 0;
+ }
+
+ if (sinfo->rx[chan].running) {
+ return 0;
+ }
+
+ if (sinfo->rx[chan].free < MAX_RX_DCBS) {
+ return 1;
+ }
+
+ desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty];
+ sinfo->rx[chan].chain_complete = 0;
+ DBG_DCB_RX(("Restart Rx%d DMA, DCB @ 0x%08x (%d).\n",
+ chan, (uint32_t)desc->dcb_dma, sinfo->rx[chan].dirty));
+ dev_dma_chan_clear(sinfo, XGS_DMA_RX_CHAN + chan);
+ dev_irq_mask_enable(sinfo, XGS_DMA_RX_CHAN + chan, 1);
+ dev_dma_chan_start(sinfo, XGS_DMA_RX_CHAN + chan, desc->dcb_dma);
+ sinfo->rx[chan].running = 1;
+
+ /* Request one extra poll if chain was restarted during poll */
+ if (sinfo->napi_poll_mode) {
+ sinfo->napi_poll_again = 1;
+ }
+
+ return 0;
+}
+
+static int
+bkn_tx_dma_start(bkn_switch_info_t *sinfo)
+{
+ bkn_desc_info_t *desc;
+
+ desc = &sinfo->tx.desc[sinfo->tx.cur];
+ if (sinfo->tx.free == MAX_TX_DCBS) {
+ if (!sinfo->tx.api_active) {
+ DBG_DCB_TX(("Start Tx DMA, DCB @ 0x%08x (%d).\n",
+ (uint32_t)desc->dcb_dma, sinfo->tx.cur));
+ dev_dma_chan_clear(sinfo, XGS_DMA_TX_CHAN);
+ dev_irq_mask_enable(sinfo, XGS_DMA_TX_CHAN, 1);
+ dev_dma_chan_start(sinfo, XGS_DMA_TX_CHAN, desc->dcb_dma);
+ }
+ }
+
+ return 0;
+}
+
+static int
+bkn_dma_init(bkn_switch_info_t *sinfo)
+{
+ int chan;
+
+ dev_dma_chan_init(sinfo, XGS_DMA_TX_CHAN, 1);
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ bkn_tx_dma_start(sinfo);
+ }
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ dev_dma_chan_init(sinfo, XGS_DMA_RX_CHAN + chan, 0);
+ bkn_rx_refill(sinfo, chan);
+ bkn_rx_restart(sinfo, chan);
+ }
+
+ return 0;
+}
+
+static int
+bkn_dma_abort_tx(bkn_switch_info_t *sinfo)
+{
+ bkn_dcb_chain_t *dcb_chain;
+
+ DBG_VERB(("Aborting Tx DMA.\n"));
+
+ dev_irq_mask_disable(sinfo, XGS_DMA_TX_CHAN, 1);
+
+ dev_dma_chan_abort(sinfo, XGS_DMA_TX_CHAN, 10000);
+
+ if (sinfo->tx.api_dcb_chain) {
+ DBG_DCB_TX(("Freeing active Tx DCB chain.\n"));
+ kfree(sinfo->tx.api_dcb_chain);
+ sinfo->tx.api_dcb_chain = NULL;
+ }
+ while (!list_empty(&sinfo->tx.api_dcb_list)) {
+ dcb_chain = list_entry(sinfo->tx.api_dcb_list.next,
+ bkn_dcb_chain_t, list);
+ list_del(&dcb_chain->list);
+ DBG_DCB_TX(("Freeing Tx DCB chain.\n"));
+ kfree(dcb_chain);
+ }
+ sinfo->tx.api_dcb_chain_end = NULL;
+
+ return 0;
+}
+
+static int
+bkn_dma_abort_rx(bkn_switch_info_t *sinfo, int chan)
+{
+ bkn_dcb_chain_t *dcb_chain;
+
+ DBG_VERB(("Aborting Rx%d DMA.\n", chan));
+
+ dev_irq_mask_disable(sinfo, XGS_DMA_RX_CHAN + chan, 1);
+
+ dev_dma_chan_abort(sinfo, XGS_DMA_RX_CHAN + chan, 10000);
+
+ if (sinfo->rx[chan].api_dcb_chain) {
+ DBG_DCB_RX(("Freeing active Rx%d DCB chain.\n", chan));
+ kfree(sinfo->rx[chan].api_dcb_chain);
+ sinfo->rx[chan].api_dcb_chain = NULL;
+ }
+ while (!list_empty(&sinfo->rx[chan].api_dcb_list)) {
+ dcb_chain = list_entry(sinfo->rx[chan].api_dcb_list.next,
+ bkn_dcb_chain_t, list);
+ list_del(&dcb_chain->list);
+ DBG_DCB_RX(("Freeing Rx%d DCB chain.\n", chan));
+ kfree(dcb_chain);
+ }
+ sinfo->rx[chan].api_dcb_chain_end = NULL;
+
+ return 0;
+}
+
+static int
+bkn_dma_abort(bkn_switch_info_t *sinfo)
+{
+ int chan;
+
+ bkn_dma_abort_tx(sinfo);
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ bkn_dma_abort_rx(sinfo, chan);
+ }
+
+ return 0;
+}
+
+static int
+device_is_dpp(bkn_switch_info_t *sinfo)
+{
+ int is_dpp = 0;
+
+ is_dpp = (sinfo->dcb_type == 28) ? 1 : 0;
+ return is_dpp;
+}
+
+static int
+device_is_dnx(bkn_switch_info_t *sinfo)
+{
+ int is_dnx = 0;
+
+ is_dnx = (sinfo->dcb_type == 39) ? 1 : 0;
+ return is_dnx;
+}
+
+/* is DPP or is DNX*/
+static int
+device_is_sand(bkn_switch_info_t *sinfo)
+{
+ int is_sand = 0;
+
+ if (device_is_dpp(sinfo) || device_is_dnx(sinfo)) {
+ is_sand = 1;
+ }
+ return is_sand;
+}
+
+static bkn_filter_t *
+bkn_match_rx_pkt(bkn_switch_info_t *sinfo, uint8_t *pkt, int pktlen,
+ void *meta, int chan, bkn_filter_t *cbf)
+{
+ struct list_head *list;
+ bkn_filter_t *filter;
+ kcom_filter_t scratch, *kf;
+ uint8_t *oob = (uint8_t *)meta;
+ int size, wsize;
+ int idx, match;
+
+ list_for_each(list, &sinfo->rxpf_list) {
+ filter = (bkn_filter_t *)list;
+ kf = &filter->kf;
+ memcpy(&scratch.data.b[0],
+ &oob[kf->oob_data_offset], kf->oob_data_size);
+ memcpy(&scratch.data.b[kf->oob_data_size],
+ &pkt[kf->pkt_data_offset], kf->pkt_data_size);
+ size = kf->oob_data_size + kf->pkt_data_size;
+ wsize = BYTES2WORDS(size);
+ DBG_VERB(("Filter: size = %d (%d), data = 0x%08x, mask = 0x%08x\n",
+ size, wsize, kf->data.w[0], kf->mask.w[0]));
+
+ if (device_is_sand(sinfo)) {
+ DBG_DUNE(("Filter: size = %d (wsize %d)\n", size, wsize));
+ for (idx = 0; idx < wsize; idx++)
+ {
+ DBG_DUNE(("OOB[%d]: 0x%08x [0x%08x]\n", idx, kf->data.w[idx], kf->mask.w[idx]));
+ }
+ DBG_DUNE(("Meta Data [+ Selected Raw packet data]\n"));
+ for (idx = 0; idx < wsize; idx++)
+ {
+ DBG_DUNE(("Scratch[%d]: 0x%08x\n", idx, scratch.data.w[idx]));
+ }
+ }
+
+ match = 1;
+ if (match) {
+ if (device_is_dnx(sinfo))
+ {
+ /*
+ * Mutliple RX channels are enabled on JR2 and above devices
+ * Bind between priority 0 and RX channel 0 is not checked, then all enabled RX channels can receive packets.
+ */
+ if (kf->priority && (kf->priority < (num_rx_prio * sinfo->rx_chans))) {
+ if (kf->priority < (num_rx_prio * chan) ||
+ kf->priority >= (num_rx_prio * (chan + 1))) {
+ match = 0;
+ }
+ }
+ }
+ else {
+ if (kf->priority < (num_rx_prio * sinfo->rx_chans)) {
+ if (kf->priority < (num_rx_prio * chan) ||
+ kf->priority >= (num_rx_prio * (chan + 1))) {
+ match = 0;
+ }
+ }
+ }
+ }
+ if (match) {
+ for (idx = 0; idx < wsize; idx++) {
+ scratch.data.w[idx] &= kf->mask.w[idx];
+ if (scratch.data.w[idx] != kf->data.w[idx]) {
+ match = 0;
+ break;
+ }
+ }
+ }
+ if (match) {
+ if (kf->dest_type == KCOM_DEST_T_CB) {
+ /* Check for custom filters */
+ if (knet_filter_cb != NULL && cbf != NULL) {
+ memset(cbf, 0, sizeof(*cbf));
+ memcpy(&cbf->kf, kf, sizeof(cbf->kf));
+ if (knet_filter_cb(pkt, pktlen, sinfo->dev_no,
+ meta, chan, &cbf->kf)) {
+ filter->hits++;
+ return cbf;
+ }
+ } else {
+ DBG_FLTR(("Match, but not filter callback\n"));
+ }
+ } else {
+ filter->hits++;
+ return filter;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static bkn_priv_t *
+bkn_netif_lookup(bkn_switch_info_t *sinfo, int id)
+{
+ struct list_head *list;
+ bkn_priv_t *priv;
+ int found;
+
+ /* Fast path */
+ if (id < sinfo->ndev_max) {
+ if (sinfo->ndevs[id] != NULL) {
+ DBG_NDEV(("Look up netif ID %d successful\n", id));
+ return netdev_priv(sinfo->ndevs[id]);
+ }
+ }
+
+ /* Slow path - should normally not get here */
+ found = 0;
+ priv = NULL;
+ list_for_each(list, &sinfo->ndev_list) {
+ priv = (bkn_priv_t *)list;
+ if (priv->id == id) {
+ found = 1;
+ break;
+ }
+ }
+ if (found && priv != NULL) {
+ return priv;
+ }
+ return NULL;
+}
+
+static int
+bkn_hw_tstamp_rx_set(bkn_switch_info_t *sinfo, int phys_port, struct sk_buff *skb, uint32 *meta)
+{
+ struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
+ uint64_t ts = 0;
+
+
+ if (knet_hw_tstamp_rx_time_upscale_cb) {
+ if (knet_hw_tstamp_rx_time_upscale_cb(sinfo->dev_no, phys_port, skb, meta, &ts) < 0) {
+ return -1;
+ }
+ }
+
+ memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+ shhwtstamps->hwtstamp = ns_to_ktime(ts);
+
+ return 0;
+}
+
+static int
+bkn_add_rcpu_encap(bkn_switch_info_t *sinfo, struct sk_buff *skb, void *meta, int len)
+{
+ int pktlen = skb->len;
+ uint32_t *dmeta, *smeta, wsize, psize;
+ int idx;
+
+ /* Add and clear RCPU encapsulation */
+ if (device_is_sand(sinfo)) {
+ psize = RCPU_RX_ENCAP_SIZE;
+ skb_push(skb, psize);
+ memset(skb->data, 0, RCPU_RX_ENCAP_SIZE);
+ } else if (sinfo->cmic_type == 'x') {
+ psize = RCPU_HDR_SIZE + sinfo->pkt_hdr_size;
+ skb_push(skb, psize);
+ memset(skb->data, 0, RCPU_HDR_SIZE);
+ } else {
+ psize = RCPU_RX_ENCAP_SIZE;
+ skb_push(skb, psize);
+ memset(skb->data, 0, RCPU_RX_ENCAP_SIZE);
+ }
+
+ /* RCPU Header */
+ memcpy(skb->data, &skb->data[psize], 12);
+ if (rcpu_dmac != NULL) {
+ memcpy(skb->data, bkn_rcpu_dmac, 6);
+ }
+ if (rcpu_smac != NULL) {
+ memcpy(&skb->data[6], bkn_rcpu_smac, 6);
+ }
+ skb->data[12] = 0x81;
+ skb->data[14] = rcpu_vlan >> 8;
+ skb->data[15] = rcpu_vlan & 0xff;
+ skb->data[16] = rcpu_ethertype >> 8;
+ skb->data[17] = rcpu_ethertype & 0xff;
+ skb->data[18] = sinfo->rcpu_sig >> 8;
+ skb->data[19] = sinfo->rcpu_sig & 0xff;
+ skb->data[20] = RCPU_OPCODE_RX;
+ skb->data[21] = RCPU_F_MODHDR;
+ skb->data[24] = pktlen >> 8;
+ skb->data[25] = pktlen & 0xff;
+
+ /* Meta data */
+ dmeta = (uint32_t *)&skb->data[RCPU_HDR_SIZE];
+
+ if (device_is_sand(sinfo)) {
+ /* Copy at most 64 bytes system headers */
+ len = len > RCPU_RX_META_SIZE ? RCPU_RX_META_SIZE : len;
+ memcpy(&skb->data[RCPU_HDR_SIZE], (uint8_t *)meta, len);
+ } else {
+ smeta = sinfo->cmic_type == 'x' ? (uint32_t *)meta : (uint32_t *)meta + 2;
+ wsize = sinfo->cmic_type == 'x' ? sinfo->pkt_hdr_size / 4 : sinfo->dcb_wsize - 3;
+ for (idx = 0; idx < wsize; idx++) {
+ dmeta[idx] = htonl(smeta[idx]);
+ }
+ }
+
+
+ return 0;
+}
+
+static void
+bkn_eth_type_update(struct sk_buff *skb, int ethertype)
+{
+#if defined(PM_ETH_TYPE) && defined(PM_FC_TYPE)
+ /* Optionally override standard protocol */
+ skb->protocol = PM_ETH_TYPE;
+ if (ethertype == ETH_P_FCOE) {
+ skb->protocol = PM_FC_TYPE;
+ }
+#endif
+}
+
+#define BKN_DNX_BIT(x) (1<<(x))
+#define BKN_DNX_RBIT(x) (~(1<<(x)))
+#ifdef __LITTLE_ENDIAN
+#define BKN_DNX_BYTE_SWAP(x) (x)
+#else
+#define BKN_DNX_BYTE_SWAP(x) ((((x) << 24)) | (((x) & 0xff00) << 8) | (((x) & 0xff0000) >> 8) | (((x) >> 24)))
+#endif
+
+static int
+packet_is_untagged(uint16_t tpid)
+{
+ int is_untagged = 0;
+
+ /* 0x8100 is used in 802.1Q */
+ /* 0x8848 is used in 802.11ad, the dtag tpid can be set to anything besides 0x8848, 0x9100 is a typical value, but couldn't cover all scenarios. */
+ is_untagged = ((tpid != 0x8100) && (tpid != 0x8848) && (tpid != 0x9100));
+ return is_untagged;
+}
+
+static void
+bkn_bitstream_set_field(uint32_t *input_buffer, uint32_t start_bit, uint32_t nof_bits, uint32_t field)
+{
+ uint32_t place;
+ uint32_t field_bit_i;
+ uint32_t bit_indicator;
+
+ if( nof_bits > 32)
+ {
+ return;
+ }
+
+ for( place=start_bit, field_bit_i = 0; field_bit_i< nof_bits; ++place, ++field_bit_i)
+ {
+ bit_indicator = field & BKN_DNX_BIT(nof_bits-field_bit_i-1);
+ if(bit_indicator)
+ {
+ input_buffer[place>>5] |= (0x80000000 >> (place & 0x0000001F));
+ }
+ else
+ {
+ input_buffer[place>>5] &= ~(0x80000000 >> (place & 0x0000001F));
+ }
+ }
+ return;
+}
+
+static void
+bkn_bitstream_get_field(uint8_t *input_buffer, uint32_t start_bit, uint32_t nof_bits, uint32_t *output_value)
+{
+ uint32_t idx;
+ uint32_t buf_sizes=0;
+ uint32_t tmp_output_value[2]={0};
+ uint32_t first_byte_ndx;
+ uint32_t last_byte_ndx;
+ uint32_t place;
+ uint32_t field_bit_i;
+ uint8_t *tmp_output_value_u8_ptr = (uint8_t*)&tmp_output_value;
+ uint32_t bit_indicator;
+
+ if (nof_bits > 32)
+ {
+ return;
+ }
+
+ first_byte_ndx = start_bit / 8;
+ last_byte_ndx = ((start_bit + nof_bits - 1) / 8);
+ *output_value=0;
+
+ /* get 32 bit value, MSB */
+ for (idx = first_byte_ndx; idx <= last_byte_ndx; ++idx)
+ {
+ tmp_output_value_u8_ptr[last_byte_ndx - idx] = input_buffer[idx];
+ buf_sizes += 8;
+ }
+ tmp_output_value[0] = BKN_DNX_BYTE_SWAP(tmp_output_value[0]);
+ if (last_byte_ndx > 4)
+ {
+ tmp_output_value[1] = BKN_DNX_BYTE_SWAP(tmp_output_value[1]);
+ }
+
+ place = buf_sizes - (start_bit % 8 + nof_bits);
+ for (field_bit_i = 0; field_bit_i< nof_bits; ++place, ++field_bit_i)
+ {
+ uint32_t result;
+ result = tmp_output_value[place>>5] & BKN_DNX_BIT(place & 0x0000001F);
+ if (result)
+ {
+ bit_indicator = 1;
+ } else {
+ bit_indicator = 0;
+ }
+ *output_value |= bit_indicator << field_bit_i;
+ }
+ return;
+}
+
+static void
+bkn_dpp_packet_parse_ftmh(
+ bkn_switch_info_t *sinfo,
+ uint8_t *buf,
+ uint32_t buf_len,
+ bkn_dune_system_header_info_t *packet_info,
+ uint8_t *is_tsh_en,
+ uint8_t *is_inter_hdr_en)
+{
+ uint32_t pkt_offset = packet_info->system_header_size;
+ uint32_t dsp_ext_exist = 0;
+ uint32_t fld_val;
+
+ /* FTMH: Source-system-port-aggregate */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DPP_FTMH_SRC_SYS_PORT_MSB,
+ BKN_DPP_FTMH_SRC_SYS_PORT_NOF_BITS,
+ &packet_info->ftmh.source_sys_port_aggregate);
+ /* FTMH: TM-action-type */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DPP_FTMH_ACTION_TYPE_MSB,
+ BKN_DPP_FTMH_ACTION_TYPE_NOF_BITS,
+ &packet_info->ftmh.action_type);
+ /* FTMH: Internal-type */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DPP_FTMH_PPH_TYPE_MSB,
+ BKN_DPP_FTMH_PPH_TYPE_NOF_BITS,
+ &fld_val);
+
+ /* FTMH: DSP Extension */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DPP_FTMH_EXT_DSP_EXIST_MSB,
+ BKN_DPP_FTMH_EXT_DSP_EXIST_NOF_BITS,
+ &dsp_ext_exist);
+
+ if (fld_val & 0x1)
+ {
+ *is_inter_hdr_en = TRUE;
+ }
+ if (fld_val & 0x2)
+ {
+ *is_tsh_en = TRUE;
+ }
+
+ pkt_offset += BKN_DPP_FTMH_SIZE_BYTE;
+ DBG_DUNE(("FTMH(9-%u): Action-type %d Source-system-port 0x%x\n", pkt_offset,
+ packet_info->ftmh.action_type,
+ packet_info->ftmh.source_sys_port_aggregate));
+
+ /* FTMH LB-Key Extension */
+ if (sinfo->ftmh_lb_key_ext_size)
+ {
+ pkt_offset += sinfo->ftmh_lb_key_ext_size;
+ DBG_DUNE(("FTMH LB-Key Extension(1-%u) is present\n", pkt_offset));
+ }
+
+ if (dsp_ext_exist)
+ {
+ pkt_offset += BKN_DPP_FTMH_DEST_EXT_SIZE_BYTE;
+ DBG_DUNE(("FTMH DSP Extension(2-%u) is present\n", pkt_offset));
+ }
+
+ /* FTMH Stacking Extension */
+ if (sinfo->ftmh_stacking_ext_size)
+ {
+ pkt_offset += sinfo->ftmh_stacking_ext_size;
+ DBG_DUNE(("FTMH Stacking Extension(2-%u) is present\n", pkt_offset));
+ }
+
+ packet_info->system_header_size = pkt_offset;
+ return;
+}
+
+static void
+bkn_dpp_packet_parse_otsh(
+ bkn_switch_info_t *sinfo,
+ uint8_t *buf,
+ uint32_t buf_len,
+ bkn_dune_system_header_info_t *packet_info,
+ uint8_t *is_oam_dm_tod_en,
+ uint8_t *is_skip_udh)
+{
+ uint32_t pkt_offset = packet_info->system_header_size;
+ uint32_t type = 0;
+ uint32_t oam_sub_type = 0;
+
+ /* OTSH: TYPE */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DPP_OTSH_TYPE_MSB,
+ BKN_DPP_OTSH_TYPE_NOF_BITS,
+ &type);
+ if (type == BKN_DPP_OTSH_TYPE_OAM) {
+ /* OTSH: OAM_SUB_TYPE */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DPP_OTSH_OAM_SUB_TYPE_MSB,
+ BKN_DPP_OTSH_OAM_SUB_TYPE_NOF_BITS,
+ &oam_sub_type);
+ if ((oam_sub_type == BKN_DPP_OTSH_OAM_SUB_TYPE_DM_1588) || (oam_sub_type == BKN_DPP_OTSH_OAM_SUB_TYPE_DM_NTP)) {
+ *is_oam_dm_tod_en = TRUE;
+ /* Down MEP DM trapped packets will not have UDH present (even if configured), except for QAX when custom_feature_oam_dm_tod_msb_add_enable=0 */
+ if (!sinfo->no_skip_udh_check) {
+ *is_skip_udh = TRUE;
+ }
+ }
+ }
+ packet_info->system_header_size += BKN_DPP_OTSH_SIZE_BYTE;
+
+ DBG_DUNE(("OTSH(%d): Type 0x%x OAM-Sub-Type 0x%x\n", BKN_DPP_OTSH_SIZE_BYTE, type, oam_sub_type));
+ return;
+}
+
+static void
+bkn_dpp_packet_parse_internal(
+ bkn_switch_info_t *sinfo,
+ uint8_t *buf,
+ uint32_t buf_len,
+ bkn_dune_system_header_info_t *packet_info,
+ uint8_t is_oamp_punted,
+ uint8_t *is_trapped)
+{
+ uint32_t pkt_offset = packet_info->system_header_size;
+ uint32_t fld_val = 0;
+ uint32_t eei_extension_present = 0;
+ uint32_t learn_extension_present = 0;
+ uint32_t fhei_size = 0;
+
+ /* Internal: EEI EXT */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DPP_INTERNAL_EEI_EXTENSION_PRESENT_MSB,
+ BKN_DPP_INTERNAL_EEI_EXTENSION_PRESENT_NOF_BITS,
+ &eei_extension_present);
+ /* Internal: LERAN EXT */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DPP_INTERNAL_LEARN_EXENSION_PRESENT_MSB,
+ BKN_DPP_INTERNAL_LEARN_EXENSION_PRESENT_NOF_BITS,
+ &learn_extension_present);
+ /* Internal: FHEI EXT */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DPP_INTERNAL_FHEI_SIZE_MSB,
+ BKN_DPP_INTERNAL_FHEI_SIZE_NOF_BITS,
+ &fhei_size);
+ /* Internal: FORWARD_CODE */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DPP_INTERNAL_FORWARD_CODE_MSB,
+ BKN_DPP_INTERNAL_FORWARD_CODE_NOF_BITS,
+ &fld_val);
+ *is_trapped = (uint8_t)(fld_val == BKN_DPP_INTERNAL_FORWARD_CODE_CPU_TRAP);
+ /* Internal: VSI */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DPP_INTERNAL_VSI_MSB,
+ BKN_DPP_INTERNAL_VSI_NOF_BITS,
+ &fld_val);
+ packet_info->internal.forward_domain = fld_val;
+
+ if (is_oamp_punted && *is_trapped) {
+ if(fhei_size == 3) {
+ /* Force to FHEI size 1 when packets are punted by OAMP */
+ fhei_size = 1;
+ }
+ }
+
+ /* Move forward to end of Internal header */
+ pkt_offset += BKN_DPP_INTERNAL_SIZE_BYTE;
+
+ DBG_DUNE(("PPH(7-%u): EEI-Extension %d Learn-Extension %d VSI %d FHEI-size %d\n",
+ pkt_offset, eei_extension_present,learn_extension_present, packet_info->internal.forward_domain, fhei_size));
+
+ /* Advance header according to FHEI Trap extension */
+ switch(fhei_size) {
+ case 1:
+ /* 3B FHEI Extension: do nothing, header poniter is in the right location */
+ break;
+ case 2:
+ /* 5B FHEI Extension: adavance header pointer in 2B */
+ pkt_offset += 2;
+ break;
+ case 3:
+ /* 8B FHEI Extension: adavance header pointer in 5B */
+ pkt_offset += 5;
+ break;
+ default:
+ break;
+ }
+
+ /* Internal extension */
+ if (*is_trapped && fhei_size)
+ {
+ /* CPU trap code qualifier */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DPP_INTERNAL_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_MSB,
+ BKN_DPP_INTERNAL_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_QUALIFIER_NOF_BITS,
+ &packet_info->internal.trap_qualifier);
+ /* CPU trap code */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DPP_INTERNAL_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_MSB,
+ BKN_DPP_INTERNAL_FHEI_TRAP_SNOOP_3B_CPU_TRAP_CODE_NOF_BITS,
+ &packet_info->internal.trap_id);
+
+ DBG_DUNE(("FHEI: trap_qualifier 0x%x trap_id 0x%x\n",
+ packet_info->internal.trap_qualifier,
+ packet_info->internal.trap_id));
+ }
+
+ /* Move forward to end of FHEI Trap extension */
+ if (fhei_size) {
+ pkt_offset += 3;
+ }
+
+ /* EEI extension */
+ if (eei_extension_present) {
+ pkt_offset += BKN_DPP_INTERNAL_EXPLICIT_EDITING_INFOMATION_EXTENSION_SIZE_BYTE;
+ }
+ /* Learn extension */
+ if (learn_extension_present) {
+ pkt_offset += BKN_DPP_INTERNAL_LEARN_EXTENSION_SIZE_BYTE;
+ }
+
+ packet_info->system_header_size = pkt_offset;
+ return;
+}
+
+static int
+bkn_dpp_packet_header_parse(
+ bkn_switch_info_t *sinfo,
+ uint8_t *buff,
+ uint32_t buff_len,
+ bkn_dune_system_header_info_t *packet_info)
+{
+ uint8_t is_inter_hdr_en = FALSE;
+ uint8_t is_tsh_en = FALSE;
+ uint8_t is_oamp_punted = FALSE;
+ uint8_t is_trapped = FALSE;
+ uint8_t is_oam_dm_tod_en = FALSE;
+ uint8_t is_skip_udh = FALSE;
+
+ if ((sinfo == NULL) || (buff == NULL) || (packet_info == NULL)) {
+ return -1;
+ }
+
+ /* FTMH */
+ bkn_dpp_packet_parse_ftmh(sinfo, buff, buff_len, packet_info, &is_tsh_en, &is_inter_hdr_en);
+ /* Check if packet is punted from OAMP */
+ if (sinfo->oamp_punt && (packet_info->ftmh.source_sys_port_aggregate == sinfo->oamp_punt)) {
+ is_oamp_punted = TRUE;
+ }
+ /* OTSH */
+ if (is_tsh_en == TRUE)
+ {
+ bkn_dpp_packet_parse_otsh(sinfo, buff, buff_len, packet_info, &is_oam_dm_tod_en, &is_skip_udh);
+ }
+ /* Internal header is forced to be present if packet was punted to CPU by OAMP */
+ if (sinfo->oamp_punt && (packet_info->ftmh.source_sys_port_aggregate == sinfo->oamp_punt))
+ {
+ is_inter_hdr_en = TRUE;
+ }
+ /* Internal */
+ if (is_inter_hdr_en)
+ {
+ bkn_dpp_packet_parse_internal(sinfo, buff, buff_len, packet_info, is_oamp_punted, &is_trapped);
+ }
+ /* Skip UDH for the outer layer when packet is punted by OAM for JR2 in JR1 mode */
+ if (device_is_dnx(sinfo) && is_oamp_punted) {
+ is_skip_udh = TRUE;
+ }
+ /* UDH */
+ if (sinfo->udh_size && !is_skip_udh) {
+ packet_info->system_header_size += sinfo->udh_size;
+ }
+ /* OAM DM TOD header */
+ if(is_oam_dm_tod_en) {
+ packet_info->system_header_size += BKN_DPP_OAM_DM_TOD_SIZE_BYTE;
+ }
+
+ /* Additional layer of system headers */
+ if (is_oamp_punted && is_trapped)
+ {
+ is_inter_hdr_en = FALSE;
+ is_tsh_en = FALSE;
+ is_oamp_punted = FALSE;
+ is_trapped = FALSE;
+ is_oam_dm_tod_en = FALSE;
+ is_skip_udh = FALSE;
+
+ /* FTMH */
+ bkn_dpp_packet_parse_ftmh(sinfo, buff, buff_len, packet_info, &is_tsh_en, &is_inter_hdr_en);
+ /* OTSH */
+ if (is_tsh_en == TRUE)
+ {
+ bkn_dpp_packet_parse_otsh(sinfo, buff, buff_len, packet_info, &is_oam_dm_tod_en, &is_skip_udh);
+ }
+ /* Internal */
+ if (is_inter_hdr_en)
+ {
+ bkn_dpp_packet_parse_internal(sinfo, buff, buff_len, packet_info, is_oamp_punted, &is_trapped);
+ }
+ /* OAMP Punted packets do not have UDH in the inner header for both JR1 and JR2 in JR1 mode */
+ /* OAM DM TOD header */
+ if(is_oam_dm_tod_en) {
+ packet_info->system_header_size += BKN_DPP_OAM_DM_TOD_SIZE_BYTE;
+ }
+ }
+
+ DBG_DUNE(("Total length of headers is %u\n", packet_info->system_header_size));
+
+ return 0;
+}
+
+
+static int
+bkn_dnx_packet_parse_ftmh(
+ bkn_switch_info_t *sinfo,
+ uint8_t *buf,
+ uint32_t buf_len,
+ bkn_dune_system_header_info_t *packet_info,
+ uint8_t *is_tsh_en,
+ uint8_t *is_inter_hdr_en)
+{
+ uint32_t fld_val;
+ uint32_t pkt_offset = packet_info->system_header_size;
+ uint8_t tm_dst_ext_present = 0;
+ uint8_t app_specific_ext_size = 0;
+ uint8_t flow_id_ext_size = 0;
+ uint8_t bier_bfr_ext_size = 0;
+
+ if ((sinfo == NULL) || (buf == NULL) || (packet_info == NULL)) {
+ return -1;
+ }
+
+ /* FTMH: Source-System-Port-Aggregate */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_MSB,
+ BKN_DNX_FTMH_SRC_SYS_PORT_AGGREGATE_NOF_BITS,
+ &fld_val);
+ packet_info->ftmh.source_sys_port_aggregate = fld_val;
+ /* FTMH: Action-Type */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_FTMH_ACTION_TYPE_MSB,
+ BKN_DNX_FTMH_ACTION_TYPE_NOF_BITS,
+ &fld_val);
+ packet_info->ftmh.action_type = fld_val;
+ /* FTMH: PPH-Type TSH */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_MSB,
+ BKN_DNX_FTMH_PPH_TYPE_IS_TSH_EN_NOF_BITS,
+ &fld_val);
+ *is_tsh_en = fld_val;
+ /* FTMH: PPH-Type PPH base */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_MSB,
+ BKN_DNX_FTMH_PPH_TYPE_IS_PPH_EN_NOF_BITS,
+ &fld_val);
+ *is_inter_hdr_en = fld_val;
+ /* FTMH: TM-Destination-Extension-Present */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_FTMH_TM_DST_EXT_PRESENT_MSB,
+ BKN_DNX_FTMH_TM_DST_EXT_PRESENT_NOF_BITS,
+ &fld_val);
+ tm_dst_ext_present = fld_val;
+ /* FTMH: Application-Specific-Extension-Size */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_MSB,
+ BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE_NOF_BITS,
+ &fld_val);
+ app_specific_ext_size = fld_val;
+ /* FTMH: Flow-ID-Extension-Size */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_MSB,
+ BKN_DNX_FTMH_FLOW_ID_EXT_SIZE_NOF_BITS,
+ &fld_val);
+ flow_id_ext_size = fld_val;
+ /* FTMH: BIER-BFR-Extension-Size */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_MSB,
+ BKN_DNX_FTMH_BIER_BFR_EXT_SIZE_NOF_BITS,
+ &fld_val);
+ bier_bfr_ext_size = fld_val;
+
+ pkt_offset += BKN_DNX_FTMH_BASE_SIZE;
+
+ DBG_DUNE(("FTMH(10-%u): source-system-port 0x%x action_type %u is_tsh_en %u is_inter_hdr_en %u\n",
+ pkt_offset, packet_info->ftmh.source_sys_port_aggregate,
+ packet_info->ftmh.action_type, *is_tsh_en, *is_inter_hdr_en));
+
+ /* FTMH LB-Key Extension */
+ if (sinfo->ftmh_lb_key_ext_size > 0)
+ {
+ pkt_offset += sinfo->ftmh_lb_key_ext_size;
+ DBG_DUNE(("FTMH LB-Key Extension(%u-%u) is present\n", sinfo->ftmh_lb_key_ext_size, pkt_offset));
+ }
+ /* FTMH Stacking Extension */
+ if (sinfo->ftmh_stacking_ext_size > 0)
+ {
+ pkt_offset += sinfo->ftmh_stacking_ext_size;
+ DBG_DUNE(("FTMH Stacking Extension(%u-%u) is present\n", sinfo->ftmh_stacking_ext_size, pkt_offset));
+ }
+ /* FTMH BIER BFR Extension */
+ if (bier_bfr_ext_size > 0)
+ {
+ pkt_offset += BKN_DNX_FTMH_BIER_BFR_EXT_SIZE;
+ DBG_DUNE(("FTMH BIER BFR Extension(2-%u) is present\n", pkt_offset));
+ }
+ /* FTMH TM Destination Extension */
+ if (tm_dst_ext_present > 0)
+ {
+ pkt_offset += BKN_DNX_FTMH_TM_DST_EXT_SIZE;
+ DBG_DUNE(("FTMH TM Destination Extension(3-%u) is present\n", pkt_offset));
+ }
+ /* FTMH Application Specific Extension */
+ if (app_specific_ext_size > 0)
+ {
+ pkt_offset += BKN_DNX_FTMH_APP_SPECIFIC_EXT_SIZE;
+ DBG_DUNE(("FTMH Application Specific Extension(6-%u) is present\n", pkt_offset));
+ }
+ /* FTMH Flow-ID Extension */
+ if (flow_id_ext_size > 0)
+ {
+ pkt_offset += BKN_DNX_FTMH_FLOW_ID_EXT_SIZE;
+ DBG_DUNE(("FTMH Flow-ID Extension(3-%u) is present\n", pkt_offset));
+ }
+
+ packet_info->system_header_size = pkt_offset;
+
+ return 0;
+}
+
+
+static int
+bkn_dnx_packet_parse_internal(
+ bkn_switch_info_t *sinfo,
+ uint8_t *buf,
+ uint32_t buf_len,
+ bkn_dune_system_header_info_t *packet_info,
+ uint8_t is_oamp_punted,
+ uint8_t *is_trapped)
+{
+ uint32_t fld_val;
+ uint32_t pkt_offset = packet_info->system_header_size;
+ uint8_t learn_ext_present;
+ uint8_t fhei_size;
+ uint8_t lif_ext_type;
+ uint8_t udh_en = sinfo->udh_enable;
+
+ if ((sinfo == NULL) || (buf == NULL) || (packet_info == NULL)) {
+ return -1;
+ }
+
+ /* Internal: Forward-Domain */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_INTERNAL_12_FORWARD_DOMAIN_MSB,
+ BKN_DNX_INTERNAL_12_FORWARD_DOMAIN_NOF_BITS,
+ &fld_val);
+ packet_info->internal.forward_domain = fld_val;
+ /* Internal: Learn-Extension-Present */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_INTERNAL_12_LEARN_EXT_PRESENT_MSB,
+ BKN_DNX_INTERNAL_12_LEARN_EXT_PRESENT_NOF_BITS,
+ &fld_val);
+ learn_ext_present = fld_val;
+ /* Internal: FHEI-Size */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_INTERNAL_12_FHEI_SIZE_MSB,
+ BKN_DNX_INTERNAL_12_FHEI_SIZE_NOF_BITS,
+ &fld_val);
+ fhei_size = fld_val;
+ /* Internal: LIF-Extension-Type */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_INTERNAL_12_LIF_EXT_TYPE_MSB,
+ BKN_DNX_INTERNAL_12_LIF_EXT_TYPE_NOF_BITS,
+ &fld_val);
+ lif_ext_type = fld_val;
+
+ pkt_offset += BKN_DNX_INTERNAL_BASE_TYPE_12;
+ DBG_DUNE(("Internal(12-%u): FWD_DOMAIN %d, LEARN_EXT %d, FHEI_SIZE %d, LIF_EXT %d \n",
+ pkt_offset, packet_info->internal.forward_domain,
+ learn_ext_present, fhei_size, lif_ext_type));
+
+ if (fhei_size)
+ {
+ switch (fhei_size)
+ {
+ case BKN_DNX_INTERNAL_FHEI_TYPE_SZ0:
+ pkt_offset += BKN_DNX_INTERNAL_FHEI_SZ0_SIZE;
+ DBG_DUNE(("FHEI(3-%u) is present\n", pkt_offset));
+ break;
+ case BKN_DNX_INTERNAL_FHEI_TYPE_SZ1:
+ /* FHEI: Type */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_INTERNAL_FHEI_TRAP_5B_TYPE_MSB,
+ BKN_DNX_INTERNAL_FHEI_TRAP_5B_TYPE_NOF_BITS,
+ &fld_val);
+ /* FHEI-Size == 5B, FHEI-Type == Trap/Sniff */
+ if (fld_val == 0x5)
+ {
+ *is_trapped = TRUE;
+ /* FHEI: Qualifier */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_INTERNAL_FHEI_TRAP_5B_QUALIFIER_MSB,
+ BKN_DNX_INTERNAL_FHEI_TRAP_5B_QUALIFIER_NOF_BITS,
+ &fld_val);
+ packet_info->internal.trap_qualifier = fld_val;
+ /* FHEI: Code */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_INTERNAL_FHEI_TRAP_5B_CODE_MSB,
+ BKN_DNX_INTERNAL_FHEI_TRAP_5B_CODE_NOF_BITS,
+ &fld_val);
+ packet_info->internal.trap_id= fld_val;
+ }
+ pkt_offset += BKN_DNX_INTERNAL_FHEI_SZ1_SIZE;
+ DBG_DUNE(("FHEI(5-%u): code 0x%x qualifier 0x%x\n", pkt_offset, packet_info->internal.trap_id, packet_info->internal.trap_qualifier));
+ break;
+ case BKN_DNX_INTERNAL_FHEI_TYPE_SZ2:
+ pkt_offset += BKN_DNX_INTERNAL_FHEI_SZ1_SIZE;
+ DBG_DUNE(("FHEI(8-%u) is present\n", pkt_offset));
+ break;
+ }
+ }
+
+ /* PPH LIF Extension */
+ if (lif_ext_type)
+ {
+ pkt_offset += sinfo->pph_lif_ext_size[lif_ext_type];
+ DBG_DUNE(("PPH LIF Extension(%d-%u) is present\n", sinfo->pph_lif_ext_size[lif_ext_type], pkt_offset));
+ }
+
+ /* PPH Learn Extension */
+ if (learn_ext_present)
+ {
+ pkt_offset += BKN_DNX_INTERNAL_LEARN_EXT_SIZE;
+ DBG_DUNE(("PPH Learn Extension(19-%u) is present\n", pkt_offset));
+ }
+
+ /** Skip UDH If packet is punted to CPU by OAMP */
+ if (is_oamp_punted) {
+ udh_en = FALSE;
+ }
+
+ /* UDH Header */
+ if (udh_en)
+ {
+ uint8_t data_type_0;
+ uint8_t data_type_1;
+ uint8_t data_type_2;
+ uint8_t data_type_3;
+
+ /* UDH: UDH-Data-Type[0] */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_UDH_DATA_TYPE_0_MSB,
+ BKN_DNX_UDH_DATA_TYPE_0_NOF_BITS,
+ &fld_val);
+ data_type_0 = fld_val;
+ /* UDH: UDH-Data-Type[1] */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_UDH_DATA_TYPE_1_MSB,
+ BKN_DNX_UDH_DATA_TYPE_1_NOF_BITS,
+ &fld_val);
+ data_type_1 = fld_val;
+ /* UDH: UDH-Data-Type[2] */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_UDH_DATA_TYPE_2_MSB,
+ BKN_DNX_UDH_DATA_TYPE_2_NOF_BITS,
+ &fld_val);
+ data_type_2 = fld_val;
+ /* UDH: UDH-Data-Type[3] */
+ bkn_bitstream_get_field(
+ &buf[pkt_offset],
+ BKN_DNX_UDH_DATA_TYPE_3_MSB,
+ BKN_DNX_UDH_DATA_TYPE_3_NOF_BITS,
+ &fld_val);
+ data_type_3 = fld_val;
+ pkt_offset += BKN_DNX_UDH_BASE_SIZE;
+ pkt_offset += sinfo->udh_length_type[data_type_0];
+ pkt_offset += sinfo->udh_length_type[data_type_1];
+ pkt_offset += sinfo->udh_length_type[data_type_2];
+ pkt_offset += sinfo->udh_length_type[data_type_3];
+ DBG_DUNE(("UDH base(1-%u) is present\n", pkt_offset));
+ }
+
+ packet_info->system_header_size = pkt_offset;
+
+ return 0;
+}
+
+static int
+bkn_dnx_packet_header_parse(
+ bkn_switch_info_t *sinfo,
+ uint8_t *buff,
+ uint32_t buff_len,
+ bkn_dune_system_header_info_t *packet_info)
+{
+ uint8_t is_inter_hdr_en = FALSE;
+ uint8_t is_tsh_en = FALSE;
+ uint8_t is_oamp_punted = FALSE;
+ uint8_t is_trapped = FALSE;
+
+ if ((sinfo == NULL) || (buff == NULL) || (packet_info == NULL)) {
+ return -1;
+ }
+
+ /* FTMH */
+ bkn_dnx_packet_parse_ftmh(sinfo, buff, buff_len, packet_info, &is_tsh_en, &is_inter_hdr_en);
+
+ /* Time-Stamp */
+ if (is_tsh_en == TRUE)
+ {
+ packet_info->system_header_size += BKN_DNX_TSH_SIZE;
+ DBG_DUNE(("Time-Stamp Header(4-%u) is present\n", packet_info->system_header_size));
+ }
+
+ /* Check if packet was punted to CPU by OAMP */
+ if ((packet_info->ftmh.source_sys_port_aggregate == 232)
+ || (packet_info->ftmh.source_sys_port_aggregate == 233))
+ {
+ is_oamp_punted = TRUE;
+ }
+
+ /* Internal */
+ if (is_inter_hdr_en)
+ {
+ bkn_dnx_packet_parse_internal(sinfo, buff, buff_len, packet_info, is_oamp_punted, &is_trapped);
+ }
+
+ if (is_oamp_punted)
+ {
+ is_inter_hdr_en = FALSE;
+ is_tsh_en = FALSE;
+ is_oamp_punted = FALSE;
+ is_trapped = FALSE;
+
+ /* FTMH */
+ bkn_dnx_packet_parse_ftmh(sinfo, buff, buff_len, packet_info, &is_tsh_en, &is_inter_hdr_en);
+ /* Time-Stamp */
+ if (is_tsh_en == TRUE)
+ {
+ packet_info->system_header_size += BKN_DNX_TSH_SIZE;
+ DBG_DUNE(("Time-Stamp Header(4-%u) is present\n", packet_info->system_header_size));
+ }
+ /* Internal */
+ if (is_inter_hdr_en)
+ {
+ bkn_dnx_packet_parse_internal(sinfo, buff, buff_len, packet_info, is_oamp_punted, &is_trapped);
+ }
+ }
+
+ DBG_DUNE(("Total length of headers is %u\n", packet_info->system_header_size));
+
+ return 0;
+}
+
+static int
+bkn_packet_header_parse(bkn_switch_info_t *sinfo, uint8_t *buf, uint32_t buf_len, bkn_dune_system_header_info_t *packet_info)
+{
+ if (device_is_dpp(sinfo))
+ {
+ bkn_dpp_packet_header_parse(sinfo, buf, buf_len, packet_info);
+ }
+ else if (device_is_dnx(sinfo))
+ {
+ if (sinfo->system_headers_mode == BKN_DNX_JR2_MODE)
+ {
+ /* Jericho 2 mode */
+ bkn_dnx_packet_header_parse(sinfo, buf, buf_len, packet_info);
+ }
+ else
+ {
+ /* Jericho/QMX/QAX mode */
+ bkn_dpp_packet_header_parse(sinfo, buf, buf_len, packet_info);
+ }
+ }
+ return 0;
+}
+
+static int
+bkn_do_api_rx(bkn_switch_info_t *sinfo, int chan, int budget)
+{
+ bkn_priv_t *priv;
+ bkn_dcb_chain_t *dcb_chain;
+ struct sk_buff *skb;
+ bkn_filter_t cbf;
+ bkn_filter_t *filter;
+ uint32_t err_woff;
+ uint32_t *dcb, *meta;
+ uint8_t *pkt;
+ uint64_t pkt_dma;
+ int drop_api;
+ int ethertype;
+ int pktlen;
+ int idx;
+ int dcbs_done = 0;
+ bkn_dune_system_header_info_t packet_info;
+ uint32_t sand_scratch_data[BKN_SAND_SCRATCH_DATA_SIZE] = {0};
+
+ dcb_chain = sinfo->rx[chan].api_dcb_chain;
+ if (dcb_chain == NULL) {
+ /* No active chains */
+ return 0;
+ }
+
+ while (dcb_chain->dcb_cur < dcb_chain->dcb_cnt) {
+ dcb = &dcb_chain->dcb_mem[dcb_chain->dcb_cur * sinfo->dcb_wsize];
+ DBG_VERB(("DCB %2d: 0x%08x\n",
+ dcb_chain->dcb_cur, dcb[sinfo->dcb_wsize-1]));
+ if ((dcb[sinfo->dcb_wsize-1] & (1 << 31)) == 0) {
+ break;
+ }
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ /* Handle for Continuous DMA mode */
+ if (dcbs_done >= budget) {
+ break;
+ }
+ if ((sinfo->cmic_type == 'x' && dcb[2] & (1 << 18)) ||
+ (sinfo->cmic_type != 'x' && dcb[1] & (1 << 18))) {
+ dcb[sinfo->dcb_wsize-1] |= SOC_DCB_KNET_DONE;
+ bkn_api_rx_chain_done(sinfo, chan);
+ dcb_chain = sinfo->rx[chan].api_dcb_chain;
+ if (dcb_chain == NULL) {
+ break;
+ }
+ continue;
+ }
+ }
+ if ((sinfo->cmic_type == 'x' && (dcb[2] & (1 << 16)) == 0) ||
+ (sinfo->cmic_type != 'x' && (dcb[1] & (1 << 16)) == 0)) {
+ sinfo->rx[chan].chain_complete = 1;
+ }
+ sinfo->rx[chan].pkts++;
+ if (sinfo->cmic_type == 'x') {
+ pkt_dma = BUS_TO_DMA_HI(dcb[1]);
+ pkt_dma = pkt_dma << 32 | dcb[0];
+ } else {
+ pkt_dma = dcb[0];
+ }
+ pkt = (uint8_t *)kernel_bde->p2l(sinfo->dev_no, (sal_paddr_t)pkt_dma);
+
+ if (device_is_sand(sinfo)) {
+ err_woff = BKN_SAND_SCRATCH_DATA_SIZE - 1;
+ sand_scratch_data[err_woff] = dcb[sinfo->dcb_wsize-1];
+ meta = (uint32_t *)pkt;
+ } else {
+ if (sinfo->cmic_type == 'x') {
+ meta = (uint32_t *)pkt;
+ err_woff = sinfo->pkt_hdr_size / sizeof(uint32_t) - 1;
+ meta[err_woff] = dcb[sinfo->dcb_wsize-1];
+ } else {
+ meta = dcb;
+ err_woff = sinfo->dcb_wsize - 1;
+ }
+ }
+
+ pktlen = dcb[sinfo->dcb_wsize-1] & SOC_DCB_KNET_COUNT_MASK;
+ bkn_dump_pkt(pkt, pktlen, XGS_DMA_RX_CHAN);
+
+ if (device_is_sand(sinfo)) {
+ memset(&packet_info, 0, sizeof(bkn_dune_system_header_info_t));
+ /* decode system headers and fill sratch data */
+ bkn_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info);
+ bkn_bitstream_set_field(sand_scratch_data, 0, 16, packet_info.internal.trap_id);
+ bkn_bitstream_set_field(sand_scratch_data, 16, 16, packet_info.internal.trap_qualifier);
+ bkn_bitstream_set_field(sand_scratch_data, 32, 16, packet_info.ftmh.source_sys_port_aggregate);
+ bkn_bitstream_set_field(sand_scratch_data, 48, 16, packet_info.internal.forward_domain);
+ bkn_bitstream_set_field(sand_scratch_data, 64, 2, packet_info.ftmh.action_type);
+
+ if (force_tagged) {
+ uint8_t *eth_hdr = pkt + packet_info.system_header_size;
+ uint16_t tpid = 0;
+
+ tpid = PKT_U16_GET(eth_hdr, 12);
+ if (packet_is_untagged(tpid)) {
+ int raw_packet_len = pktlen - packet_info.system_header_size;
+ uint32_t vid = 0;
+
+ if ((pktlen + 4) < rx_buffer_size) {
+ for (idx = (raw_packet_len - 1); idx >= 12; idx--) {
+ eth_hdr[idx+4] = eth_hdr[idx];
+ }
+ if (ft_vid) {
+ vid = ft_vid;
+ }
+ else if (packet_info.internal.forward_domain) {
+ vid = packet_info.internal.forward_domain & 0xfff;
+ }
+ else {
+ vid = 1;
+ }
+ DBG_DUNE(("add vlan tag (%d) to untagged packets\n", vid));
+
+ eth_hdr[12] = (ft_tpid >> 8) & 0xff;
+ eth_hdr[13] = ft_tpid & 0xff;
+ eth_hdr[14] = (((ft_pri & 0x7) << 5) | ((ft_cfi & 0x1) << 4) | ((vid >> 8) & 0xf)) & 0xff;
+ eth_hdr[15] = vid & 0xff;
+ /* reset packet length in DCB */
+ pktlen += 4;
+ bkn_dump_pkt(pkt, pktlen, XGS_DMA_RX_CHAN);
+ dcb[sinfo->dcb_wsize-1] &= ~SOC_DCB_KNET_COUNT_MASK;
+ dcb[sinfo->dcb_wsize-1] |= pktlen & SOC_DCB_KNET_COUNT_MASK;
+ }
+ }
+ }
+ }
+
+ if (device_is_sand(sinfo)) {
+ filter = bkn_match_rx_pkt(sinfo, pkt + packet_info.system_header_size,
+ pktlen - packet_info.system_header_size, sand_scratch_data, chan, &cbf);
+ } else {
+ filter = bkn_match_rx_pkt(sinfo, pkt + sinfo->pkt_hdr_size,
+ pktlen - sinfo->pkt_hdr_size, meta, chan, &cbf);
+ }
+ if ((dcb[sinfo->dcb_wsize-1] & 0xf0000) != 0x30000) {
+ /* Fragment or error */
+ if (filter && filter->kf.mask.w[err_woff] == 0) {
+ /* Drop unless DCB status is part of filter */
+ filter = NULL;
+ }
+ }
+ drop_api = 1;
+ if (filter) {
+ DBG_FLTR(("Match filter ID %d\n", filter->kf.id));
+ switch (filter->kf.dest_type) {
+ case KCOM_DEST_T_API:
+ DBG_FLTR(("Send to Rx API\n"));
+ sinfo->rx[chan].pkts_f_api++;
+ drop_api = 0;
+ break;
+ case KCOM_DEST_T_NETIF:
+ priv = bkn_netif_lookup(sinfo, filter->kf.dest_id);
+ if (priv) {
+ /* Check that software link is up */
+ if (!netif_carrier_ok(priv->dev)) {
+ sinfo->rx[chan].pkts_d_no_link++;
+ break;
+ }
+
+ if (device_is_sand(sinfo)) {
+ pkt += packet_info.system_header_size;
+ pktlen -= packet_info.system_header_size;
+ } else if (sinfo->cmic_type == 'x') {
+ pkt += sinfo->pkt_hdr_size;
+ pktlen -= sinfo->pkt_hdr_size;
+ }
+
+ /* Add 2 bytes for IP header alignment (see below) */
+ skb = dev_alloc_skb(pktlen + RCPU_RX_ENCAP_SIZE + 2);
+ if (skb == NULL) {
+ sinfo->rx[chan].pkts_d_no_skb++;
+ break;
+ }
+ skb_reserve(skb, RCPU_RX_ENCAP_SIZE);
+
+ DBG_FLTR(("Send to netif %d (%s)\n",
+ priv->id, priv->dev->name));
+ sinfo->rx[chan].pkts_f_netif++;
+ skb->dev = priv->dev;
+ skb_reserve(skb, 2); /* 16 byte align the IP fields. */
+
+ /* Save for RCPU before stripping tag */
+ ethertype = PKT_U16_GET(pkt, 16);
+ if ((priv->flags & KCOM_NETIF_F_KEEP_RX_TAG) == 0) {
+ uint16_t vlan_proto = PKT_U16_GET(pkt, 12);
+
+ if (filter->kf.flags & KCOM_FILTER_F_STRIP_TAG) {
+ /* Strip the VLAN tag */
+ if (vlan_proto == ETH_P_8021Q ||
+ vlan_proto == ETH_P_8021AD) {
+ DBG_FLTR(("Strip VLAN tag\n"));
+ for (idx = 11; idx >= 0; idx--) {
+ pkt[idx+4] = pkt[idx];
+ }
+ pktlen -= 4;
+ pkt += 4;
+ }
+ } else {
+ /*
+ * Mark packet as VLAN-tagged, otherwise newer
+ * kernels will strip the tag.
+ */
+ uint16_t tci = PKT_U16_GET(pkt, 14);
+
+ if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) {
+ bkn_vlan_hwaccel_put_tag(skb, ETH_P_8021Q, tci);
+ } else {
+ if (vlan_proto == ETH_P_8021AD) {
+ bkn_vlan_hwaccel_put_tag
+ (skb, ETH_P_8021AD, tci);
+ } else {
+ bkn_vlan_hwaccel_put_tag
+ (skb, ETH_P_8021Q, tci);
+ }
+ }
+ }
+ }
+
+ skb_copy_to_linear_data(skb, pkt, pktlen);
+ if (device_is_sand(sinfo)) {
+ /* CRC has been stripped */
+ skb_put(skb, pktlen);
+ } else {
+ skb_put(skb, pktlen - 4); /* Strip CRC */
+ }
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += skb->len;
+
+ /* Optional SKB updates */
+ KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF;
+ if (knet_rx_cb != NULL) {
+ KNET_SKB_CB(skb)->netif_user_data = priv->cb_user_data;
+ KNET_SKB_CB(skb)->filter_user_data = filter->kf.cb_user_data;
+ if (device_is_sand(sinfo)) {
+ skb = knet_rx_cb(skb, sinfo->dev_no, sand_scratch_data);
+ }
+ else {
+ skb = knet_rx_cb(skb, sinfo->dev_no, meta);
+ }
+ if (skb == NULL) {
+ /* Consumed by call-back */
+ sinfo->rx[chan].pkts_d_callback++;
+ break;
+ }
+ }
+
+ /* Do Rx timestamping */
+ if (priv->rx_hwts) {
+ bkn_hw_tstamp_rx_set(sinfo, priv->phys_port, skb, meta);
+ }
+
+ if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) {
+ bkn_add_rcpu_encap(sinfo, skb, meta, packet_info.system_header_size);
+ DBG_PDMP(("After add RCPU ENCAP\n"));
+ bkn_dump_pkt(skb->data, pktlen + RCPU_RX_ENCAP_SIZE, XGS_DMA_RX_CHAN);
+ }
+ skb->protocol = eth_type_trans(skb, skb->dev);
+ if (filter->kf.dest_proto) {
+ skb->protocol = filter->kf.dest_proto;
+ }
+ if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) {
+ bkn_eth_type_update(skb, ethertype);
+ }
+ DBG_DUNE(("skb protocol 0x%04x\n",skb->protocol));
+
+ /* Unlock while calling up network stack */
+ spin_unlock(&sinfo->lock);
+ if (use_napi) {
+ netif_receive_skb(skb);
+ } else {
+ netif_rx(skb);
+ }
+ spin_lock(&sinfo->lock);
+
+ if (filter->kf.mirror_type == KCOM_DEST_T_API ||
+ dbg_pkt_enable) {
+ DBG_FLTR(("Mirror to Rx API\n"));
+ sinfo->rx[chan].pkts_m_api++;
+ drop_api = 0;
+ }
+ } else {
+ DBG_FLTR(("Unknown netif %d\n",
+ filter->kf.dest_id));
+ sinfo->rx[chan].pkts_d_unkn_netif++;
+ }
+ break;
+ default:
+ /* Drop packet */
+ DBG_FLTR(("Unknown dest type %d\n",
+ filter->kf.dest_type));
+ sinfo->rx[chan].pkts_d_unkn_dest++;
+ break;
+ }
+ } else {
+ DBG_PKT(("Rx packet dropped.\n"));
+ sinfo->rx[chan].pkts_d_no_match++;
+ }
+ if (drop_api) {
+ /* If count is zero, the DCB will just be recycled */
+ dcb[sinfo->dcb_wsize-1] &= ~SOC_DCB_KNET_COUNT_MASK;
+ }
+ dcb[sinfo->dcb_wsize-1] |= SOC_DCB_KNET_DONE;
+ dcb_chain->dcb_cur++;
+ dcbs_done++;
+ }
+
+ return dcbs_done;
+}
+
+static int
+bkn_do_skb_rx(bkn_switch_info_t *sinfo, int chan, int budget)
+{
+ bkn_priv_t *priv;
+ bkn_desc_info_t *desc;
+ struct sk_buff *skb;
+ bkn_filter_t cbf;
+ bkn_filter_t *filter;
+ uint32_t err_woff;
+ uint32_t *dcb, *meta;
+ int ethertype;
+ int pktlen;
+ int idx;
+ int dcbs_done = 0;
+ bkn_dune_system_header_info_t packet_info = {0};
+ uint32_t sand_scratch_data[BKN_SAND_SCRATCH_DATA_SIZE] = {0};
+ uint8_t sand_system_headers[RCPU_RX_META_SIZE] = {0};
+ uint8_t *pkt = NULL;
+
+ if (!sinfo->rx[chan].running) {
+ /* Rx not ready */
+ return 0;
+ }
+
+ while (dcbs_done < budget) {
+ char str[32];
+ sprintf(str, "Rx DCB (%d)", sinfo->rx[chan].dirty);
+ desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty];
+ dcb = desc->dcb_mem;
+ bkn_dump_dcb(str, dcb, sinfo->dcb_wsize, XGS_DMA_RX_CHAN);
+ if ((dcb[sinfo->dcb_wsize-1] & (1 << 31)) == 0) {
+ break;
+ }
+ if ((sinfo->cmic_type == 'x' && (dcb[2] & (1 << 16)) == 0) ||
+ (sinfo->cmic_type != 'x' && (dcb[1] & (1 << 16)) == 0)) {
+ sinfo->rx[chan].chain_complete = 1;
+ /* Request one extra poll to check for chain done interrupt */
+ if (sinfo->napi_poll_mode) {
+ sinfo->napi_poll_again = 1;
+ }
+ }
+ sinfo->rx[chan].pkts++;
+ skb = desc->skb;
+
+ if (device_is_sand(sinfo)) {
+ err_woff = BKN_SAND_SCRATCH_DATA_SIZE - 1;
+ sand_scratch_data[err_woff] = dcb[sinfo->dcb_wsize-1];
+ meta = (uint32_t *)skb->data;
+ pkt = skb->data;
+ } else {
+ if (sinfo->cmic_type == 'x') {
+ meta = (uint32_t *)skb->data;
+ err_woff = sinfo->pkt_hdr_size / sizeof(uint32_t) - 1;
+ meta[err_woff] = dcb[sinfo->dcb_wsize-1];
+ } else {
+ meta = dcb;
+ err_woff = sinfo->dcb_wsize - 1;
+ }
+ }
+
+ pktlen = dcb[sinfo->dcb_wsize-1] & 0xffff;
+ priv = netdev_priv(sinfo->dev);
+ DBG_DCB_RX(("Rx%d SKB DMA done (%d).\n", chan, sinfo->rx[chan].dirty));
+ BKN_DMA_UNMAP_SINGLE(sinfo->dma_dev,
+ desc->skb_dma, desc->dma_size,
+ BKN_DMA_FROMDEV);
+ desc->skb_dma = 0;
+ bkn_dump_pkt(skb->data, pktlen, XGS_DMA_RX_CHAN);
+
+ if (device_is_sand(sinfo)) {
+ memset(&packet_info, 0, sizeof(bkn_dune_system_header_info_t));
+ /* decode system headers and fill sratch data */
+ bkn_packet_header_parse(sinfo, pkt, (uint32_t)pktlen, &packet_info);
+ bkn_bitstream_set_field(sand_scratch_data, 0, 16, packet_info.internal.trap_id);
+ bkn_bitstream_set_field(sand_scratch_data, 16, 16, packet_info.internal.trap_qualifier);
+ bkn_bitstream_set_field(sand_scratch_data, 32, 16, packet_info.ftmh.source_sys_port_aggregate);
+ bkn_bitstream_set_field(sand_scratch_data, 48, 16, packet_info.internal.forward_domain);
+ bkn_bitstream_set_field(sand_scratch_data, 64, 2, packet_info.ftmh.action_type);
+ memcpy(sand_system_headers, pkt,
+ ((packet_info.system_header_size > RCPU_RX_META_SIZE) ? RCPU_RX_META_SIZE : packet_info.system_header_size));
+ meta = (uint32_t *)sand_system_headers;
+ if (force_tagged) {
+ uint8_t *eth_hdr = pkt + packet_info.system_header_size;
+ uint16_t tpid = 0;
+
+ tpid = PKT_U16_GET(eth_hdr, 12);
+ if (packet_is_untagged(tpid)) {
+ int raw_packet_len = pktlen - packet_info.system_header_size;
+ uint32_t vid = 0;
+
+ if ((pktlen + 4) < rx_buffer_size) {
+ for (idx = (raw_packet_len - 1); idx >= 12; idx--) {
+ eth_hdr[idx+4] = eth_hdr[idx];
+ }
+ if (ft_vid) {
+ vid = ft_vid;
+ }
+ else if (packet_info.internal.forward_domain) {
+ vid = packet_info.internal.forward_domain & 0xfff;
+ }
+ else {
+ vid = 1;
+ }
+ DBG_DUNE(("add vlan tag (%d) to untagged packets\n", vid));
+ eth_hdr[12] = (ft_tpid >> 8) & 0xff;
+ eth_hdr[13] = ft_tpid & 0xff;
+ eth_hdr[14] = (((ft_pri & 0x7) << 5) | ((ft_cfi & 0x1) << 4) | ((vid >> 8) & 0xf)) & 0xff;
+ eth_hdr[15] = vid & 0xff;
+ /* reset packet length in DCB */
+ pktlen += 4;
+ bkn_dump_pkt(pkt, pktlen, XGS_DMA_RX_CHAN);
+ dcb[sinfo->dcb_wsize-1] &= ~SOC_DCB_KNET_COUNT_MASK;
+ dcb[sinfo->dcb_wsize-1] |= pktlen & SOC_DCB_KNET_COUNT_MASK;
+ }
+ }
+ }
+ }
+ if (device_is_sand(sinfo)) {
+ filter = bkn_match_rx_pkt(sinfo, skb->data + packet_info.system_header_size,
+ pktlen - packet_info.system_header_size, sand_scratch_data, chan, &cbf);
+ } else {
+ filter = bkn_match_rx_pkt(sinfo, skb->data + sinfo->pkt_hdr_size,
+ pktlen - sinfo->pkt_hdr_size, meta, chan, &cbf);
+ }
+ if ((dcb[sinfo->dcb_wsize-1] & 0xf0000) != 0x30000) {
+ /* Fragment or error */
+ priv->stats.rx_errors++;
+ if (filter && filter->kf.mask.w[err_woff] == 0) {
+ /* Drop unless DCB status is part of filter */
+ filter = NULL;
+ }
+ }
+ DBG_PKT(("Rx packet (%d bytes).\n", pktlen));
+ if (filter) {
+ DBG_FLTR(("Match filter ID %d\n", filter->kf.id));
+ switch (filter->kf.dest_type) {
+ case KCOM_DEST_T_API:
+ DBG_FLTR(("Send to Rx API\n"));
+ sinfo->rx[chan].pkts_f_api++;
+ bkn_api_rx_copy_from_skb(sinfo, chan, desc);
+ break;
+ case KCOM_DEST_T_NETIF:
+ priv = bkn_netif_lookup(sinfo, filter->kf.dest_id);
+ if (priv) {
+ /* Check that software link is up */
+ if (!netif_carrier_ok(priv->dev)) {
+ sinfo->rx[chan].pkts_d_no_link++;
+ break;
+ }
+ DBG_FLTR(("Send to netif %d (%s)\n",
+ priv->id, priv->dev->name));
+ sinfo->rx[chan].pkts_f_netif++;
+
+ if ((filter->kf.mirror_type == KCOM_DEST_T_API) || dbg_pkt_enable) {
+ sinfo->rx[chan].pkts_m_api++;
+ bkn_api_rx_copy_from_skb(sinfo, chan, desc);
+ }
+
+ if (device_is_sand(sinfo)) {
+ /* CRC has been stripped on Dune*/
+ skb_put(skb, pktlen);
+ } else {
+ skb_put(skb, pktlen - 4); /* Strip CRC */
+ }
+
+ if (device_is_sand(sinfo)) {
+ skb_pull(skb, packet_info.system_header_size);
+ } else if (sinfo->cmic_type == 'x') {
+ skb_pull(skb, sinfo->pkt_hdr_size);
+ }
+
+ /* Optional SKB updates */
+ KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF;
+ /* Do Rx timestamping */
+ if (priv->rx_hwts) {
+ bkn_hw_tstamp_rx_set(sinfo, priv->phys_port, skb, meta);
+ }
+
+ /* Save for RCPU before stripping tag */
+ ethertype = PKT_U16_GET(skb->data, 16);
+ if ((priv->flags & KCOM_NETIF_F_KEEP_RX_TAG) == 0) {
+ uint16_t vlan_proto;
+
+ vlan_proto = PKT_U16_GET(skb->data, 12);
+ if (filter->kf.flags & KCOM_FILTER_F_STRIP_TAG) {
+ /* Strip VLAN tag */
+ if (vlan_proto == ETH_P_8021Q ||
+ vlan_proto == ETH_P_8021AD) {
+ DBG_FLTR(("Strip VLAN tag\n"));
+ ((u32*)skb->data)[3] = ((u32*)skb->data)[2];
+ ((u32*)skb->data)[2] = ((u32*)skb->data)[1];
+ ((u32*)skb->data)[1] = ((u32*)skb->data)[0];
+ skb_pull(skb, 4);
+ if (device_is_sand(sinfo)) {
+ for (idx = packet_info.system_header_size; idx >= 4; idx--) {
+ pkt[idx] = pkt[idx - 4];
+ }
+ } else if (sinfo->cmic_type == 'x') {
+ for (idx = sinfo->pkt_hdr_size / sizeof(uint32_t); idx; idx--) {
+ meta[idx] = meta[idx - 1];
+ }
+ meta++;
+ }
+ }
+ } else {
+ /*
+ * Mark packet as VLAN-tagged, otherwise newer
+ * kernels will strip the tag.
+ */
+ uint16_t tci = PKT_U16_GET(skb->data, 14);
+
+ if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) {
+ bkn_vlan_hwaccel_put_tag(skb, ETH_P_8021Q, tci);
+ } else {
+ if (vlan_proto == ETH_P_8021AD) {
+ bkn_vlan_hwaccel_put_tag
+ (skb, ETH_P_8021AD, tci);
+ } else {
+ bkn_vlan_hwaccel_put_tag
+ (skb, ETH_P_8021Q, tci);
+ }
+ }
+ }
+ }
+
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += skb->len;
+ skb->dev = priv->dev;
+
+ if (knet_rx_cb != NULL) {
+ KNET_SKB_CB(skb)->netif_user_data = priv->cb_user_data;
+ KNET_SKB_CB(skb)->filter_user_data = filter->kf.cb_user_data;
+ if (device_is_sand(sinfo)) {
+ skb = knet_rx_cb(skb, sinfo->dev_no, sand_scratch_data);
+ }
+ else {
+ skb = knet_rx_cb(skb, sinfo->dev_no, meta);
+ }
+ if (skb == NULL) {
+ /* Consumed by call-back */
+ sinfo->rx[chan].pkts_d_callback++;
+ priv->stats.rx_dropped++;
+ desc->skb = NULL;
+ break;
+ }
+ }
+
+ if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) {
+ bkn_add_rcpu_encap(sinfo, skb, meta, packet_info.system_header_size);
+ DBG_PDMP(("After add RCPU ENCAP\n"));
+ bkn_dump_pkt(skb->data, pktlen + RCPU_RX_ENCAP_SIZE, XGS_DMA_RX_CHAN);
+ }
+ skb->protocol = eth_type_trans(skb, skb->dev);
+ if (filter->kf.dest_proto) {
+ skb->protocol = filter->kf.dest_proto;
+ }
+ if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) {
+ bkn_eth_type_update(skb, ethertype);
+ }
+ DBG_DUNE(("skb protocol 0x%04x\n",skb->protocol));
+
+ if (filter->kf.mirror_type == KCOM_DEST_T_NETIF) {
+ bkn_priv_t *mpriv;
+ struct sk_buff *mskb;
+ mpriv = bkn_netif_lookup(sinfo, filter->kf.mirror_id);
+ if (mpriv && netif_carrier_ok(mpriv->dev)) {
+ mskb = skb_clone(skb, GFP_ATOMIC);
+ if (mskb == NULL) {
+ sinfo->rx[chan].pkts_d_no_skb++;
+ } else {
+ sinfo->rx[chan].pkts_m_netif++;
+ mpriv->stats.rx_packets++;
+ mpriv->stats.rx_bytes += mskb->len;
+ skb->dev = mpriv->dev;
+ if (filter->kf.mirror_proto) {
+ skb->protocol = filter->kf.mirror_proto;
+ }
+ /* Unlock while calling up network stack */
+ spin_unlock(&sinfo->lock);
+ if (use_napi) {
+ netif_receive_skb(mskb);
+ } else {
+ netif_rx(mskb);
+ }
+ spin_lock(&sinfo->lock);
+ }
+ }
+ }
+
+ /* Unlock while calling up network stack */
+ spin_unlock(&sinfo->lock);
+ if (use_napi) {
+ netif_receive_skb(skb);
+ } else {
+ netif_rx(skb);
+ }
+ spin_lock(&sinfo->lock);
+
+ /* Ensure that we reallocate SKB for this DCB */
+ desc->skb = NULL;
+ } else {
+ DBG_FLTR(("Unknown netif %d\n",
+ filter->kf.dest_id));
+ sinfo->rx[chan].pkts_d_unkn_netif++;
+ }
+ break;
+ default:
+ /* Drop packet */
+ DBG_FLTR(("Unknown dest type %d\n",
+ filter->kf.dest_type));
+ sinfo->rx[chan].pkts_d_unkn_dest++;
+ break;
+ }
+ } else {
+ DBG_PKT(("Rx packet dropped.\n"));
+ sinfo->rx[chan].pkts_d_no_match++;
+ priv->stats.rx_dropped++;
+ }
+ dcb[sinfo->dcb_wsize-1] &= ~(1 << 31);
+ if (++sinfo->rx[chan].dirty >= MAX_RX_DCBS) {
+ sinfo->rx[chan].dirty = 0;
+ }
+ sinfo->rx[chan].free--;
+ dcbs_done++;
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ /* Right now refill for Continuous DMA mode */
+ bkn_rx_refill(sinfo, chan);
+ }
+ }
+
+ return dcbs_done;
+}
+
+static int
+bkn_do_rx(bkn_switch_info_t *sinfo, int chan, int budget)
+{
+ if (sinfo->rx[chan].use_rx_skb == 0) {
+ /* Rx buffers are provided by BCM Rx API */
+ return bkn_do_api_rx(sinfo, chan, budget);
+ } else {
+ /* Rx buffers are provided by Linux kernel */
+ return bkn_do_skb_rx(sinfo, chan, budget);
+ }
+}
+
+static void
+bkn_rx_desc_done(bkn_switch_info_t *sinfo, int chan)
+{
+ bkn_evt_resource_t *evt;
+ evt = &_bkn_evt[sinfo->evt_idx];
+ DBG_IRQ(("Rx%d desc done\n", chan));
+
+ if (sinfo->rx[chan].use_rx_skb == 0) {
+ sinfo->dma_events |= KCOM_DMA_INFO_F_RX_DONE;
+ evt->evt_wq_put++;
+ wake_up_interruptible(&evt->evt_wq);
+ }
+}
+
+static void
+bkn_rx_chain_done(bkn_switch_info_t *sinfo, int chan)
+{
+ DBG_IRQ(("Rx%d chain done\n", chan));
+
+ if (sinfo->rx[chan].chain_complete == 0) {
+ /*
+ * In certain environments the DCB memory is updated after
+ * the corresponding interrupt has been received.
+ * The following code will ensure that this situation is
+ * handled properly.
+ */
+ int maxloop = 0;
+ while (sinfo->rx[chan].chain_complete == 0) {
+ sinfo->rx[chan].sync_retry++;
+ if (maxloop == 0) {
+ sinfo->rx[chan].sync_err++;
+ }
+ if (maxloop > sinfo->rx[chan].sync_maxloop) {
+ sinfo->rx[chan].sync_maxloop = maxloop;
+ }
+ if (bkn_do_rx(sinfo, chan, MAX_RX_DCBS) > 0) {
+ bkn_rx_desc_done(sinfo, chan);
+ }
+ if (++maxloop > rx_sync_retry) {
+ gprintk("Fatal error: Incomplete chain\n");
+ sinfo->rx[chan].chain_complete = 1;
+ break;
+ }
+ }
+ }
+
+ sinfo->rx[chan].running = 0;
+
+ if (sinfo->rx[chan].use_rx_skb == 0) {
+ bkn_api_rx_chain_done(sinfo, chan);
+ } else {
+ bkn_rx_refill(sinfo, chan);
+
+ if (bkn_rx_restart(sinfo, chan) != 0) {
+ /* Presumably out of resources */
+ sinfo->timer.expires = jiffies + 1;
+ if (!sinfo->timer_queued) {
+ sinfo->timer_queued = 1;
+ add_timer(&sinfo->timer);
+ }
+ }
+ }
+}
+
+static void
+bkn_suspend_tx(bkn_switch_info_t *sinfo)
+{
+ struct list_head *list;
+ bkn_priv_t *priv = netdev_priv(sinfo->dev);
+
+ /* Stop main device */
+ netif_stop_queue(priv->dev);
+ sinfo->tx.suspends++;
+ /* Stop associated virtual devices */
+ list_for_each(list, &sinfo->ndev_list) {
+ priv = (bkn_priv_t *)list;
+ netif_stop_queue(priv->dev);
+ }
+}
+
+static void
+bkn_resume_tx(bkn_switch_info_t *sinfo)
+{
+ struct list_head *list;
+ bkn_priv_t *priv = netdev_priv(sinfo->dev);
+
+ /* Check main device */
+ if (netif_queue_stopped(priv->dev) && sinfo->tx.free > 1) {
+ netif_wake_queue(priv->dev);
+ }
+ /* Check associated virtual devices */
+ list_for_each(list, &sinfo->ndev_list) {
+ priv = (bkn_priv_t *)list;
+ if (netif_queue_stopped(priv->dev) && sinfo->tx.free > 1) {
+ netif_wake_queue(priv->dev);
+ }
+ }
+}
+
+static void
+bkn_skb_tstamp_copy(struct sk_buff *new_skb, struct sk_buff *skb)
+{
+ bkn_skb_tx_flags(new_skb) = bkn_skb_tx_flags(skb);
+ new_skb->sk = skb->sk;
+
+ return;
+}
+
+static int
+bkn_hw_tstamp_tx_set(bkn_switch_info_t *sinfo, struct sk_buff *skb)
+{
+ int hwts;
+ int port;
+ uint64_t ts = 0;
+ uint32_t hdrlen = sinfo->cmic_type == 'x' ? PKT_TX_HDR_SIZE : 0;
+ struct skb_shared_hwtstamps shhwtstamps;
+
+ if (!knet_hw_tstamp_tx_time_get_cb) {
+ return -1;
+ }
+
+ port = KNET_SKB_CB(skb)->port;
+ hwts = KNET_SKB_CB(skb)->hwts;
+ ts = KNET_SKB_CB(skb)->ts;
+
+
+ if (hwts == HWTSTAMP_TX_ONESTEP_SYNC) {
+ if (ts == 0) {
+ return 1;
+ }
+ } else if (hwts == HWTSTAMP_TX_ON) {
+ if (knet_hw_tstamp_tx_time_get_cb(sinfo->dev_no, port, skb->data + hdrlen, &ts) < 0) {
+ return -1;
+ }
+ }
+
+ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+ shhwtstamps.hwtstamp = ns_to_ktime(ts);
+ skb_tstamp_tx(skb, &shhwtstamps);
+
+ return 0;
+}
+
+static void
+bkn_hw_tstamp_tx_work(struct work_struct *work)
+{
+ bkn_switch_info_t *sinfo = container_of(work, bkn_switch_info_t, tx_ptp_work);
+ struct sk_buff *skb;
+
+ while (skb_queue_len(&sinfo->tx_ptp_queue)) {
+ skb = skb_dequeue(&sinfo->tx_ptp_queue);
+ if (bkn_hw_tstamp_tx_set(sinfo, skb) < 0) {
+ gprintk("Timestamp has not been taken for the current skb.\n");
+ }
+ dev_kfree_skb_any(skb);
+ }
+}
+
+static int
+bkn_do_tx(bkn_switch_info_t *sinfo)
+{
+ bkn_desc_info_t *desc;
+ int dcbs_done = 0;
+
+ if (!CDMA_CH(sinfo, XGS_DMA_TX_CHAN) && sinfo->tx.api_active) {
+ return dcbs_done;
+ }
+
+ while (dcbs_done < MAX_TX_DCBS) {
+ char str[32];
+ if (sinfo->tx.free == MAX_TX_DCBS) {
+ break;
+ }
+ sprintf(str, "Tx DCB (%d)", sinfo->tx.dirty);
+ desc = &sinfo->tx.desc[sinfo->tx.dirty];
+ bkn_dump_dcb(str, desc->dcb_mem, sinfo->dcb_wsize, XGS_DMA_TX_CHAN);
+ if ((desc->dcb_mem[sinfo->dcb_wsize-1] & (1 << 31)) == 0) {
+ break;
+ }
+ if (desc->skb) {
+ DBG_DCB_TX(("Tx SKB DMA done (%d).\n", sinfo->tx.dirty));
+ BKN_DMA_UNMAP_SINGLE(sinfo->dma_dev,
+ desc->skb_dma, desc->dma_size,
+ BKN_DMA_TODEV);
+
+ if ((KNET_SKB_CB(desc->skb)->hwts == HWTSTAMP_TX_ONESTEP_SYNC) &&
+ (bkn_skb_tx_flags(desc->skb) & SKBTX_IN_PROGRESS)) {
+
+ if (bkn_hw_tstamp_tx_set(sinfo, desc->skb) < 0) {
+ gprintk("Timestamp has not been taken for the current skb.\n");
+ }
+ bkn_skb_tx_flags(desc->skb) &= ~SKBTX_IN_PROGRESS;
+ }
+
+ if (bkn_skb_tx_flags(desc->skb) & SKBTX_IN_PROGRESS) {
+ skb_queue_tail(&sinfo->tx_ptp_queue, desc->skb);
+ schedule_work(&sinfo->tx_ptp_work);
+ } else {
+ dev_kfree_skb_any(desc->skb);
+ }
+ desc->skb = NULL;
+ desc->skb_dma = 0;
+ }
+ desc->dcb_mem[sinfo->dcb_wsize-1] &= ~(1 << 31);
+ if (++sinfo->tx.dirty >= MAX_TX_DCBS) {
+ sinfo->tx.dirty = 0;
+ }
+ if (++sinfo->tx.free > MAX_TX_DCBS) {
+ gprintk("Too many free Tx DCBs(%d).\n", sinfo->tx.free);
+ }
+ dcbs_done++;
+ }
+
+ return dcbs_done;
+}
+
+static void
+bkn_tx_cdma_chain_switch(bkn_switch_info_t *sinfo)
+{
+ bkn_dcb_chain_t *dcb_chain = sinfo->tx.api_dcb_chain;
+ uint32_t *dcb_mem;
+ uint64_t dcb_dma;
+ int woffset;
+
+ /* Switch between SKB Tx and API Tx for Continuous DMA mode */
+ if (!sinfo->tx.api_active) {
+ /*
+ * Set the current SKB DCB as reload DCB and the last DCB of
+ * the pending API chain as the new halt location.
+ */
+ sinfo->tx.api_active = 1;
+ dcb_mem = sinfo->tx.desc[sinfo->tx.cur].dcb_mem;
+ memset(dcb_mem, 0, sinfo->dcb_wsize * sizeof(uint32_t));
+ dcb_mem[0] = dcb_chain->dcb_dma;
+ if (sinfo->cmic_type == 'x') {
+ dcb_mem[1] = DMA_TO_BUS_HI(dcb_chain->dcb_dma >> 32);
+ dcb_mem[2] |= 1 << 24 | 1 << 18 | 1 << 16;
+ } else {
+ dcb_mem[1] |= 1 << 24 | 1 << 18 | 1 << 16;
+ }
+ if (++sinfo->tx.cur >= MAX_TX_DCBS) {
+ sinfo->tx.cur = 0;
+ }
+ sinfo->tx.free--;
+ woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize;
+ dcb_dma = dcb_chain->dcb_dma + woffset * sizeof(uint32_t);
+ /* DMA run to the new halt location */
+ bkn_cdma_goto(sinfo, XGS_DMA_TX_CHAN, dcb_dma);
+ } else {
+ /* Only need to set the current SKB DCB as the new halt location */
+ sinfo->tx.api_active = 0;
+ woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize;
+ dcb_mem = &dcb_chain->dcb_mem[woffset];
+ dcb_mem[0] = sinfo->tx.desc[sinfo->tx.dirty].dcb_dma;
+ if (sinfo->cmic_type == 'x') {
+ dcb_mem[1] = DMA_TO_BUS_HI(sinfo->tx.desc[sinfo->tx.dirty].dcb_dma >> 32);
+ }
+ dcb_dma = sinfo->tx.desc[sinfo->tx.cur].dcb_dma;
+ /* DMA run to the new halt location */
+ bkn_cdma_goto(sinfo, XGS_DMA_TX_CHAN, dcb_dma);
+ }
+}
+
+static void
+bkn_skb_tx(bkn_switch_info_t *sinfo)
+{
+ if (sinfo->tx.api_active) {
+ /* Switch from API Tx to SKB Tx */
+ bkn_tx_cdma_chain_switch(sinfo);
+ }
+}
+
+static void
+bkn_api_tx(bkn_switch_info_t *sinfo)
+{
+ bkn_dcb_chain_t *dcb_chain;
+ uint64_t pkt_dma;
+ unsigned char *pktdata;
+ int pktlen;
+ int i;
+
+ /* Assume that driver lock is held */
+ if (list_empty(&sinfo->tx.api_dcb_list)) {
+ sinfo->tx.api_active = 0;
+ } else {
+ sinfo->tx.pkts++;
+ dcb_chain = list_entry(sinfo->tx.api_dcb_list.next,
+ bkn_dcb_chain_t, list);
+ DBG_DCB_TX(("Start API Tx DMA, first DCB @ 0x%08x (%d DCBs).\n",
+ (uint32_t)dcb_chain->dcb_dma, dcb_chain->dcb_cnt));
+ for (i = 0; i < dcb_chain->dcb_cnt && debug & DBG_LVL_PDMP; i++) {
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN) && i == dcb_chain->dcb_cnt - 1) {
+ break;
+ }
+ if (sinfo->cmic_type == 'x') {
+ pkt_dma = BUS_TO_DMA_HI(dcb_chain->dcb_mem[sinfo->dcb_wsize * i + 1]);
+ pkt_dma = pkt_dma << 32 | dcb_chain->dcb_mem[sinfo->dcb_wsize * i];
+ } else {
+ pkt_dma = dcb_chain->dcb_mem[sinfo->dcb_wsize * i];
+ }
+ pktdata = kernel_bde->p2l(sinfo->dev_no, pkt_dma);
+ if (sinfo->cmic_type == 'x') {
+ pktlen = dcb_chain->dcb_mem[sinfo->dcb_wsize * i + 2] & 0xffff;
+ } else {
+ pktlen = dcb_chain->dcb_mem[sinfo->dcb_wsize * i + 1] & 0xffff;
+ }
+ bkn_dump_pkt(pktdata, pktlen, XGS_DMA_TX_CHAN);
+ }
+
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ sinfo->tx.api_dcb_chain = dcb_chain;
+ if (!sinfo->tx.api_active) {
+ /* Switch from SKB Tx to API Tx */
+ bkn_tx_cdma_chain_switch(sinfo);
+ }
+ list_del(&dcb_chain->list);
+ } else {
+ sinfo->tx.api_active = 1;
+ dev_dma_chan_clear(sinfo, XGS_DMA_TX_CHAN);
+ dev_irq_mask_enable(sinfo, XGS_DMA_TX_CHAN, 1);
+ dev_dma_chan_start(sinfo, XGS_DMA_TX_CHAN, dcb_chain->dcb_dma);
+ list_del(&dcb_chain->list);
+ kfree(dcb_chain);
+ }
+ }
+}
+
+static void
+bkn_tx_cdma_chain_done(bkn_switch_info_t *sinfo, int done)
+{
+ int woffset;
+ int dcbs_done = 0;
+ bkn_evt_resource_t *evt;
+
+ DBG_IRQ(("Tx CDMA chain done \n"));
+
+ evt = &_bkn_evt[sinfo->evt_idx];
+
+ if (sinfo->tx.api_active) {
+ /* Drain API Tx chains */
+ while (sinfo->tx.api_dcb_chain != sinfo->tx.api_dcb_chain_end) {
+ woffset = sinfo->tx.api_dcb_chain->dcb_cnt * sinfo->dcb_wsize - 1;
+ if (!(sinfo->tx.api_dcb_chain->dcb_mem[woffset] & (1 << 31))) {
+ return;
+ }
+ sinfo->tx.api_dcb_chain->dcb_mem[woffset - sinfo->dcb_wsize] |= SOC_DCB_KNET_DONE;
+ sinfo->dma_events |= KCOM_DMA_INFO_F_TX_DONE;
+ evt->evt_wq_put++;
+ wake_up_interruptible(&evt->evt_wq);
+ kfree(sinfo->tx.api_dcb_chain);
+ sinfo->tx.api_dcb_chain = NULL;
+ bkn_api_tx(sinfo);
+ if ((++dcbs_done + done) >= MAX_TX_DCBS) {
+ if (sinfo->napi_poll_mode) {
+ /* Request one extra poll to reschedule Tx */
+ sinfo->napi_poll_again = 1;
+ } else {
+ /* Request to yield for Continuous DMA mode */
+ sinfo->tx_yield = 1;
+ }
+ return;
+ }
+ }
+ woffset = (sinfo->tx.api_dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize - 1;
+ if (!(sinfo->tx.api_dcb_chain->dcb_mem[woffset] & (1 << 31))) {
+ return;
+ }
+ sinfo->tx.api_dcb_chain->dcb_mem[woffset] |= SOC_DCB_KNET_DONE;
+ /* Try and park at SKB Tx if API Tx done */
+ bkn_skb_tx(sinfo);
+ sinfo->dma_events |= KCOM_DMA_INFO_F_TX_DONE;
+ evt->evt_wq_put++;
+ wake_up_interruptible(&evt->evt_wq);
+ kfree(sinfo->tx.api_dcb_chain);
+ sinfo->tx.api_dcb_chain = NULL;
+ sinfo->tx.api_dcb_chain_end = NULL;
+ if (!sinfo->napi_poll_mode) {
+ /* Not need to yield for Continuous DMA mode */
+ sinfo->tx_yield = 0;
+ }
+ } else {
+ if (sinfo->tx.free == MAX_TX_DCBS) {
+ /* Try API Tx if SKB Tx done */
+ bkn_api_tx(sinfo);
+ if (sinfo->tx.api_active) {
+ return;
+ }
+ }
+ }
+
+ /* Resume if netif Tx resources available and API Tx not active */
+ bkn_resume_tx(sinfo);
+}
+
+static void
+bkn_tx_chain_done(bkn_switch_info_t *sinfo, int done)
+{
+ bkn_desc_info_t *desc;
+ int idx, pending;
+ bkn_evt_resource_t *evt;
+
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ return bkn_tx_cdma_chain_done(sinfo, done);
+ }
+
+ DBG_IRQ(("Tx chain done (%d/%d)\n", sinfo->tx.cur, sinfo->tx.dirty));
+
+ dev_irq_mask_disable(sinfo, XGS_DMA_TX_CHAN, 0);
+
+ evt = &_bkn_evt[sinfo->evt_idx];
+
+ if (sinfo->tx.api_active) {
+ sinfo->dma_events |= KCOM_DMA_INFO_F_TX_DONE;
+ evt->evt_wq_put++;
+ wake_up_interruptible(&evt->evt_wq);
+ /* Check if BCM API has more to send */
+ bkn_api_tx(sinfo);
+ if (sinfo->tx.api_active) {
+ return;
+ }
+ }
+
+ if (sinfo->tx.free == MAX_TX_DCBS) {
+ /* If netif Tx is idle then allow BCM API to send */
+ bkn_api_tx(sinfo);
+ if (sinfo->tx.api_active) {
+ return;
+ }
+ } else {
+ /* If two or more DCBs are pending, chain them */
+ pending = MAX_TX_DCBS - sinfo->tx.free;
+ idx = sinfo->tx.dirty;
+ while (--pending && idx < (MAX_TX_DCBS - 1)) {
+ if (sinfo->cmic_type == 'x') {
+ sinfo->tx.desc[idx++].dcb_mem[2] |= 1 << 16;
+ } else {
+ sinfo->tx.desc[idx++].dcb_mem[1] |= 1 << 16;
+ }
+ DBG_DCB_TX(("Chain Tx DCB %d (%d)\n", idx, pending));
+ }
+ /* Restart DMA from where we stopped */
+ desc = &sinfo->tx.desc[sinfo->tx.dirty];
+ DBG_DCB_TX(("Restart Tx DMA, DCB @ 0x%08x (%d).\n",
+ (uint32_t)desc->dcb_dma, sinfo->tx.dirty));
+ dev_dma_chan_clear(sinfo, XGS_DMA_TX_CHAN);
+ dev_irq_mask_enable(sinfo, XGS_DMA_TX_CHAN, 0);
+ dev_dma_chan_start(sinfo, XGS_DMA_TX_CHAN, desc->dcb_dma);
+ }
+
+ /* Resume if netif Tx resources available and API Tx not active */
+ bkn_resume_tx(sinfo);
+}
+
+static void
+bkn_schedule_napi_poll(bkn_switch_info_t *sinfo)
+{
+ /* Schedule NAPI poll */
+ DBG_NAPI(("Schedule NAPI poll on %s.\n", sinfo->dev->name));
+ /* Disable interrupts until poll job is complete */
+ sinfo->napi_poll_mode = 1;
+ /* Unlock while calling up network stack */
+ spin_unlock(&sinfo->lock);
+ if (bkn_napi_schedule_prep(sinfo->dev, &sinfo->napi)) {
+ __bkn_napi_schedule(sinfo->dev, &sinfo->napi);
+ DBG_NAPI(("Schedule prep OK on %s.\n", sinfo->dev->name));
+ } else {
+ /* Most likely the base device is has not been opened */
+ gprintk("Warning: Unable to schedule NAPI - base device not up?\n");
+ }
+ spin_lock(&sinfo->lock);
+}
+
+static void
+bkn_napi_poll_complete(bkn_switch_info_t *sinfo)
+{
+ /* Unlock while calling up network stack */
+ spin_unlock(&sinfo->lock);
+ bkn_napi_complete(sinfo->dev, &sinfo->napi);
+ spin_lock(&sinfo->lock);
+ /* Re-enable interrupts */
+ sinfo->napi_poll_mode = 0;
+ dev_irq_mask_set(sinfo, sinfo->irq_mask);
+}
+
+static int
+xgs_do_dma(bkn_switch_info_t *sinfo, int budget)
+{
+ int rx_dcbs_done = 0, tx_dcbs_done = 0;
+ int chan_done, budget_chans = 0;
+ uint32_t dma_stat;
+ int chan;
+
+ DEV_READ32(sinfo, CMIC_DMA_STATr, &dma_stat);
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (dma_stat & DS_DESC_DONE_TST(XGS_DMA_RX_CHAN + chan)) {
+ xgs_dma_desc_clear(sinfo, XGS_DMA_RX_CHAN + chan);
+ sinfo->poll_channels |= 1 << chan;
+ }
+ }
+ if (!sinfo->poll_channels) {
+ sinfo->poll_channels = (uint32_t)(1 << sinfo->rx_chans) - 1;
+ budget_chans = budget / sinfo->rx_chans;
+ } else {
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (1 << chan & sinfo->poll_channels) {
+ budget_chans++;
+ }
+ }
+ budget_chans = budget / budget_chans;
+ }
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (1 << chan & sinfo->poll_channels) {
+ chan_done = bkn_do_rx(sinfo, chan, budget_chans);
+ rx_dcbs_done += chan_done;
+ if (chan_done < budget_chans) {
+ sinfo->poll_channels &= ~(1 << chan);
+ }
+ bkn_rx_desc_done(sinfo, chan);
+ }
+
+ if (dma_stat & DS_CHAIN_DONE_TST(XGS_DMA_RX_CHAN + chan)) {
+ xgs_dma_chain_clear(sinfo, XGS_DMA_RX_CHAN + chan);
+ bkn_rx_chain_done(sinfo, chan);
+ }
+ }
+
+ if (dma_stat & DS_CHAIN_DONE_TST(XGS_DMA_TX_CHAN)) {
+ xgs_dma_chain_clear(sinfo, XGS_DMA_TX_CHAN);
+ tx_dcbs_done = bkn_do_tx(sinfo);
+ bkn_tx_chain_done(sinfo, tx_dcbs_done);
+ }
+
+ return sinfo->poll_channels ? budget : rx_dcbs_done;
+}
+
+static int
+xgsm_do_dma(bkn_switch_info_t *sinfo, int budget)
+{
+ int rx_dcbs_done = 0, tx_dcbs_done = 0;
+ int chan_done, budget_chans = 0;
+ uint32_t dma_stat, irq_stat = 0;
+ int chan;
+
+ /* Get Controlled interrupt states for Continuous DMA mode */
+ if (sinfo->cdma_channels) {
+ DEV_READ32(sinfo, CMICM_IRQ_STATr, &irq_stat);
+ }
+
+ DEV_READ32(sinfo, CMICM_DMA_STATr, &dma_stat);
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (dma_stat & (0x10 << (XGS_DMA_RX_CHAN + chan)) ||
+ irq_stat & (0x08000000 << (XGS_DMA_RX_CHAN + chan))) {
+ xgsm_dma_desc_clear(sinfo, XGS_DMA_RX_CHAN + chan);
+ sinfo->poll_channels |= 1 << chan;
+ }
+ }
+ if (!sinfo->poll_channels) {
+ sinfo->poll_channels = (uint32_t)(1 << sinfo->rx_chans) - 1;
+ budget_chans = budget / sinfo->rx_chans;
+ } else {
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (1 << chan & sinfo->poll_channels) {
+ budget_chans++;
+ }
+ }
+ budget_chans = budget / budget_chans;
+ }
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (1 << chan & sinfo->poll_channels) {
+ chan_done = bkn_do_rx(sinfo, chan, budget_chans);
+ rx_dcbs_done += chan_done;
+ if (chan_done < budget_chans) {
+ sinfo->poll_channels &= ~(1 << chan);
+ }
+ bkn_rx_desc_done(sinfo, chan);
+ }
+
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ continue;
+ }
+
+ if (dma_stat & (0x1 << (XGS_DMA_RX_CHAN + chan))) {
+ xgsm_dma_chain_clear(sinfo, XGS_DMA_RX_CHAN + chan);
+ bkn_rx_chain_done(sinfo, chan);
+ }
+ }
+
+ if (dma_stat & (0x1 << XGS_DMA_TX_CHAN) ||
+ irq_stat & (0x08000000 << XGS_DMA_TX_CHAN)) {
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ xgsm_dma_desc_clear(sinfo, XGS_DMA_TX_CHAN);
+ } else {
+ xgsm_dma_chain_clear(sinfo, XGS_DMA_TX_CHAN);
+ }
+ tx_dcbs_done = bkn_do_tx(sinfo);
+ bkn_tx_chain_done(sinfo, tx_dcbs_done);
+ }
+
+ return sinfo->poll_channels ? budget : rx_dcbs_done;
+}
+
+static int
+xgsx_do_dma(bkn_switch_info_t *sinfo, int budget)
+{
+ int rx_dcbs_done = 0, tx_dcbs_done = 0;
+ int chan_done, budget_chans = 0;
+ uint32_t irq_stat, tx_dma_stat, rx_dma_stat[NUM_CMICX_RX_CHAN];
+ int chan;
+
+ DEV_READ32(sinfo, CMICX_IRQ_STATr, &irq_stat);
+ DEV_READ32(sinfo, CMICX_DMA_STATr + 0x80 * XGS_DMA_TX_CHAN, &tx_dma_stat);
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ DEV_READ32(sinfo,
+ CMICX_DMA_STATr + 0x80 * (XGS_DMA_RX_CHAN + chan),
+ &rx_dma_stat[chan]);
+ }
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if ((irq_stat & CMICX_DS_CMC_CTRLD_INT(XGS_DMA_RX_CHAN + chan)) ||
+ (irq_stat & CMICX_DS_CMC_DESC_DONE(XGS_DMA_RX_CHAN + chan))) {
+ xgsx_dma_desc_clear(sinfo, XGS_DMA_RX_CHAN + chan);
+ sinfo->poll_channels |= 1 << chan;
+ }
+ }
+ if (!sinfo->poll_channels) {
+ sinfo->poll_channels = (uint32_t)(1 << sinfo->rx_chans) - 1;
+ budget_chans = budget / sinfo->rx_chans;
+ } else {
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (1 << chan & sinfo->poll_channels) {
+ budget_chans++;
+ }
+ }
+ budget_chans = budget / budget_chans;
+ }
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (1 << chan & sinfo->poll_channels) {
+ chan_done = bkn_do_rx(sinfo, chan, budget_chans);
+ rx_dcbs_done += chan_done;
+ if (chan_done < budget_chans) {
+ sinfo->poll_channels &= ~(1 << chan);
+ }
+ bkn_rx_desc_done(sinfo, chan);
+ }
+
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ continue;
+ }
+
+ if (rx_dma_stat[chan] & CMICX_DS_CMC_DMA_CHAIN_DONE) {
+ xgsx_dma_chain_clear(sinfo, XGS_DMA_RX_CHAN + chan);
+ bkn_rx_chain_done(sinfo, chan);
+ }
+ }
+
+ if ((irq_stat & CMICX_DS_CMC_CTRLD_INT(XGS_DMA_TX_CHAN)) ||
+ (tx_dma_stat & CMICX_DS_CMC_DMA_CHAIN_DONE)) {
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ xgsx_dma_desc_clear(sinfo, XGS_DMA_TX_CHAN);
+ } else {
+ xgsx_dma_chain_clear(sinfo, XGS_DMA_TX_CHAN);
+ }
+ tx_dcbs_done = bkn_do_tx(sinfo);
+ bkn_tx_chain_done(sinfo, tx_dcbs_done);
+ }
+
+ return sinfo->poll_channels ? budget : rx_dcbs_done;
+}
+
+static int
+dev_do_dma(bkn_switch_info_t *sinfo, int budget)
+{
+ if (DEV_IS_CMICX(sinfo)) {
+ return xgsx_do_dma(sinfo, budget);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ return xgsm_do_dma(sinfo, budget);
+ } else {
+ return xgs_do_dma(sinfo, budget);
+ }
+}
+
+static void
+xgs_isr(bkn_switch_info_t *sinfo)
+{
+ uint32_t irq_stat;
+ int rx_dcbs_done;
+
+ DEV_READ32(sinfo, CMIC_IRQ_STATr, &irq_stat);
+ if ((irq_stat & sinfo->irq_mask) == 0) {
+ /* Not ours */
+ return;
+ }
+ sinfo->interrupts++;
+
+ DBG_IRQ(("Got interrupt on device %d (0x%08x)\n",
+ sinfo->dev_no, irq_stat));
+
+ if (use_napi) {
+ bkn_schedule_napi_poll(sinfo);
+ } else {
+ xgs_irq_mask_set(sinfo, 0);
+ do {
+ rx_dcbs_done = xgs_do_dma(sinfo, MAX_RX_DCBS);
+ } while (rx_dcbs_done);
+ }
+
+ xgs_irq_mask_set(sinfo, sinfo->irq_mask);
+}
+
+static void
+xgsm_isr(bkn_switch_info_t *sinfo)
+{
+ uint32_t irq_stat;
+ int rx_dcbs_done;
+
+ DEV_READ32(sinfo, CMICM_IRQ_STATr, &irq_stat);
+ if ((irq_stat & sinfo->irq_mask) == 0) {
+ /* Not ours */
+ return;
+ }
+ sinfo->interrupts++;
+
+ DBG_IRQ(("Got interrupt on device %d (0x%08x)\n",
+ sinfo->dev_no, irq_stat));
+
+ if (use_napi) {
+ bkn_schedule_napi_poll(sinfo);
+ } else {
+ xgsm_irq_mask_set(sinfo, 0);
+ do {
+ rx_dcbs_done = xgsm_do_dma(sinfo, MAX_RX_DCBS);
+ if (sinfo->cdma_channels) {
+ if (rx_dcbs_done >= MAX_RX_DCBS || sinfo->tx_yield) {
+ /* Continuous DMA mode requires to yield timely */
+ break;
+ }
+ }
+ } while (rx_dcbs_done);
+ }
+
+ xgsm_irq_mask_set(sinfo, sinfo->irq_mask);
+}
+
+static void
+xgsx_isr(bkn_switch_info_t *sinfo)
+{
+ uint32_t irq_stat;
+ int rx_dcbs_done;
+
+ DEV_READ32(sinfo, CMICX_IRQ_STATr, &irq_stat);
+ if ((irq_stat & sinfo->irq_mask) == 0) {
+ /* Not ours */
+ return;
+ }
+
+ /* Bypass chain_done from Abort */
+ if (device_is_dnx(sinfo)) {
+ uint32_t ctrl = 0;
+ int chan = 0;
+ for (chan = 0; chan < NUM_DMA_CHAN; chan++) {
+ if (irq_stat & CMICX_DS_CMC_CHAIN_DONE(chan)) {
+ DEV_READ32(sinfo, CMICX_DMA_CTRLr + 0x80 * chan, &ctrl);
+ if (ctrl & CMICX_DC_CMC_ABORT) {
+ DBG_IRQ(("chain %d: chain done for Abort\n", chan));
+ return;
+ }
+ }
+ }
+ }
+
+ sinfo->interrupts++;
+
+ DBG_IRQ(("Got interrupt on device %d (0x%08x)\n",
+ sinfo->dev_no, irq_stat));
+
+ if (use_napi) {
+ bkn_schedule_napi_poll(sinfo);
+ } else {
+ xgsx_irq_mask_set(sinfo, 0);
+ do {
+ rx_dcbs_done = xgsx_do_dma(sinfo, MAX_RX_DCBS);
+ if (sinfo->cdma_channels) {
+ if (rx_dcbs_done >= MAX_RX_DCBS || sinfo->tx_yield) {
+ /* Continuous DMA mode requires to yield timely */
+ break;
+ }
+ }
+ } while (rx_dcbs_done);
+ }
+
+ xgsx_irq_mask_set(sinfo, sinfo->irq_mask);
+}
+
+static void
+bkn_isr(void *isr_data)
+{
+ bkn_switch_info_t *sinfo = isr_data;
+
+ /* Safe exit on SMP systems */
+ if (!module_initialized) {
+ return;
+ }
+
+ /* Ensure that we do not touch registers during device reset */
+ if (sinfo->irq_mask == 0) {
+ /* Not ours */
+ return;
+ }
+
+ spin_lock(&sinfo->lock);
+
+ if (sinfo->napi_poll_mode) {
+ /* Not ours */
+ spin_unlock(&sinfo->lock);
+ return;
+ }
+
+ if (DEV_IS_CMICX(sinfo)) {
+ xgsx_isr(sinfo);
+ } else if (DEV_IS_CMICM(sinfo)) {
+ xgsm_isr(sinfo);
+ } else {
+ xgs_isr(sinfo);
+ }
+
+ spin_unlock(&sinfo->lock);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void
+bkn_poll_controller(struct net_device *dev)
+{
+ bkn_priv_t *priv = netdev_priv(dev);
+
+ disable_irq(dev->irq);
+ bkn_isr(priv->sinfo);
+ enable_irq(dev->irq);
+}
+#endif
+
+static void
+bkn_resume_rx(bkn_switch_info_t *sinfo)
+{
+ bkn_desc_info_t *desc;
+ bkn_dcb_chain_t *dcb_chain;
+ uint64_t cur_halt, last_dcb, dcb_dma;
+ int woffset, chan, cdma_running;
+
+ /* Resume Rx DMA on all channels */
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (sinfo->rx[chan].use_rx_skb) {
+ cdma_running = 0;
+ bkn_api_rx_restart(sinfo, chan);
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ cur_halt = sinfo->halt_addr[XGS_DMA_RX_CHAN + chan];
+ last_dcb = sinfo->rx[chan].desc[MAX_RX_DCBS].dcb_dma;
+ if (cur_halt != last_dcb) {
+ desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty + 1];
+ bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, desc->dcb_dma);
+ cdma_running = 1;
+ }
+ }
+ if (!cdma_running) {
+ bkn_rx_restart(sinfo, chan);
+ }
+ } else {
+ cdma_running = 0;
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ if (sinfo->rx[chan].api_active) {
+ dcb_chain = sinfo->rx[chan].api_dcb_chain_end;
+ woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize;
+ dcb_dma = dcb_chain->dcb_dma + woffset * sizeof(uint32_t);
+ bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, dcb_dma);
+ cdma_running = 1;
+ }
+ }
+ if (!cdma_running) {
+ bkn_api_rx_restart(sinfo, chan);
+ }
+ }
+ }
+}
+
+static int
+bkn_open(struct net_device *dev)
+{
+ bkn_priv_t *priv = netdev_priv(dev);
+ bkn_switch_info_t *sinfo = priv->sinfo;
+ unsigned long flags;
+
+ /* Check if base device */
+ if (priv->id <= 0) {
+ /* NAPI used only on base device */
+ if (use_napi) {
+ bkn_napi_enable(dev, &sinfo->napi);
+ }
+
+ /* Start DMA when base device is started */
+ if (sinfo->basedev_suspended) {
+ spin_lock_irqsave(&sinfo->lock, flags);
+ dev_do_dma(sinfo, MAX_RX_DCBS);
+ sinfo->basedev_suspended = 0;
+ bkn_api_tx(sinfo);
+ if (!sinfo->tx.api_active) {
+ bkn_resume_tx(sinfo);
+ }
+ bkn_resume_rx(sinfo);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ }
+ }
+
+ if (!sinfo->basedev_suspended) {
+ netif_start_queue(dev);
+ }
+
+ return 0;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
+static int
+bkn_set_mac_address(struct net_device *dev, void *addr)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,12))
+ if (!is_valid_ether_addr((const u8*)(((struct sockaddr *)addr)->sa_data))) {
+#else
+ if (!is_valid_ether_addr(((struct sockaddr *)addr)->sa_data)) {
+#endif
+ return -EINVAL;
+ }
+ memcpy(dev->dev_addr, ((struct sockaddr *)addr)->sa_data, dev->addr_len);
+ return 0;
+}
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
+static int
+bkn_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ bkn_priv_t *priv = netdev_priv(dev);
+ bkn_switch_info_t *sinfo = priv->sinfo;
+ struct hwtstamp_config config;
+
+ if (cmd == SIOCSHWTSTAMP) {
+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) {
+ return -EFAULT;
+ }
+
+ if (!knet_hw_tstamp_enable_cb || !knet_hw_tstamp_disable_cb ||
+ priv->type != KCOM_NETIF_T_PORT) {
+ return -ENOSYS;
+ }
+
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ knet_hw_tstamp_disable_cb(sinfo->dev_no, priv->phys_port, config.tx_type);
+ priv->tx_hwts = (config.tx_type);
+ break;
+ case HWTSTAMP_TX_ON:
+ knet_hw_tstamp_enable_cb(sinfo->dev_no, priv->phys_port, config.tx_type);
+ priv->tx_hwts = (config.tx_type);
+ break;
+ case HWTSTAMP_TX_ONESTEP_SYNC:
+ knet_hw_tstamp_enable_cb(sinfo->dev_no, priv->phys_port, config.tx_type);
+ priv->tx_hwts = (config.tx_type);
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ if (priv->rx_hwts) {
+ knet_hw_tstamp_disable_cb(sinfo->dev_no, priv->phys_port, config.tx_type);
+ priv->rx_hwts = 0;
+ }
+ break;
+ default:
+ if (!priv->rx_hwts) {
+ knet_hw_tstamp_enable_cb(sinfo->dev_no, priv->phys_port, config.tx_type);
+ priv->rx_hwts = 1;
+ }
+ config.rx_filter = HWTSTAMP_FILTER_ALL;
+ break;
+ }
+
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0;
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
+ if (cmd == SIOCGHWTSTAMP) {
+ config.flags = 0;
+ config.tx_type = priv->tx_hwts;
+ config.rx_filter = priv->rx_hwts ? HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE;
+
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0;
+ }
+#endif
+
+ return -EINVAL;
+}
+#endif
+
+static int
+bkn_change_mtu(struct net_device *dev, int new_mtu)
+{
+ int max_size = new_mtu + ETH_HLEN + VLAN_HLEN + 4;
+
+ if (new_mtu < 68 || max_size > rx_buffer_size) {
+ return -EINVAL;
+ }
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+static int
+bkn_poll(struct net_device *dev, int *budget)
+{
+ bkn_priv_t *priv = netdev_priv(dev);
+ bkn_switch_info_t *sinfo = priv->sinfo;
+ int cur_budget = *budget;
+ int poll_again = 0;
+ int rx_dcbs_done;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ DBG_NAPI(("NAPI poll on %s.\n", dev->name));
+
+ sinfo->napi_poll_again = 0;
+
+ if (cur_budget > dev->quota) {
+ cur_budget = dev->quota;
+ }
+
+ rx_dcbs_done = dev_do_dma(sinfo, cur_budget);
+
+ *budget -= rx_dcbs_done;
+ cur_budget -= rx_dcbs_done;
+ dev->quota -= rx_dcbs_done;
+
+ if (sinfo->napi_poll_again || cur_budget <= 0) {
+ poll_again = 1;
+ sinfo->napi_not_done++;
+ } else {
+ bkn_napi_poll_complete(sinfo);
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return poll_again;
+}
+#else
+static int
+bkn_poll(struct napi_struct *napi, int budget)
+{
+ bkn_switch_info_t *sinfo = container_of(napi, bkn_switch_info_t, napi);
+ int rx_dcbs_done;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ DBG_NAPI(("NAPI poll on %s.\n", sinfo->dev->name));
+
+ sinfo->napi_poll_again = 0;
+
+ rx_dcbs_done = dev_do_dma(sinfo, budget);
+
+ if (sinfo->napi_poll_again || rx_dcbs_done >= budget) {
+ /* Force poll again */
+ rx_dcbs_done = budget;
+ sinfo->napi_not_done++;
+ } else {
+ bkn_napi_poll_complete(sinfo);
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return rx_dcbs_done;
+}
+#endif
+
+static int
+bkn_stop(struct net_device *dev)
+{
+ bkn_priv_t *priv = netdev_priv(dev);
+ bkn_switch_info_t *sinfo = priv->sinfo;
+ unsigned long flags;
+
+ netif_stop_queue(dev);
+
+ /* Check if base device */
+ if (priv->id <= 0) {
+ /* NAPI used only on base device */
+ if (use_napi) {
+ bkn_napi_disable(dev, &sinfo->napi);
+ }
+ /* Suspend all devices if base device is stopped */
+ if (basedev_suspend) {
+ spin_lock_irqsave(&sinfo->lock, flags);
+ bkn_suspend_tx(sinfo);
+ sinfo->basedev_suspended = 1;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Network Device Statistics.
+ * Cleared at init time.
+ */
+static struct net_device_stats *
+bkn_get_stats(struct net_device *dev)
+{
+ bkn_priv_t *priv = netdev_priv(dev);
+
+ return &priv->stats;
+}
+
+/* Fake multicast ability */
+static void
+bkn_set_multicast_list(struct net_device *dev)
+{
+}
+
+static int
+bkn_hw_tstamp_tx_config(bkn_switch_info_t *sinfo,
+ int hwts, int hdrlen,
+ struct sk_buff *skb, u32 *meta)
+{
+ uint32_t *md = NULL;
+
+ if (!knet_hw_tstamp_tx_meta_get_cb) {
+ return -1;
+ }
+
+ KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF;
+ knet_hw_tstamp_tx_meta_get_cb(sinfo->dev_no, hwts, hdrlen, skb,
+ &(KNET_SKB_CB(skb)->ts), (meta ? &md : NULL));
+
+ if (!meta) {
+ return 0;
+ }
+
+ if (!md) {
+ return -1;
+ }
+
+ switch (sinfo->dcb_type) {
+ case 26:
+ case 32:
+ case 33:
+ meta[2] |= md[0];
+ meta[3] |= md[1];
+ meta[4] |= md[2];
+ meta[5] |= md[3];
+ break;
+ case 36:
+ case 38:
+ meta[0] |= htonl(md[0]);
+ meta[1] |= htonl(md[1]);
+ meta[2] |= htonl(md[2]);
+ meta[3] |= htonl(md[3]);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+bkn_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ bkn_priv_t *priv = netdev_priv(dev);
+ bkn_switch_info_t *sinfo = priv->sinfo;
+ struct sk_buff *new_skb = NULL;
+ unsigned char *pktdata;
+ int pktlen, hdrlen, taglen, rcpulen, metalen;
+ int sop, idx;
+ uint16_t tpid;
+ uint32_t *metadata;
+ unsigned long flags;
+ uint32_t cpu_channel = 0;
+ int headroom, tailroom;
+
+ DBG_VERB(("Netif Tx: Len=%d priv->id=%d\n", skb->len, priv->id));
+
+ if (priv->id <= 0) {
+ /* Do not transmit on base device */
+ priv->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+
+ if (device_is_dnx(sinfo) && (skb->len == 0)) {
+ priv->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+
+ if (!netif_carrier_ok(dev)) {
+ DBG_WARN(("Tx drop: Netif link is down.\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_no_link++;
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ if (sinfo->tx.free > 1) {
+ bkn_desc_info_t *desc = &sinfo->tx.desc[sinfo->tx.cur];
+ uint32_t *dcb, *meta;
+
+ pktdata = skb->data;
+ pktlen = skb->len;
+
+ if (device_is_sand(sinfo)) {
+ hdrlen = priv->system_headers_size;
+ }
+ else {
+ hdrlen = (sinfo->cmic_type == 'x' ) ? PKT_TX_HDR_SIZE : 0;
+ }
+ rcpulen = 0;
+ sop = 0;
+
+ if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) {
+ rcpulen = RCPU_HDR_SIZE;
+ if (skb->len < (rcpulen + 14)) {
+ DBG_WARN(("Tx drop: Invalid RCPU encapsulation\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_rcpu_encap++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ if (check_rcpu_signature &&
+ PKT_U16_GET(skb->data, 18) != sinfo->rcpu_sig) {
+ DBG_WARN(("Tx drop: Invalid RCPU signature\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_rcpu_sig++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+
+ if (device_is_sand(sinfo)) {
+ /* Dune devices don't use meta data */
+ sop = 0;
+ /* Get CPU channel from rcpu_hdr_t.reserved */
+ cpu_channel = (skb->data[28] << 24) | (skb->data[29] << 16) | (skb->data[30] << 8) | (skb->data[31]);
+ /* System headers are supposed to be set by users in RCPU mode. */
+ hdrlen = 0;
+ } else if (skb->data[21] & RCPU_F_MODHDR) {
+ sop = skb->data[RCPU_HDR_SIZE];
+ switch (sop) {
+ case 0xff:
+ case 0x81:
+ case 0xfb:
+ case 0xfc:
+ break;
+ default:
+ DBG_WARN(("Tx drop: Invalid RCPU meta data\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_rcpu_meta++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ if (sinfo->cmic_type != 'x') {
+ rcpulen += RCPU_TX_META_SIZE;
+ }
+ }
+ /* Skip over RCPU encapsulation */
+ pktdata = &skb->data[rcpulen];
+ pktlen -= rcpulen;
+
+ /* CPU packets require tag */
+ if (sop == 0) {
+ if (device_is_sand(sinfo)) {
+ /*
+ * There should be Module Header + PTCH_2 + [ITMH] on JR2,
+ * PTCH_2 +[ITMH] on JR1
+ */
+ } else {
+ hdrlen = 0;
+ tpid = PKT_U16_GET(pktdata, 12);
+ if (tpid != 0x8100) {
+ if (skb_header_cloned(skb)) {
+ /* Current SKB cannot be modified */
+ DBG_SKB(("Realloc Tx SKB\n"));
+ /*
+ * New SKB needs extra TAG_SZ for VLAN tag
+ * and extra FCS_SZ for Ethernet FCS.
+ */
+ headroom = TAG_SZ;
+ tailroom = FCS_SZ;
+ new_skb = skb_copy_expand(skb,
+ headroom + skb_headroom(skb),
+ tailroom + skb_tailroom(skb),
+ GFP_ATOMIC);
+ if (new_skb == NULL) {
+ DBG_WARN(("Tx drop: No SKB memory\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_no_skb++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ /* Remove rcpulen from buffer. */
+ skb_pull(new_skb, rcpulen);
+ /* Extended by TAG_SZ at the start of buffer. */
+ skb_push(new_skb, TAG_SZ);
+ /* Restore the data before the tag. */
+ memcpy(new_skb->data, pktdata, 12);
+ bkn_skb_tstamp_copy(new_skb, skb);
+ dev_kfree_skb_any(skb);
+ skb = new_skb;
+ pktdata = skb->data;
+ rcpulen = 0;
+ } else {
+ /* Add tag to RCPU header space */
+ DBG_SKB(("Expand into unused RCPU header\n"));
+ rcpulen -= TAG_SZ;
+ pktdata = &skb->data[rcpulen];
+ for (idx = 0; idx < 12; idx++) {
+ pktdata[idx] = pktdata[idx + TAG_SZ];
+ }
+ }
+ pktdata[12] = 0x81;
+ pktdata[13] = 0x00;
+ pktdata[14] = (priv->vlan >> 8) & 0xf;
+ pktdata[15] = priv->vlan & 0xff;
+ pktlen += TAG_SZ;
+ }
+ }
+ }
+ } else {
+ if (((sinfo->cmic_type == 'x') && (priv->port >= 0))
+ || device_is_sand(sinfo)) {
+ if (skb_header_cloned(skb) || skb_headroom(skb) < hdrlen + 4) {
+ /* Current SKB cannot be modified */
+ DBG_SKB(("Realloc Tx SKB\n"));
+ if (device_is_sand(sinfo)) {
+ headroom = hdrlen;
+ } else {
+ headroom = hdrlen + 4;
+ }
+ tailroom = FCS_SZ;
+ new_skb = skb_copy_expand(skb,
+ headroom + skb_headroom(skb),
+ tailroom + skb_tailroom(skb),
+ GFP_ATOMIC);
+ if (new_skb == NULL) {
+ DBG_WARN(("Tx drop: No SKB memory\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_no_skb++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ skb_push(new_skb, hdrlen);
+ bkn_skb_tstamp_copy(new_skb, skb);
+ dev_kfree_skb_any(skb);
+ skb = new_skb;
+ } else {
+ DBG_SKB(("Expand Tx SKB\n"));
+ skb_push(skb, hdrlen);
+ }
+ memset(skb->data, 0, hdrlen);
+ pktdata = skb->data;
+ pktlen += hdrlen;
+ } else {
+ hdrlen = 0;
+ }
+
+ if (priv->port < 0 || (priv->flags & KCOM_NETIF_F_ADD_TAG)) {
+ DBG_DUNE(("ADD VLAN TAG\n"));
+ /* Need to add VLAN tag if packet is untagged */
+ tpid = PKT_U16_GET(skb->data, hdrlen + 12);
+ if (tpid != 0x8100) {
+ if (skb_header_cloned(skb) || skb_headroom(skb) < 4) {
+ /* Current SKB cannot be modified */
+ DBG_SKB(("Realloc Tx SKB\n"));
+ headroom = TAG_SZ;
+ tailroom = FCS_SZ;
+ new_skb = skb_copy_expand(skb,
+ headroom + skb_headroom(skb),
+ tailroom + skb_tailroom(skb),
+ GFP_ATOMIC);
+ if (new_skb == NULL) {
+ DBG_WARN(("Tx drop: No SKB memory\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_no_skb++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ skb_push(new_skb, TAG_SZ);
+ memcpy(new_skb->data, pktdata, hdrlen + 12);
+ bkn_skb_tstamp_copy(new_skb, skb);
+ dev_kfree_skb_any(skb);
+ skb = new_skb;
+ } else {
+ /* Add tag to existing buffer */
+ DBG_SKB(("Expand Tx SKB\n"));
+ skb_push(skb, TAG_SZ);
+ for (idx = 0; idx < hdrlen + 12; idx++) {
+ skb->data[idx] = skb->data[idx + TAG_SZ];
+ }
+ }
+ pktdata = skb->data;
+ pktdata[hdrlen + 12] = 0x81;
+ pktdata[hdrlen + 13] = 0x00;
+ pktdata[hdrlen + 14] = (priv->vlan >> 8) & 0xf;
+ pktdata[hdrlen + 15] = priv->vlan & 0xff;
+ pktlen += TAG_SZ;
+ }
+ }
+ }
+
+ /* Pad packet if needed */
+ taglen = 0;
+ tpid = PKT_U16_GET(pktdata, hdrlen + 12);
+ if (tpid == 0x8100) {
+ taglen = 4;
+ }
+ if (pktlen < (60 + taglen + hdrlen)) {
+ pktlen = (60 + taglen + hdrlen);
+ if (SKB_PADTO(skb, pktlen) != 0) {
+ DBG_WARN(("Tx drop: skb_padto failed\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_pad_fail++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ /* skb_padto may update the skb->data pointer */
+ pktdata = &skb->data[rcpulen];
+ }
+
+ if ((pktlen + FCS_SZ) > SOC_DCB_KNET_COUNT_MASK) {
+ DBG_WARN(("Tx drop: size of pkt (%d) is out of range(%d)\n",
+ (pktlen + FCS_SZ), SOC_DCB_KNET_COUNT_MASK));
+ sinfo->tx.pkts_d_over_limit++;
+ priv->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+
+ dcb = desc->dcb_mem;
+ meta = (sinfo->cmic_type == 'x') ? (uint32_t *)pktdata : dcb;
+ memset(dcb, 0, sinfo->dcb_wsize * sizeof(uint32_t));
+ if (priv->flags & KCOM_NETIF_F_RCPU_ENCAP) {
+ if (device_is_sand(sinfo)) {
+ if (sinfo->cmic_type == 'x') {
+ dcb[2] |= 1 << 19;
+ /* Given Module Header exists and set first byte to be CPU channel */
+ pktdata[0] = cpu_channel;
+ } else {
+ dcb[1] |= 1 << 19;
+ /* Set CPU channel */
+ dcb[2] = (cpu_channel & 0xff) << 24;
+ }
+
+ } else if (sop != 0) {
+ /* If module header SOP is non-zero, use RCPU meta data */
+ if (sinfo->cmic_type == 'x') {
+ dcb[2] |= 1 << 19;
+ } else {
+ metalen = (sinfo->dcb_wsize - 3) * sizeof(uint32_t);
+ if (metalen > RCPU_TX_META_SIZE) {
+ metalen = RCPU_TX_META_SIZE;
+ }
+ metadata = (uint32_t *)&skb->data[RCPU_HDR_SIZE];
+ for (idx = 0; idx < BYTES2WORDS(metalen); idx++) {
+ dcb[idx + 2] = ntohl(metadata[idx]);
+ }
+ dcb[1] |= 1 << 19;
+ }
+ }
+ } else if (priv->port >= 0) {
+ /* Send to physical port */
+ if (sinfo->cmic_type == 'x') {
+ dcb[2] |= 1 << 19;
+ } else {
+ dcb[1] |= 1 << 19;
+ }
+ switch (sinfo->dcb_type) {
+ case 23:
+ case 26:
+ case 30:
+ case 31:
+ case 34:
+ case 37:
+ dcb[2] = 0x81000000;
+ dcb[3] = priv->port;
+ dcb[3] |= (priv->qnum & 0xc00) << 20;
+ dcb[4] = 0x00040000;
+ dcb[4] |= (priv->qnum & 0x3ff) << 8;
+ break;
+ case 24:
+ dcb[2] = 0xff000000;
+ dcb[3] = 0x00000100;
+ dcb[4] = priv->port;
+ dcb[4] |= (priv->qnum & 0xfff) << 14;
+ break;
+ case 28:
+ /*
+ * If KCOM_NETIF_T_PORT, add PTCH+ITMH header
+ * If KCOM_NETIF_T_VLAN, add PTCH+header
+ */
+ pktdata = skb->data;
+ memcpy(&pktdata[0], priv->system_headers, priv->system_headers_size);
+ /* Set CPU channel */
+ dcb[2] = ((priv->qnum & 0xff) << 24);
+ break;
+ case 29:
+ dcb[2] = 0x81000000;
+ dcb[3] = priv->port;
+ dcb[4] = 0x00100000;
+ dcb[4] |= (priv->qnum & 0xfff) << 8;
+ break;
+ case 32:
+ dcb[2] = 0x81000000;
+ dcb[3] = priv->port;
+ dcb[4] = 0x00004000;
+ dcb[4] |= (priv->qnum & 0x3f) << 8;
+ break;
+ case 33:
+ dcb[2] = 0x81000000;
+ dcb[3] = (priv->port) << 2;
+ dcb[4] = 0x00100000;
+ dcb[4] |= (priv->qnum & 0xfff) << 8;
+ break;
+ case 35:
+ dcb[2] = 0x81000000;
+ dcb[3] = (priv->port) << 4;
+ dcb[4] = 0x00400000;
+ dcb[4] |= (priv->qnum & 0x3fff) << 8;
+ break;
+ case 36:
+ if (sinfo->cmic_type == 'x') {
+ meta[0] = htonl(0x81000000);
+ meta[1] = htonl(priv->port);
+ meta[2] = htonl(0x00008000 | (priv->qnum & 0x3f) << 9);
+ } else {
+ dcb[2] = 0x81000000;
+ dcb[3] = priv->port;
+ dcb[4] = 0x00008000;
+ dcb[4] |= (priv->qnum & 0x3f) << 9;
+ }
+ break;
+ case 38:
+ if (sinfo->cmic_type == 'x') {
+ meta[0] = htonl(0x81000000);
+ meta[1] = htonl(priv->port);
+ meta[2] = htonl(0x00004000 | (priv->qnum & 0x3f) << 8);
+ } else {
+ dcb[2] = 0x81000000;
+ dcb[3] = priv->port;
+ dcb[4] = 0x00004000;
+ dcb[4] |= (priv->qnum & 0x3f) << 8;
+ }
+ break;
+ case 39:
+ if (device_is_dnx(sinfo)) {
+ /*
+ * if KCOM_NETIF_T_PORT, add MH+PTCH+ITMH header
+ * if KCOM_NETIF_T_VLAN, add MH+PTCH+header
+ */
+ pktdata = skb->data;
+ memcpy(&pktdata[0], priv->system_headers, priv->system_headers_size);
+ }
+ break;
+ case 40:
+ if (sinfo->cmic_type == 'x') {
+ meta[0] = htonl(0x81000000);
+ meta[1] = htonl(priv->port | (priv->qnum & 0xc00) << 20);
+ meta[2] = htonl(0x00040000 | (priv->qnum & 0x3ff) << 8);
+ } else {
+ dcb[2] = 0x81000000;
+ dcb[3] = priv->port;
+ dcb[3] |= (priv->qnum & 0xc00) << 20;
+ dcb[4] = 0x00040000;
+ dcb[4] |= (priv->qnum & 0x3ff) << 8;
+ }
+ break;
+ default:
+ dcb[2] = 0xff000000;
+ dcb[3] = 0x00000100;
+ dcb[4] = priv->port;
+ break;
+ }
+ }
+
+ /* Optional SKB updates */
+ if (knet_tx_cb != NULL) {
+ KNET_SKB_CB(skb)->netif_user_data = priv->cb_user_data;
+ KNET_SKB_CB(skb)->dcb_type = sinfo->dcb_type & 0xFFFF;
+ skb = knet_tx_cb(skb, sinfo->dev_no, meta);
+ if (skb == NULL) {
+ /* Consumed by call-back */
+ DBG_WARN(("Tx drop: Consumed by call-back\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_callback++;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ /* Restore (possibly) altered packet variables
+ * bit0 -bit15 of dcb[1] is used to save requested byte count
+ */
+ if ((skb->len + FCS_SZ) <= SOC_DCB_KNET_COUNT_MASK) {
+ pktlen = skb->len;
+ if (pktlen < (60 + taglen + hdrlen)) {
+ pktlen = (60 + taglen + hdrlen);
+ if (SKB_PADTO(skb, pktlen) != 0) {
+ DBG_WARN(("Tx drop: skb_padto failed\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_pad_fail++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ DBG_SKB(("Packet padded to %d bytes after tx callback\n", pktlen));
+ }
+ pktdata = skb->data;
+ if (sinfo->cmic_type == 'x') {
+ meta = (uint32_t *)pktdata;
+ }
+ } else {
+ DBG_WARN(("Tx drop: size of pkt (%d) is out of range(%d)\n",
+ (pktlen + FCS_SZ), SOC_DCB_KNET_COUNT_MASK));
+ sinfo->tx.pkts_d_over_limit++;
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_callback++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ }
+
+ /* Do Tx timestamping */
+ if (bkn_skb_tx_flags(skb) & SKBTX_HW_TSTAMP) {
+ KNET_SKB_CB(skb)->hwts = priv->tx_hwts;
+ if ((priv->port >= 0) && (priv->tx_hwts & HWTSTAMP_TX_ON)) {
+ /* TwoStep Processing of ptp-packets */
+ KNET_SKB_CB(skb)->port = priv->phys_port;
+ bkn_hw_tstamp_tx_config(sinfo, priv->tx_hwts, PKT_TX_HDR_SIZE, skb, meta);
+
+ bkn_skb_tx_flags(skb) |= SKBTX_IN_PROGRESS;
+ bkn_skb_tx_timestamp(skb);
+
+ } else if (priv->tx_hwts & HWTSTAMP_TX_ONESTEP_SYNC) {
+
+ /* OneStep Processing of ptp-packets */
+ KNET_SKB_CB(skb)->port = priv->phys_port;
+ KNET_SKB_CB(skb)->ts = 0;
+ bkn_hw_tstamp_tx_config(sinfo, priv->tx_hwts, PKT_TX_HDR_SIZE, skb,
+ ((priv->port >= 0) ? meta : NULL));
+
+ if (KNET_SKB_CB(skb)->ts != 0) {
+ bkn_skb_tx_flags(skb) |= SKBTX_IN_PROGRESS;
+ bkn_skb_tx_timestamp(skb);
+ }
+
+ }
+ }
+
+ /* Prepare for DMA */
+ desc->skb = skb;
+ /*
+ * Add FCS bytes
+ * FCS bytes are always appended to packet by MAC on Dune devices
+ */
+ if (!device_is_sand(sinfo)) {
+ pktlen = pktlen + FCS_SZ;
+ }
+ desc->dma_size = pktlen;
+ desc->skb_dma = BKN_DMA_MAP_SINGLE(sinfo->dma_dev,
+ pktdata, desc->dma_size,
+ BKN_DMA_TODEV);
+ if (BKN_DMA_MAPPING_ERROR(sinfo->dma_dev, desc->skb_dma)) {
+ priv->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return 0;
+ }
+ dcb[0] = desc->skb_dma;
+ if (sinfo->cmic_type == 'x') {
+ dcb[1] = DMA_TO_BUS_HI(desc->skb_dma >> 32);
+ dcb[2] &= ~SOC_DCB_KNET_COUNT_MASK;
+ dcb[2] |= pktlen;
+ } else {
+ dcb[1] &= ~SOC_DCB_KNET_COUNT_MASK;
+ dcb[1] |= pktlen;
+ }
+
+ bkn_dump_dcb("Tx RCPU", dcb, sinfo->dcb_wsize, XGS_DMA_TX_CHAN);
+ DBG_DCB_TX(("Add Tx DCB @ 0x%08x (%d) [%d free] (%d bytes).\n",
+ (uint32_t)desc->dcb_dma, sinfo->tx.cur,
+ sinfo->tx.free, pktlen));
+ bkn_dump_pkt(pktdata, pktlen, XGS_DMA_TX_CHAN);
+
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ if (sinfo->cmic_type == 'x') {
+ dcb[2] |= 1 << 24 | 1 << 16;
+ } else {
+ dcb[1] |= 1 << 24 | 1 << 16;
+ }
+ } else {
+ bkn_tx_dma_start(sinfo);
+ }
+ if (++sinfo->tx.cur >= MAX_TX_DCBS) {
+ sinfo->tx.cur = 0;
+ }
+ sinfo->tx.free--;
+
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN) && !sinfo->tx.api_active) {
+ /* DMA run to the new halt location */
+ bkn_cdma_goto(sinfo, XGS_DMA_TX_CHAN,
+ sinfo->tx.desc[sinfo->tx.cur].dcb_dma);
+ }
+
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += pktlen;
+ sinfo->tx.pkts++;
+ } else {
+ DBG_WARN(("Tx drop: No DMA resources\n"));
+ priv->stats.tx_dropped++;
+ sinfo->tx.pkts_d_dma_resrc++;
+ dev_kfree_skb_any(skb);
+ }
+
+ /* Check our Tx resources */
+ if (sinfo->tx.free <= 1) {
+ bkn_suspend_tx(sinfo);
+ }
+
+ NETDEV_UPDATE_TRANS_START_TIME(dev);
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return 0;
+}
+
+static void
+bkn_timer_func(bkn_switch_info_t *sinfo)
+{
+ unsigned long flags;
+ int chan;
+ int restart_timer;
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ sinfo->timer_runs++;
+
+ restart_timer = 0;
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ /* Restart channel if not running */
+ if (sinfo->rx[chan].running == 0) {
+ bkn_rx_refill(sinfo, chan);
+ if (bkn_rx_restart(sinfo, chan) != 0) {
+ restart_timer = 1;
+ }
+ }
+ }
+
+ if (restart_timer) {
+ /* Presumably still out of memory */
+ sinfo->timer.expires = jiffies + 1;
+ add_timer(&sinfo->timer);
+ } else {
+ sinfo->timer_queued = 0;
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
+static void
+bkn_timer(unsigned long context)
+{
+ bkn_switch_info_t *sinfo = (bkn_switch_info_t *)context;
+ return bkn_timer_func(sinfo);
+}
+#else
+static void
+bkn_timer(struct timer_list *t)
+{
+ bkn_switch_info_t *sinfo = from_timer(sinfo, t, timer);
+ return bkn_timer_func(sinfo);
+}
+#endif
+
+static void
+bkn_rx_add_tokens(bkn_switch_info_t *sinfo, int chan)
+{
+ unsigned long cur_jif, ticks;
+ uint32_t tokens_per_tick;
+ bkn_desc_info_t *desc;
+
+ tokens_per_tick = sinfo->rx[chan].rate_max / HZ;
+ cur_jif = jiffies;
+ ticks = cur_jif - sinfo->rx[chan].tok_jif;
+ sinfo->rx[chan].tokens += ticks * tokens_per_tick;
+ sinfo->rx[chan].tok_jif = cur_jif;
+ if (sinfo->rx[chan].tokens > sinfo->rx[chan].burst_max) {
+ sinfo->rx[chan].tokens = sinfo->rx[chan].burst_max;
+ }
+
+ /* Restart channel if Rx is suppressed */
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ bkn_rx_refill(sinfo, chan);
+ desc = &sinfo->rx[chan].desc[sinfo->rx[chan].dirty];
+ if (desc->dcb_dma == sinfo->halt_addr[XGS_DMA_RX_CHAN + chan]) {
+ desc = &sinfo->rx[chan].desc[MAX_RX_DCBS];
+ bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, desc->dcb_dma);
+ }
+ } else {
+ if (sinfo->rx[chan].running == 0) {
+ bkn_rx_refill(sinfo, chan);
+ bkn_rx_restart(sinfo, chan);
+ }
+ }
+}
+
+static void
+bkn_rxtick_func(bkn_switch_info_t *sinfo)
+{
+ unsigned long flags;
+ unsigned long cur_jif, ticks;
+ uint32_t pkt_diff;
+ int chan;
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ sinfo->rxtick.expires = jiffies + sinfo->rxtick_jiffies;
+
+ /* For debug purposes we maintain a rough actual packet rate */
+ if (++sinfo->rxticks >= sinfo->rxticks_per_sec) {
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ pkt_diff = sinfo->rx[chan].pkts - sinfo->rx[chan].pkts_ref;
+ cur_jif = jiffies;
+ ticks = cur_jif - sinfo->rx[chan].rate_jif;
+ sinfo->rx[chan].rate = (pkt_diff * HZ) / ticks;
+ sinfo->rx[chan].rate_jif = cur_jif;
+ sinfo->rx[chan].pkts_ref = sinfo->rx[chan].pkts;
+ }
+ sinfo->rxticks = 0;
+ }
+
+ /* Update tokens for Rx rate control */
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (sinfo->rx[chan].tokens < sinfo->rx[chan].burst_max) {
+ bkn_rx_add_tokens(sinfo, chan);
+ }
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ add_timer(&sinfo->rxtick);
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
+static void
+bkn_rxtick(unsigned long context)
+{
+ bkn_switch_info_t *sinfo = (bkn_switch_info_t *)context;
+ return bkn_rxtick_func(sinfo);
+}
+#else
+static void
+bkn_rxtick(struct timer_list *t)
+{
+ bkn_switch_info_t *sinfo = from_timer(sinfo, t, rxtick);
+ return bkn_rxtick_func(sinfo);
+}
+#endif
+
+static void
+bkn_rx_rate_config(bkn_switch_info_t *sinfo)
+{
+ unsigned long flags;
+ int chan;
+ uint32_t rxticks_per_sec, rps;
+ uint32_t jiffies_per_rxtick;
+ uint32_t tokens_per_rxtick;
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ /* Calculate the minimum update frequency across all channels */
+ rxticks_per_sec = 1;
+ for (chan = 0; chan < NUM_RX_CHAN; chan++) {
+ if (sinfo->rx[chan].burst_max == 0) {
+ sinfo->rx[chan].burst_max = sinfo->rx[chan].rate_max / 10;
+ }
+ rps = sinfo->rx[chan].rate_max / sinfo->rx[chan].burst_max;
+ if (rxticks_per_sec < rps) {
+ rxticks_per_sec = rps;
+ }
+ }
+
+ /* Convert update frequency to system ticks */
+ jiffies_per_rxtick = HZ / rxticks_per_sec;
+ if (jiffies_per_rxtick == 0) {
+ jiffies_per_rxtick = 1;
+ }
+ rxticks_per_sec = HZ / jiffies_per_rxtick;
+
+ for (chan = 0; chan < NUM_RX_CHAN; chan++) {
+ /* Ensure that burst size satifies overall rate */
+ tokens_per_rxtick = sinfo->rx[chan].rate_max / rxticks_per_sec;
+ if (sinfo->rx[chan].burst_max < tokens_per_rxtick) {
+ sinfo->rx[chan].burst_max = tokens_per_rxtick;
+ }
+ /* Ensure that rate has a sane value */
+ if (sinfo->rx[chan].rate_max != 0) {
+ if (sinfo->rx[chan].rate_max < rxticks_per_sec) {
+ sinfo->rx[chan].rate_max = rxticks_per_sec;
+ }
+ }
+ sinfo->rx[chan].tokens = sinfo->rx[chan].burst_max;
+ }
+
+ /* Update timer controls */
+ sinfo->rxticks_per_sec = rxticks_per_sec;
+ sinfo->rxtick_jiffies = jiffies_per_rxtick;
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+}
+
+static void
+bkn_destroy_sinfo(bkn_switch_info_t *sinfo)
+{
+ list_del(&sinfo->list);
+ bkn_free_dcbs(sinfo);
+ kfree(sinfo);
+}
+
+static bkn_switch_info_t *
+bkn_create_sinfo(int dev_no)
+{
+ bkn_switch_info_t *sinfo;
+ int chan;
+
+ if ((sinfo = kmalloc(sizeof(*sinfo), GFP_KERNEL)) == NULL) {
+ return NULL;
+ }
+ memset(sinfo, 0, sizeof(*sinfo));
+ INIT_LIST_HEAD(&sinfo->ndev_list);
+ INIT_LIST_HEAD(&sinfo->rxpf_list);
+ sinfo->base_addr = lkbde_get_dev_virt(dev_no);
+ sinfo->dma_dev = lkbde_get_dma_dev(dev_no);
+ sinfo->pdev = lkbde_get_hw_dev(dev_no);
+ sinfo->dev_no = dev_no;
+ sinfo->evt_idx = -1;
+
+ spin_lock_init(&sinfo->lock);
+ skb_queue_head_init(&sinfo->tx_ptp_queue);
+ INIT_WORK(&sinfo->tx_ptp_work, bkn_hw_tstamp_tx_work);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
+ init_timer(&sinfo->timer);
+ sinfo->timer.data = (unsigned long)sinfo;
+ sinfo->timer.function = bkn_timer;
+#else
+ timer_setup(&sinfo->timer, bkn_timer, 0);
+#endif
+ sinfo->timer.expires = jiffies + 1;
+
+ INIT_LIST_HEAD(&sinfo->tx.api_dcb_list);
+
+ for (chan = 0; chan < NUM_RX_CHAN; chan++) {
+ INIT_LIST_HEAD(&sinfo->rx[chan].api_dcb_list);
+ sinfo->rx[chan].use_rx_skb = use_rx_skb;
+ }
+
+ /*
+ * Check for dual DMA mode where Rx DMA channel 0 uses DMA buffers
+ * provided by the BCM API, and the remaining Rx DMA channel(s)
+ * use socket buffers (SKB) provided by the Linux kernel.
+ */
+ if (use_rx_skb == 2) {
+ sinfo->rx[0].use_rx_skb = 0;
+ }
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
+ init_timer(&sinfo->rxtick);
+ sinfo->rxtick.data = (unsigned long)sinfo;
+ sinfo->rxtick.function = bkn_rxtick;
+#else
+ timer_setup(&sinfo->rxtick, bkn_rxtick, 0);
+#endif
+ sinfo->rxtick.expires = jiffies + 1;
+
+ for (chan = 0; chan < NUM_RX_CHAN; chan++) {
+ sinfo->rx[chan].rate_max = rx_rate[chan];
+ sinfo->rx[chan].burst_max = rx_burst[chan];
+ }
+ bkn_rx_rate_config(sinfo);
+
+ add_timer(&sinfo->rxtick);
+
+ list_add_tail(&sinfo->list, &_sinfo_list);
+
+ return sinfo;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
+static const struct net_device_ops bkn_netdev_ops = {
+ .ndo_open = bkn_open,
+ .ndo_stop = bkn_stop,
+ .ndo_start_xmit = bkn_tx,
+ .ndo_get_stats = bkn_get_stats,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_rx_mode = bkn_set_multicast_list,
+ .ndo_set_mac_address = bkn_set_mac_address,
+ .ndo_do_ioctl = bkn_ioctl,
+ .ndo_tx_timeout = NULL,
+ .ndo_change_mtu = bkn_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = bkn_poll_controller,
+#endif
+};
+#endif
+
+static void
+bkn_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
+{
+ strlcpy(drvinfo->driver, "bcm-knet", sizeof(drvinfo->driver));
+ snprintf(drvinfo->version, sizeof(drvinfo->version), "%d", KCOM_VERSION);
+ strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+ strlcpy(drvinfo->bus_info, "N/A", sizeof(drvinfo->bus_info));
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0))
+static int
+bkn_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
+{
+ bkn_priv_t *priv = netdev_priv(dev);
+ bkn_switch_info_t *sinfo = priv->sinfo;
+
+ switch (sinfo->dcb_type) {
+ case 26:
+ case 32:
+ case 33:
+ case 36:
+ case 38:
+ case 40:
+ info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+ info->tx_types = 1 << HWTSTAMP_TX_OFF | 1 << HWTSTAMP_TX_ON;
+ info->rx_filters = 1 << HWTSTAMP_FILTER_NONE | 1 << HWTSTAMP_FILTER_ALL;
+ if (knet_hw_tstamp_ptp_clock_index_cb) {
+ info->phc_index = knet_hw_tstamp_ptp_clock_index_cb(sinfo->dev_no);
+ } else {
+ info->phc_index = -1;
+ }
+ break;
+ default:
+ info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE;
+ info->phc_index = -1;
+ break;
+ }
+
+ return 0;
+}
+#endif
+
+static const struct ethtool_ops bkn_ethtool_ops = {
+ .get_drvinfo = bkn_get_drvinfo,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0))
+ .get_ts_info = bkn_get_ts_info,
+#endif
+};
+
+static struct net_device *
+bkn_init_ndev(u8 *mac, char *name)
+{
+ struct net_device *dev;
+
+ /* Create Ethernet device */
+ dev = alloc_etherdev(sizeof(bkn_priv_t));
+
+ if (dev == NULL) {
+ DBG_WARN(("Error allocating Ethernet device.\n"));
+ return NULL;
+ }
+#ifdef SET_MODULE_OWNER
+ SET_MODULE_OWNER(dev);
+#endif
+
+ /* Set the device MAC address */
+ memcpy(dev->dev_addr, mac, 6);
+
+ /* Device information -- not available right now */
+ dev->irq = 0;
+ dev->base_addr = 0;
+
+ /* Default MTU should not exceed MTU of switch front-panel ports */
+ dev->mtu = default_mtu;
+ if (dev->mtu == 0) {
+ dev->mtu = rx_buffer_size;
+ }
+
+ /* Device vectors */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
+ dev->netdev_ops = &bkn_netdev_ops;
+#else
+ dev->open = bkn_open;
+ dev->hard_start_xmit = bkn_tx;
+ dev->stop = bkn_stop;
+ dev->set_multicast_list = bkn_set_multicast_list;
+ dev->do_ioctl = NULL;
+ dev->get_stats = bkn_get_stats;
+ dev->change_mtu = bkn_change_mtu;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = bkn_poll_controller;
+#endif
+#endif
+ dev->ethtool_ops = &bkn_ethtool_ops;
+ if (name && *name) {
+ strncpy(dev->name, name, IFNAMSIZ-1);
+ }
+
+ bkn_dev_net_set(dev, current->nsproxy->net_ns);
+
+ /* Register the kernel Ethernet device */
+ if (register_netdev(dev)) {
+ DBG_WARN(("Error registering Ethernet device.\n"));
+ free_netdev(dev);
+ return NULL;
+ }
+ DBG_VERB(("Created Ethernet device %s.\n", dev->name));
+
+ return dev;
+}
+
+/*
+ * Device Link Control Proc Read Entry
+ */
+static int
+bkn_proc_link_show(struct seq_file *m, void *v)
+{
+ struct list_head *slist, *dlist;
+ struct net_device *dev;
+ bkn_priv_t *priv;
+ bkn_switch_info_t *sinfo;
+ unsigned long flags;
+
+ seq_printf(m, "Software link status:\n");
+ list_for_each(slist, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)slist;
+ spin_lock_irqsave(&sinfo->lock, flags);
+ list_for_each(dlist, &sinfo->ndev_list) {
+ priv = (bkn_priv_t *)dlist;
+ dev = priv->dev;
+ if (dev) {
+ seq_printf(m, " %-14s %s\n", dev->name,
+ netif_carrier_ok(dev) ? "up" : "down");
+ }
+ }
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ }
+ return 0;
+}
+
+static int
+bkn_proc_link_open(struct inode * inode, struct file * file)
+{
+ return single_open(file, bkn_proc_link_show, NULL);
+}
+
+/*
+ * Device Link Control Proc Write Entry
+ *
+ * Syntax:
+ * <netif>=up|down
+ *
+ * Where <netif> is a virtual network interface name.
+ *
+ * Examples:
+ * eth4=up
+ * eth4=down
+ */
+static ssize_t
+bkn_proc_link_write(struct file *file, const char *buf,
+ size_t count, loff_t *loff)
+{
+ struct list_head *slist, *dlist;
+ struct net_device *dev;
+ bkn_priv_t *priv;
+ bkn_switch_info_t *sinfo;
+ unsigned long flags;
+ char link_str[40];
+ char *ptr;
+ char *newline;
+
+ if (count > sizeof(link_str)) {
+ count = sizeof(link_str) - 1;
+ link_str[count] = '\0';
+ }
+ if (copy_from_user(link_str, buf, count)) {
+ return -EFAULT;
+ }
+ link_str[count] = 0;
+ newline = strchr(link_str, '\n');
+ if (newline) {
+ /* Chop off the trailing newline */
+ *newline = '\0';
+ }
+
+ if ((ptr = strchr(link_str, '=')) == NULL &&
+ (ptr = strchr(link_str, ':')) == NULL) {
+ gprintk("Error: link syntax not recognized: '%s'\n", link_str);
+ return count;
+ }
+ *ptr++ = 0;
+
+ dev = NULL;
+ list_for_each(slist, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)slist;
+ spin_lock_irqsave(&sinfo->lock, flags);
+ list_for_each(dlist, &sinfo->ndev_list) {
+ priv = (bkn_priv_t *)dlist;
+ if (priv->dev) {
+ if (strcmp(priv->dev->name, link_str) == 0) {
+ dev = priv->dev;
+ break;
+ }
+ }
+ }
+ if (dev) {
+ if (strcmp(ptr, "up") == 0) {
+ netif_carrier_on(dev);
+ } else if (strcmp(ptr, "down") == 0) {
+ netif_carrier_off(dev);
+ } else {
+ gprintk("Warning: unknown link state setting: '%s'\n", ptr);
+ }
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return count;
+ }
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ }
+
+ gprintk("Warning: unknown network interface: '%s'\n", link_str);
+
+ return count;
+}
+
+struct file_operations bkn_proc_link_file_ops = {
+ owner: THIS_MODULE,
+ open: bkn_proc_link_open,
+ read: seq_read,
+ llseek: seq_lseek,
+ write: bkn_proc_link_write,
+ release: single_release,
+};
+
+/*
+ * Device Rate Control Proc Read Entry
+ */
+static int
+bkn_proc_rate_show(struct seq_file *m, void *v)
+{
+ int unit = 0;
+ struct list_head *list;
+ bkn_switch_info_t *sinfo;
+ int chan;
+
+ list_for_each(list, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)list;
+
+ seq_printf(m, "Rate control (unit %d):\n", unit);
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ seq_printf(m, " Rx%d max rate %8u\n",
+ chan, sinfo->rx[chan].rate_max);
+ seq_printf(m, " Rx%d max burst %8u\n",
+ chan, sinfo->rx[chan].burst_max);
+ seq_printf(m, " Rx%d rate %8u\n",
+ chan, sinfo->rx[chan].rate);
+ seq_printf(m, " Rx%d tokens %8u\n",
+ chan, sinfo->rx[chan].tokens);
+ }
+
+ unit++;
+ }
+ return 0;
+}
+
+static int
+bkn_proc_rate_open(struct inode * inode, struct file * file)
+{
+ return single_open(file, bkn_proc_rate_show, NULL);
+}
+
+/*
+ * Device Rate Control Proc Write Entry
+ *
+ * Syntax:
+ * [<unit>:]rx_rate=<rate0>[,<rate1>[,<rate2]]
+ *
+ * Where <rate0> is packets/sec for the first Rx DMA channel,
+ * <rate1> is packets/sec for the second Rx DMA channel, etc.
+ *
+ * Examples:
+ * rx_rate=5000
+ * 0:rx_rate=10000,10000
+ * 1:rx_rate=10000,5000
+ */
+static ssize_t
+bkn_proc_rate_write(struct file *file, const char *buf,
+ size_t count, loff_t *loff)
+{
+ bkn_switch_info_t *sinfo;
+ char rate_str[80];
+ char *ptr;
+ int unit, chan;
+
+ if (count > sizeof(rate_str)) {
+ count = sizeof(rate_str) - 1;
+ rate_str[count] = '\0';
+ }
+ if (copy_from_user(rate_str, buf, count)) {
+ return -EFAULT;
+ }
+
+ unit = simple_strtol(rate_str, NULL, 10);
+ sinfo = bkn_sinfo_from_unit(unit);
+ if (sinfo == NULL) {
+ gprintk("Warning: unknown unit: %d\n", unit);
+ return count;
+ }
+
+ if ((ptr = strstr(rate_str, "rx_rate=")) != NULL) {
+ ptr += 7;
+ chan = 0;
+ do {
+ ptr++;
+ sinfo->rx[chan].rate_max = simple_strtol(ptr, NULL, 10);
+ } while ((ptr = strchr(ptr, ',')) != NULL && ++chan < sinfo->rx_chans);
+ bkn_rx_rate_config(sinfo);
+ } else if ((ptr = strstr(rate_str, "rx_burst=")) != NULL) {
+ ptr += 8;
+ chan = 0;
+ do {
+ ptr++;
+ sinfo->rx[chan].burst_max = simple_strtol(ptr, NULL, 10);
+ } while ((ptr = strchr(ptr, ',')) != NULL && ++chan < sinfo->rx_chans);
+ bkn_rx_rate_config(sinfo);
+ } else {
+ gprintk("Warning: unknown configuration setting\n");
+ }
+
+ return count;
+}
+
+struct file_operations bkn_proc_rate_file_ops = {
+ owner: THIS_MODULE,
+ open: bkn_proc_rate_open,
+ read: seq_read,
+ llseek: seq_lseek,
+ write: bkn_proc_rate_write,
+ release: single_release,
+};
+
+/*
+ * Driver DMA Proc Entry
+ *
+ * This output can be rather large (> PAGE_SIZE) so we use the
+ * seq_file interface to do the output. Special header records
+ * are indicated by a negative DCB index.
+ */
+typedef struct {
+ int dev_no; /* Current unit */
+ int rx_dma; /* 0: Tx DMA, 1: Rx DMA*/
+ int ch_no; /* DMA channel no. (Rx only) */
+ int idx; /* DCB index */
+} bkn_seq_dma_iter_t;
+
+/* From current record, move forward 'pos' records */
+static int
+bkn_seq_dma_next_pos(bkn_seq_dma_iter_t *iter, loff_t pos)
+{
+ bkn_switch_info_t *sinfo;
+
+ sinfo = bkn_sinfo_from_unit(iter->dev_no);
+ while (pos) {
+ if (iter->rx_dma) {
+ if (++iter->idx >= MAX_RX_DCBS + 1) {
+ iter->idx = -1;
+ if (++iter->ch_no >= sinfo->rx_chans) {
+ iter->rx_dma = 0;
+ iter->ch_no = 0;
+ iter->dev_no++;
+ if ((sinfo = bkn_sinfo_from_unit(iter->dev_no)) == NULL) {
+ return -1;
+ }
+ }
+ }
+ } else {
+ if (++iter->idx >= MAX_TX_DCBS + 1) {
+ iter->idx = -1;
+ iter->rx_dma = 1;
+ }
+ }
+ pos--;
+ }
+ return 0;
+}
+
+/* Initialize private data and move to requested start record */
+static void *
+bkn_seq_dma_start(struct seq_file *s, loff_t *pos)
+{
+ bkn_seq_dma_iter_t *iter;
+
+ iter = kmalloc(sizeof(bkn_seq_dma_iter_t), GFP_KERNEL);
+ if (!iter) {
+ return NULL;
+ }
+ memset(iter, 0, sizeof(*iter));
+ iter->idx = -2;
+ if (bkn_seq_dma_next_pos(iter, *pos) < 0) {
+ kfree(iter);
+ return NULL;
+ }
+ return iter;
+}
+
+/* Move to next record */
+static void *
+bkn_seq_dma_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ bkn_seq_dma_iter_t *iter = (bkn_seq_dma_iter_t *)v;
+ void *rv = iter;
+
+ if (bkn_seq_dma_next_pos(iter, 1) < 0) {
+ return NULL;
+ }
+ (*pos)++;
+ return rv;
+}
+
+/* Release private data */
+static void
+bkn_seq_dma_stop(struct seq_file *s, void *v)
+{
+ if (v) {
+ kfree(v);
+ }
+}
+
+/* Print current record */
+static int
+bkn_seq_dma_show(struct seq_file *s, void *v)
+{
+ bkn_seq_dma_iter_t *iter = (bkn_seq_dma_iter_t *)v;
+ bkn_switch_info_t *sinfo;
+ uint32_t *dcb = NULL;
+ bkn_dcb_chain_t *dcb_chain = NULL;
+ struct list_head *curr, *next;
+ unsigned long flags;
+ int chan, cnt;
+
+ sinfo = bkn_sinfo_from_unit(iter->dev_no);
+ if (sinfo == NULL) {
+ /* Should not happen */
+ return 0;
+ }
+
+ if (iter->rx_dma == 0) {
+ if (iter->idx == -2) {
+ seq_printf(s, "Pending events: 0x%x\n", sinfo->dma_events);
+ } else if (iter->idx == -1) {
+ spin_lock_irqsave(&sinfo->lock, flags);
+ curr = &sinfo->tx.api_dcb_list;
+ dcb_chain = sinfo->tx.api_dcb_chain;
+ while (dcb_chain) {
+ seq_printf(s, " [0x%08lx]--->\n", (unsigned long)dcb_chain->dcb_dma);
+ for (cnt = 0; cnt < dcb_chain->dcb_cnt; cnt++) {
+ dcb = &dcb_chain->dcb_mem[sinfo->dcb_wsize * cnt];
+ if (sinfo->cmic_type == 'x') {
+ seq_printf(s, " DCB %2d: 0x%08x 0x%08x 0x%08x 0x%08x\n", cnt,
+ dcb[0], dcb[1], dcb[2], dcb[sinfo->dcb_wsize-1]);
+ } else {
+ seq_printf(s, " DCB %2d: 0x%08x 0x%08x ... 0x%08x\n", cnt,
+ dcb[0], dcb[1], dcb[sinfo->dcb_wsize-1]);
+ }
+ }
+ next = curr->next;
+ if (next != &sinfo->tx.api_dcb_list) {
+ dcb_chain = list_entry(next, bkn_dcb_chain_t, list);
+ curr = next;
+ } else {
+ dcb_chain = NULL;
+ }
+ }
+ dcb = NULL;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ seq_printf(s,
+ "Tx DCB info (unit %d):\n"
+ " api: %d\n"
+ " dirty: %d\n"
+ " cur: %d\n"
+ " free: %d\n"
+ " pause: %s\n",
+ iter->dev_no,
+ sinfo->tx.api_active,
+ sinfo->tx.dirty,
+ sinfo->tx.cur,
+ sinfo->tx.free,
+ netif_queue_stopped(sinfo->dev) ? "yes" : "no");
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ bkn_desc_info_t *desc = &sinfo->tx.desc[0];
+ uint64_t halt = sinfo->halt_addr[XGS_DMA_TX_CHAN];
+ seq_printf(s,
+ " halt: %d\n",
+ (int)((uint32_t)(halt - desc->dcb_dma) / (sinfo->dcb_wsize * sizeof(uint32_t))));
+ }
+ } else {
+ dcb = sinfo->tx.desc[iter->idx].dcb_mem;
+ if (iter->idx == 0) {
+ seq_printf(s, " [0x%08lx]--->\n", (unsigned long)sinfo->tx.desc[0].dcb_dma);
+ }
+ }
+ } else {
+ if (iter->idx == -1) {
+ chan = iter->ch_no;
+ seq_printf(s,
+ "Rx%d DCB info (unit %d):\n"
+ " api: %d\n"
+ " dirty: %d\n"
+ " cur: %d\n"
+ " free: %d\n"
+ " run: %d\n",
+ chan, iter->dev_no,
+ sinfo->rx[chan].api_active,
+ sinfo->rx[chan].dirty,
+ sinfo->rx[chan].cur,
+ sinfo->rx[chan].free,
+ sinfo->rx[chan].running);
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan) && sinfo->rx[chan].use_rx_skb) {
+ bkn_desc_info_t *desc = &sinfo->rx[chan].desc[0];
+ uint64_t halt = sinfo->halt_addr[XGS_DMA_RX_CHAN + chan];
+ seq_printf(s,
+ " halt: %d\n",
+ (int)((uint32_t)(halt - desc->dcb_dma) / (sinfo->dcb_wsize * sizeof(uint32_t))));
+ }
+ } else if (sinfo->rx[iter->ch_no].use_rx_skb) {
+ dcb = sinfo->rx[iter->ch_no].desc[iter->idx].dcb_mem;
+ if (iter->idx == 0) {
+ seq_printf(s, " [0x%08lx]--->\n", (unsigned long)sinfo->rx[iter->ch_no].desc[0].dcb_dma);
+ }
+ } else if (!sinfo->rx[iter->ch_no].use_rx_skb && iter->idx == 0) {
+ spin_lock_irqsave(&sinfo->lock, flags);
+ curr = &sinfo->rx[iter->ch_no].api_dcb_list;
+ dcb_chain = sinfo->rx[iter->ch_no].api_dcb_chain;
+ while (dcb_chain) {
+ seq_printf(s, " [0x%08lx]--->\n", (unsigned long)dcb_chain->dcb_dma);
+ for (cnt = 0; cnt < dcb_chain->dcb_cnt; cnt++) {
+ dcb = &dcb_chain->dcb_mem[sinfo->dcb_wsize * cnt];
+ if (sinfo->cmic_type == 'x') {
+ seq_printf(s, " DCB %2d: 0x%08x 0x%08x 0x%08x 0x%08x\n", cnt,
+ dcb[0], dcb[1], dcb[2], dcb[sinfo->dcb_wsize-1]);
+ } else {
+ seq_printf(s, " DCB %2d: 0x%08x 0x%08x ... 0x%08x\n", cnt,
+ dcb[0], dcb[1], dcb[sinfo->dcb_wsize-1]);
+ }
+ }
+ next = curr->next;
+ if (next != &sinfo->rx[iter->ch_no].api_dcb_list) {
+ dcb_chain = list_entry(next, bkn_dcb_chain_t, list);
+ curr = next;
+ } else {
+ dcb_chain = NULL;
+ }
+ }
+ dcb = NULL;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ }
+ }
+ if (dcb) {
+ if (sinfo->cmic_type == 'x') {
+ seq_printf(s, " DCB %2d: 0x%08x 0x%08x 0x%08x 0x%08x\n", iter->idx,
+ dcb[0], dcb[1], dcb[2], dcb[sinfo->dcb_wsize-1]);
+ } else {
+ seq_printf(s, " DCB %2d: 0x%08x 0x%08x ... 0x%08x\n", iter->idx,
+ dcb[0], dcb[1], dcb[sinfo->dcb_wsize-1]);
+ }
+ }
+ return 0;
+}
+
+static struct seq_operations bkn_seq_dma_ops = {
+ .start = bkn_seq_dma_start,
+ .next = bkn_seq_dma_next,
+ .stop = bkn_seq_dma_stop,
+ .show = bkn_seq_dma_show
+};
+
+static int
+bkn_seq_dma_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &bkn_seq_dma_ops);
+};
+
+static struct file_operations bkn_seq_dma_file_ops = {
+ .owner = THIS_MODULE,
+ .open = bkn_seq_dma_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release
+};
+
+/*
+ * Device Debug Control Proc Write Entry
+ *
+ * Syntax:
+ * [<unit>:]debug=<mask>
+ *
+ * Where <mask> corresponds to the debug module parameter.
+ *
+ * Examples:
+ * debug=0xffff
+ * 0:debug-0x2000
+ */
+static ssize_t
+bkn_proc_debug_write(struct file *file, const char *buf,
+ size_t count, loff_t *loff)
+{
+ bkn_switch_info_t *sinfo;
+ char debug_str[40];
+ char *ptr;
+ int unit;
+
+ if (count > sizeof(debug_str)) {
+ count = sizeof(debug_str) - 1;
+ debug_str[count] = '\0';
+ }
+ if (copy_from_user(debug_str, buf, count)) {
+ return -EFAULT;
+ }
+
+ unit = simple_strtol(debug_str, NULL, 10);
+ sinfo = bkn_sinfo_from_unit(unit);
+ if (sinfo == NULL) {
+ gprintk("Warning: unknown unit: %d\n", unit);
+ return count;
+ }
+
+ if ((ptr = strstr(debug_str, "debug=")) != NULL) {
+ ptr += 6;
+ debug = simple_strtol(ptr, NULL, 0);
+ } else {
+ gprintk("Warning: unknown configuration setting\n");
+ }
+
+ return count;
+}
+
+/*
+ * Driver Debug Proc Entry
+ */
+static int
+bkn_proc_debug_show(struct seq_file *m, void *v)
+{
+ int unit = 0;
+ struct list_head *list;
+ bkn_switch_info_t *sinfo;
+
+ seq_printf(m, "Configuration:\n");
+ seq_printf(m, " debug: 0x%x\n", debug);
+ seq_printf(m, " mac_addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bkn_dev_mac[0], bkn_dev_mac[1], bkn_dev_mac[2],
+ bkn_dev_mac[3], bkn_dev_mac[4], bkn_dev_mac[5]);
+ seq_printf(m, " rx_buffer_size: %d (0x%x)\n",
+ rx_buffer_size, rx_buffer_size);
+ seq_printf(m, " rcpu_mode: %d\n", rcpu_mode);
+ seq_printf(m, " rcpu_dmac: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bkn_rcpu_dmac[0], bkn_rcpu_dmac[1], bkn_rcpu_dmac[2],
+ bkn_rcpu_dmac[3], bkn_rcpu_dmac[4], bkn_rcpu_dmac[5]);
+ seq_printf(m, " rcpu_smac: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bkn_rcpu_smac[0], bkn_rcpu_smac[1], bkn_rcpu_smac[2],
+ bkn_rcpu_smac[3], bkn_rcpu_smac[4], bkn_rcpu_smac[5]);
+ seq_printf(m, " rcpu_ethertype: 0x%x\n", rcpu_ethertype);
+ seq_printf(m, " rcpu_signature: 0x%x\n", rcpu_signature);
+ seq_printf(m, " rcpu_vlan: %d\n", rcpu_vlan);
+ seq_printf(m, " use_rx_skb: %d\n", use_rx_skb);
+ seq_printf(m, " num_rx_prio: %d\n", num_rx_prio);
+ seq_printf(m, " check_rcpu_sig: %d\n", check_rcpu_signature);
+ seq_printf(m, " default_mtu: %d\n", default_mtu);
+ seq_printf(m, " rx_sync_retry: %d\n", rx_sync_retry);
+ seq_printf(m, " use_napi: %d\n", use_napi);
+ seq_printf(m, " napi_weight: %d\n", napi_weight);
+ seq_printf(m, " basedev_susp: %d\n", basedev_suspend);
+ seq_printf(m, " force_tagged: %d\n", force_tagged);
+ seq_printf(m, " ft_tpid: %d\n", ft_tpid);
+ seq_printf(m, " ft_pri: %d\n", ft_pri);
+ seq_printf(m, " ft_pri: %d\n", ft_cfi);
+ seq_printf(m, " ft_tpid: %d\n", ft_vid);
+ seq_printf(m, "Active IOCTLs:\n");
+ seq_printf(m, " Command: %d\n", ioctl_cmd);
+ seq_printf(m, " Event: %d\n", ioctl_evt);
+
+ list_for_each(list, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)list;
+
+ seq_printf(m, "Device %d:\n", unit);
+ seq_printf(m, " base_addr: 0x%p\n", sinfo->base_addr);
+ seq_printf(m, " dev_no: %d\n", sinfo->dev_no);
+ seq_printf(m, " cmic_type: %c\n", sinfo->cmic_type);
+ seq_printf(m, " dcb_type: %d\n", sinfo->dcb_type);
+ seq_printf(m, " dcb_wsize: %d\n", sinfo->dcb_wsize);
+ seq_printf(m, " pkt_hdr_size: %d\n", sinfo->pkt_hdr_size);
+ seq_printf(m, " rx_chans: %d\n", sinfo->rx_chans);
+ seq_printf(m, " cdma_chans: 0x%x\n", sinfo->cdma_channels);
+ seq_printf(m, " irq_mask: 0x%x\n", sinfo->irq_mask);
+ seq_printf(m, " dma_events: 0x%x\n", sinfo->dma_events);
+ seq_printf(m, " dcb_dma: 0x%p\n", (void *)(sal_paddr_t)sinfo->dcb_dma);
+ seq_printf(m, " dcb_mem_size: 0x%x\n", sinfo->dcb_mem_size);
+ seq_printf(m, " rcpu_sig: 0x%x\n", sinfo->rcpu_sig);
+ seq_printf(m, " napi_poll_mode: %d\n", sinfo->napi_poll_mode);
+ seq_printf(m, " inst_id: 0x%x\n", sinfo->inst_id);
+ seq_printf(m, " evt_queue: %d\n", sinfo->evt_idx);
+
+ unit++;
+ }
+
+ return 0;
+}
+
+static int bkn_proc_debug_open(struct inode * inode, struct file * file)
+{
+ return single_open(file, bkn_proc_debug_show, NULL);
+}
+
+struct file_operations bkn_proc_debug_file_ops = {
+ owner: THIS_MODULE,
+ open: bkn_proc_debug_open,
+ read: seq_read,
+ llseek: seq_lseek,
+ write: bkn_proc_debug_write,
+ release: single_release,
+};
+
+/*
+ * Device Statistics Proc Entry
+ */
+static int
+bkn_proc_stats_show(struct seq_file *m, void *v)
+{
+ int unit = 0;
+ struct list_head *list, *flist;
+ bkn_switch_info_t *sinfo;
+ bkn_filter_t *filter;
+ int chan;
+
+
+ list_for_each(list, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)list;
+
+ seq_printf(m, "Device stats (unit %d):\n", unit);
+ seq_printf(m, " Interrupts %10u\n", sinfo->interrupts);
+ seq_printf(m, " Tx packets %10u\n", sinfo->tx.pkts);
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ seq_printf(m, " Rx%d packets %10u\n", chan, sinfo->rx[chan].pkts);
+ }
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (sinfo->interrupts == 0) {
+ /* Avoid divide-by-zero */
+ seq_printf(m, " Rx%d pkts/intr -\n", chan);
+ } else {
+ seq_printf(m, " Rx%d pkts/intr %8u\n",
+ chan, sinfo->rx[chan].pkts / sinfo->interrupts);
+ }
+ }
+ seq_printf(m, " Timer runs %10u\n", sinfo->timer_runs);
+ seq_printf(m, " NAPI reruns %10u\n", sinfo->napi_not_done);
+
+ list_for_each(flist, &sinfo->rxpf_list) {
+ filter = (bkn_filter_t *)flist;
+
+ seq_printf(m, " Filter %d stats:\n", filter->kf.id);
+ seq_printf(m, " Hits %10lu\n", filter->hits);
+ }
+
+ unit++;
+ }
+ return 0;
+}
+
+static int bkn_proc_stats_open(struct inode * inode, struct file * file)
+{
+ return single_open(file, bkn_proc_stats_show, NULL);
+}
+
+/*
+ * Device Statistics Proc Write Entry
+ *
+ * Syntax:
+ * [<unit>:]clear[=all]
+ *
+ * Where <mask> corresponds to the debug module parameter.
+ *
+ * Examples:
+ * clear
+ * 0:clear=all
+ */
+static ssize_t
+bkn_proc_stats_write(struct file *file, const char *buf,
+ size_t count, loff_t *loff)
+{
+ bkn_switch_info_t *sinfo;
+ struct list_head *flist;
+ bkn_filter_t *filter;
+ char debug_str[40];
+ char *ptr;
+ int unit;
+ int clear_mask;
+ int chan;
+
+ if (count > sizeof(debug_str)) {
+ count = sizeof(debug_str) - 1;
+ debug_str[count] = '\0';
+ }
+ if (copy_from_user(debug_str, buf, count)) {
+ return -EFAULT;
+ }
+
+ unit = simple_strtol(debug_str, NULL, 10);
+ sinfo = bkn_sinfo_from_unit(unit);
+ if (sinfo == NULL) {
+ gprintk("Warning: unknown unit: %d\n", unit);
+ return count;
+ }
+
+ clear_mask = 0;
+ if ((ptr = strstr(debug_str, "clear=")) != NULL) {
+ ptr += 6;
+ if (strncmp(ptr, "all", 3) == 0) {
+ clear_mask = ~0;
+ }
+ } else if ((ptr = strstr(debug_str, "clear")) != NULL) {
+ clear_mask = ~0;
+ } else {
+ gprintk("Warning: unknown configuration setting\n");
+ }
+
+ if (clear_mask) {
+ sinfo->tx.pkts = 0;
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ sinfo->rx[chan].pkts = 0;
+ }
+ sinfo->interrupts = 0;
+ sinfo->timer_runs = 0;
+ sinfo->napi_not_done = 0;
+ list_for_each(flist, &sinfo->rxpf_list) {
+ filter = (bkn_filter_t *)flist;
+ filter->hits = 0;
+ }
+ }
+
+ return count;
+}
+
+struct file_operations bkn_proc_stats_file_ops = {
+ owner: THIS_MODULE,
+ open: bkn_proc_stats_open,
+ read: seq_read,
+ llseek: seq_lseek,
+ write: bkn_proc_stats_write,
+ release: single_release,
+};
+
+/*
+ * Device Debug Statistics Proc Entry
+ */
+static int
+bkn_proc_dstats_show(struct seq_file *m, void *v)
+{
+ int unit = 0;
+ struct list_head *list;
+ bkn_switch_info_t *sinfo;
+ int chan;
+
+ list_for_each(list, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)list;
+
+ seq_printf(m, "Device debug stats (unit %d):\n", unit);
+ seq_printf(m, " Tx drop no skb %10u\n",
+ sinfo->tx.pkts_d_no_skb);
+ seq_printf(m, " Tx drop rcpu encap %10u\n",
+ sinfo->tx.pkts_d_rcpu_encap);
+ seq_printf(m, " Tx drop rcpu sig %10u\n",
+ sinfo->tx.pkts_d_rcpu_sig);
+ seq_printf(m, " Tx drop rcpu meta %10u\n",
+ sinfo->tx.pkts_d_rcpu_meta);
+ seq_printf(m, " Tx drop pad failed %10u\n",
+ sinfo->tx.pkts_d_pad_fail);
+ seq_printf(m, " Tx drop no resource %10u\n",
+ sinfo->tx.pkts_d_dma_resrc);
+ seq_printf(m, " Tx drop callback %10u\n",
+ sinfo->tx.pkts_d_callback);
+ seq_printf(m, " Tx drop no link %10u\n",
+ sinfo->tx.pkts_d_no_link);
+ seq_printf(m, " Tx drop oversized %10u\n",
+ sinfo->tx.pkts_d_over_limit);
+ seq_printf(m, " Tx suspends %10u\n",
+ sinfo->tx.suspends);
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ seq_printf(m, " Rx%d filter to api %10u\n",
+ chan, sinfo->rx[chan].pkts_f_api);
+ seq_printf(m, " Rx%d filter to netif %10u\n",
+ chan, sinfo->rx[chan].pkts_f_netif);
+ seq_printf(m, " Rx%d mirror to api %10u\n",
+ chan, sinfo->rx[chan].pkts_m_api);
+ seq_printf(m, " Rx%d mirror to netif %10u\n",
+ chan, sinfo->rx[chan].pkts_m_netif);
+ seq_printf(m, " Rx%d drop no skb %10u\n",
+ chan, sinfo->rx[chan].pkts_d_no_skb);
+ seq_printf(m, " Rx%d drop no match %10u\n",
+ chan, sinfo->rx[chan].pkts_d_no_match);
+ seq_printf(m, " Rx%d drop unkn netif %10u\n",
+ chan, sinfo->rx[chan].pkts_d_unkn_netif);
+ seq_printf(m, " Rx%d drop unkn dest %10u\n",
+ chan, sinfo->rx[chan].pkts_d_unkn_dest);
+ seq_printf(m, " Rx%d drop callback %10u\n",
+ chan, sinfo->rx[chan].pkts_d_callback);
+ seq_printf(m, " Rx%d drop no link %10u\n",
+ chan, sinfo->rx[chan].pkts_d_no_link);
+ seq_printf(m, " Rx%d sync error %10u\n",
+ chan, sinfo->rx[chan].sync_err);
+ seq_printf(m, " Rx%d sync retry %10u\n",
+ chan, sinfo->rx[chan].sync_retry);
+ seq_printf(m, " Rx%d sync maxloop %10u\n",
+ chan, sinfo->rx[chan].sync_maxloop);
+ seq_printf(m, " Rx%d drop no buffer %10u\n",
+ chan, sinfo->rx[chan].pkts_d_no_api_buf);
+ }
+ unit++;
+ }
+ return 0;
+}
+
+static int bkn_proc_dstats_open(struct inode * inode, struct file * file)
+{
+ return single_open(file, bkn_proc_dstats_show, NULL);
+}
+
+/*
+ * Device Debug Statistics Proc Write Entry
+ *
+ * Syntax:
+ * [<unit>:]clear[=all|tx|rx[<chan>]]
+ *
+ * Where <mask> corresponds to the debug module parameter.
+ *
+ * Examples:
+ * clear
+ * 0:clear=rx1
+ */
+static ssize_t
+bkn_proc_dstats_write(struct file *file, const char *buf,
+ size_t count, loff_t *loff)
+{
+ bkn_switch_info_t *sinfo;
+ char debug_str[40];
+ char *ptr;
+ int unit;
+ int clear_mask;
+ int chan;
+
+ if (count > sizeof(debug_str)) {
+ count = sizeof(debug_str) - 1;
+ debug_str[count] = '\0';
+ }
+ if (copy_from_user(debug_str, buf, count)) {
+ return -EFAULT;
+ }
+
+ unit = simple_strtol(debug_str, NULL, 10);
+ sinfo = bkn_sinfo_from_unit(unit);
+ if (sinfo == NULL) {
+ gprintk("Warning: unknown unit: %d\n", unit);
+ return count;
+ }
+
+ clear_mask = 0;
+ if ((ptr = strstr(debug_str, "clear=")) != NULL) {
+ ptr += 6;
+ if (strncmp(ptr, "all", 3) == 0) {
+ clear_mask = ~0;
+ } else if (strncmp(ptr, "dev", 3) == 0) {
+ clear_mask = 0x20;
+ } else if (strncmp(ptr, "tx", 2) == 0) {
+ clear_mask = 0x10;
+ } else if (strncmp(ptr, "rx0", 3) == 0) {
+ clear_mask = (1 << 0);
+ } else if (strncmp(ptr, "rx1", 3) == 0) {
+ clear_mask = (1 << 1);
+ } else if (strncmp(ptr, "rx", 2) == 0) {
+ clear_mask = 0xf;
+ }
+ } else if ((ptr = strstr(debug_str, "clear")) != NULL) {
+ clear_mask = ~0;
+ } else {
+ gprintk("Warning: unknown configuration setting\n");
+ }
+
+ /* Tx counters */
+ if (clear_mask & 0x10) {
+ sinfo->tx.pkts_d_no_skb = 0;
+ sinfo->tx.pkts_d_rcpu_encap = 0;
+ sinfo->tx.pkts_d_rcpu_sig = 0;
+ sinfo->tx.pkts_d_rcpu_meta = 0;
+ sinfo->tx.pkts_d_pad_fail = 0;
+ sinfo->tx.pkts_d_over_limit = 0;
+ sinfo->tx.pkts_d_dma_resrc = 0;
+ sinfo->tx.suspends = 0;
+ }
+ /* Rx counters */
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (clear_mask & (1 << chan)) {
+ sinfo->rx[chan].pkts_f_api = 0;
+ sinfo->rx[chan].pkts_f_netif = 0;
+ sinfo->rx[chan].pkts_m_api = 0;
+ sinfo->rx[chan].pkts_m_netif = 0;
+ sinfo->rx[chan].pkts_d_no_skb = 0;
+ sinfo->rx[chan].pkts_d_no_match = 0;
+ sinfo->rx[chan].pkts_d_unkn_netif = 0;
+ sinfo->rx[chan].pkts_d_unkn_dest = 0;
+ sinfo->rx[chan].pkts_d_no_api_buf = 0;
+ sinfo->rx[chan].sync_err = 0;
+ sinfo->rx[chan].sync_retry = 0;
+ sinfo->rx[chan].sync_maxloop = 0;
+ }
+ }
+
+ return count;
+}
+
+struct file_operations bkn_proc_dstats_file_ops = {
+ owner: THIS_MODULE,
+ open: bkn_proc_dstats_open,
+ read: seq_read,
+ llseek: seq_lseek,
+ write: bkn_proc_dstats_write,
+ release: single_release,
+};
+
+static int
+bkn_proc_init(void)
+{
+ struct proc_dir_entry *entry;
+
+ PROC_CREATE(entry, "link", 0666, bkn_proc_root, &bkn_proc_link_file_ops);
+ if (entry == NULL) {
+ return -1;
+ }
+ PROC_CREATE(entry, "rate", 0666, bkn_proc_root, &bkn_proc_rate_file_ops);
+ if (entry == NULL) {
+ return -1;
+ }
+ PROC_CREATE(entry, "dma", 0, bkn_proc_root, &bkn_seq_dma_file_ops);
+ if (entry == NULL) {
+ return -1;
+ }
+ PROC_CREATE(entry, "debug", 0666, bkn_proc_root, &bkn_proc_debug_file_ops);
+ if (entry == NULL) {
+ return -1;
+ }
+ PROC_CREATE(entry, "stats", 0666, bkn_proc_root, &bkn_proc_stats_file_ops);
+ if (entry == NULL) {
+ return -1;
+ }
+ PROC_CREATE(entry, "dstats", 0666, bkn_proc_root, &bkn_proc_dstats_file_ops);
+ if (entry == NULL) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+bkn_proc_cleanup(void)
+{
+ remove_proc_entry("link", bkn_proc_root);
+ remove_proc_entry("rate", bkn_proc_root);
+ remove_proc_entry("dma", bkn_proc_root);
+ remove_proc_entry("debug", bkn_proc_root);
+ remove_proc_entry("stats", bkn_proc_root);
+ remove_proc_entry("dstats", bkn_proc_root);
+ return 0;
+}
+
+/*
+ * Generic module functions
+ */
+
+static int
+_pprint(void)
+{
+ pprintf("Broadcom BCM KNET Linux Network Driver\n");
+
+ return 0;
+}
+
+static int
+bkn_knet_dma_info(kcom_msg_dma_info_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ bkn_dcb_chain_t *dcb_chain, *dcb_chain_end;
+ unsigned long flags;
+ int chan;
+ uint64_t dcb_dma;
+ int woffset;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ dcb_chain = kmalloc(sizeof(*dcb_chain), GFP_KERNEL);
+ if (dcb_chain == NULL) {
+ gprintk("Fatal error: No memory for dcb_chain\n");
+ kmsg->hdr.status = KCOM_E_RESOURCE;
+ return sizeof(kcom_msg_hdr_t);
+ }
+ memset(dcb_chain, 0, sizeof(*dcb_chain));
+ dcb_chain->dcb_cnt = kmsg->dma_info.cnt;
+ dcb_chain->dcb_dma = kmsg->dma_info.data.dcb_start;
+ dcb_chain->dcb_mem = kernel_bde->p2l(sinfo->dev_no,
+ (sal_paddr_t)dcb_chain->dcb_dma);
+
+ if (kmsg->dma_info.type == KCOM_DMA_INFO_T_TX_DCB) {
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ /* Hold back packets from kernel */
+ bkn_suspend_tx(sinfo);
+
+ list_add_tail(&dcb_chain->list, &sinfo->tx.api_dcb_list);
+
+ /* Handle for Continuous DMA mode */
+ if (CDMA_CH(sinfo, XGS_DMA_TX_CHAN)) {
+ woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize + 1;
+ if (sinfo->cmic_type == 'x') {
+ woffset += 1;
+ }
+ if ((dcb_chain->dcb_mem[woffset] & ((1 << 18) | (1 << 16))) != 0x50000) {
+ gprintk("Not suitable API DCB chain for Continuous DMA mode\n");
+ list_del(&dcb_chain->list);
+ kfree(dcb_chain);
+ kmsg->hdr.status = KCOM_E_PARAM;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return sizeof(kcom_msg_hdr_t);
+ }
+ dcb_chain_end = sinfo->tx.api_dcb_chain_end;
+ if (dcb_chain_end != NULL) {
+ /* Stitch this chain */
+ woffset = (dcb_chain_end->dcb_cnt - 1) * sinfo->dcb_wsize;
+ dcb_chain_end->dcb_mem[woffset] = dcb_chain->dcb_dma;
+ if (sinfo->cmic_type == 'x') {
+ dcb_chain_end->dcb_mem[woffset + 1] = DMA_TO_BUS_HI(dcb_chain->dcb_dma >> 32);
+ }
+ MEMORY_BARRIER;
+ }
+ sinfo->tx.api_dcb_chain_end = dcb_chain;
+ if (sinfo->tx.api_active) {
+ /* Set new halt location */
+ woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize;
+ dcb_dma = dcb_chain->dcb_dma + woffset * sizeof(uint32_t);
+ /* DMA run to the new halt location */
+ bkn_cdma_goto(sinfo, XGS_DMA_TX_CHAN, dcb_dma);
+ }
+ }
+
+ if (sinfo->tx.free == MAX_TX_DCBS &&
+ !sinfo->tx.api_active &&
+ !sinfo->basedev_suspended) {
+ bkn_api_tx(sinfo);
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ } else if (kmsg->dma_info.type == KCOM_DMA_INFO_T_RX_DCB) {
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ chan = kmsg->dma_info.chan - 1;
+ if ((chan < 0) || (chan > sinfo->rx_chans)) {
+ gprintk("Invalid RX DMA channel specified: %d\n",
+ kmsg->dma_info.chan);
+ kmsg->hdr.status = KCOM_E_PARAM;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ list_add_tail(&dcb_chain->list, &sinfo->rx[chan].api_dcb_list);
+
+ /* Handle for Continuous DMA mode */
+ if (CDMA_CH(sinfo, XGS_DMA_RX_CHAN + chan)) {
+ woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize + 1;
+ if (sinfo->cmic_type == 'x') {
+ woffset += 1;
+ }
+ if ((dcb_chain->dcb_mem[woffset] & ((1 << 18) | (1 << 16))) != 0x50000) {
+ gprintk("Not suitable API DCB chain for Continuous DMA mode\n");
+ list_del(&dcb_chain->list);
+ kfree(dcb_chain);
+ kmsg->hdr.status = KCOM_E_PARAM;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return sizeof(kcom_msg_hdr_t);
+ }
+ dcb_chain_end = sinfo->rx[chan].api_dcb_chain_end;
+ if (dcb_chain_end != NULL) {
+ /* Stitch this chain */
+ woffset = (dcb_chain_end->dcb_cnt - 1) * sinfo->dcb_wsize;
+ dcb_chain_end->dcb_mem[woffset] = dcb_chain->dcb_dma;
+ if (sinfo->cmic_type == 'x') {
+ dcb_chain_end->dcb_mem[woffset + 1] = DMA_TO_BUS_HI(dcb_chain->dcb_dma >> 32);
+ }
+ MEMORY_BARRIER;
+ }
+ sinfo->rx[chan].api_dcb_chain_end = dcb_chain;
+ if (!sinfo->rx[chan].use_rx_skb) {
+ /* Set new halt location */
+ woffset = (dcb_chain->dcb_cnt - 1) * sinfo->dcb_wsize;
+ dcb_dma = dcb_chain->dcb_dma + woffset * sizeof(uint32_t);
+ /* DMA run to the new halt location */
+ bkn_cdma_goto(sinfo, XGS_DMA_RX_CHAN + chan, dcb_dma);
+ }
+ }
+
+ if (sinfo->rx[chan].api_active == 0) {
+ bkn_api_rx_restart(sinfo, chan);
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ } else {
+ DBG_DCB(("Unknown DCB_INFO type (%d).\n", kmsg->dma_info.type));
+ kfree(dcb_chain);
+ kmsg->hdr.status = KCOM_E_PARAM;
+ }
+
+ return sizeof(kcom_msg_hdr_t);
+}
+
+static int
+bkn_create_inst(uint32 inst_id)
+{
+ bkn_switch_info_t *sinfo;
+ bkn_evt_resource_t *evt;
+ unsigned long flags;
+ int i, evt_idx = -1;
+
+ /* multiple instance mode */
+ for (i = 0; i < kernel_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ evt = &_bkn_evt[i];
+ if (evt->inst_id == inst_id) {
+ evt_idx = i;
+ DBG_INST(("%s evt_idx %d inst_id 0x%x\n",__FUNCTION__, i, inst_id));
+ break;
+ }
+ if ((_bkn_multi_inst == 0) || (evt->inst_id == 0)) {
+ _bkn_multi_inst ++;
+ evt_idx = i;
+ init_waitqueue_head(&evt->evt_wq);
+ evt->inst_id = inst_id;
+ DBG_INST(("%s evt_idx %d inst_id 0x%x\n",__FUNCTION__, i, inst_id));
+ break;
+ }
+ }
+
+ if (evt_idx == -1) {
+ DBG_WARN(("Run out the event queue resource !\n"));
+ return -1;
+ }
+ for (i = 0; i < kernel_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ if (inst_id & (1 << i)) {
+ sinfo = bkn_sinfo_from_unit(i);
+ spin_lock_irqsave(&sinfo->lock, flags);
+ sinfo->evt_idx = evt_idx;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ DBG_INST(("%s d(%d) evt_idx %d \n",__FUNCTION__, i, evt_idx));
+ }
+ }
+ return 0;
+}
+
+/*
+ * Device reprobe driven by application to check if new device is probed or
+ * existed device is changed after inserting KNET module.
+ */
+static int
+bkn_knet_dev_reprobe(void)
+{
+ bkn_switch_info_t *sinfo;
+ int i;
+
+ for (i = 0; i < kernel_bde->num_devices(BDE_ALL_DEVICES); i++) {
+ sinfo = bkn_sinfo_from_unit(i);
+ if (sinfo == NULL) {
+ /* New device found after re-probe. */
+ if (bkn_knet_dev_init(i) < 0) {
+ return -1;
+ }
+ } else {
+ /* Existed device reinit after re-probe. */
+ if (bkn_knet_dev_reinit(i) < 0) {
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Assign the inst_id and evt_idx */
+static int
+bkn_knet_dev_inst_set(kcom_msg_reprobe_t *kmsg)
+{
+ bkn_switch_info_t *sinfo;
+ int d = kmsg->hdr.unit;
+ uint32 inst = 0;
+ unsigned long flags;
+ struct list_head *list;
+
+ sinfo = bkn_sinfo_from_unit(d);
+ lkbde_dev_instid_get(d, &inst);
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+ if (sinfo->inst_id != inst) {
+ /* Instance database changed, reinit the inst_id */
+ sinfo->inst_id = 0;
+ sinfo->evt_idx = -1;
+ }
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ if (inst) {
+ if (sinfo->inst_id == 0) {
+ if (bkn_create_inst(inst) != 0) {
+ return -1;
+ }
+ }
+ spin_lock_irqsave(&sinfo->lock, flags);
+ sinfo->inst_id = inst;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ } else {
+ /* legacy mode */
+ list_for_each(list, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)list;
+ spin_lock_irqsave(&sinfo->lock, flags);
+ sinfo->evt_idx = 0;
+ sinfo->inst_id = 0;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ }
+ }
+ return 0;
+}
+
+static int
+bkn_knet_version(kcom_msg_version_t *kmsg, int len)
+{
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+ kmsg->version = KCOM_VERSION;
+ kmsg->netif_max = KCOM_NETIF_MAX;
+ kmsg->filter_max = KCOM_FILTER_MAX;
+
+ return sizeof(kcom_msg_version_t);
+}
+
+static int
+bkn_knet_hw_reset(kcom_msg_hw_reset_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ unsigned long flags;
+ int chan;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ if (kmsg->channels == 0) {
+ /* Clean all if no channels specified */
+ bkn_dma_abort(sinfo);
+ bkn_clean_dcbs(sinfo);
+ skb_queue_purge(&sinfo->tx_ptp_queue);
+ } else {
+ if (kmsg->channels & (1 << XGS_DMA_TX_CHAN)) {
+ bkn_dma_abort_tx(sinfo);
+ bkn_clean_tx_dcbs(sinfo);
+ skb_queue_purge(&sinfo->tx_ptp_queue);
+ }
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (kmsg->channels & (1 << (XGS_DMA_RX_CHAN + chan))) {
+ bkn_dma_abort_rx(sinfo, chan);
+ bkn_clean_rx_dcbs(sinfo, chan);
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return sizeof(kcom_msg_hdr_t);
+}
+
+static int
+bkn_knet_hw_init(kcom_msg_hw_init_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ uint32_t dev_type;
+ unsigned long flags;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ DBG_DCB(("DCB size %d, type %d\n", kmsg->dcb_size, kmsg->dcb_type));
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ sinfo->cmic_type = kmsg->cmic_type;
+ sinfo->dcb_type = kmsg->dcb_type;
+ sinfo->dcb_wsize = BYTES2WORDS(kmsg->dcb_size);
+ sinfo->pkt_hdr_size = kmsg->pkt_hdr_size;
+ sinfo->dma_hi = kmsg->dma_hi;
+ sinfo->rx_chans = sinfo->cmic_type == 'x' ? NUM_CMICX_RX_CHAN : NUM_CMICM_RX_CHAN;
+ if (sinfo->rx_chans > NUM_RX_CHAN) {
+ sinfo->rx_chans = NUM_RX_CHAN;
+ }
+
+ DBG_DUNE(("CMIC:%c DCB:%d WSIZE:%d DMA HI: 0x%08x HDR size: %d\n",
+ sinfo->cmic_type, sinfo->dcb_type, sinfo->dcb_wsize,
+ sinfo->dma_hi, sinfo->pkt_hdr_size));
+
+ /* Config Continuous DMA mode */
+ sinfo->cdma_channels = kmsg->cdma_channels & ~(~0 << (sinfo->rx_chans + 1));
+
+ /* Ensure 32-bit PCI DMA is mapped properly on 64-bit platforms */
+ dev_type = kernel_bde->get_dev_type(sinfo->dev_no);
+ if (dev_type & BDE_PCI_DEV_TYPE && sinfo->cmic_type != 'x') {
+ if (pci_set_dma_mask(sinfo->pdev, 0xffffffff)) {
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ gprintk("No suitable DMA available for SKBs\n");
+ kmsg->hdr.status = KCOM_E_RESOURCE;
+ return sizeof(kcom_msg_hdr_t);
+ }
+ }
+
+ /* First time called we need to allocate DCBs */
+ if (sinfo->dcb_mem == NULL) {
+ if (bkn_alloc_dcbs(sinfo) < 0) {
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ kmsg->hdr.status = KCOM_E_RESOURCE;
+ return sizeof(kcom_msg_hdr_t);
+ }
+ }
+
+ if (device_is_sand(sinfo)) {
+ int idx = 0;
+ /* Information to parser Dune system headers */
+ sinfo->ftmh_lb_key_ext_size = kmsg->ftmh_lb_key_ext_size;
+ sinfo->ftmh_stacking_ext_size = kmsg->ftmh_stacking_ext_size;
+ sinfo->pph_base_size = kmsg->pph_base_size;
+ for (idx = 0; idx < 8; idx++)
+ {
+ sinfo->pph_lif_ext_size[idx] = kmsg->pph_lif_ext_size[idx];
+ }
+ for (idx = 0; idx < 4; idx++)
+ {
+ sinfo->udh_length_type[idx] = kmsg->udh_length_type[idx];
+ }
+ sinfo->udh_size = kmsg->udh_size;
+ sinfo->oamp_punt = kmsg->oamp_punted;
+ sinfo->no_skip_udh_check = kmsg->no_skip_udh_check;
+ sinfo->system_headers_mode = kmsg->system_headers_mode;
+ sinfo->udh_enable = kmsg->udh_enable;
+ }
+
+ /* Ensure that we restart properly */
+ bkn_dma_abort(sinfo);
+ bkn_clean_dcbs(sinfo);
+
+ if (basedev_suspend) {
+ if (!netif_running(sinfo->dev)) {
+ sinfo->basedev_suspended = 1;
+ }
+ }
+
+ /* Ensure all interrupts are disabled, e.g. if warmbooting */
+ dev_irq_mask_set(sinfo, 0);
+
+ /* Register interrupt handler */
+ kernel_bde->interrupt_connect(sinfo->dev_no | LKBDE_ISR2_DEV,
+ bkn_isr, sinfo);
+
+ /* Init DCBs */
+ bkn_init_dcbs(sinfo);
+
+ bkn_dma_init(sinfo);
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return sizeof(kcom_msg_hdr_t);
+}
+
+static int
+bkn_knet_detach(kcom_msg_detach_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ unsigned long flags;
+ bkn_evt_resource_t *evt;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+ if (sinfo->evt_idx != -1) {
+ /* Create dummy event to unblock pending IOCTL */
+ sinfo->dma_events |= KCOM_DMA_INFO_F_TX_DONE;
+ evt = &_bkn_evt[sinfo->evt_idx];
+ evt->evt_wq_put++;
+ wake_up_interruptible(&evt->evt_wq);
+ }
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ /* Ensure that we return a valid unit number */
+ kmsg->hdr.unit = sinfo->dev_no;
+
+ return sizeof(kcom_msg_detach_t);
+}
+
+static int
+bkn_knet_reprobe(kcom_msg_reprobe_t *kmsg, int len)
+{
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ /* Support pci hot plug and multiple instance */
+ if ((bkn_knet_dev_reprobe() < 0) ||
+ (bkn_knet_dev_inst_set(kmsg) < 0)) {
+ kmsg->hdr.status = KCOM_E_RESOURCE;
+ return sizeof(kcom_msg_reprobe_t);
+ }
+
+ return sizeof(kcom_msg_reprobe_t);
+}
+
+static int
+bkn_knet_netif_create(kcom_msg_netif_create_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ struct net_device *dev;
+ struct list_head *list;
+ bkn_priv_t *priv, *lpriv;
+ unsigned long flags;
+ int found, id;
+ uint8_t *ma;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ switch (kmsg->netif.type) {
+ case KCOM_NETIF_T_VLAN:
+ case KCOM_NETIF_T_PORT:
+ case KCOM_NETIF_T_META:
+ break;
+ default:
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+ ma = kmsg->netif.macaddr;
+ if ((ma[0] | ma[1] | ma[2] | ma[3] | ma[4] | ma[5]) == 0) {
+ bkn_dev_mac[5]++;
+ ma = bkn_dev_mac;
+ }
+ if ((dev = bkn_init_ndev(ma, kmsg->netif.name)) == NULL) {
+ kmsg->hdr.status = KCOM_E_RESOURCE;
+ return sizeof(kcom_msg_hdr_t);
+ }
+ priv = netdev_priv(dev);
+ priv->dev = dev;
+ priv->sinfo = sinfo;
+ priv->type = kmsg->netif.type;
+ priv->vlan = kmsg->netif.vlan;
+ /* System headers are prepared at BCM API for Dune headers */
+ if (device_is_sand(sinfo)) {
+ int idx = 0;
+ for (idx = 0; idx < KCOM_NETIF_SYSTEM_HEADERS_SIZE_MAX; idx++)
+ {
+ priv->system_headers[idx] = kmsg->netif.system_headers[idx];
+ }
+ priv->system_headers_size = kmsg->netif.system_headers_size;
+ }
+ if (priv->type == KCOM_NETIF_T_PORT) {
+ priv->port = kmsg->netif.port;
+ priv->phys_port = kmsg->netif.phys_port;
+ priv->qnum = kmsg->netif.qnum;
+ } else {
+ if (device_is_sand(sinfo) && (priv->type == KCOM_NETIF_T_VLAN)) {
+ /* PTCH.SSPA */
+ priv->port = kmsg->netif.port;
+ priv->qnum = kmsg->netif.qnum;
+ } else {
+ priv->port = -1;
+ }
+ }
+ priv->flags = kmsg->netif.flags;
+ priv->cb_user_data = kmsg->netif.cb_user_data;
+
+ /* Force RCPU encapsulation if rcpu_mode */
+ if (rcpu_mode) {
+ priv->flags |= KCOM_NETIF_F_RCPU_ENCAP;
+ DBG_RCPU(("RCPU auto-enabled\n"));
+ }
+
+ /* Prevent (incorrect) compiler warning */
+ lpriv = NULL;
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ /*
+ * We insert network interfaces sorted by ID.
+ * In case an interface is destroyed, we reuse the ID
+ * the next time an interface is created.
+ */
+ found = 0;
+ id = 1;
+ list_for_each(list, &sinfo->ndev_list) {
+ lpriv = (bkn_priv_t *)list;
+ if (id < lpriv->id) {
+ found = 1;
+ break;
+ }
+ id = lpriv->id + 1;
+ }
+ priv->id = id;
+ if (found) {
+ /* Replace previously removed interface */
+ list_add_tail(&priv->list, &lpriv->list);
+ } else {
+ /* No holes - add to end of list */
+ list_add_tail(&priv->list, &sinfo->ndev_list);
+ }
+
+ if (id < sinfo->ndev_max) {
+ DBG_NDEV(("Add netif ID %d to table\n", id));
+ sinfo->ndevs[id] = dev;
+ } else {
+ int ndev_max = sinfo->ndev_max + NDEVS_CHUNK;
+ int size = ndev_max * sizeof(struct net_device *);
+ void *ndevs = kmalloc(size, GFP_ATOMIC);
+ if (ndevs != NULL) {
+ DBG_NDEV(("Reallocate netif table for ID %d\n", id));
+ memset(ndevs, 0, size);
+ if (sinfo->ndevs != NULL) {
+ size = sinfo->ndev_max * sizeof(struct net_device *);
+ memcpy(ndevs, sinfo->ndevs, size);
+ kfree(sinfo->ndevs);
+ }
+ sinfo->ndevs = ndevs;
+ sinfo->ndev_max = ndev_max;
+ sinfo->ndevs[id] = dev;
+ }
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ DBG_VERB(("Assigned ID %d to Ethernet device %s\n",
+ priv->id, dev->name));
+
+ kmsg->netif.id = priv->id;
+ memcpy(kmsg->netif.macaddr, dev->dev_addr, 6);
+ memcpy(kmsg->netif.name, dev->name, KCOM_NETIF_NAME_MAX - 1);
+
+ if (device_is_sand(sinfo)) {
+ int idx = 0;
+ for (idx = 0; idx < priv->system_headers_size; idx++) {
+ DBG_DUNE(("System Header[%d]: 0x%02x\n", idx, priv->system_headers[idx]));
+ }
+ }
+
+ return sizeof(*kmsg);
+}
+
+static int
+bkn_knet_netif_destroy(kcom_msg_netif_destroy_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ struct net_device *dev;
+ bkn_priv_t *priv;
+ struct list_head *list;
+ unsigned long flags;
+ int found;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ found = 0;
+ list_for_each(list, &sinfo->ndev_list) {
+ priv = (bkn_priv_t *)list;
+ if (kmsg->hdr.id == priv->id) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ kmsg->hdr.status = KCOM_E_NOT_FOUND;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ list_del(&priv->list);
+
+ if (priv->id < sinfo->ndev_max) {
+ sinfo->ndevs[priv->id] = NULL;
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ dev = priv->dev;
+ DBG_VERB(("Removing virtual Ethernet device %s (%d).\n",
+ dev->name, priv->id));
+ unregister_netdev(dev);
+ free_netdev(dev);
+
+ return sizeof(kcom_msg_hdr_t);
+}
+
+static int
+bkn_knet_netif_list(kcom_msg_netif_list_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ bkn_priv_t *priv;
+ struct list_head *list;
+ unsigned long flags;
+ int idx;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ idx = 0;
+ list_for_each(list, &sinfo->ndev_list) {
+ if (idx >= KCOM_NETIF_MAX) {
+ DBG_WARN(("Too many network interfaces to list (max %d).\n",
+ KCOM_NETIF_MAX));
+ break;
+ }
+ priv = (bkn_priv_t *)list;
+ kmsg->id[idx] = priv->id;
+ idx++;
+ }
+ kmsg->ifcnt = idx;
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return sizeof(*kmsg) - sizeof(kmsg->id) + (idx * sizeof(kmsg->id[0]));
+}
+
+static int
+bkn_knet_netif_get(kcom_msg_netif_get_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ bkn_priv_t *priv;
+ unsigned long flags;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ priv = bkn_netif_lookup(sinfo, kmsg->hdr.id);
+
+ if (priv == NULL) {
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ kmsg->hdr.status = KCOM_E_NOT_FOUND;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ memcpy(kmsg->netif.macaddr, priv->dev->dev_addr, 6);
+ memcpy(kmsg->netif.name, priv->dev->name, KCOM_NETIF_NAME_MAX - 1);
+ kmsg->netif.vlan = priv->vlan;
+ kmsg->netif.type = priv->type;
+ kmsg->netif.id = priv->id;
+ kmsg->netif.flags = priv->flags;
+ kmsg->netif.cb_user_data = priv->cb_user_data;
+
+ if (priv->port < 0) {
+ kmsg->netif.port = 0;
+ } else {
+ kmsg->netif.port = priv->port;
+ }
+ kmsg->netif.qnum = priv->qnum;
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return sizeof(*kmsg);
+}
+
+static int
+bkn_knet_filter_create(kcom_msg_filter_create_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ struct list_head *list;
+ bkn_filter_t *filter, *lfilter;
+ unsigned long flags;
+ int found, id;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ switch (kmsg->filter.type) {
+ case KCOM_FILTER_T_RX_PKT:
+ break;
+ default:
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ /*
+ * Find available ID
+ */
+ found = 1;
+ id = 0;
+ while (found && ++id < KCOM_FILTER_MAX) {
+ found = 0;
+ list_for_each(list, &sinfo->rxpf_list) {
+ lfilter = (bkn_filter_t *)list;
+ if (id == lfilter->kf.id) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (found) {
+ /* Too many filters */
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ kmsg->hdr.status = KCOM_E_RESOURCE;
+ return sizeof(kcom_msg_hdr_t);
+ }
+ filter = kmalloc(sizeof(*filter), GFP_ATOMIC);
+ if (filter == NULL) {
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+ memset(filter, 0, sizeof(*filter));
+ memcpy(&filter->kf, &kmsg->filter, sizeof(filter->kf));
+ filter->kf.id = id;
+
+ /* Add according to priority */
+ found = 0;
+ list_for_each(list, &sinfo->rxpf_list) {
+ lfilter = (bkn_filter_t *)list;
+ if (filter->kf.priority < lfilter->kf.priority) {
+ list_add_tail(&filter->list, &lfilter->list);
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ list_add_tail(&filter->list, &sinfo->rxpf_list);
+ }
+
+ kmsg->filter.id = filter->kf.id;
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ DBG_VERB(("Created filter ID %d (%s).\n",
+ filter->kf.id, filter->kf.desc));
+ if (device_is_sand(sinfo)) {
+ int idx, wsize;
+ wsize = BYTES2WORDS(filter->kf.oob_data_size + filter->kf.pkt_data_size);
+ DBG_DUNE(("Filter: oob_data_size = %d pkt_data_size=%d wsize %d\n", filter->kf.oob_data_size, filter->kf.pkt_data_size, wsize));
+ for (idx = 0; idx < wsize; idx++)
+ {
+ DBG_DUNE(("OOB[%d]: 0x%08x [0x%08x]\n", idx, filter->kf.data.w[idx], filter->kf.mask.w[idx]));
+ }
+ DBG_DUNE(("DNX system headers parameters:LB_KEY_EXT %d, STK_EXT %d, PPH_BASE %d, LIF_EXT %d %d %d, UDH_ENA %d, %d %d %d %d\n",
+ sinfo->ftmh_lb_key_ext_size, sinfo->ftmh_stacking_ext_size, sinfo->pph_base_size,
+ sinfo->pph_lif_ext_size[1],sinfo->pph_lif_ext_size[2], sinfo->pph_lif_ext_size[3],
+ sinfo->udh_enable, sinfo->udh_length_type[0], sinfo->udh_length_type[1], sinfo->udh_length_type[2], sinfo->udh_length_type[3]));
+ }
+ return len;
+}
+
+static int
+bkn_knet_filter_destroy(kcom_msg_filter_destroy_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ bkn_filter_t *filter;
+ struct list_head *list;
+ unsigned long flags;
+ int found;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ found = 0;
+ list_for_each(list, &sinfo->rxpf_list) {
+ filter = (bkn_filter_t *)list;
+ if (kmsg->hdr.id == filter->kf.id) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ kmsg->hdr.status = KCOM_E_NOT_FOUND;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ list_del(&filter->list);
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ DBG_VERB(("Removing filter ID %d.\n", filter->kf.id));
+ kfree(filter);
+
+ return sizeof(kcom_msg_hdr_t);
+}
+
+static int
+bkn_knet_filter_list(kcom_msg_filter_list_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ bkn_filter_t *filter;
+ struct list_head *list;
+ unsigned long flags;
+ int idx;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ idx = 0;
+ list_for_each(list, &sinfo->rxpf_list) {
+ if (idx >= KCOM_FILTER_MAX) {
+ DBG_WARN(("Too many filters to list (max %d).\n",
+ KCOM_FILTER_MAX));
+ break;
+ }
+ filter = (bkn_filter_t *)list;
+ kmsg->id[idx] = filter->kf.id;
+ idx++;
+ }
+ kmsg->fcnt = idx;
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ return sizeof(*kmsg) - sizeof(kmsg->id) + (idx * sizeof(kmsg->id[0]));
+}
+
+static int
+bkn_knet_filter_get(kcom_msg_filter_get_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ bkn_filter_t *filter;
+ struct list_head *list;
+ unsigned long flags;
+ int found;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ found = 0;
+ list_for_each(list, &sinfo->rxpf_list) {
+ filter = (bkn_filter_t *)list;
+ if (kmsg->hdr.id == filter->kf.id) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ kmsg->hdr.status = KCOM_E_NOT_FOUND;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ memcpy(&kmsg->filter, &filter->kf, sizeof(kmsg->filter));
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return sizeof(*kmsg);
+}
+
+static int
+bkn_knet_dbg_pkt_set(kcom_msg_dbg_pkt_set_t *kmsg, int len)
+{
+ dbg_pkt_enable = kmsg->enable;
+ return sizeof(kcom_msg_dbg_pkt_set_t);
+}
+
+static int
+bkn_knet_dbg_pkt_get(kcom_msg_dbg_pkt_get_t *kmsg, int len)
+{
+ kmsg->value = dbg_pkt_enable;
+ return sizeof(kcom_msg_dbg_pkt_get_t);
+}
+
+static int
+bkn_knet_wb_cleanup(kcom_msg_wb_cleanup_t *kmsg, int len)
+{
+ bkn_switch_info_t *sinfo;
+ bkn_dcb_chain_t *dcb_chain;
+ unsigned long flags;
+ int chan;
+
+ kmsg->hdr.type = KCOM_MSG_TYPE_RSP;
+
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ kmsg->hdr.status = KCOM_E_PARAM;
+ return sizeof(kcom_msg_hdr_t);
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+
+ for (chan = 0; chan < sinfo->rx_chans; chan++) {
+ if (sinfo->rx[chan].api_dcb_chain) {
+ DBG_DCB_RX(("Freeing active Rx%d DCB chain.\n", chan));
+ kfree(sinfo->rx[chan].api_dcb_chain);
+ sinfo->rx[chan].api_dcb_chain = NULL;
+ }
+ while (!list_empty(&sinfo->rx[chan].api_dcb_list)) {
+ dcb_chain = list_entry(sinfo->rx[chan].api_dcb_list.next,
+ bkn_dcb_chain_t, list);
+ list_del(&dcb_chain->list);
+ DBG_DCB_RX(("Freeing Rx%d DCB chain.\n", chan));
+ kfree(dcb_chain);
+ }
+ sinfo->rx[chan].api_dcb_chain_end = NULL;
+ sinfo->rx[chan].api_active = 0;
+ }
+
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ return sizeof(kcom_msg_hdr_t);
+}
+
+static int
+bkn_handle_cmd_req(kcom_msg_t *kmsg, int len)
+{
+ /* Silently drop events and unrecognized message types */
+ if (kmsg->hdr.type != KCOM_MSG_TYPE_CMD) {
+ if (kmsg->hdr.opcode == KCOM_M_STRING) {
+ DBG_VERB(("Debug string: '%s'\n", kmsg->string.val));
+ return 0;
+ }
+ DBG_WARN(("Unsupported message (type=%d, opcode=%d)\n",
+ kmsg->hdr.type, kmsg->hdr.opcode));
+ return 0;
+ }
+
+ switch (kmsg->hdr.opcode) {
+ case KCOM_M_DMA_INFO:
+ DBG_CMD(("KCOM_M_DMA_INFO\n"));
+ /* Packet buffer */
+ len = bkn_knet_dma_info(&kmsg->dma_info, len);
+ break;
+ case KCOM_M_VERSION:
+ DBG_CMD(("KCOM_M_VERSION\n"));
+ /* Return procotol version */
+ len = bkn_knet_version(&kmsg->version, len);
+ break;
+ case KCOM_M_HW_RESET:
+ DBG_CMD(("KCOM_M_HW_RESET\n"));
+ /* Shut down DMA and release buffers */
+ len = bkn_knet_hw_reset(&kmsg->hw_reset, len);
+ break;
+ case KCOM_M_HW_INIT:
+ DBG_CMD(("KCOM_M_HW_INIT\n"));
+ /* Initialize DMA */
+ len = bkn_knet_hw_init(&kmsg->hw_init, len);
+ break;
+ case KCOM_M_DETACH:
+ DBG_CMD(("KCOM_M_DETACH\n"));
+ /* Detach kernel module */
+ len = bkn_knet_detach(&kmsg->detach, len);
+ break;
+ case KCOM_M_REPROBE:
+ DBG_CMD(("KCOM_M_REPROBE\n"));
+ /* Reprobe device */
+ len = bkn_knet_reprobe(&kmsg->reprobe, len);
+ break;
+ case KCOM_M_NETIF_CREATE:
+ DBG_CMD(("KCOM_M_NETIF_CREATE\n"));
+ /* Create network interface */
+ len = bkn_knet_netif_create(&kmsg->netif_create, len);
+ break;
+ case KCOM_M_NETIF_DESTROY:
+ DBG_CMD(("KCOM_M_NETIF_DESTROY\n"));
+ /* Destroy network interface */
+ len = bkn_knet_netif_destroy(&kmsg->netif_destroy, len);
+ break;
+ case KCOM_M_NETIF_LIST:
+ DBG_CMD(("KCOM_M_NETIF_LIST\n"));
+ /* Return list of IDs of installed network interfaces */
+ len = bkn_knet_netif_list(&kmsg->netif_list, len);
+ break;
+ case KCOM_M_NETIF_GET:
+ DBG_CMD(("KCOM_M_NETIF_GET\n"));
+ /* Return network interface info */
+ len = bkn_knet_netif_get(&kmsg->netif_get, len);
+ break;
+ case KCOM_M_FILTER_CREATE:
+ DBG_CMD(("KCOM_M_FILTER_CREATE\n"));
+ /* Create packet filter */
+ len = bkn_knet_filter_create(&kmsg->filter_create, len);
+ break;
+ case KCOM_M_FILTER_DESTROY:
+ DBG_CMD(("KCOM_M_FILTER_DESTROY\n"));
+ /* Destroy packet filter */
+ len = bkn_knet_filter_destroy(&kmsg->filter_destroy, len);
+ break;
+ case KCOM_M_FILTER_LIST:
+ DBG_CMD(("KCOM_M_FILTER_LIST\n"));
+ /* Return list of IDs of installed packet filters */
+ len = bkn_knet_filter_list(&kmsg->filter_list, len);
+ break;
+ case KCOM_M_FILTER_GET:
+ DBG_CMD(("KCOM_M_FILTER_GET\n"));
+ /* Return packet filter info */
+ len = bkn_knet_filter_get(&kmsg->filter_get, len);
+ break;
+ case KCOM_M_DBGPKT_SET:
+ DBG_CMD(("KCOM_M_DBGPKT_SET\n"));
+ /* Set debugging packet function */
+ len = bkn_knet_dbg_pkt_set(&kmsg->dbg_pkt_set, len);
+ break;
+ case KCOM_M_DBGPKT_GET:
+ DBG_CMD(("KCOM_M_DBGPKT_GET\n"));
+ /* Get debugging packet function info */
+ len = bkn_knet_dbg_pkt_get(&kmsg->dbg_pkt_get, len);
+ break;
+ case KCOM_M_WB_CLEANUP:
+ DBG_CMD(("KCOM_M_WB_CLEANUP\n"));
+ /* Clean up for warmbooting */
+ len = bkn_knet_wb_cleanup(&kmsg->wb_cleanup, len);
+ break;
+ case KCOM_M_CLOCK_CMD:
+ /* PHC clock control*/
+ if (knet_hw_tstamp_ioctl_cmd_cb) {
+ bkn_switch_info_t *sinfo;
+ sinfo = bkn_sinfo_from_unit(kmsg->hdr.unit);
+ if (sinfo == NULL) {
+ /* The device is not probed or initialized yet.*/
+ return 0;
+ }
+ DBG_CMD(("KCOM_M_CLOCK_CMD\n"));
+ len = knet_hw_tstamp_ioctl_cmd_cb(&kmsg->clock_cmd, len, sinfo->dcb_type);
+ } else {
+ DBG_WARN(("Unsupported command (type=%d, opcode=%d)\n",
+ kmsg->hdr.type, kmsg->hdr.opcode));
+ kmsg->hdr.opcode = 0;
+ len = sizeof(kcom_msg_hdr_t);
+ }
+ break;
+ default:
+ DBG_WARN(("Unsupported command (type=%d, opcode=%d)\n",
+ kmsg->hdr.type, kmsg->hdr.opcode));
+ kmsg->hdr.opcode = 0;
+ len = sizeof(kcom_msg_hdr_t);
+ break;
+ }
+ return len;
+}
+
+static int
+bkn_get_next_dma_event(kcom_msg_dma_info_t *kmsg)
+{
+ static int last_dev_no = 0;
+ bkn_switch_info_t *sinfo;
+ unsigned long flags;
+ int dev_no, dev_evt;
+ bkn_evt_resource_t *evt;
+
+ dev_evt = kmsg->hdr.unit;
+ sinfo = bkn_sinfo_from_unit(dev_evt);
+ if (sinfo == NULL) {
+ /* The device is not probed or initialized yet.*/
+ return 0;
+ }
+ if (sinfo->evt_idx == -1) {
+ /* Event queue is not ready yet */
+ return 0;
+ }
+
+ DBG_INST(("%s dev %d evt_idx %d\n",__FUNCTION__, dev_evt, sinfo->evt_idx));
+ dev_no = last_dev_no;
+ while (1) {
+ dev_no++;
+ sinfo = bkn_sinfo_from_unit(dev_no);
+ if (sinfo == NULL) {
+ dev_no = 0;
+ sinfo = bkn_sinfo_from_unit(dev_no);
+ }
+
+ if (sinfo && (sinfo->inst_id != 0) &&
+ ((sinfo->inst_id & (1 << dev_evt)) == 0)) {
+ DBG_INST((" %s skip dev(%d)\n",__FUNCTION__,dev_no));
+ continue;
+ }
+
+ if (sinfo->evt_idx == -1) {
+ /* Event queue is not ready yet */
+ continue;
+ }
+ if (sinfo && sinfo->dma_events) {
+ DBG_EVT(("Next DMA events (0x%08x)\n", sinfo->dma_events));
+ kmsg->hdr.unit = sinfo->dev_no;
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+ kmsg->dma_info.flags = sinfo->dma_events;
+ sinfo->dma_events = 0;
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ last_dev_no = dev_no;
+ break;
+ }
+
+ if ((dev_no == last_dev_no) ||
+ (_bkn_multi_inst && (dev_no == dev_evt))) {
+ evt = &_bkn_evt[sinfo->evt_idx];
+ DBG_INST(("dev_no %d dev_evt %d wait queue index %d\n",
+ dev_no, dev_evt, sinfo->evt_idx));
+ wait_event_interruptible(evt->evt_wq,
+ evt->evt_wq_get != evt->evt_wq_put);
+ DBG_VERB(("Event thread wakeup\n"));
+
+ /* Thread interrupted */
+ if (signal_pending(current)) {
+ return 0;
+ }
+
+ evt->evt_wq_get = evt->evt_wq_put;
+ }
+ }
+ return sizeof(*kmsg);
+}
+
+static int
+_cleanup(void)
+{
+ struct list_head *list;
+ struct net_device *dev;
+ bkn_filter_t *filter;
+ bkn_priv_t *priv;
+ bkn_switch_info_t *sinfo;
+ unsigned long flags;
+
+ /* Inidicate that we are shutting down */
+ module_initialized = 0;
+
+ bkn_proc_cleanup();
+ remove_proc_entry("bcm/knet", NULL);
+ remove_proc_entry("bcm", NULL);
+
+ list_for_each(list, &_sinfo_list) {
+ sinfo = (bkn_switch_info_t *)list;
+
+ del_timer_sync(&sinfo->timer);
+ del_timer_sync(&sinfo->rxtick);
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+ bkn_dma_abort(sinfo);
+ dev_irq_mask_set(sinfo, 0);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ DBG_IRQ(("Unregister ISR.\n"));
+ kernel_bde->interrupt_disconnect(sinfo->dev_no | LKBDE_ISR2_DEV);
+
+ if (use_napi) {
+ while (sinfo->napi_poll_mode) {
+ bkn_sleep(1);
+ }
+ }
+
+ spin_lock_irqsave(&sinfo->lock, flags);
+ bkn_clean_dcbs(sinfo);
+ skb_queue_purge(&sinfo->tx_ptp_queue);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+ }
+
+ /* Destroy all switch devices */
+ while (!list_empty(&_sinfo_list)) {
+ sinfo = list_entry(_sinfo_list.next, bkn_switch_info_t, list);
+
+ /* Destroy all associated Rx packet filters */
+ while (!list_empty(&sinfo->rxpf_list)) {
+ filter = list_entry(sinfo->rxpf_list.next, bkn_filter_t, list);
+ list_del(&filter->list);
+ DBG_VERB(("Removing filter ID %d.\n", filter->kf.id));
+ kfree(filter);
+ }
+
+ /* Destroy all associated virtual net devices */
+ while (!list_empty(&sinfo->ndev_list)) {
+ priv = list_entry(sinfo->ndev_list.next, bkn_priv_t, list);
+ list_del(&priv->list);
+ dev = priv->dev;
+ DBG_VERB(("Removing virtual Ethernet device %s.\n", dev->name));
+ unregister_netdev(dev);
+ free_netdev(dev);
+ }
+ if (sinfo->ndevs != NULL) {
+ kfree(sinfo->ndevs);
+ }
+
+ /* Destroy base net device */
+ if (sinfo->dev) {
+ DBG_VERB(("Removing Ethernet device %s.\n", sinfo->dev->name));
+ unregister_netdev(sinfo->dev);
+ free_netdev(sinfo->dev);
+ }
+
+ DBG_VERB(("Removing switch device.\n"));
+ bkn_destroy_sinfo(sinfo);
+ }
+
+ return 0;
+}
+
+static int
+bkn_knet_dev_reinit(int d)
+{
+ bkn_switch_info_t *sinfo;
+ uint32 dev_state;
+ unsigned long flags;
+
+ if (lkbde_dev_state_get(d, &dev_state) < 0) {
+ return -1;
+ }
+ DBG_VERB(("%s dev %d dev_state %d\n",__FUNCTION__, d, dev_state));
+ if (dev_state == BDE_DEV_STATE_CHANGED) {
+ sinfo = bkn_sinfo_from_unit(d);
+ spin_lock_irqsave(&sinfo->lock, flags);
+ sinfo->base_addr = lkbde_get_dev_virt(d);
+ sinfo->dma_dev = lkbde_get_dma_dev(d);
+ sinfo->pdev = lkbde_get_hw_dev(d);
+ spin_unlock_irqrestore(&sinfo->lock, flags);
+
+ dev_state = 0;
+ lkbde_dev_state_set(d, dev_state);
+ }
+ return 0;
+}
+
+static int
+bkn_knet_dev_init(int d)
+{
+ uint32_t dev_type;
+ struct net_device *dev;
+ bkn_switch_info_t *sinfo;
+ bkn_priv_t *priv;
+ char *bdev_name;
+ const ibde_dev_t *bde_dev;
+
+ DBG_VERB(("%s dev %d\n",__FUNCTION__, d));
+ /* Base network device name */
+ bdev_name = "bcm%d";
+ if (base_dev_name) {
+ if (strlen(base_dev_name) < IFNAMSIZ) {
+ bdev_name = base_dev_name;
+ } else {
+ DBG_WARN(("Base device name too long\n"));
+ }
+ }
+
+ dev_type = kernel_bde->get_dev_type(d);
+ DBG_VERB(("Found device type 0x%x\n", dev_type));
+ if ((dev_type & BDE_SWITCH_DEV_TYPE) == 0) {
+ DBG_WARN(("Not switch device - skipping\n"));
+ return 0;
+ }
+ switch (dev_type & BDE_DEV_BUS_TYPE_MASK) {
+ case BDE_PCI_DEV_TYPE:
+ case BDE_ICS_DEV_TYPE:
+ case BDE_AXI_DEV_TYPE:
+ break;
+ default:
+ DBG_WARN(("Not PCI/ICS/AXI device - skipping\n"));
+ return 0;
+ }
+
+ if ((sinfo = bkn_create_sinfo(d)) == NULL) {
+ _cleanup();
+ return -ENOMEM;
+ }
+
+ /* Initialize the cpu_no.*/
+ if (dev_type & BDE_AXI_DEV_TYPE) {
+ /* AXI device type implies the activated iProc iHost */
+ sinfo->cpu_no = 1;
+ }
+ /* Initialize default RCPU signature */
+ if ((bde_dev = kernel_bde->get_dev(d)) != NULL) {
+ sinfo->rcpu_sig = bde_dev->device & ~0xf;
+ }
+ /* Check for override */
+ if (rcpu_signature) {
+ sinfo->rcpu_sig = rcpu_signature;
+ }
+
+ /* Create base virtual net device */
+ bkn_dev_mac[5]++;
+ if ((dev = bkn_init_ndev(bkn_dev_mac, bdev_name)) == NULL) {
+ _cleanup();
+ return -ENOMEM;
+ } else {
+ sinfo->dev = dev;
+ priv = netdev_priv(dev);
+ priv->dev = dev;
+ priv->sinfo = sinfo;
+ priv->vlan = 1;
+ priv->port = -1;
+ priv->id = -1;
+ }
+
+ if (use_napi) {
+ netif_napi_add(dev, &sinfo->napi, bkn_poll, napi_weight);
+ }
+ return 0;
+}
+
+static int
+_init(void)
+{
+ int idx;
+ int num_dev;
+ int rv;
+ bkn_evt_resource_t *evt;
+
+ /* Connect to the kernel bde */
+ if ((linux_bde_create(NULL, &kernel_bde) < 0) || kernel_bde == NULL) {
+ return -ENODEV;
+ }
+
+ /* Randomize Lower 3 bytes of the MAC address (TESTING ONLY) */
+ get_random_bytes(&bkn_dev_mac[3], 3);
+
+ /* Check for user-supplied MAC address (recommended) */
+ if (mac_addr != NULL && strlen(mac_addr) == 17) {
+ for (idx = 0; idx < 6; idx++) {
+ bkn_dev_mac[idx] = simple_strtoul(&mac_addr[idx*3], NULL, 16);
+ }
+ /* Do not allow multicast address */
+ bkn_dev_mac[0] &= ~0x01;
+ }
+
+ /* Optional RCPU MAC addresses */
+ if (rcpu_dmac != NULL && strlen(rcpu_dmac) == 17) {
+ for (idx = 0; idx < 6; idx++) {
+ bkn_rcpu_dmac[idx] = simple_strtoul(&rcpu_dmac[idx*3], NULL, 16);
+ }
+ }
+ if (rcpu_smac != NULL && strlen(rcpu_smac) == 17) {
+ for (idx = 0; idx < 6; idx++) {
+ bkn_rcpu_smac[idx] = simple_strtoul(&rcpu_smac[idx*3], NULL, 16);
+ }
+ }
+
+ /* NAPI implies that base device must be up before we can pass traffic */
+ if (use_napi) {
+ basedev_suspend = 1;
+ }
+
+ num_dev = kernel_bde->num_devices(BDE_ALL_DEVICES);
+ for (idx = 0; idx < num_dev; idx++) {
+ rv = bkn_knet_dev_init(idx);
+ if (rv) {
+ return rv;
+ }
+ }
+
+ /* Initialize proc files */
+ proc_mkdir("bcm", NULL);
+ bkn_proc_root = proc_mkdir("bcm/knet", NULL);
+
+ bkn_proc_init();
+
+ /* Initialize event queue */
+ for (idx = 0; idx < LINUX_BDE_MAX_DEVICES; idx++) {
+ memset(&_bkn_evt[idx], 0, sizeof(bkn_evt_resource_t));
+ }
+ evt = &_bkn_evt[0];
+ init_waitqueue_head(&evt->evt_wq);
+
+ module_initialized = 1;
+
+ return 0;
+}
+
+static int
+_ioctl(unsigned int cmd, unsigned long arg)
+{
+ bkn_ioctl_t io;
+ kcom_msg_t kmsg;
+
+ if (!module_initialized) {
+ return -EFAULT;
+ }
+
+ if (copy_from_user(&io, (void*)arg, sizeof(io))) {
+ return -EFAULT;
+ }
+
+ if (io.len > sizeof(kmsg)) {
+ return -EINVAL;
+ }
+
+ io.rc = 0;
+
+ switch(cmd) {
+ case 0:
+ if (io.len > 0) {
+ if (copy_from_user(&kmsg, (void *)(unsigned long)io.buf, io.len)) {
+ return -EFAULT;
+ }
+ ioctl_cmd++;
+ io.len = bkn_handle_cmd_req(&kmsg, io.len);
+ ioctl_cmd--;
+ } else {
+ memset(&kmsg, 0, sizeof(kcom_msg_t));
+ /*
+ * Retrive the kmsg.hdr.unit from user space. The dma event queue
+ * selection is based the instance derived from unit.
+ */
+ if (copy_from_user(&kmsg, (void *)(unsigned long)io.buf, sizeof(kmsg))) {
+ return -EFAULT;
+ }
+ kmsg.hdr.type = KCOM_MSG_TYPE_EVT;
+ kmsg.hdr.opcode = KCOM_M_DMA_INFO;
+ ioctl_evt++;
+ io.len = bkn_get_next_dma_event((kcom_msg_dma_info_t *)&kmsg);
+ ioctl_evt--;
+ }
+ if (io.len > 0) {
+ if (copy_to_user((void *)(unsigned long)io.buf, &kmsg, io.len)) {
+ return -EFAULT;
+ }
+ }
+ break;
+ default:
+ gprintk("Invalid IOCTL");
+ io.rc = -1;
+ break;
+ }
+
+ if (copy_to_user((void*)arg, &io, sizeof(io))) {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static gmodule_t _gmodule = {
+ name: MODULE_NAME,
+ major: MODULE_MAJOR,
+ init: _init,
+ cleanup: _cleanup,
+ pprint: _pprint,
+ ioctl: _ioctl,
+ open: NULL,
+ close: NULL,
+};
+
+gmodule_t *
+gmodule_get(void)
+{
+ EXPORT_NO_SYMBOLS;
+ return &_gmodule;
+}
+
+/*
+ * Call-back interfaces for other Linux kernel drivers.
+ *
+ * The Rx call-back allows an external module to modify SKB contents
+ * before it is handed off to the Linux network stack.
+ *
+ * The Tx call-back allows an external module to modify SKB contents
+ * before it is injected inot the switch.
+ *
+ * The HW timestamp callbacks invoke an external module to enable, disable
+ * HW timestamp on a specific port which is indicated while the netif is
+ * created through KNET API. KNET can also get device-specific SOBMH and
+ * timestamp for a Tx PTP packet through these callbacks.
+ */
+
+int
+bkn_rx_skb_cb_register(knet_skb_cb_f rx_cb)
+{
+ if (knet_rx_cb != NULL) {
+ return -1;
+ }
+ knet_rx_cb = rx_cb;
+ return 0;
+}
+
+int
+bkn_rx_skb_cb_unregister(knet_skb_cb_f rx_cb)
+{
+ if (rx_cb != NULL && knet_rx_cb != rx_cb) {
+ return -1;
+ }
+ knet_rx_cb = NULL;
+ return 0;
+}
+
+int
+bkn_tx_skb_cb_register(knet_skb_cb_f tx_cb)
+{
+ if (knet_tx_cb != NULL) {
+ return -1;
+ }
+ knet_tx_cb = tx_cb;
+ return 0;
+}
+
+int
+bkn_tx_skb_cb_unregister(knet_skb_cb_f tx_cb)
+{
+ if (tx_cb != NULL && knet_tx_cb != tx_cb) {
+ return -1;
+ }
+ knet_tx_cb = NULL;
+ return 0;
+}
+
+int
+bkn_filter_cb_register(knet_filter_cb_f filter_cb)
+{
+ if (knet_filter_cb != NULL) {
+ return -1;
+ }
+ knet_filter_cb = filter_cb;
+ return 0;
+}
+
+int
+bkn_filter_cb_unregister(knet_filter_cb_f filter_cb)
+{
+ if (filter_cb != NULL && knet_filter_cb != filter_cb) {
+ return -1;
+ }
+ knet_filter_cb = NULL;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_enable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb)
+{
+ if (knet_hw_tstamp_enable_cb != NULL) {
+ return -1;
+ }
+ knet_hw_tstamp_enable_cb = hw_tstamp_enable_cb;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_enable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb)
+{
+ if (hw_tstamp_enable_cb == NULL ||
+ knet_hw_tstamp_enable_cb != hw_tstamp_enable_cb) {
+ return -1;
+ }
+ knet_hw_tstamp_enable_cb = NULL;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_disable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb)
+{
+ if (knet_hw_tstamp_disable_cb != NULL) {
+ return -1;
+ }
+ knet_hw_tstamp_disable_cb = hw_tstamp_disable_cb;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_disable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb)
+{
+ if (hw_tstamp_disable_cb == NULL ||
+ knet_hw_tstamp_disable_cb != hw_tstamp_disable_cb) {
+ return -1;
+ }
+ knet_hw_tstamp_disable_cb = NULL;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_tx_time_get_cb_register(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb)
+{
+ if (knet_hw_tstamp_tx_time_get_cb != NULL) {
+ return -1;
+ }
+ knet_hw_tstamp_tx_time_get_cb = hw_tstamp_tx_time_get_cb;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_tx_time_get_cb_unregister(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb)
+{
+ if (hw_tstamp_tx_time_get_cb == NULL ||
+ knet_hw_tstamp_tx_time_get_cb != hw_tstamp_tx_time_get_cb) {
+ return -1;
+ }
+ knet_hw_tstamp_tx_time_get_cb = NULL;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_tx_meta_get_cb_register(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb)
+{
+ if (knet_hw_tstamp_tx_meta_get_cb != NULL) {
+ return -1;
+ }
+ knet_hw_tstamp_tx_meta_get_cb = hw_tstamp_tx_meta_get_cb;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_tx_meta_get_cb_unregister(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb)
+{
+ if (hw_tstamp_tx_meta_get_cb == NULL ||
+ knet_hw_tstamp_tx_meta_get_cb != hw_tstamp_tx_meta_get_cb) {
+ return -1;
+ }
+ knet_hw_tstamp_tx_meta_get_cb = NULL;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_ptp_clock_index_cb_register(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb)
+{
+ if (knet_hw_tstamp_ptp_clock_index_cb != NULL) {
+ return -1;
+ }
+ knet_hw_tstamp_ptp_clock_index_cb = hw_tstamp_ptp_clock_index_cb;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_ptp_clock_index_cb_unregister(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb)
+{
+ if (hw_tstamp_ptp_clock_index_cb == NULL ||
+ knet_hw_tstamp_ptp_clock_index_cb != hw_tstamp_ptp_clock_index_cb) {
+ return -1;
+ }
+ knet_hw_tstamp_ptp_clock_index_cb = NULL;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_rx_time_upscale_cb_register(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb)
+{
+ if (knet_hw_tstamp_rx_time_upscale_cb != NULL) {
+ return -1;
+ }
+ knet_hw_tstamp_rx_time_upscale_cb = hw_tstamp_rx_time_upscale_cb;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_rx_time_upscale_cb_unregister(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb)
+{
+ if (hw_tstamp_rx_time_upscale_cb == NULL ||
+ knet_hw_tstamp_rx_time_upscale_cb != hw_tstamp_rx_time_upscale_cb) {
+ return -1;
+ }
+ knet_hw_tstamp_rx_time_upscale_cb = NULL;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_ioctl_cmd_cb_register(knet_hw_tstamp_ioctl_cmd_cb_f hw_tstamp_ioctl_cmd_cb)
+{
+ if (knet_hw_tstamp_ioctl_cmd_cb != NULL) {
+ return -1;
+ }
+ knet_hw_tstamp_ioctl_cmd_cb = hw_tstamp_ioctl_cmd_cb;
+ return 0;
+}
+
+int
+bkn_hw_tstamp_ioctl_cmd_cb_unregister(knet_hw_tstamp_ioctl_cmd_cb_f hw_tstamp_ioctl_cmd_cb)
+{
+ if (knet_hw_tstamp_ioctl_cmd_cb == NULL ||
+ knet_hw_tstamp_ioctl_cmd_cb != hw_tstamp_ioctl_cmd_cb) {
+ return -1;
+ }
+ knet_hw_tstamp_ioctl_cmd_cb = NULL;
+ return 0;
+}
+
+LKM_EXPORT_SYM(bkn_rx_skb_cb_register);
+LKM_EXPORT_SYM(bkn_rx_skb_cb_unregister);
+LKM_EXPORT_SYM(bkn_tx_skb_cb_register);
+LKM_EXPORT_SYM(bkn_tx_skb_cb_unregister);
+LKM_EXPORT_SYM(bkn_filter_cb_register);
+LKM_EXPORT_SYM(bkn_filter_cb_unregister);
+LKM_EXPORT_SYM(bkn_hw_tstamp_enable_cb_register);
+LKM_EXPORT_SYM(bkn_hw_tstamp_enable_cb_unregister);
+LKM_EXPORT_SYM(bkn_hw_tstamp_disable_cb_register);
+LKM_EXPORT_SYM(bkn_hw_tstamp_disable_cb_unregister);
+LKM_EXPORT_SYM(bkn_hw_tstamp_tx_time_get_cb_register);
+LKM_EXPORT_SYM(bkn_hw_tstamp_tx_time_get_cb_unregister);
+LKM_EXPORT_SYM(bkn_hw_tstamp_tx_meta_get_cb_register);
+LKM_EXPORT_SYM(bkn_hw_tstamp_tx_meta_get_cb_unregister);
+LKM_EXPORT_SYM(bkn_hw_tstamp_ptp_clock_index_cb_register);
+LKM_EXPORT_SYM(bkn_hw_tstamp_ptp_clock_index_cb_unregister);
+LKM_EXPORT_SYM(bkn_hw_tstamp_rx_time_upscale_cb_register);
+LKM_EXPORT_SYM(bkn_hw_tstamp_rx_time_upscale_cb_unregister);
+LKM_EXPORT_SYM(bkn_hw_tstamp_ioctl_cmd_cb_register);
+LKM_EXPORT_SYM(bkn_hw_tstamp_ioctl_cmd_cb_unregister);
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/include/bcm-knet.h b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/include/bcm-knet.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: bcm-knet.h,v 1.4 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+#ifndef __LINUX_BCM_KNET_H__
+#define __LINUX_BCM_KNET_H__
+
+#ifndef __KERNEL__
+#include <stdint.h>
+#endif
+
+typedef struct {
+ int rc;
+ int len;
+ int bufsz;
+ int reserved;
+ uint64_t buf;
+} bkn_ioctl_t;
+
+#ifdef __KERNEL__
+
+/*
+ * Call-back interfaces for other Linux kernel drivers.
+ */
+#include <linux/skbuff.h>
+
+typedef struct {
+ uint32 netif_user_data;
+ uint32 filter_user_data;
+ uint16 dcb_type;
+ int port;
+ uint64_t ts;
+ uint32 hwts;
+} knet_skb_cb_t;
+
+#define KNET_SKB_CB(_skb) ((knet_skb_cb_t *)_skb->cb)
+
+typedef struct sk_buff *
+(*knet_skb_cb_f)(struct sk_buff *skb, int dev_no, void *meta);
+
+typedef int
+(*knet_filter_cb_f)(uint8_t *pkt, int size, int dev_no, void *meta,
+ int chan, kcom_filter_t *filter);
+
+typedef int
+(*knet_hw_tstamp_enable_cb_f)(int dev_no, int phys_port, int tx_type);
+
+typedef int
+(*knet_hw_tstamp_tx_time_get_cb_f)(int dev_no, int phys_port, uint8_t *pkt, uint64_t *ts);
+
+typedef int
+(*knet_hw_tstamp_tx_meta_get_cb_f)(int dev_no, int hwts, int hdrlen, struct sk_buff *skb, uint64_t *ts, uint32_t **md);
+
+typedef int
+(*knet_hw_tstamp_ptp_clock_index_cb_f)(int dev_no);
+
+typedef int
+(*knet_hw_tstamp_rx_time_upscale_cb_f)(int dev_no, int phys_port, struct sk_buff *skb, uint32_t *meta, uint64_t *ts);
+
+typedef int
+(*knet_hw_tstamp_ioctl_cmd_cb_f)(kcom_msg_clock_cmd_t *kmsg, int len, int dcb_type);
+
+extern int
+bkn_rx_skb_cb_register(knet_skb_cb_f rx_cb);
+
+extern int
+bkn_rx_skb_cb_unregister(knet_skb_cb_f rx_cb);
+
+extern int
+bkn_tx_skb_cb_register(knet_skb_cb_f tx_cb);
+
+extern int
+bkn_tx_skb_cb_unregister(knet_skb_cb_f tx_cb);
+
+extern int
+bkn_filter_cb_register(knet_filter_cb_f filter_cb);
+
+extern int
+bkn_filter_cb_unregister(knet_filter_cb_f filter_cb);
+
+extern int
+bkn_hw_tstamp_enable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb);
+
+extern int
+bkn_hw_tstamp_enable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_enable_cb);
+
+extern int
+bkn_hw_tstamp_disable_cb_register(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb);
+
+extern int
+bkn_hw_tstamp_disable_cb_unregister(knet_hw_tstamp_enable_cb_f hw_tstamp_disable_cb);
+
+extern int
+bkn_hw_tstamp_tx_time_get_cb_register(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb);
+
+extern int
+bkn_hw_tstamp_tx_time_get_cb_unregister(knet_hw_tstamp_tx_time_get_cb_f hw_tstamp_tx_time_get_cb);
+
+extern int
+bkn_hw_tstamp_tx_meta_get_cb_register(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb);
+
+extern int
+bkn_hw_tstamp_tx_meta_get_cb_unregister(knet_hw_tstamp_tx_meta_get_cb_f hw_tstamp_tx_meta_get_cb);
+
+extern int
+bkn_hw_tstamp_ptp_clock_index_cb_register(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb);
+
+extern int
+bkn_hw_tstamp_ptp_clock_index_cb_unregister(knet_hw_tstamp_ptp_clock_index_cb_f hw_tstamp_ptp_clock_index_cb);
+
+extern int
+bkn_hw_tstamp_rx_time_upscale_cb_register(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb);
+
+extern int
+bkn_hw_tstamp_rx_time_upscale_cb_unregister(knet_hw_tstamp_rx_time_upscale_cb_f hw_tstamp_rx_time_upscale_cb);
+
+extern int
+bkn_hw_tstamp_ioctl_cmd_cb_register(knet_hw_tstamp_ioctl_cmd_cb_f hw_tstamp_ioctl_cmd_cb);
+
+extern int
+bkn_hw_tstamp_ioctl_cmd_cb_unregister(knet_hw_tstamp_ioctl_cmd_cb_f hw_tstamp_ioctl_cmd_cb);
+
+#endif
+
+#endif /* __LINUX_BCM_KNET_H__ */
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/include/gmodule.h b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/include/gmodule.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: gmodule.h,v 1.9 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#ifndef __COMMON_LINUX_KRN_GMODULE_H__
+#define __COMMON_LINUX_KRN_GMODULE_H__
+
+#include <lkm.h>
+
+typedef struct gmodule_s {
+
+ const char* name;
+ int major;
+ int minor;
+
+ int (*init)(void);
+ int (*cleanup)(void);
+
+ int (*pprint)(void);
+
+ int (*open)(void);
+ int (*ioctl)(unsigned int cmd, unsigned long arg);
+ int (*close)(void);
+ int (*mmap) (struct file *filp, struct vm_area_struct *vma);
+
+} gmodule_t;
+
+
+/* The framework will ask for your module definition */
+extern gmodule_t* gmodule_get(void);
+
+
+/* Proc Filesystem information */
+extern int pprintf(const char* fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+extern int gmodule_vpprintf(char** page, const char* fmt, va_list args)
+ __attribute__ ((format (printf, 2, 0)));
+extern int gmodule_pprintf(char** page, const char* fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+
+extern int gprintk(const char* fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+extern int gdbg(const char* fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+#define GDBG gdbg
+
+#endif /* __COMMON_LINUX_KRN_GMODULE_H__ */
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/include/lkm.h b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/include/lkm.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: lkm.h,v 1.22 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#ifndef __COMMON_LINUX_KRN_LKM_H__
+#define __COMMON_LINUX_KRN_LKM_H__
+
+#ifndef __KERNEL__
+# define __KERNEL__
+#endif
+#ifndef MODULE
+# define MODULE
+#endif
+
+#include <linux/init.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include <linux/config.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+/* The version kconfig.h became available in. */
+#include <linux/kconfig.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+#if defined(INCLUDE_KNET) && LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0)
+#ifdef CONFIG_NF_CONNTRACK_MODULE
+#include <linux/netfilter.h>
+#endif
+#endif
+#include <linux/slab.h>
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)
+#include <linux/smp_lock.h>
+#endif
+#include <linux/module.h>
+
+/* Helper defines for multi-version kernel support */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#define LKM_2_4
+#else
+#define LKM_2_6
+#endif
+
+#include <linux/kernel.h> /* printk() */
+#include <linux/fs.h> /* everything... */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/proc_fs.h>
+#include <linux/fcntl.h> /* O_ACCMODE */
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/stat.h>
+#include <linux/sched.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)
+#include <linux/sched/signal.h>
+#endif
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/hardirq.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#endif
+
+#define PROC_INTERFACE_KERN_VER_3_10 (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
+
+/* Compatibility Macros */
+
+#ifdef LKM_2_4
+
+#include <linux/compatmac.h>
+#include <linux/wrapper.h>
+#define LKM_MOD_PARAM(n,ot,nt,d) MODULE_PARM(n,ot)
+#define LKM_MOD_PARAM_ARRAY(n,ot,nt,c,d) MODULE_PARM(n,ot)
+#define LKM_EXPORT_SYM(s)
+#define _free_netdev kfree
+
+#else /* LKM_2_6 */
+
+#define LKM_MOD_PARAM(n,ot,nt,d) module_param(n,nt,d)
+#define LKM_MOD_PARAM_ARRAY(n,ot,nt,c,d) module_param_array(n,nt,c,d)
+#define LKM_EXPORT_SYM(s) EXPORT_SYMBOL(s)
+#define _free_netdev free_netdev
+
+#endif /* LKM_2_x */
+
+#ifndef list_for_each_safe
+#define list_for_each_safe(l,t,i) t = 0; list_for_each((l),(i))
+#endif
+
+#ifndef reparent_to_init
+#define reparent_to_init()
+#endif
+
+#ifndef MODULE_LICENSE
+#define MODULE_LICENSE(str)
+#endif
+
+#ifndef EXPORT_NO_SYMBOLS
+#define EXPORT_NO_SYMBOLS
+#endif
+
+#ifndef DEFINE_SPINLOCK
+#define DEFINE_SPINLOCK(_lock) spinlock_t _lock = SPIN_LOCK_UNLOCKED
+#endif
+
+#ifndef __SPIN_LOCK_UNLOCKED
+#define __SPIN_LOCK_UNLOCKED(_lock) SPIN_LOCK_UNLOCKED
+#endif
+
+#ifndef lock_kernel
+#ifdef preempt_disable
+#define lock_kernel() preempt_disable()
+#else
+#define lock_kernel()
+#endif
+#endif
+
+#ifndef unlock_kernel
+#ifdef preempt_enable
+#define unlock_kernel() preempt_enable()
+#else
+#define unlock_kernel()
+#endif
+#endif
+
+#ifndef init_MUTEX_LOCKED
+#define init_MUTEX_LOCKED(_sem) sema_init(_sem, 0)
+#endif
+
+#ifdef CONFIG_BCM98245
+#define CONFIG_BMW
+#endif
+
+#if PROC_INTERFACE_KERN_VER_3_10
+#define PROC_CREATE(_entry, _name, _acc, _path, _fops) \
+ do { \
+ _entry = proc_create(_name, _acc, _path, _fops); \
+ } while (0)
+
+#define PROC_CREATE_DATA(_entry, _name, _acc, _path, _fops, _data) \
+ do { \
+ _entry = proc_create_data(_name, _acc, _path, _fops, _data); \
+ } while (0)
+
+#define PROC_PDE_DATA(_node) PDE_DATA(_node)
+
+#else
+#define PROC_CREATE(_entry, _name, _acc, _path, _fops) \
+ do { \
+ _entry = create_proc_entry(_name, _acc, _path); \
+ if (_entry) { \
+ _entry->proc_fops = _fops; \
+ } \
+ } while (0)
+
+#define PROC_CREATE_DATA(_entry, _name, _acc, _path, _fops, _data) \
+ do { \
+ _entry = create_proc_entry(_name, _acc, _path); \
+ if (_entry) { \
+ _entry->proc_fops = _fops; \
+ _entry->data=_data; \
+ } \
+ } while (0)
+
+#define PROC_PDE_DATA(_node) PROC_I(_node)->pde->data
+#endif
+
+#endif /* __COMMON_LINUX_KRN_LKM_H__ */
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/knet-cb/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/knet-cb/Makefile
@@ -0,0 +1,64 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.3 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+LOCALDIR = systems/linux/kernel/modules/knet-cb
+
+include ${SDK}/make/Make.config
+
+LIBS = $(LIBDIR)/libkern.a
+
+ifeq ($(kernel_version),2_4)
+MODULE = $(LIBDIR)/linux-knet-cb.o
+else
+KERNEL_MODULE_DIR = kernel_module
+
+THIS_MOD_NAME := linux-knet-cb
+MODULE = $(LIBDIR)/$(THIS_MOD_NAME).o
+KMODULE = $(LIBDIR)/$(THIS_MOD_NAME).ko
+
+build: $(MODULE) $(KMODULE)
+endif
+
+KBUILD_EXTRA_SYMBOLS := ${BLDDIR}/../bcm-knet/kernel_module/Module.symvers
+
+# BCM Network Device
+
+$(MODULE): $(BLDDIR)/.tree $(BOBJS) $(LIBS)
+ $(LD) $(MODULE_LDFLAGS) -r -d $(BOBJS) $(LIBS) -o $@
+ifneq ($(kernel_version),2_4)
+$(KMODULE): $(MODULE)
+ rm -fr $(BLDDIR)/$(KERNEL_MODULE_DIR)
+ mkdir $(BLDDIR)/$(KERNEL_MODULE_DIR)
+ cp ${SDK}/make/Makefile.linux-kmodule $(BLDDIR)/$(KERNEL_MODULE_DIR)/Makefile
+ cat ${KBUILD_EXTRA_SYMBOLS} > $(BLDDIR)/$(KERNEL_MODULE_DIR)/Module.symvers
+ MOD_NAME=$(THIS_MOD_NAME) $(MAKE) -C $(BLDDIR)/$(KERNEL_MODULE_DIR) $(THIS_MOD_NAME).ko
+endif
+
+# Make.depend is before clean:: so that Make.depend's clean:: runs first.
+
+include ${SDK}/make/Make.depend
+
+clean::
+ $(RM) $(BLDDIR)/version.c $(BLDDIR)/version.o
+ $(RM) $(BOBJS) $(MODULE)
+
+ifneq ($(kernel_version),2_4)
+.PHONY: build
+endif
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/knet-cb/knet-cb.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+
+/*
+ * Test driver for call-back functions in Linux KNET driver.
+ *
+ * The module can be built from the standard Linux user mode target
+ * directories using the following command (assuming bash), e.g.
+ *
+ * cd $SDK/systems/linux/user/gto-2_6
+ * BUILD_KNET_CB=1 make -s mod
+ *
+ */
+
+#include <gmodule.h> /* Must be included first */
+#include <kcom.h>
+#include <bcm-knet.h>
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom Linux KNET Call-Back Driver");
+MODULE_LICENSE("GPL");
+
+/* Module Information */
+#define MODULE_MAJOR 121
+#define MODULE_NAME "linux-knet-cb"
+
+static void
+show_mac(struct sk_buff *skb)
+{
+ printk("DMAC=%02X:%02X:%02X:%02X:%02X:%02X\n",
+ skb->data[0], skb->data[1], skb->data[2],
+ skb->data[3], skb->data[4], skb->data[5]);
+}
+
+static struct sk_buff *
+test_rx_cb(struct sk_buff *skb, int dev_no, void *meta)
+{
+ printk("rx_cb for dev %d\n", dev_no);
+ printk("netif user data 0x%x\n", KNET_SKB_CB(skb)->netif_user_data);
+ printk("filter user data 0x%x\n", KNET_SKB_CB(skb)->filter_user_data);
+ printk("dcb type 0x%x\n", KNET_SKB_CB(skb)->dcb_type);
+ if (skb->data[5] == 0x03) {
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+ show_mac(skb);
+ return skb;
+}
+
+static struct sk_buff *
+test_tx_cb(struct sk_buff *skb, int dev_no, void *meta)
+{
+ printk("tx_cb for dev %d\n", dev_no);
+ show_mac(skb);
+ skb->data[5] += 1;
+ return skb;
+}
+
+static int
+test_filter_cb(uint8_t *pkt, int size, int dev_no, void *meta,
+ int chan, kcom_filter_t *kf)
+{
+ printk("filter_cb (%d) for dev %d\n", kf->dest_id, dev_no);
+ if (pkt[12] == 0x81 && pkt[13] == 0x00) {
+ printk(" VTAG %d\n", pkt[15]);
+ kf->dest_type = KCOM_DEST_T_NETIF;
+ kf->dest_id = pkt[15];
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Generic module functions
+ */
+
+static int
+_pprint(void)
+{
+ pprintf("Broadcom Linux KNET Call-Back Driver\n");
+
+ return 0;
+}
+
+static int
+_cleanup(void)
+{
+ bkn_rx_skb_cb_unregister(test_rx_cb);
+ bkn_tx_skb_cb_unregister(test_tx_cb);
+ bkn_filter_cb_unregister(test_filter_cb);
+
+ return 0;
+}
+
+static int
+_init(void)
+{
+ bkn_rx_skb_cb_register(test_rx_cb);
+ bkn_tx_skb_cb_register(test_tx_cb);
+ bkn_filter_cb_register(test_filter_cb);
+
+ return 0;
+}
+
+static gmodule_t _gmodule = {
+ name: MODULE_NAME,
+ major: MODULE_MAJOR,
+ init: _init,
+ cleanup: _cleanup,
+ pprint: _pprint,
+ ioctl: NULL,
+ open: NULL,
+ close: NULL,
+};
+
+gmodule_t*
+gmodule_get(void)
+{
+ EXPORT_NO_SYMBOLS;
+ return &_gmodule;
+}
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/shared/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/shared/Makefile
@@ -0,0 +1,29 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.2 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+LOCALDIR = systems/linux/kernel/modules/shared
+
+include ${SDK}/make/Make.config
+
+lib = libkern
+
+include ${SDK}/make/Make.kernlib
+
+include ${SDK}/make/Make.depend
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/shared/gmodule.c b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/shared/gmodule.c
@@ -0,0 +1,427 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: gmodule.c,v 1.20 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ *
+ * Generic Linux Module Framework
+ *
+ * Hooks up your driver to the kernel
+ */
+
+#include <lkm.h>
+#include <gmodule.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+
+/* Module Vector Table */
+static gmodule_t* _gmodule = NULL;
+
+
+/* Allow DEVFS Support on 2.4 Kernels */
+#if defined(LKM_2_4) && defined(CONFIG_DEVFS_FS)
+#define GMODULE_CONFIG_DEVFS_FS
+#endif
+
+
+#ifdef GMODULE_CONFIG_DEVFS_FS
+devfs_handle_t devfs_handle = NULL;
+#endif
+
+/* FIXME: support dynamic debugging */
+
+static int _dbg_enable = 0;
+
+static int
+gvprintk(const char* fmt, va_list args)
+ __attribute__ ((format (printf, 1, 0)));
+
+static int
+gvprintk(const char* fmt, va_list args)
+{
+ static char _buf[256];
+
+ strcpy(_buf, "");
+ sprintf(_buf, "%s (%d): ", _gmodule->name, current->pid);
+ vsprintf(_buf+strlen(_buf), fmt, args);
+ printk("%s",_buf);
+
+ return 0;
+}
+
+int
+gprintk(const char* fmt, ...)
+{
+ int rv;
+
+ va_list args;
+ va_start(args, fmt);
+ rv = gvprintk(fmt, args);
+ va_end(args);
+ return rv;
+}
+
+int
+gdbg(const char* fmt, ...)
+{
+ int rv = 0;
+
+ va_list args;
+ va_start(args, fmt);
+ if(_dbg_enable) {
+ rv = gvprintk(fmt, args);
+ }
+ va_end(args);
+ return rv;
+}
+
+
+/*
+ * Proc FS Utilities
+ */
+#if PROC_INTERFACE_KERN_VER_3_10
+static struct seq_file* _proc_buf = NULL;
+
+int
+pprintf(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ seq_vprintf(_proc_buf, fmt, args);
+ va_end(args);
+ return 0;
+}
+
+static int _gmodule_proc_show(struct seq_file *m, void *v){
+ _proc_buf = m;
+ _gmodule->pprint();
+ return 0;
+}
+
+static int
+_gmodule_proc_open(struct inode * inode, struct file * file) {
+ if(_gmodule->open) {
+ _gmodule->open();
+ }
+
+ return single_open(file, _gmodule_proc_show, NULL);
+}
+
+static ssize_t
+_gmodule_proc_write(struct file *file, const char *buffer,
+ size_t count, loff_t *loff)
+{
+ /* Workaround to toggle debugging */
+ if(count > 2) {
+ if(buffer[0] == 'd') {
+ _dbg_enable = buffer[1] - '0';
+ GDBG("Debugging Enabled");
+ }
+ }
+ return count;
+}
+
+static int _gmodule_proc_release(struct inode * inode, struct file * file) {
+ if(_gmodule->close) {
+ _gmodule->close();
+ }
+
+ return single_release(inode, file);
+}
+
+struct file_operations _gmodule_proc_fops = {
+ owner: THIS_MODULE,
+ open: _gmodule_proc_open,
+ read: seq_read,
+ llseek: seq_lseek,
+ write: _gmodule_proc_write,
+ release: _gmodule_proc_release,
+};
+#else
+int
+gmodule_vpprintf(char** page_ptr, const char* fmt, va_list args)
+{
+ *page_ptr += vsprintf(*page_ptr, fmt, args);
+ return 0;
+}
+
+int
+gmodule_pprintf(char** page_ptr, const char* fmt, ...)
+{
+ int rv;
+
+ va_list args;
+ va_start(args, fmt);
+ rv = gmodule_vpprintf(page_ptr, fmt, args);
+ va_end(args);
+ return rv;
+}
+
+static char* _proc_buf = NULL;
+
+int
+pprintf(const char* fmt, ...)
+{
+ int rv;
+
+ va_list args;
+ va_start(args, fmt);
+ rv = gmodule_vpprintf(&_proc_buf, fmt, args);
+ va_end(args);
+ return rv;
+}
+
+#define PSTART(b) _proc_buf = b
+#define PPRINT proc_print
+#define PEND(b) (_proc_buf-b)
+
+static int
+_gmodule_pprint(char* buf)
+{
+ PSTART(buf);
+ _gmodule->pprint();
+ return PEND(buf);
+}
+
+static int
+_gmodule_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ *eof = 1;
+ return _gmodule_pprint(page);
+}
+
+static int
+_gmodule_write_proc(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ /* Workaround to toggle debugging */
+ if(count > 2) {
+ if(buffer[0] == 'd') {
+ _dbg_enable = buffer[1] - '0';
+ GDBG("Debugging Enabled");
+ }
+ }
+ return count;
+}
+#endif
+
+static int
+_gmodule_create_proc(void)
+{
+ struct proc_dir_entry* ent;
+#if PROC_INTERFACE_KERN_VER_3_10
+ if((ent = proc_create(_gmodule->name,
+ S_IRUGO | S_IWUGO,
+ NULL,
+ &_gmodule_proc_fops)) != NULL) {
+ return 0;
+ }
+#else
+ if((ent = create_proc_entry(_gmodule->name, S_IRUGO | S_IWUGO, NULL)) != NULL) {
+ ent->read_proc = _gmodule_read_proc;
+ ent->write_proc = _gmodule_write_proc;
+ return 0;
+ }
+#endif
+ return -1;
+}
+
+static void
+_gmodule_remove_proc(void)
+{
+ remove_proc_entry(_gmodule->name, NULL);
+}
+
+static int
+_gmodule_open(struct inode *inode, struct file *filp)
+{
+ if(_gmodule->open) {
+ _gmodule->open();
+ }
+ return 0;
+}
+
+static int
+_gmodule_release(struct inode *inode, struct file *filp)
+{
+ if(_gmodule->close) {
+ _gmodule->close();
+ }
+ return 0;
+}
+
+#ifdef HAVE_UNLOCKED_IOCTL
+static long
+_gmodule_unlocked_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ if(_gmodule->ioctl) {
+ return _gmodule->ioctl(cmd, arg);
+ } else {
+ return -1;
+ }
+}
+#else
+static int
+_gmodule_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ if(_gmodule->ioctl) {
+ return _gmodule->ioctl(cmd, arg);
+ } else {
+ return -1;
+ }
+}
+#endif
+
+#ifdef HAVE_COMPAT_IOCTL
+static long
+_gmodule_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ if(_gmodule->ioctl) {
+ return _gmodule->ioctl(cmd, arg);
+ } else {
+ return -1;
+ }
+}
+#endif
+
+
+static int
+_gmodule_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ if (_gmodule->mmap) {
+ return _gmodule->mmap(filp, vma);
+ }
+#ifdef BCM_PLX9656_LOCAL_BUS
+ vma->vm_flags |= VM_RESERVED | VM_IO;
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+
+ if (io_remap_pfn_range( vma,
+ vma->vm_start,
+ vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
+ return (-EAGAIN);
+ }
+ return (0);
+#else/* BCM_PLX9656_LOCAL_BUS */
+ return -EPERM;
+#endif/* BCM_PLX9656_LOCAL_BUS */
+}
+
+/* FILE OPERATIONS */
+
+struct file_operations _gmodule_fops = {
+#ifdef HAVE_UNLOCKED_IOCTL
+ unlocked_ioctl: _gmodule_unlocked_ioctl,
+#else
+ ioctl: _gmodule_ioctl,
+#endif
+ open: _gmodule_open,
+ release: _gmodule_release,
+ mmap: _gmodule_mmap,
+#ifdef HAVE_COMPAT_IOCTL
+ compat_ioctl: _gmodule_compat_ioctl,
+#endif
+};
+
+
+void __exit
+cleanup_module(void)
+{
+ if(!_gmodule) return;
+
+ /* Specific Cleanup */
+ if(_gmodule->cleanup) {
+ _gmodule->cleanup();
+ }
+
+ /* Remove any proc entries */
+ if(_gmodule->pprint) {
+ _gmodule_remove_proc();
+ }
+
+ /* Finally, remove ourselves from the universe */
+#ifdef GMODULE_CONFIG_DEVFS_FS
+ if(devfs_handle) devfs_unregister(devfs_handle);
+#else
+ unregister_chrdev(_gmodule->major, _gmodule->name);
+#endif
+}
+
+int __init
+init_module(void)
+{
+ int rc;
+
+ /* Get our definition */
+ _gmodule = gmodule_get();
+ if(!_gmodule) return -ENODEV;
+
+
+ /* Register ourselves */
+#ifdef GMODULE_CONFIG_DEVFS_FS
+ devfs_handle = devfs_register(NULL,
+ _gmodule->name,
+ DEVFS_FL_NONE,
+ _gmodule->major,
+ _gmodule->minor,
+ S_IFCHR | S_IRUGO | S_IWUGO,
+ &_gmodule_fops,
+ NULL);
+ if(!devfs_handle) {
+ printk(KERN_WARNING "%s: can't register device with devfs",
+ _gmodule->name);
+ }
+ rc = 0;
+#else
+ rc = register_chrdev(_gmodule->major,
+ _gmodule->name,
+ &_gmodule_fops);
+ if (rc < 0) {
+ printk(KERN_WARNING "%s: can't get major %d",
+ _gmodule->name, _gmodule->major);
+ return rc;
+ }
+
+ if(_gmodule->major == 0) {
+ _gmodule->major = rc;
+ }
+#endif
+
+ /* Specific module Initialization */
+ if(_gmodule->init) {
+ int rc;
+ if((rc = _gmodule->init()) < 0) {
+#ifdef GMODULE_CONFIG_DEVFS_FS
+ if(devfs_handle) devfs_unregister(devfs_handle);
+#else
+ unregister_chrdev(_gmodule->major, _gmodule->name);
+#endif
+ return rc;
+ }
+ }
+
+ /* Add a /proc entry, if valid */
+ if(_gmodule->pprint) {
+ _gmodule_create_proc();
+ }
+
+ return 0; /* succeed */
+}
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/shared/ksal.c b/sdk-6.5.20/src/gpl-modules/systems/linux/kernel/modules/shared/ksal.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+/*
+ * $Id: ksal.c,v 1.1 Broadcom SDK $
+ * $Copyright: (c) 2005 Broadcom Corp.
+ * All Rights Reserved.$
+ */
+
+#include <sal/core/sync.h>
+#include <sal/core/thread.h>
+
+#include "lkm.h"
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+#include <linux/semaphore.h>
+#else
+#include <asm/semaphore.h>
+#endif
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
+#include <linux/sched/rt.h>
+#endif
+#include <linux/time.h>
+
+#ifdef MAX_USER_RT_PRIO
+/* Assume 2.6 scheduler */
+#define SAL_YIELD(task) \
+ yield()
+#else
+/* Assume 2.4 scheduler */
+#define SAL_YIELD(task) \
+do { \
+ task->policy |= SCHED_YIELD; \
+ schedule(); \
+} while (0)
+#endif
+
+#define SECOND_USEC (1000000)
+#define USECS_PER_JIFFY (SECOND_USEC / HZ)
+#define USEC_TO_JIFFIES(usec) ((usec + (USECS_PER_JIFFY - 1)) / USECS_PER_JIFFY)
+
+#define sal_alloc(size, desc) kmalloc(size, GFP_KERNEL)
+#define sal_free(ptr) kfree(ptr)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
+#define WQ_SLEEP(a, b) wait_event_interruptible_timeout(a, NULL, b)
+#else
+#define WQ_SLEEP(a, b) interruptible_sleep_on_timeout(&(a), b)
+#endif
+/*
+ * sem_ctrl_t
+ *
+ * The semaphore control type uses the binary property to implement
+ * timed semaphores with improved performance using wait queues.
+ */
+
+typedef struct sem_ctrl_s {
+ struct semaphore sem;
+ int binary;
+ int cnt;
+ wait_queue_head_t wq;
+} sem_ctrl_t;
+
+sal_sem_t
+sal_sem_create(char *desc, int binary, int initial_count)
+{
+ sem_ctrl_t *s;
+
+ if ((s = sal_alloc(sizeof(*s), desc)) != 0) {
+ sema_init(&s->sem, initial_count);
+ s->binary = binary;
+ if (s->binary) {
+ init_waitqueue_head(&s->wq);
+ }
+ }
+
+ return (sal_sem_t) s;
+}
+
+void
+sal_sem_destroy(sal_sem_t b)
+{
+ sem_ctrl_t *s = (sem_ctrl_t *) b;
+
+ if (s == NULL) {
+ return;
+ }
+
+ /*
+ * the linux kernel does not have a sema_destroy(s)
+ */
+ sal_free(s);
+}
+
+int
+sal_sem_take(sal_sem_t b, int usec)
+{
+ sem_ctrl_t *s = (sem_ctrl_t *) b;
+ int err;
+
+ if (usec == sal_sem_FOREVER && !in_interrupt()) {
+ err = down_interruptible(&s->sem);
+ } else {
+ int time_wait = 1;
+ int cnt = s->cnt;
+
+ for (;;) {
+ if (down_trylock(&s->sem) == 0) {
+ err = 0;
+ break;
+ }
+
+ if (s->binary) {
+
+ /* Wait for event or timeout */
+
+ if (time_wait > 1) {
+ err = 1;
+ break;
+ }
+ err = wait_event_interruptible_timeout(s->wq, cnt != s->cnt,
+ USEC_TO_JIFFIES(usec));
+ if (err < 0) {
+ break;
+ }
+ time_wait++;
+
+ } else {
+
+ /* Retry algorithm with exponential backoff */
+
+ if (time_wait > usec) {
+ time_wait = usec;
+ }
+
+ sal_usleep(time_wait);
+
+ usec -= time_wait;
+
+ if (usec == 0) {
+ err = ETIMEDOUT;
+ break;
+ }
+
+ if ((time_wait *= 2) > 100000) {
+ time_wait = 100000;
+ }
+ }
+ }
+ }
+ return err ? -1 : 0;
+}
+
+int
+sal_sem_give(sal_sem_t b)
+{
+ sem_ctrl_t *s = (sem_ctrl_t *) b;
+
+ up(&s->sem);
+ if (s->binary) {
+ s->cnt++;
+ wake_up_interruptible(&s->wq);
+ }
+ return 0;
+}
+
+uint32
+sal_time_usecs(void)
+{
+ struct timeval ltv;
+ do_gettimeofday(<v);
+ return (ltv.tv_sec * SECOND_USEC + ltv.tv_usec);
+}
+
+void
+sal_usleep(uint32 usec)
+{
+ uint32 start_usec;
+ wait_queue_head_t queue;
+
+ if (usec <= SECOND_USEC / HZ) {
+ start_usec = sal_time_usecs();
+ do {
+ SAL_YIELD(current);
+ } while ((sal_time_usecs() - start_usec) < usec);
+ } else {
+ init_waitqueue_head(&queue);
+ WQ_SLEEP(queue, USEC_TO_JIFFIES(usec));
+ }
+}
+
+void
+sal_udelay(uint32 usec)
+{
+ static volatile int _sal_udelay_counter;
+ static int loops = 0;
+ int ix, iy;
+
+ if (loops == 0 || usec == 0) { /* Need calibration? */
+ int max_loops;
+ int start = 0, stop = 0;
+ int mpt = USECS_PER_JIFFY; /* usec/tick */
+
+ for (loops = 1; loops < 0x1000 && stop == start; loops <<= 1) {
+ /* Wait for clock turn over */
+ for (stop = start = jiffies; start == stop; start = jiffies) {
+ /* Empty */
+ }
+ sal_udelay(mpt); /* Single recursion */
+ stop = jiffies;
+ }
+
+ max_loops = loops / 2; /* Loop above overshoots */
+
+ start = stop = 0;
+
+ if (loops < 4) {
+ loops = 4;
+ }
+
+ for (loops /= 4; loops < max_loops && stop == start; loops++) {
+ /* Wait for clock turn over */
+ for (stop = start = jiffies; start == stop; start = jiffies) {
+ /* Empty */
+ }
+ sal_udelay(mpt); /* Single recursion */
+ stop = jiffies;
+ }
+ }
+
+ for (iy = 0; iy < usec; iy++) {
+ for (ix = 0; ix < loops; ix++) {
+ _sal_udelay_counter++; /* Prevent optimizations */
+ }
+ }
+}
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/user/common/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/common/Makefile
@@ -0,0 +1,229 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.4 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+#
+
+SDK :=$(shell if [ -n "$$SDK" ] ; then\
+ echo $$SDK;\
+ else\
+ cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \
+ dir=`cd ../;pwd`; \
+ if [ "$$dir" = "/" ] ; then \
+ echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \
+ exit 1; \
+ fi ; \
+ cd $$dir; \
+ done ; \
+ pwd; \
+ fi)
+
+ifeq ($(SDK),)
+$(error Please run this in a tree)
+endif
+
+export SDK
+
+override-target=linux-$(platform)
+
+ifeq ($(LINUX_MAKE_SHARED_LIB),1)
+libext = so.$(SHAREDLIBVER)
+else
+libext = a
+endif
+
+ifeq (,$(platform))
+$(error Internal error: platform variable is not set)
+endif
+
+include $(SDK)/make/Make.config
+LOCALDIR=systems/linux/user/common
+include $(SDK)/make/Make.depend
+kernel-override=linux-$(platform)
+ifdef BLDCONFIG
+KERN_BLDROOT=${SDK}/${SDKBUILD}/${BLDCONFIG}/$(kernel-override)$(bldroot_suffix)
+else
+KERN_BLDROOT=${SDK}/${SDKBUILD}/$(kernel-override)$(bldroot_suffix)
+endif
+
+ifeq (,$(kernel_version))
+kernel_version=2_4
+endif
+
+ifneq ($(kernel_version),2_4)
+KOBJ=ko
+else
+KOBJ=o
+endif
+
+ifneq (,$(TOOLS_DIR))
+override PATH := $(TOOLS_DIR):$(PATH)
+endif
+
+ifeq ($(DEST_DIR),)
+DEST_DIR=${BLDDIR}
+endif
+
+KERNEL_BDE_LOCAL :=linux-kernel-bde.$(KOBJ)
+KERNEL_BDE :=$(DEST_DIR)/$(KERNEL_BDE_LOCAL)
+
+USER_BDE_LOCAL :=linux-user-bde.$(KOBJ)
+USER_BDE=$(DEST_DIR)/$(USER_BDE_LOCAL)
+
+KNET_CB_LOCAL := linux-knet-cb.$(KOBJ)
+KNET_CB := $(DEST_DIR)/$(KNET_CB_LOCAL)
+
+BCM_KNET_LOCAL :=linux-bcm-knet.$(KOBJ)
+BCM_KNET=$(DEST_DIR)/$(BCM_KNET_LOCAL)
+
+ifeq (,$(findstring DELIVER,$(MAKECMDGOALS)))
+.DEFAULT_GOAL := all
+all_targets := kernel_modules $(KERNEL_BDE) $(USER_BDE)
+
+LOCAL_TARGETS :=
+
+ifeq ($(NO_LOCAL_TARGETS),)
+LOCAL_TARGETS +=$(patsubst %,$(realpath ..)/$(platform)/%,$(KERNEL_BDE_LOCAL) $(USER_BDE_LOCAL))
+
+all_targets +=$(LOCAL_TARGETS)
+endif
+
+# Build all by default
+ifndef BUILD_KNET
+BUILD_KNET = 1
+endif
+
+ifeq ($(BUILD_KNET),1)
+# Kernel network support
+all_targets += $(BCM_KNET)
+
+ifeq ($(NO_LOCAL_TARGETS),)
+LOCAL_TARGETS +=$(patsubst %,../$(platform)/%,$(BCM_KNET_LOCAL))
+all_targets +=$(LOCAL_TARGETS)
+endif
+
+ifdef BUILD_KNET_CB
+all_targets += $(KNET_CB)
+
+ifeq ($(NO_LOCAL_TARGETS),)
+LOCAL_TARGETS +=$(patsubst %,../$(platform)/%,$(KNET_CB_LOCAL))
+all_targets +=$(LOCAL_TARGETS)
+endif
+endif
+
+ADD_TO_CFLAGS += -I$(SDK)/systems/linux/kernel/modules/include
+COND_KNET_LIBS = libuser.$(libext)
+endif
+
+all: $(BLDDIR)/.tree $(all_targets)
+
+ifeq ($(NO_LOCAL_TARGETS),)
+define LOCAL_TARGET_DEF
+$(1) : $(DEST_DIR)/$(notdir $(1))
+ cp $$? $$@
+endef
+endif
+
+# User BDE libraries
+ADD_TO_CFLAGS += -I$(SDK)/systems/bde/linux/include
+
+# Use raw IOCTL for KNET
+ADD_TO_CFLAGS += -DPROXY_SUPPORT=0
+
+CFLAGS += $(ADD_TO_CFLAGS)
+
+kernel_modules:
+ $(MAKE) -C $(SDK)/systems/bde/linux/kernel kernel_version=$(kernel_version)
+ $(MAKE) -C $(SDK)/systems/bde/linux/user/kernel kernel_version=$(kernel_version)
+ifeq ($(BUILD_KNET),1)
+ $(MAKE) -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \
+ subdirs="shared bcm-knet" override-target=linux-$(platform) CFLAGS="$(CFLAGS)"
+ifdef BUILD_KNET_CB
+ $(MAKE) -C $(SDK)/systems/linux/kernel/modules kernel_version=$(kernel_version) \
+ subdirs="knet-cb" override-target=linux-$(platform) CFLAGS="$(CFLAGS)"
+endif
+endif
+
+$(KERNEL_BDE): $(KERN_BLDROOT)/linux-kernel-bde.$(KOBJ)
+ mkdir -p $(@D)
+ $(OBJCOPY) --strip-debug $< $@
+
+$(USER_BDE): $(KERN_BLDROOT)/linux-user-bde.$(KOBJ)
+ $(OBJCOPY) --strip-debug $< $@
+
+$(BCM_KNET): $(KERN_BLDROOT)/linux-bcm-knet.$(KOBJ)
+ $(OBJCOPY) --strip-debug $< $@
+
+$(KNET_CB): $(KERN_BLDROOT)/linux-knet-cb.$(KOBJ)
+ $(OBJCOPY) --strip-debug $< $@
+
+ifeq ($(NO_LOCAL_TARGETS),)
+$(foreach targ,$(LOCAL_TARGETS),$(eval $(call LOCAL_TARGET_DEF,$(targ))))
+endif
+
+clean::
+ $(MAKE) -C $(SDK)/systems/bde/linux/kernel $@
+ $(MAKE) -C $(SDK)/systems/bde/linux/user/kernel $@
+ $(MAKE) -C $(SDK)/systems/linux/kernel/modules \
+ subdirs="shared bcm-knet knet-cb" \
+ override-target=linux-$(platform) $@
+ $(RM) $(KERNEL_BDE) $(USER_BDE)
+ $(RM) $(BCM_KNET) $(KNET_CB)
+ $(RM) $(KERN_BLDROOT)/linux-kernel-bde.$(KOBJ)
+ $(RM) $(KERN_BLDROOT)/linux-user-bde.$(KOBJ)
+ $(RM) $(KERN_BLDROOT)/linux-bcm-knet.$(KOBJ)
+ $(RM) $(KERN_BLDROOT)/linux-knet-cb.$(KOBJ)
+ $(RM) $(LOCAL_TARGETS)
+
+distclean:: clean
+
+.PHONY: variable
+
+#
+# Echo variable values used for configuration
+# usage: make VAR=CC variable
+#
+variable::
+ @echo $($(VAR))
+
+else
+ifndef DELIVERY
+$(error DELIVERY required)
+endif
+
+DELIVERABLES := $(KERNEL_BDE) $(USER_BDE)
+# 1= source
+define DELIVERY_RULE
+_DEL_TARG += $(DELIVERY)/$(notdir $(1))
+$(DELIVERY)/$(notdir $(1)) : $(1)
+ @mkdir -p $(DELIVERY)
+ifeq ($(filter $(notdir $(BCM)) $(notdir $(BCM).dbg),$(notdir $1)),)
+ $(OBJCOPY) --strip-debug $$< $$@
+else
+ $(CP) -p $$< $$@
+endif
+endef
+
+$(foreach f,$(DELIVERABLES),$(eval $(call DELIVERY_RULE,$(f))))
+
+DELIVER: $(_DEL_TARG)
+endif
+
+# Make.config defines remaining phony targets
+.PHONY: build kernel_modules DELIVER
+
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/user/gts/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/gts/Makefile
@@ -0,0 +1,63 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 0.1 Broadcom SDK $
+# $Copyright: (c) 2015 Broadcom Corp.
+# All Rights Reserved.$
+
+#
+# This make job requires the following environment variables to be set:
+#
+# SDK - path to StrataXGS SDK root directory
+#
+# Optionally the following environment variables can be set to
+# override the default build server configuration:
+#
+# TOOLS_DIR - path to build tools (if not in PATH already)
+# CROSS_COMPILE - cross compile tools prefix
+# LINUX_INCLUDE - path to Linux kernel include directory
+#
+
+SDK :=$(shell if [ -n "$$SDK" ] ; then\
+ echo $$SDK;\
+ else\
+ cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \
+ dir=`cd ../;pwd`; \
+ if [ "$$dir" = "/" ] ; then \
+ echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \
+ exit 1; \
+ fi ; \
+ cd $$dir; \
+ done ; \
+ pwd; \
+ fi)
+
+ifeq ($(SDK),)
+$(error Please run this in a tree)
+endif
+
+export SDK
+
+override kernel_version=4_19
+platform=gts
+LINUX_MAKE_USER=1
+export LINKER_RELAX = 1
+export ADD_TO_CFLAGS
+export BR_NO_CCACHE
+
+
+include ${SDK}/make/Make.linux
+
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/user/iproc-3_14/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/iproc-3_14/Makefile
@@ -0,0 +1,65 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.7 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+#
+# This make job requires the following environment variables to be set:
+#
+# SDK - path to StrataXGS SDK root directory
+#
+# Optionally the following environment variables can be set to
+# override the default build server configuration:
+#
+# MIPS_TOOLS_DIR - path to build tools (if not in PATH already)
+# MIPS_CROSS_COMPILE - cross compile tools prefix
+# LINUX_INCLUDE - path to Linux kernel include directory
+#
+
+SDK :=$(shell if [ -n "$$SDK" ] ; then\
+ echo $$SDK;\
+ else\
+ cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \
+ dir=`cd ../;pwd`; \
+ if [ "$$dir" = "/" ] ; then \
+ echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \
+ exit 1; \
+ fi ; \
+ cd $$dir; \
+ done ; \
+ pwd; \
+ fi)
+
+ifeq ($(SDK),)
+$(error Please run this in a tree)
+endif
+
+export SDK
+
+override kernel_version=3_14
+platform=iproc-$(kernel_version)
+
+IPROC_BUILD=1
+export IPROC_BUILD
+export BUILD_PLATFORM
+export ARM_LINUX_VERSION
+
+LINUX_MAKE_USER=1
+export ADD_TO_CFLAGS
+
+include ${SDK}/make/Make.linux
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/user/iproc-4_4/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/iproc-4_4/Makefile
@@ -0,0 +1,59 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.7 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+#
+# This make job requires the following environment variables to be set:
+#
+# SDK - path to StrataXGS SDK root directory
+#
+
+SDK :=$(shell if [ -n "$$SDK" ] ; then\
+ echo $$SDK;\
+ else\
+ cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \
+ dir=`cd ../;pwd`; \
+ if [ "$$dir" = "/" ] ; then \
+ echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \
+ exit 1; \
+ fi ; \
+ cd $$dir; \
+ done ; \
+ pwd; \
+ fi)
+
+ifeq ($(SDK),)
+$(error Please run this in a tree)
+endif
+
+export SDK
+
+override kernel_version=4_4
+platform=iproc-$(kernel_version)
+
+IPROC_BUILD=1
+export IPROC_BUILD
+export BUILD_PLATFORM
+export ARM_LINUX_VERSION
+
+LINUX_MAKE_USER=1
+export ADD_TO_CFLAGS
+export BR_NO_CCACHE
+
+include ${SDK}/make/Make.linux
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/user/iproc/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/iproc/Makefile
@@ -0,0 +1,59 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.7 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+#
+# This make job requires the following environment variables to be set:
+#
+# SDK - path to StrataXGS SDK root directory
+#
+
+SDK :=$(shell if [ -n "$$SDK" ] ; then\
+ echo $$SDK;\
+ else\
+ cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \
+ dir=`cd ../;pwd`; \
+ if [ "$$dir" = "/" ] ; then \
+ echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \
+ exit 1; \
+ fi ; \
+ cd $$dir; \
+ done ; \
+ pwd; \
+ fi)
+
+ifeq ($(SDK),)
+$(error Please run this in a tree)
+endif
+
+export SDK
+
+override kernel_version=4_14
+platform=iproc
+
+IPROC_BUILD=1
+export IPROC_BUILD
+export BUILD_PLATFORM
+export ARM_LINUX_VERSION
+
+LINUX_MAKE_USER=1
+export ADD_TO_CFLAGS
+export BR_NO_CCACHE
+
+include ${SDK}/make/Make.linux
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/user/iproc_64/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/iproc_64/Makefile
@@ -0,0 +1,59 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.7 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+#
+# This make job requires the following environment variables to be set:
+#
+# SDK - path to StrataXGS SDK root directory
+#
+
+SDK :=$(shell if [ -n "$$SDK" ] ; then\
+ echo $$SDK;\
+ else\
+ cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \
+ dir=`cd ../;pwd`; \
+ if [ "$$dir" = "/" ] ; then \
+ echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \
+ exit 1; \
+ fi ; \
+ cd $$dir; \
+ done ; \
+ pwd; \
+ fi)
+
+ifeq ($(SDK),)
+$(error Please run this in a tree)
+endif
+
+export SDK
+
+override kernel_version=4_14
+platform=iproc_64
+
+IPROC_BUILD=1
+export IPROC_BUILD
+export BUILD_PLATFORM
+export ARM_LINUX_VERSION
+
+LINUX_MAKE_USER=1
+export ADD_TO_CFLAGS
+export BR_NO_CCACHE
+
+include ${SDK}/make/Make.linux
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/user/slk/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/slk/Makefile
@@ -0,0 +1,60 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 0.1 Broadcom SDK $
+# $Copyright: (c) 2015 Broadcom Corp.
+# All Rights Reserved.$
+
+#
+# This make job requires the following environment variables to be set:
+#
+# SDK - path to StrataXGS SDK root directory
+#
+# Optionally the following environment variables can be set to
+# override the default build server configuration:
+#
+# TOOLS_DIR - path to build tools (if not in PATH already)
+# CROSS_COMPILE - cross compile tools prefix
+# LINUX_INCLUDE - path to Linux kernel include directory
+#
+
+SDK :=$(shell if [ -n "$$SDK" ] ; then\
+ echo $$SDK;\
+ else\
+ cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \
+ dir=`cd ../;pwd`; \
+ if [ "$$dir" = "/" ] ; then \
+ echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \
+ exit 1; \
+ fi ; \
+ cd $$dir; \
+ done ; \
+ pwd; \
+ fi)
+
+ifeq ($(SDK),)
+$(error Please run this in a tree)
+endif
+
+export SDK
+
+override kernel_version=3_14
+platform=slk
+LINUX_MAKE_USER=1
+export LINKER_RELAX = 1
+
+include ${SDK}/make/Make.linux
+
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/x86-smp_generic_64-2_6/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 1.2 Broadcom SDK $
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved.$
+
+SDK :=$(shell if [ -n "$$SDK" ] ; then\
+ echo $$SDK;\
+ else\
+ cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \
+ dir=`cd ../;pwd`; \
+ if [ "$$dir" = "/" ] ; then \
+ echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \
+ exit 1; \
+ fi ; \
+ cd $$dir; \
+ done ; \
+ pwd; \
+ fi)
+
+ifeq ($(SDK),)
+$(error Please run this in a tree)
+endif
+
+export SDK
+
+override kernel_version=2_6
+platform=x86-smp_generic_64-$(kernel_version)
+
+LINUX_MAKE_USER=1
+include ${SDK}/make/Make.linux
diff --git a/sdk-6.5.20/src/gpl-modules/systems/linux/user/xlr/Makefile b/sdk-6.5.20/src/gpl-modules/systems/linux/user/xlr/Makefile
@@ -0,0 +1,63 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+# -*- Makefile -*-
+# $Id: Makefile,v 0.1 Broadcom SDK $
+# $Copyright: (c) 2015 Broadcom Corp.
+# All Rights Reserved.$
+
+#
+# This make job requires the following environment variables to be set:
+#
+# SDK - path to StrataXGS SDK root directory
+#
+# Optionally the following environment variables can be set to
+# override the default build server configuration:
+#
+# TOOLS_DIR - path to build tools (if not in PATH already)
+# CROSS_COMPILE - cross compile tools prefix
+# LINUX_INCLUDE - path to Linux kernel include directory
+#
+
+SDK :=$(shell if [ -n "$$SDK" ] ; then\
+ echo $$SDK;\
+ else\
+ cd $(dir $(lastword $(MAKEFILE_LIST))); while /usr/bin/test ! -e RELEASE ; do \
+ dir=`cd ../;pwd`; \
+ if [ "$$dir" = "/" ] ; then \
+ echo Cannot find SDK in $(lastword $(MAKEFILE_LIST)) 1>&2; \
+ exit 1; \
+ fi ; \
+ cd $$dir; \
+ done ; \
+ pwd; \
+ fi)
+
+ifeq ($(SDK),)
+$(error Please run this in a tree)
+endif
+
+export SDK
+
+override kernel_version=4_19
+platform=xlr
+LINUX_MAKE_USER=1
+export LINKER_RELAX = 1
+export ADD_TO_CFLAGS
+export BR_NO_CCACHE
+
+
+include ${SDK}/make/Make.linux
+
diff --git a/sdk-6.5.20/src/gpl-modules/tools/mktool.pl b/sdk-6.5.20/src/gpl-modules/tools/mktool.pl
@@ -0,0 +1,292 @@
+#
+# Copyright 2017 Broadcom
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation (the "GPL").
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License version 2 (GPLv2) for more details.
+#
+# You should have received a copy of the GNU General Public License
+# version 2 (GPLv2) along with this source code.
+#
+#
+# mktool.pl
+#
+# $Id: mktool.pl,v 1.5 Broadcom SDK $
+#
+# $Copyright: (c) 2005 Broadcom Corp.
+# All Rights Reserved. $
+
+use File::Path;
+use File::Find;
+use File::Copy;
+use Cwd;
+
+($prog = $0) =~ s/.*\///;
+
+SWITCH:
+{
+ $op = shift;
+
+ if ($op eq "-rm") { mktool_rm(@ARGV); last SWITCH; }
+ if ($op eq "-cp") { mktool_cp(@ARGV); last SWITCH; }
+ if ($op eq "-md") { mktool_md(@ARGV); last SWITCH; }
+ if ($op eq "-ln") { mktool_ln(@ARGV); last SWITCH; }
+ if ($op eq "-foreach") { mktool_foreach(@ARGV); last SWITCH; }
+ if ($op eq "-dep") { mktool_makedep(@ARGV); last SWITCH; }
+ if ($op eq "-echo") { mktool_echo(@ARGV); last SWITCH; }
+ if ($op eq "-beep") { mktool_beep(@ARGV); last SWITCH; }
+ die("$prog: unknown option '$op'\n");
+}
+
+exit 0;
+
+
+
+
+#
+# mktool_execute
+#
+# Executes a command, returns exist status.
+# Performs token special translation before execution.
+#
+
+sub mktool_execute
+{
+ my $token = shift;
+ my @cmds = @_;
+
+# printf("mktool_execute: token = '$token'\n");
+ foreach $cmd (@cmds)
+ {
+ #printf("mktool_execute: cmd = '$cmd'\n");
+ $cmd =~ s/\#\#/$token/g;
+ if($cmd =~ /^-p/)
+ {
+ $cmd =~ s/^-p//;
+ printf("$cmd\n");
+ }
+ else
+ {
+ system($cmd);
+ my $excode = ($? >> 8);
+ exit $excode if $excode;
+ }
+ }
+}
+
+
+$find_regexp = "";
+@find_cmd;
+
+#
+# mktool_foreach
+#
+sub mktool_foreach
+{
+ if($_[0] eq "-find")
+ {
+ shift;
+ $find_dir = shift;
+ $find_regexp = shift;
+ @find_cmds = @_;
+
+ if(!($find_dir =~ /^\//))
+ {
+ $find_dir = cwd() . "/" . $find_dir;
+ }
+ find(\&_mktool_foreach_find_wanted, $find_dir);
+ }
+ else
+ {
+ my $subdir = 0;
+ if($_[0] eq "-subdir")
+ {
+ $subdir = 1;
+ shift;
+ }
+
+ my @thingies = split(' ', shift);
+
+ foreach $thingy (@thingies)
+ {
+ chdir $thingy unless $subdir == 0;
+ mktool_execute($thingy, @_);
+ chdir ".." unless $subdir == 0;
+ }
+ }
+}
+
+
+
+sub _mktool_foreach_find_wanted
+{
+ my $expr = "\$File::Find::name =~ /\^$find_regexp\$/";
+
+ if(eval($expr))
+ {
+ mktool_execute($File::Find::name, @find_cmds);
+ exit $excode if $excode;
+ }
+}
+
+
+#
+# rm
+#
+# Removes a list of objects
+#
+sub mktool_rm
+{
+ my($f);
+
+ foreach $f (@_) {
+ eval { rmtree($f) };
+ if ($@) {
+ die "$prog $op: failed to remove $f: $@\n";
+ }
+ }
+}
+
+#
+# md
+#
+# Makes a list of directories
+#
+sub mktool_md
+{
+ my($dir);
+
+ foreach $dir (@_) {
+ $dir =~ s!/+$!!;
+ eval { mkpath($dir) };
+ if ($@) {
+ die "$prog $op: failed to make directory $dir: $@\n";
+ }
+ }
+}
+
+
+sub mktool_cp
+{
+ my($from, $to) = @_;
+
+ if (@_ != 2) {
+ die "$prog $op: must have two arguments\n";
+ }
+ copy($from, $to) ||
+ die "$prog $op: failed to copy $from to $to: $!\n";
+}
+
+sub mktool_ln
+{
+ my($old, $new) = @_;
+
+ if (@_ != 2) {
+ die "$prog $op: must have two arguments\n";
+ }
+ link ($old, $new) ||
+ die "$prog $op: failed to link $new to $old: $!\n";
+}
+
+
+# @echo "$@ \\" > ${BLDDIR}/$(notdir $@)
+# @if ($(DEPEND)) >> $(BLDDIR)/$(notdir $@); then \
+# exit 0; \
+# else \
+# rm -f ${BLDDIR}/$(notdir $@); \
+# exit 1; \
+# fi
+
+# $(MAKEDEP) "$@" "$(BLDDIR)/$(notdir $@)" "$(DEPEND)"
+
+sub mktool_makedep
+{
+ my ($source, $target, $cmd, $curdir) = @_;
+ my @result = `$cmd`;
+ my $sdk = $ENV{'SDK'};
+ my $count;
+ my $tmp;
+ local $resultant;
+
+## Comman $cmd
+#Command $cmd
+print <<MKTOOL;
+
+mktool.pl::
+curdir $curdir
+
+MKTOOL
+
+ # derive the path to the target
+ $curdir = "$sdk/$curdir";
+
+ # save the basename
+ $dirName = substr($target,0,rindex($target,"\/"));
+
+ # prepare the top line of the %.d file
+ $resultant="$source \\\n\${BLDDIR}/";
+ if(!$?)
+ {
+ foreach $line (@result)
+ {
+ $line =~ s/^#.*\n//g; # some makedeps produce comments
+ $line =~ s/\n+$//; # toss trailing newlines
+ $line =~ s/(\s+)(\.\/)/ /g; # remove leading ./
+
+ # insert SDK path before ../
+ $line =~ s/(\s+)(\.\.\/)/${1}$curdir\/${2}/g;
+
+ # insert SDK path
+ $line =~ s/(\s+)(\w+)/${1}$curdir\/${2}/g;
+
+ $count=0;
+ $tmp=$line;
+ while( (index($line,"..")>-1) & ($count < 20) )
+ {
+ $line=~s/\/\w+\/\.\.//;
+ # if we hit a major recursion, revert the line, report
+ # this to the output and drop out of the loop, but do
+ # continue, this should not halt generation
+ if($count++>19)
+ {
+ print "mktool.pl: could not process $line \n\n";
+ print ":: curdir $curdir\n";
+ print ":: target $target\n";
+ print ":: cmd $cmd\n";
+ $line=$tmp;
+ }
+ }
+
+ # set all the paths to use the $SDK variable
+ $line =~ s/$ENV{'SDK'}/\$\{SDK\}/g;
+ $resultant=$resultant . $line;
+ }
+
+ # some compilers return extra newlines
+ $resultant=~s/\n//g;
+
+ # now clean up the result
+ $resultant=~s/\\/\\\n/g;
+
+ mktool_md($dirName) unless (-d $dirName);
+ open (TARGET, ">$target") ||
+ die("$prog $op: cannot open '$target' for writing: $!\n");
+ print TARGET "$resultant\n";
+ close(TARGET);
+ }
+}
+
+sub mktool_echo
+{
+ print "@_\n";
+}
+
+sub mktool_beep
+{
+ -t STDOUT && defined $ENV{MAKEBEEP} && print "\007";
+}