sonic-buildimage/platform/broadcom/saibcm-modules/systems/bde/linux/kernel/linux-kernel-bde.c

5210 lines
168 KiB
C
Raw Normal View History

/*
* Copyright 2017 Broadcom
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation (the "GPL").
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 (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 <linux/version.h>
#include "linux_shbde.h"
#ifdef BCM_ROBO_SUPPORT
/* robo/et related header files */
#include <shared/et/typedefs.h>
#include <shared/et/sbconfig.h>
#if defined(KEYSTONE)
#include <shared/et/aiutils.h>
#include <sbchipc.h>
#include <etc_robo_spi.h>
#include <soc/gmac0_core.h>
#elif defined(IPROC_CMICD)
#include <shared/et/aiutils.h>
#include <sbchipc.h>
#ifdef BCM_STARFIGHTER3_SUPPORT
#include <robo_spi.h>
#endif
#include <robo_srab.h>
#include <soc/nsgmac2reg.h>
#else /* BCM4704 */
#include <shared/et/sbutils.h>
#include <etc_robo.h>
#endif
#endif /* BCM_ROBO_SUPPORT */
#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)");
/*
* 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
/* local defined device IDs, refer to bcmdevs.h */
#ifndef BCM53000_GMAC_ID
#define BCM53000_GMAC_ID 0x4715 /* 53003 gmac id */
#endif
#ifndef BCM53010_GMAC_ID
#define BCM53010_GMAC_ID 0x4715 /* 5301x gmac id */
#endif
#ifndef BCM47XX_ENET_ID
#define BCM47XX_ENET_ID 0x4713 /* 4710 enet */
#endif
#ifndef BCM53010_CHIP_ID
#define BCM53010_CHIP_ID 0xcf12 /* 53010 chipcommon chipid */
#endif
#ifndef BCM53018_CHIP_ID
#define BCM53018_CHIP_ID 0xcf1a /* 53018 chipcommon chipid */
#endif
#ifndef BCM53020_CHIP_ID
#define BCM53020_CHIP_ID 0xcf1e /* 53020 chipcommon chipid */
#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
#if defined(BCM_EA_SUPPORT)
#if defined(BCM_TK371X_SUPPORT)
static int eadevices;
LKM_MOD_PARAM(eadevices, "i", int, 0);
MODULE_PARM_DESC(eadevices,
"Number of TK371X devices");
#endif /* */
#endif /* BCM_EA_SUPPORT */
/* 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,31))
#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
#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;
static int robo_switch = 0;
#define VALID_DEVICE(_n) ((_n >= 0) && (_n < _ndevices))
/* CPU MMIO area used with CPU cards provided on demo boards */
#if (defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT)) && (defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_GTO_BCM_CPU__))
static void *cpu_address = NULL;
#endif
#ifdef BCM_ROBO_SUPPORT
/* for SPI access via bcm4710 core */
static void *robo = NULL;
static void *sbh = NULL;
#ifdef ALTA_ROBO_SPI
extern void *alta_eth_spi_ctrl;
extern int
robo_spi_read(void *cookie, uint16_t reg, uint8_t *buf, int len);
extern int
robo_spi_write(void *cookie, uint16_t reg, uint8_t *buf, int len);
#define ROBO_RREG(_robo, _dev, _page, _reg, _buf, _len) \
robo_spi_read(_dev ? NULL : alta_eth_spi_ctrl, \
(_page << 8) | (_reg), _buf, _len)
#define ROBO_WREG(_robo, _dev, _page, _reg, _buf, _len) \
robo_spi_write(_dev ? NULL : alta_eth_spi_ctrl, \
(_page << 8) | (_reg), _buf, _len)
#else /* !ALTA_ROBO_SPI */
#if defined(KEYSTONE) || defined(IPROC_CMICD)
#define ROBO_RREG(_robo, _dev, _page, _reg, _buf, _len) \
robo_rreg(_robo, _dev, _page, _reg, _buf, _len)
#define ROBO_WREG(_robo, _dev, _page, _reg, _buf, _len) \
robo_wreg(_robo, _dev, _page, _reg, _buf, _len)
#else
#define ROBO_RREG(_robo, _dev, _page, _reg, _buf, _len)
#define ROBO_WREG(_robo, _dev, _page, _reg, _buf, _len)
#endif
#endif /* ALTA_ROBO_SPI */
#endif /* BCM_ROBO_SUPPORT */
/* 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
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)
{
/*
* In order to be backward compatible with the user mode BDE
* (specifically the interrupt IOCTLs) and the CM, switch devices
* *must* come first. If this is not the case (due to the probing
* order), we let the non-switch device(s) drop down to the end of
* the device array.
*/
if (_switch_ndevices > 0) {
bde_ctrl_t tmp_dev;
int i, s = 0;
while (s < _switch_ndevices) {
if (_devices[s].dev_type & BDE_SWITCH_DEV_TYPE) {
s++;
continue;
}
tmp_dev = _devices[s];
for (i = s; i < _ndevices - 1; i++) {
_devices[i] = _devices[i+1];
}
_devices[i] = tmp_dev;
}
}
/* Initialize device locks and dma */
if (_ndevices > 0) {
spin_lock_init(&_devices[_ndevices-1].lock);
_dma_init(robo_switch, _ndevices-1);
}
}
static int
_eb_device_create(resource_size_t paddr, int irq, int rd_hw, int wr_hw)
{
bde_ctrl_t *ctrl;
uint32 dev_rev_id = 0x0, dev_id;
dev_id = _ndevices;
ctrl = _devices + _ndevices++;
_switch_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;
_bde_add_device();
gprintk("Created EB device at BA=%x IRQ=%d RD16=%d WR16=%d device=0x%x\n",
(unsigned int)paddr, irq, rd_hw, wr_hw, ctrl->bde_dev.device);
return 0;
}
#if defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_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__
_switch_ndevices++;
_ndevices++;
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
#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 void iproc_platform_driver_register(struct platform_driver *drv);
extern void iproc_platform_driver_unregister(struct platform_driver *drv);
extern void iproc_platform_device_register(struct platform_device *drv);
extern 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"
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++;
_switch_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;
/* Read switch device ID from CMIC */
dev_rev_id = *((uint32_t*)(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
#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]);
}
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 = "brcm,iproc-cmicd" },
{},
};
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) {
case BCM53010_CHIP_ID:
case BCM53018_CHIP_ID:
case BCM53020_CHIP_ID:
return 0;
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=%x, cmicd_mem.end=%x\n",
found_cmicd_dev ? "EROM" : "Default",
iproc_cmicd_resources[IPROC_CMICD_RES_MEM].start,
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++;
_switch_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;
_bde_add_device();
printk("Created ICS device ..%x\n", ctrl->bde_dev.base_address);
}
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, BCM56613_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, BCM88230_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
{ BROADCOM_VENDOR_ID, BCM88030_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
{ BROADCOM_VENDOR_ID, BCM88034_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
{ BROADCOM_VENDOR_ID, BCM88039_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
{ BROADCOM_VENDOR_ID, BCM88231_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
{ BROADCOM_VENDOR_ID, BCM88235_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
{ BROADCOM_VENDOR_ID, BCM88236_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
{ BROADCOM_VENDOR_ID, BCM88239_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, 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 },
#ifdef BCM_ROBO_SUPPORT
{ BROADCOM_VENDOR_ID, BCM47XX_ENET_ID, PCI_ANY_ID, PCI_ANY_ID },
#ifdef KEYSTONE
{ BROADCOM_VENDOR_ID, BCM53000_GMAC_ID, PCI_ANY_ID, PCI_ANY_ID },
#endif
#endif
{ SANDBURST_VENDOR_ID, QE2000_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
{ SANDBURST_VENDOR_ID, BCM88020_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
{ SANDBURST_VENDOR_ID, BCM88025_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, 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, BCM88690_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_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, BCM56980_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
{ BROADCOM_VENDOR_ID, BCM56873_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;
}
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)*ret, GFP_KERNEL);
if (!ctrl->entries) {
goto er_intx;
}
/* We need only that much interrupt vecotrs */
ctrl->msix_cnt = ret/4;
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;
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;
ret = pci_enable_msix(ctrl->pci_device,
ctrl->entries, ctrl->msix_cnt);
if (ret != 0)
goto er_intx_free;
} else if (ret < 0) {
/* Error */
goto er_intx_free;
} else {
gprintk("Enabled MSI-X interrupts = %d\n", ctrl->msix_cnt);
}
}
#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/MSIC 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) {
pci_disable_msix(ctrl->pci_device);
kfree(ctrl->entries);
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(bde_ctrl_t *ctrl)
{
#ifdef CONFIG_PCI_MSI
int ret;
ctrl->use_msi = use_msi;
if (unlikely(debug > 1))
gprintk("%s: msi = %d\n", __func__, ctrl->use_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\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;
uint32 gmac_base = 0;
int plx_dev = 0;
int eth_dev = 0;
int cpu_dev = 0;
int update_devid = 0;
int paxb_core = 0;
int 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;
#if defined (BCM_ROBO_SUPPORT) && defined(KEYSTONE)
case BCM53000_GMAC_ID:
eth_dev = 1;
gmac_base = SB_ENUM_BASE;
break;
#endif
#if defined (BCM_ROBO_SUPPORT)
case BCM47XX_ENET_ID:
eth_dev = 1;
break;
#endif
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++;
_ether_ndevices++;
ctrl->dev_type |= BDE_ETHER_DEV_TYPE;
ctrl->iLine = dev->irq;
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++;
_cpu_ndevices++;
ctrl->dev_type |= BDE_CPU_DEV_TYPE;
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++;
_switch_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;
}
/* 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);
}
}
/* Each device follows global policy by default */
ctrl->use_msi = use_msi;
/* Check is MSI is properly supported in kernel for this device */
if (ctrl->use_msi) {
if (pci_enable_msi(ctrl->pci_device) == 0) {
/* Release MSI resources until interrupt_connect is called */
pci_disable_msi(ctrl->pci_device);
} else {
gprintk("Could not enable MSI interrupts\n");
ctrl->use_msi = 0;
}
}
/* configure interrupt type */
config_pci_intr_type(ctrl);
/* 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));
/*
* Since the GMAC driver of Robo chips needs access to the
* ChipCommon and Wrapper registers, we set the base address
* as the enumeration base address and its size as 3MB to
* cover all Wrapper register regions.
*/
if (gmac_base) {
uint32_t offset;
ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(gmac_base, 0x300000);
/* Record the base address of GMAC core */
offset = ctrl->phys_address - gmac_base;
ctrl->alt_base_addr = ctrl->bde_dev.base_address + offset;
ctrl->phys_address = gmac_base;
}
/*
* Workaround bug in FE2K A1 part; shows as A0 part in PCI config space,
* read the FE's regs directly to get the true revision
*/
if (ctrl->bde_dev.device == BCM88020_DEVICE_ID && ctrl->bde_dev.rev == 0) {
#define FE2000_REVISION_OFFSET (0x0)
uint32_t fe_rev;
fe_rev = *((uint32_t*)(ctrl->bde_dev.base_address + FE2000_REVISION_OFFSET));
if ((fe_rev >> 16) == BCM88020_DEVICE_ID) {
fe_rev &= 0xff;
} else {
fe_rev = (fe_rev >> 24) & 0xff;
}
ctrl->bde_dev.rev = fe_rev;
}
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");
}
#if defined (BCM_ROBO_SUPPORT) && !defined(ALTA_ROBO_SPI)
/* MDC/MDIO path for pseudo PHY access to ROBO register on BCM5836/4704 */
if (dev->device == BCM47XX_ENET_ID) {
((uint32 *)ctrl->bde_dev.base_address)[0x410 / 4] = 0;
}
#endif
#ifdef LINUX_BDE_DMA_DEVICE_SUPPORT
ctrl->dma_dev = &dev->dev;
#endif
if (!rescan) {
_bde_add_device();
}
if (debug >= 2) {
gprintk("_pci_probe: configured dev:0x%x rev:0x%x with base_addresses: 0x%lx 0x%lx\n",
(unsigned)ctrl->bde_dev.device, (unsigned)ctrl->bde_dev.rev,
(unsigned long)ctrl->bde_dev.base_address, (unsigned long)ctrl->bde_dev.base_address1);
}
/* 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->pci_device);
}
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++;
_switch_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);
}
}
#endif /* BCM_ICS */
#ifdef BCM_ROBO_SUPPORT
#ifdef KEYSTONE
#define DEFAULT_FREQ (SPI_FREQ_DEFAULT)
#define FREQ_20MHZ (SPI_FREQ_20MHZ)
#else /* IPROC_CMICD */
#define DEFAULT_FREQ (0)
#define FREQ_20MHZ (0)
#endif
/*
* The model_info /rev_info for Robo devices is defined like this:
*
* 31 28 27 24 23 20 19 16 15 8 7 0
* +----+---------+------+-----+---------+--------+
* | op | reserved| mask |len | page |offset |
* +----+---------+------+-----+---------+--------+
*
* op: 1:OR phyidl, 2: use PCIE device ID
* mlen: mask len (in bytes) 1:means 0xf,2 means 0xff
* len: Size of model/rev ID register (in bytes)
* page: Page containing model ID and revision registers
* offset: Model/rev ID register offset
*/
static struct bde_spi_device_id _spi_id_table[] = {
{ BCM53242_PHYID_HIGH, BCM53242_PHYID_LOW , 0, 0, DEFAULT_FREQ},
{ BCM53262_PHYID_HIGH, BCM53262_PHYID_LOW , 0, 0, DEFAULT_FREQ},
{ BCM53115_PHYID_HIGH, BCM53115_PHYID_LOW , 0, 0, DEFAULT_FREQ},
{ BCM53118_PHYID_HIGH, BCM53118_PHYID_LOW , 0, 0, DEFAULT_FREQ},
{ BCM53280_PHYID_HIGH, BCM53280_PHYID_LOW , 0x101800e8, 0, FREQ_20MHZ},
{ BCM53101_PHYID_HIGH, BCM53101_PHYID_LOW , 0, 0x110240, FREQ_20MHZ},
{ BCM53125_PHYID_HIGH, BCM53125_PHYID_LOW , 0, 0x110240, FREQ_20MHZ},
{ BCM53128_PHYID_HIGH, BCM53128_PHYID_LOW , 0, 0x110240, FREQ_20MHZ},
{ BCM53600_PHYID_HIGH, BCM53600_PHYID_LOW , 0x101800e8, 0, FREQ_20MHZ},
{ BCM89500_PHYID_HIGH, BCM89500_PHYID_LOW ,0x240230, 0x110240, FREQ_20MHZ},
{ BCM53010_PHYID_HIGH, BCM53010_PHYID_LOW ,0x240230, 0x110240, 0},
{ BCM53018_PHYID_HIGH, BCM53018_PHYID_LOW ,0x240230, 0x110240, 0},
{ BCM5389_PHYID_HIGH, BCM5389_PHYID_LOW, 0x110230, 0x110240, DEFAULT_FREQ},
{ BCM53020_PHYID_HIGH, BCM53020_PHYID_LOW ,0x20240230, 0x110240, 0},
{ BCM5396_PHYID_HIGH , BCM5396_PHYID_LOW, 0x110230, 0x110240, DEFAULT_FREQ},
{ BCM53134_PHYID_HIGH, BCM53134_PHYID_LOW , 0, 0x110240, DEFAULT_FREQ},
{ 0, 0, 0, 0, 0 },
};
#endif
#ifdef BCM_ROBO_SUPPORT
static int
_spi_device_valid_check(unsigned short phyidh,unsigned short phyidl, uint8 check_flag)
{
struct bde_spi_device_id *_ids;
int idx, match_idx;
match_idx = -1;
idx = 0;
if (check_flag == 0){
/* check_flag == 0 check phyidh only*/
for (_ids = _spi_id_table;
_ids->phyid_high && _ids->phyid_low; _ids++){
if (_ids->phyid_high == phyidh) {
return 0;
}
}
/* No valid SPI devices found */
return 1;
} else {
while(_spi_id_table[idx].phyid_high){
if (phyidh == _spi_id_table[idx].phyid_high &&
phyidl == _spi_id_table[idx].phyid_low) {
/* Found a match */
match_idx = idx;
break;
}
idx++;
}
return match_idx;
}
}
#if defined(IPROC_CMICD) || defined(KEYSTONE)
#define ROBO_ATTACH_AVAIL
#endif
#ifdef ROBO_ATTACH_AVAIL
#define SOC_ATTACH(_sc)\
ai_soc_kattach(_sc)
#if defined(IPROC_CMICD)
#ifdef BCM_STARFIGHTER3_SUPPORT
#define ROBO_ATTACH_SPI(_sih, _ss)\
robo_attach_spi(_sih)
#define ROBO_DETACH_SPI(robo)\
robo_detach_spi(robo)
#define ROBO_SPI_RREG(_robo, _dev, _page, _reg, _buf, _len) \
robo_spi_rreg(_robo, _dev, _page, _reg, _buf, _len)
#define ROBO_SPI_WREG(_robo, _dev, _page, _reg, _buf, _len) \
robo_spi_wreg(_robo, _dev, _page, _reg, _buf, _len)
#endif
#define ROBO_ATTACH(_sih, _ss)\
robo_attach(_sih)
#define MAX_BUSTYPE 1
#define ROBO_SWITCH_BUS(_robo, _bustype)
#define ROBO_SELECT_DEVICE(_robo, _phyidh, _phyidl)
#else /* KEYSTONE */
#define ROBO_ATTACH(_sih, _ss)\
robo_attach(_sih, _ss)
/* bustype 2: ROBO_MDCMDIO_BUS, 1: ROBO_SPI_BUS */
#define MAX_BUSTYPE 2
#define ROBO_SWITCH_BUS(_robo, _bustype)\
robo_switch_bus(_robo, _bustype)
#define ROBO_SELECT_DEVICE(_robo, _phyidh, _phyidl) \
robo_select_device(_robo, _phyidh, _phyidl)
#endif
#else
#define SOC_ATTACH(_sc) (NULL)
#define ROBO_ATTACH(_sih, _ss) (NULL)
#define MAX_BUSTYPE (0)
#define ROBO_SWITCH_BUS(_robo, _bustype)
#define ROBO_SELECT_DEVICE(_robo, _phyidh, _phyidl)
#endif
#if defined(IPROC_CMICD) && defined(BCM_STARFIGHTER3_SUPPORT)
static int
probe_robo_switch_iproc_spi(void)
{
int dev;
int max_devices, max_bustype;
uint8 buf[8];
unsigned short phyidh = 0, phyidl = 0;
/* Get Robo device handle */
if (robo == NULL) {
robo = (void *)ROBO_ATTACH_SPI(sbh, 0);
}
if (robo == NULL) {
return -ENODEV;
}
max_bustype = MAX_BUSTYPE + 1;
while(_spi_device_valid_check(phyidh, 0, 0)) {
max_bustype --;
if(!max_bustype)
return -ENODEV;
buf[0] = buf[1] = 0;
ROBO_SPI_RREG(robo, 0, 0x10, 0x04, buf, (uint)2);
phyidh = buf[0] | (buf[1] << 8);
/* re-try */
if ((phyidh == 0x0) || (phyidh == 0xffff)) {
ROBO_SPI_RREG(robo, 0, 0x10, 0x04, buf, (uint)2);
phyidh = buf[0] | (buf[1] << 8);
}
}
/* For psedo_phy access, only support one robo switch*/
/* For Northstar, only one switch on SRAB interface */
max_devices = (max_bustype == MAX_BUSTYPE) ? 1 : LINUX_BDE_MAX_SWITCH_DEVICES;
for (dev = 0; dev < max_devices; dev++) {
bde_ctrl_t *ctrl;
int match_idx, i;
unsigned short phyidl_nr; /* phyidl with revision stripped */
uint16 model_id;
uint8 rev_id;
uint32 addr, len;
uint32 mlen;
if (_switch_ndevices >= LINUX_BDE_MAX_SWITCH_DEVICES) {
break;
}
buf[0] = buf[1] = 0;
ROBO_SPI_RREG(robo, dev, 0x10, 0x04, buf, (uint)2);
phyidh = buf[0] | (buf[1] << 8);
buf[0] = buf[1] = 0;
ROBO_SPI_RREG(robo, dev, 0x10, 0x06, buf, (uint)2);
phyidl = buf[0] | (buf[1] << 8);
/* Strip revision */
phyidl_nr = phyidl & 0xfff0;
match_idx = _spi_device_valid_check(phyidh, phyidl_nr, 1);
if (match_idx == -1) {
if (debug >= 1) gprintk("found %d robo device(s).\n", robo_switch);
break;
}
model_id = phyidl_nr;
if(_spi_id_table[match_idx].rev_info){
addr = _spi_id_table[match_idx].rev_info & 0xffff;
len = (_spi_id_table[match_idx].rev_info >> 16) & 0xf;
ROBO_SPI_RREG(robo, dev, (addr >> 8), (addr & 0xff), buf, (uint)len);
mlen = (_spi_id_table[match_idx].rev_info >> 20) & 0xf;
rev_id = 0;
for (i = 0; i < mlen; i++)
rev_id |= buf[i] << (i << 3);
} else {
rev_id = phyidl & 0xf;
}
gprintk("found robo device with %d:%04x:%04x:%04x:%02x\n",
dev, phyidh, phyidl, model_id, rev_id);
ROBO_SELECT_DEVICE(robo, phyidh, phyidl);
/* Match supported chips */
ctrl = _devices + _ndevices++;
_switch_ndevices++;
if (NULL == (ctrl->spi_device = (struct spi_dev *)
KMALLOC(sizeof(struct spi_dev), GFP_KERNEL))) {
gprintk("no memory available");
return -ENOMEM;
}
ctrl->dev_type = (BDE_SPI_DEV_TYPE | BDE_SWITCH_DEV_TYPE);
ctrl->spi_device->cid = dev;
ctrl->spi_device->part = model_id;
ctrl->spi_device->rev = rev_id;
ctrl->spi_device->robo = robo;
ctrl->spi_device->phyid_high = phyidh;
ctrl->spi_device->phyid_low = phyidl;
ctrl->bde_dev.device = model_id;
ctrl->bde_dev.rev = rev_id;
ctrl->bde_dev.base_address = (sal_vaddr_t)NULL;
ctrl->isr = NULL;
ctrl->isr_data = NULL;
robo_switch++;
_bde_add_device();
}
return robo_switch;
}
int spi_device_found = 0;
#endif /* IPROC_CMICD || SF3 */
static int
probe_robo_switch(void)
{
int dev;
int max_devices, max_bustype;
uint8 buf[8];
unsigned short phyidh = 0, phyidl = 0;
#if defined(KEYSTONE)
uint32 spi_freq = 0;
#endif
#if defined(IPROC_CMICD)
sal_vaddr_t addr_base;
uint32 data_reg;
#endif /* IPROC_CMICD */
spin_lock_init(&bus_lock);
if (_switch_ndevices) {
/*
* Currently skip probe robo if esw chips were found
* FIX this while combined plateform support.
*/
return robo_switch;
}
/* Get Robo device handle */
if (robo == NULL) {
sbh = (void *)SOC_ATTACH(NULL);
if (sbh == NULL) {
return -ENODEV;
}
}
#if defined(IPROC_CMICD) && defined(BCM_STARFIGHTER3_SUPPORT)
robo_switch = probe_robo_switch_iproc_spi();
if (robo_switch > 0) {
/* Robo switch found by SPI probe */
spi_device_found = 1;
gprintk("SPI device found, Skipping SRAB probe\n");
return robo_switch;
} else {
gprintk("SPI device NOT found, Probe SRAB probe\n");
ROBO_DETACH_SPI(robo);
}
#endif
if (robo == NULL) {
robo = (void *)ROBO_ATTACH(sbh, 0);
}
if (robo == NULL) {
return -ENODEV;
}
max_bustype = MAX_BUSTYPE + 1;
while(_spi_device_valid_check(phyidh, 0, 0)) {
max_bustype --;
if(!max_bustype)
return -ENODEV;
ROBO_SWITCH_BUS(robo, max_bustype);
buf[0] = buf[1] = 0;
ROBO_RREG(robo, 0, 0x10, 0x04, buf, (uint)2);
phyidh = buf[0] | (buf[1] << 8);
/* re-try */
if ((phyidh == 0x0) || (phyidh == 0xffff)) {
ROBO_RREG(robo, 0, 0x10, 0x04, buf, (uint)2);
phyidh = buf[0] | (buf[1] << 8);
}
}
/* For psedo_phy access, only support one robo switch*/
/* For Northstar, only one switch on SRAB interface */
max_devices = (max_bustype == MAX_BUSTYPE) ? 1 : LINUX_BDE_MAX_SWITCH_DEVICES;
for (dev = 0; dev < max_devices; dev++) {
bde_ctrl_t *ctrl;
int match_idx, i;
unsigned short phyidl_nr; /* phyidl with revision stripped */
uint16 model_id;
uint8 rev_id;
#if defined(KEYSTONE) || defined(IPROC_CMICD)
uint32 addr, len;
#endif
uint32 mlen, op;
if (_switch_ndevices >= LINUX_BDE_MAX_SWITCH_DEVICES) {
break;
}
buf[0] = buf[1] = 0;
ROBO_RREG(robo, dev, 0x10, 0x04, buf, (uint)2);
phyidh = buf[0] | (buf[1] << 8);
buf[0] = buf[1] = 0;
ROBO_RREG(robo, dev, 0x10, 0x06, buf, (uint)2);
phyidl = buf[0] | (buf[1] << 8);
/* Strip revision */
phyidl_nr = phyidl & 0xfff0;
match_idx = _spi_device_valid_check(phyidh, phyidl_nr, 1);
if (match_idx == -1) {
if (debug >= 1) gprintk("found %d robo device(s).\n", robo_switch);
break;
}
if(_spi_id_table[match_idx].model_info){
#if defined(KEYSTONE) || defined(IPROC_CMICD)
addr = _spi_id_table[match_idx].model_info & 0xffff;
len = (_spi_id_table[match_idx].model_info >> 16) & 0xf;
#endif
ROBO_RREG(robo, dev, (addr >> 8), (addr & 0xff), buf, (uint)len);
mlen = (_spi_id_table[match_idx].model_info >> 20) & 0xf;
model_id = 0;
for (i = 0; i < mlen; i++)
model_id |= buf[i] << (i << 3);
op = (_spi_id_table[match_idx].model_info >> 28) & 0xf;
if(op == 1) {
model_id |= phyidl_nr;
#if defined(IPROC_CMICD)
} else if (op == 2) {
/* The package id of NS+ is determined by :
* Write 0 to 0x18012120 (PAXB_0_CONFIG_IND_ADDR)
* Read 0x18012124 (PAX_B_CONFIG_IND_DATA),
* bits 31:16 will be the device id from OTP space
*/
#define PAXB_ENUM_BASE (0x18012000)
#define PAXB_CONFIG_IND_ADDR_OFFSET (0x120)
#define PAXB_CONFIG_IND_DATA_OFFSET (0x124)
addr_base = (sal_vaddr_t)IOREMAP(PAXB_ENUM_BASE, 0x1000);
if (!addr_base) {
gprintk("ioremap of PAXB registers failed\n");
} else {
writel(0x0, (uint32 *)(addr_base +
PAXB_CONFIG_IND_ADDR_OFFSET));
data_reg = readl((uint32 *)(addr_base +
PAXB_CONFIG_IND_DATA_OFFSET));
model_id = (data_reg >> 16);
iounmap((void *)addr_base);
/*
* Some model ID can't be determined by PCIE device ID
* It needs to refer some OTP values.
*/
robo_model_id_adjust_from_otp(robo, &model_id);
}
#undef PAXB_ENUM_BASE
#undef PAXB_CONFIG_IND_ADDR_OFFSET
#undef PAXB_CONFIG_IND_DATA_OFFSET
#endif /* IPROC_CMICD */
}
} else {
model_id = phyidl_nr;
}
if(_spi_id_table[match_idx].rev_info){
#if defined(KEYSTONE) || defined(IPROC_CMICD)
addr = _spi_id_table[match_idx].rev_info & 0xffff;
len = (_spi_id_table[match_idx].rev_info >> 16) & 0xf;
#endif
ROBO_RREG(robo, dev, (addr >> 8), (addr & 0xff), buf, (uint)len);
mlen = (_spi_id_table[match_idx].rev_info >> 20) & 0xf;
rev_id = 0;
for (i = 0; i < mlen; i++)
rev_id |= buf[i] << (i << 3);
} else {
rev_id = phyidl & 0xf;
}
gprintk("found robo device with %d:%04x:%04x:%04x:%02x\n",
dev, phyidh, phyidl, model_id, rev_id);
ROBO_SELECT_DEVICE(robo, phyidh, phyidl);
/* Match supported chips */
ctrl = _devices + _ndevices++;
_switch_ndevices++;
if (NULL == (ctrl->spi_device = (struct spi_dev *)
KMALLOC(sizeof(struct spi_dev), GFP_KERNEL))) {
gprintk("no memory available");
return -ENOMEM;
}
ctrl->dev_type = (BDE_SPI_DEV_TYPE | BDE_SWITCH_DEV_TYPE);
ctrl->spi_device->cid = dev;
ctrl->spi_device->part = model_id;
ctrl->spi_device->rev = rev_id;
ctrl->spi_device->robo = robo;
ctrl->spi_device->phyid_high = phyidh;
ctrl->spi_device->phyid_low = phyidl;
ctrl->bde_dev.device = model_id;
ctrl->bde_dev.rev = rev_id;
ctrl->bde_dev.base_address = (sal_vaddr_t)NULL;
ctrl->isr = NULL;
ctrl->isr_data = NULL;
robo_switch++;
#if defined(KEYSTONE)
spi_freq = _spi_id_table[match_idx].spifreq;
#endif
_bde_add_device();
}
#if defined(KEYSTONE)
/* Override the SPI frequency from user configuration */
if (spifreq != 0) {
spi_freq = spifreq;
}
if (spi_freq != 0) {
/*
* The underlying chip can support the SPI frequency
* higher than default (2MHz).
*/
if (spi_freq != SPI_FREQ_DEFAULT) {
chipc_spi_set_freq(robo, 0, spi_freq);
}
}
#endif
return robo_switch;
}
#endif
#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++;
_switch_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_METROCORE_LOCAL_BUS
/*
* SBX platform has both PCI- and local bus-attached devices
* The local bus devices have fixed address ranges (and don't
* support or require DMA), but are otherwise the same as PCI devices
*/
#define FPGA_IRQ 37
#define FPGA_PHYS 0x100E0000
#define BME_PHYS 0x100C0000
#define SE_PHYS 0x100D0000
#define FPGA_SIZE 0x00004000
#define BME_SIZE 0x00004000
#define MAC0_PHYS 0x100B0000
#define MAC1_PHYS 0x100B8000
#define MAC_SIZE 0x800
/*
* Please refer to "Supervisor Fabric Module (SFM) Specification"
* page 23 for the following registers.
*/
#define FPGA_LC_POWER_DISABLE_OFFSET 0x4
#define FPGA_LC_POWER_DISABLE_ENABLE_ALL_MASK 0x1e
#define FPGA_LC_POWER_RESET_OFFSET 0x5
#define FPGA_LC_POWER_RESET_ENABLE_ALL_MASK 0x1e
#define FPGA_SW_SFM_MASTER_MODE_OFFSET 0x14
#define FPGA_SW_SFM_MASTER_MODE_ENABLE_MASK 0x10
static int
probe_metrocore_local_bus(void) {
bde_ctrl_t *ctrl;
uint32_t dev_rev_id;
VOL uint8_t *fpga;
/*
* Write the FPGA on the fabric card, to let metrocore
* line cards out of reset. We actually don't bother to determine whether
* the card is a line card or a fabric card because when we do
* this on the line cards, it has no effect.
*/
fpga = (uint8_t *) IOREMAP(FPGA_PHYS, FPGA_SIZE);
fpga[FPGA_SW_SFM_MASTER_MODE_OFFSET]
|= FPGA_SW_SFM_MASTER_MODE_ENABLE_MASK;
fpga[FPGA_LC_POWER_DISABLE_OFFSET]
|= FPGA_LC_POWER_DISABLE_ENABLE_ALL_MASK;
fpga[FPGA_LC_POWER_RESET_OFFSET]
|= FPGA_LC_POWER_RESET_ENABLE_ALL_MASK;
ctrl = map_local_bus(BME_PHYS, BME_SIZE);
dev_rev_id =
*((uint32_t *)
(((uint8_t *) ctrl->bde_dev.base_address) + BME_REVISION_OFFSET));
ctrl->bde_dev.device = dev_rev_id >> 16;
ctrl->bde_dev.rev = (dev_rev_id & 0xFF);
if ((ctrl->bde_dev.device != BME3200_DEVICE_ID) &&
(ctrl->bde_dev.device != BCM88130_DEVICE_ID)) {
gprintk("probe_metrocore_local_bus: wrong BME type: "
"0x%x (vs 0x%x or 0x%x)\n",
ctrl->bde_dev.device, BME3200_DEVICE_ID, BCM88130_DEVICE_ID);
return -1;
}
ctrl->iLine = FPGA_IRQ;
ctrl->isr = NULL;
ctrl->isr_data = NULL;
/*
* <BME-- 64k --><SE -- 64k --><FPGA -- 64k -->
* We start from SE & include the FPGA, which is 128k
*/
ctrl = map_local_bus(SE_PHYS, 128 * 1024);
dev_rev_id =
*((uint32_t *)
(((uint8_t *) ctrl->bde_dev.base_address) + BME_REVISION_OFFSET));
ctrl->bde_dev.device = dev_rev_id >> 16;
ctrl->bde_dev.rev = (dev_rev_id & 0xFF);
if ((ctrl->bde_dev.device != BME3200_DEVICE_ID) &&
(ctrl->bde_dev.device != BCM88130_DEVICE_ID)) {
gprintk("probe_metrocore_local_bus: wrong SE (BME) type: "
"0x%x (vs 0x%x)\n",
ctrl->bde_dev.device, BME3200_DEVICE_ID);
return -1;
}
ctrl->iLine = FPGA_IRQ;
ctrl->isr = NULL;
ctrl->isr_data = NULL;
return 0;
}
#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++;
_switch_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) {
case BCM88130_DEVICE_ID:
case BME3200_DEVICE_ID:
break;
default:
gprintk("wrong BME type: 0x%x (vs 0x%x or 0x%x)\n",
ctrl->bde_dev.device, BME3200_DEVICE_ID, BCM88130_DEVICE_ID);
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 */
#if defined(BCM_EA_SUPPORT)
#if defined(BCM_TK371X_SUPPORT)
static void
probe_tk371x_dev(void)
{
bde_ctrl_t *ctrl;
int ea_uid=0;
/* eadevices is from the argument of insmod */
for (ea_uid = 0; ea_uid < eadevices; ea_uid++) {
ctrl = _devices + _ndevices++;
_switch_ndevices++;
ctrl->dev_type = (BDE_MII_DEV_TYPE | BDE_SWITCH_DEV_TYPE);
ctrl->bde_dev.device = TK371X_DEVICE_ID;
ctrl->bde_dev.rev = 0x0;
ctrl->bde_dev.base_address = (sal_vaddr_t)NULL;
ctrl->iLine = 0;
}
}
#endif /* BCM_TK371X_SUPPORT*/
#endif /* BCM_EA_SUPPORT */
#if defined(BCM_ROBO_SUPPORT)
#if defined(IPROC_CMICD)
struct chip_device_info {
uint32 cc_base; /* Chip-common register base */
uint32 cc_size; /* Chip-common register limit */
uint32 cid_reg_off; /* Chip id register offset */
};
static struct chip_device_info _chip_table = {
#if defined(IPROC_CMICD)
0x18000000, 0x00000300, 0x00000000
#else
0,0,0
#endif
};
struct gmac_device_info {
uint32 cid; /* chip id */
uint32 rid; /* revision id */
uint32 pid; /* package id */
uint32 gmac_dev_id; /* gmac core device id */
uint32 gmac_base_addr; /* gmac core base address */
int gmac_irq; /* gmac irq number */
};
static struct gmac_device_info _gmac_table[] = {
#if defined(IPROC_CMICD)
{BCM53010_CHIP_ID, 0, 0, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53012 */
{BCM53010_CHIP_ID, 0, 2, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53011 */
{BCM53010_CHIP_ID, 0, 1, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53010 */
{BCM53018_CHIP_ID, 0, 0, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53018 */
{BCM53018_CHIP_ID, 0, 2, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53017 */
{BCM53018_CHIP_ID, 0, 1, BCM53010_GMAC_ID, 0x18026000, 181}, /* BCM53019 */
{BCM53020_CHIP_ID, 0, 0, BCM53010_GMAC_ID, 0x18024000, 181}, /* BCM53022 */
{BCM53020_CHIP_ID, 4, 0, BCM53010_GMAC_ID, 0x18023000, 180}, /* BCM53022 */
#endif
{0,0,0,0,0,0}
};
static sal_vaddr_t _cca_base = 0;
static int
_gmac_dev_create(void)
{
bde_ctrl_t *ctrl;
uint32 gmac_base = 0;
uint32 offset = 0;
uint32 cca_cid;
uint32 cid, rid, pid;
int i = 0, found;
if (_chip_table.cc_base == 0) {
gprintk("Create GMAC device failed. Unable to identify CPU.\n");
return -1;
}
/* 1. Determine which CPU/GMAC configuration is now */
_cca_base = (sal_vaddr_t)IOREMAP(_chip_table.cc_base, _chip_table.cc_size);
cca_cid = readl((uint32 *)(_cca_base + _chip_table.cid_reg_off));
cid = cca_cid & CID_ID_MASK;
rid = (cca_cid & CID_REV_MASK) >> CID_REV_SHIFT;
pid = (cca_cid & CID_PKG_MASK) >> CID_PKG_SHIFT;
found = 0;
for (i = 0; ; i++) {
if (_gmac_table[i].cid == 0) {
/* End of table */
break;
}
if ((_gmac_table[i].cid == cid) &&
(_gmac_table[i].rid == rid) &&
(_gmac_table[i].pid == pid)) {
/* found */
found = 1;
break;
}
}
if (!found) {
gprintk("Create GMAC device failed. Unable to identify GMAC device.\n");
}
/* 2. Create GMAC device */
/* fill-in necessary information depends on the CPU/GMAC configuration */
if ((cid == BCM53010_CHIP_ID) || (cid == BCM53018_CHIP_ID) ||
(cid == BCM53020_CHIP_ID)) {
ctrl = _devices + _ndevices++;
_ether_ndevices++;
ctrl->dev_type |= BDE_ETHER_DEV_TYPE;
ctrl->dev_type |= BDE_PCI_DEV_TYPE;
ctrl->iLine = _gmac_table[i].gmac_irq;
ctrl->be_pio = 0;
ctrl->bde_dev.rev = _gmac_table[i].rid;
ctrl->bde_dev.device = _gmac_table[i].gmac_dev_id;
gmac_base = 0x18000000;
offset = _gmac_table[i].gmac_base_addr - gmac_base;
ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(gmac_base, 0x300000);
ctrl->alt_base_addr = ctrl->bde_dev.base_address + offset;
ctrl->phys_address = gmac_base;
ctrl->isr = NULL;
ctrl->isr_data = NULL;
}
return 0;
}
#endif
#endif
/*
* 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
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;
#if defined(BCM_ROBO_SUPPORT)
#if defined(IPROC_CMICD)
if (_gmac_dev_create()) {
return -ENODEV;
}
#endif
#endif /* defined (BCM_ROBO_SUPPORT) */
/* 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_ROBO_SUPPORT
probe_robo_switch();
#endif
#if defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT)
sand_device_create();
#endif
#if defined(BCM_TK371X_SUPPORT)
probe_tk371x_dev();
#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
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
#if defined(BCM_ROBO_SUPPORT)
#if defined(IPROC_CMICD)
if (_cca_base) {
iounmap((void *)_cca_base);
}
#endif
if (robo) {
#if defined(KEYSTONE) || defined(IPROC_CMICD)
robo_detach(robo);
#endif /* KEYSTONE || IPROC_CMICD */
}
if (sbh) {
#if defined(KEYSTONE) || defined(IPROC_CMICD)
ai_soc_detach(sbh);
#endif /* KEYSTONE || IPROC_CMICD */
}
#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_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_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 0x%x:0x%x:%d:0x%.8lx:0x%.8lx:%d%s\n",
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;
}
#if USE_LINUX_BDE_MMAP
/*
* Some kernels (mainly x86) prevent mapping of kernel RAM memory to
* user space via the /dev/mem device. The function below provides a
* backdoor to mapping the DMA pool to user space via the
* /dev/linux-kernel-bde device.
*/
static int _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(!_dma_range_valid(phys_addr, size)) {
return -EINVAL;
}
#ifdef REMAP_DMA_NONCACHED
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
#endif
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;
}
#endif /* USE_LINUX_BDE_MMAP */
/* 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,
#if USE_LINUX_BDE_MMAP
mmap: _mmap,
#endif
};
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++) {
ret = request_irq(ctrl->entries[i].vector, _isr,
irq_flags, LINUX_KERNEL_BDE_NAME, ctrl);
if (ret < 0)
break;
}
if (ret < 0) {
while (i >= 0)
free_irq(ctrl->entries[i--].vector, ctrl->pci_device);
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++)
free_irq(ctrl->entries[i].vector, ctrl->pci_device);
}
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) {
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) {
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_ROBO_SUPPORT
#define SOC_ROBO_PAGE_BP 8 /* for Robo Chip only */
#if defined(IPROC_CMICD)
extern int ccb_mii_read(int dev_type, int phy_addr, int reg_off, uint16 *data);
extern int ccb_mii_write(int dev_type, int phy_addr, int reg_off, uint16 data);
/* device type */
#define MII_DEV_LOCAL 0
#define MII_DEV_EXT 1
#endif
static int
_spi_read(int d, uint32 addr, uint8 *buf, int len)
{
#if defined(KEYSTONE) || defined(IPROC_CMICD)
bde_ctrl_t *ctrl;
uint8 page, offset;
#endif
#if defined(IPROC_CMICD)
int rv = 0;
uint16 value = 0;
#endif
if (!VALID_DEVICE(d)) {
return -1;
}
if (!(_devices[d].dev_type & BDE_SPI_DEV_TYPE)) {
gprintk("_spi_read: Not SPI device %d, type %x\n",
d, _devices[d].dev_type);
return -1;
}
#if defined(KEYSTONE) || defined(IPROC_CMICD)
ctrl = _devices + d;
#endif
#if defined(IPROC_CMICD)
if (addr & SOC_EXTERNAL_PHY_BUS_CPUMDIO) {
rv = ccb_mii_read(MII_DEV_EXT, (addr >> 8) & 0xff, addr & 0xff, &value);
memcpy(buf, &value, 2);
return rv;
}
#endif
#if defined(KEYSTONE) || defined(IPROC_CMICD)
page = (addr >> SOC_ROBO_PAGE_BP) & 0xFF;
offset = addr & 0xFF;
#endif
#if defined(IPROC_CMICD) && defined(BCM_STARFIGHTER3_SUPPORT)
if (spi_device_found) {
ROBO_SPI_RREG(ctrl->spi_device->robo, ctrl->spi_device->cid,
page, offset, buf, (uint)len);
} else
#endif
{
ROBO_RREG(ctrl->spi_device->robo, ctrl->spi_device->cid,
page, offset, buf, (uint)len);
}
return 0;
}
static int
_spi_write(int d, uint32 addr, uint8 *buf, int len)
{
#if defined(KEYSTONE) || defined(IPROC_CMICD)
bde_ctrl_t *ctrl;
uint8 page, offset;
#endif
#if defined(IPROC_CMICD)
int rv = 0;
uint16 value = 0;
#endif
if (!VALID_DEVICE(d)) {
return -1;
}
if (!(_devices[d].dev_type & BDE_SPI_DEV_TYPE)) {
gprintk("_spi_write: Not SPI device %d, type %x\n",
d, _devices[d].dev_type);
return -1;
}
#if defined(KEYSTONE) || defined(IPROC_CMICD)
ctrl = _devices + d;
#endif
#if defined(IPROC_CMICD)
if (addr & SOC_EXTERNAL_PHY_BUS_CPUMDIO) {
memcpy(&value, buf, 2);
rv = ccb_mii_write(MII_DEV_EXT, (addr >> 8) & 0xff, addr & 0xff, value);
return rv;
}
#endif
#if defined(KEYSTONE) || defined(IPROC_CMICD)
page = (addr >> SOC_ROBO_PAGE_BP) & 0xFF;
offset = addr & 0xFF;
#endif
#if defined(IPROC_CMICD) && defined(BCM_STARFIGHTER3_SUPPORT)
if (spi_device_found) {
ROBO_SPI_WREG(ctrl->spi_device->robo, ctrl->spi_device->cid,
page, offset, buf, (uint)len);
} else
#endif
{
ROBO_WREG(ctrl->spi_device->robo, ctrl->spi_device->cid,
page, offset, buf, (uint)len);
}
return 0;
}
#endif
#if defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_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 BCM88690_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 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;
}
/* 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 /* defined(BCM_PETRA_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,
#if defined(BCM_ROBO_SUPPORT)
spi_read: _spi_read,
spi_write: _spi_write,
#else
NULL,
NULL,
#endif /* defined(BCM_ROBO_SUPPORT) */
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);
#if (defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT))
LKM_EXPORT_SYM(lkbde_cpu_write);
LKM_EXPORT_SYM(lkbde_cpu_read);
LKM_EXPORT_SYM(lkbde_cpu_pci_register);
#endif