openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

linux-user-bde.c (46025B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * Linux User BDE Helper Module
      8  */
      9 #include <gmodule.h>
     10 #include <mpool.h>
     11 #include <linux-bde.h>
     12 
     13 #include <sal/core/thread.h>
     14 #include <sal/core/sync.h>
     15 #include <soc/devids.h>
     16 #include <soc/drv.h>
     17 
     18 #include "linux-user-bde.h"
     19 
     20 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0)
     21 #include <linux/uaccess.h>
     22 #endif
     23 
     24 
     25 MODULE_AUTHOR("Broadcom Corporation");
     26 MODULE_DESCRIPTION("User BDE Helper Module");
     27 MODULE_LICENSE("Proprietary");
     28 
     29 /* CMIC/CMICe defines */
     30 #define CMIC_IRQ_STAT                   0x00000144
     31 #define CMIC_IRQ_MASK                   0x00000148
     32 #define CMIC_IRQ_MASK_1                 0x0000006C
     33 #define CMIC_IRQ_MASK_2                 0x00000070
     34 
     35 /* CMICm defines */
     36 #define CMIC_CMCx_IRQ_STAT0_OFFSET(x)                    (0x31400 + (0x1000 * x))
     37 #define CMIC_CMCx_IRQ_STAT1_OFFSET(x)                    (0x31404 + (0x1000 * x))
     38 #define CMIC_CMCx_IRQ_STAT2_OFFSET(x)                    (0x31408 + (0x1000 * x))
     39 #define CMIC_CMCx_IRQ_STAT3_OFFSET(x)                    (0x3140c + (0x1000 * x))
     40 #define CMIC_CMCx_IRQ_STAT4_OFFSET(x)                    (0x31410 + (0x1000 * x))
     41 
     42 #define CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(x)               (0x31414 + (0x1000 * x))
     43 #define CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(x)               (0x31418 + (0x1000 * x))
     44 #define CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(x)               (0x3141c + (0x1000 * x))
     45 #define CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(x)               (0x31420 + (0x1000 * x))
     46 #define CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(x)               (0x31424 + (0x1000 * x))
     47 
     48 /* CMICd defines */
     49 #define CMIC_CMCx_IRQ_STAT5_OFFSET(x)                    (0x314b0 + (0x1000 * x))
     50 #define CMIC_CMCx_IRQ_STAT6_OFFSET(x)                    (0x314b4 + (0x1000 * x))
     51 #define CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(x)               (0x314b8 + (0x1000 * x))
     52 #define CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(x)               (0x314bc + (0x1000 * x))
     53 #define CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(x)                (0x314c0 + (0x1000 * x))
     54 #define CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(x)                (0x314c4 + (0x1000 * x))
     55 
     56 #define CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(x)                (0x31428 + (0x1000 * x))
     57 #define CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(x)                (0x3142c + (0x1000 * x))
     58 #define CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(x)                (0x31430 + (0x1000 * x))
     59 #define CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(x)                (0x31434 + (0x1000 * x))
     60 #define CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(x)                (0x31438 + (0x1000 * x))
     61 
     62 /* CMICX defines */
     63 #define INTC_INTR_REG_NUM               (8)
     64 
     65 
     66 
     67 #define INTC_INTR_ENABLE_REG0          (0x180130f0)
     68 #define INTC_INTR_STATUS_REG0          (0x18013190)
     69 #define INTC_INTR_RAW_STATUS_REG0      (0x18013140)
     70 
     71 #define INTC_INTR_ENABLE_BASE           (INTC_INTR_ENABLE_REG0)
     72 #define INTC_INTR_STATUS_BASE           (INTC_INTR_STATUS_REG0)
     73 #define INTC_INTR_RAW_STATUS_BASE       (INTC_INTR_RAW_STATUS_REG0)
     74 
     75 #define HX5_INTC_INTR_ENABLE_REG0          (0x102310f0)
     76 #define HX5_INTC_INTR_STATUS_REG0          (0x10231190)
     77 #define HX5_INTC_INTR_RAW_STATUS_REG0      (0x10231140)
     78 
     79 #define HX5_INTC_INTR_ENABLE_BASE          (HX5_INTC_INTR_ENABLE_REG0)
     80 #define HX5_INTC_INTR_STATUS_BASE          (HX5_INTC_INTR_STATUS_REG0)
     81 #define HX5_INTC_INTR_RAW_STATUS_BASE      (HX5_INTC_INTR_RAW_STATUS_REG0)
     82 
     83 #define IOREMAP(addr, size)                ioremap_nocache(addr, size)
     84 
     85 #define HX5_IHOST_GICD_ISENABLERN_0        (0x10781100)
     86 #define HX5_IHOST_GICD_ISENABLERN_1        (0x10781104)
     87 #define HX5_IHOST_GICD_ICENABLERN_1        (0x10781184)
     88 #define HX5_IHOST_GICD_ICENABLERN_8        (0x107811a0)
     89 /* Offset between ISENABLERN_1 and ICENABLERN_1 in 4-bytes */
     90 #define HX5_IHOST_IRQ_MASK_OFFSET          0x20
     91 #define HX5_IHOST_INTR_MAP_NUM             (HX5_IHOST_GICD_ICENABLERN_8 - HX5_IHOST_GICD_ISENABLERN_0)
     92 #define HX5_IHOST_INTR_STATUS_MAP_NUM      (INTC_INTR_REG_NUM * (sizeof(uint32)))
     93 #define IRQ_BIT(intr)                      (intr % (sizeof(uint32)*8))
     94 #define IRQ_MASK_INDEX(intr)               (intr / (sizeof(uint32)*8))
     95 #define HX5_CHIP_INTR_LOW_PRIORITY         119
     96 #define INTR_LOW_PRIORITY_BITPOS           (1 << IRQ_BIT(HX5_CHIP_INTR_LOW_PRIORITY))
     97 #define INTC_LOW_PRIORITY_INTR_REG_IND     IRQ_MASK_INDEX(HX5_CHIP_INTR_LOW_PRIORITY)
     98 #define INTC_PDMA_INTR_REG_IND             4
     99 
    100 #define READ_INTC_INTR(d, reg, v) \
    101         (v = user_bde->iproc_read(d, reg))
    102 #define WRITE_INTC_INTR(d, reg, v) \
    103         (user_bde->iproc_write(d, reg, v))
    104 
    105 #define IHOST_READ_INTR(d, reg, v) \
    106         (v = readl((reg)))
    107 #define IHOST_WRITE_INTR(d, reg, v) \
    108         (writel((v), (reg)))
    109 
    110 /* Allow override of default CMICm CMC */
    111 #ifndef BDE_CMICM_PCIE_CMC
    112 #define BDE_CMICM_PCIE_CMC              0
    113 #endif
    114 
    115 /* Allow override of default CMICm CMC */
    116 #ifndef BDE_CMICD_PCIE_CMC
    117 #define BDE_CMICD_PCIE_CMC              0
    118 #endif
    119 
    120 /* Defines used to distinguish CMICe from CMICm */
    121 #define CMICE_DEV_REV_ID                (0x178 / sizeof(uint32))
    122 
    123 static uint32 *ihost_intr_status_base = NULL;
    124 static uint32 *ihost_intr_enable_base = NULL;
    125 
    126 static ibde_t *user_bde = NULL;
    127 
    128 typedef void (*isr_f)(void *);
    129 
    130 typedef struct bde_ctrl_s {
    131     uint32 dev_type;
    132     int irq;
    133     int enabled;
    134     int devid;
    135     isr_f isr;
    136     uint32 *ba;
    137     int inst;   /* associate to _bde_inst_resource[] */
    138 } bde_ctrl_t;
    139 
    140 #define VALID_DEVICE(_n) (_n < LINUX_BDE_MAX_DEVICES)
    141 
    142 static bde_ctrl_t _devices[LINUX_BDE_MAX_DEVICES];
    143 
    144 static wait_queue_head_t _ether_interrupt_wq;
    145 static atomic_t _ether_interrupt_has_taken_place = ATOMIC_INIT(0);
    146 
    147 /*
    148  * Multiple instance resource data structure.
    149  * To keep the DMA resource per instance.
    150  * And track the DMA pool usage.
    151  */
    152 static int _bde_multi_inst = 0;
    153 
    154 typedef struct {
    155     unsigned int    inst_id;
    156     unsigned int    dma_offset;
    157     unsigned int    dma_size;
    158     wait_queue_head_t intr_wq;
    159     atomic_t intr;
    160 } bde_inst_resource_t;
    161 
    162 static bde_inst_resource_t _bde_inst_resource[LINUX_BDE_MAX_DEVICES];
    163 
    164 typedef struct {
    165     phys_addr_t  cpu_pbase; /* CPU physical base address of the DMA pool */
    166     phys_addr_t  dma_pbase; /* Bus base address of the DMA pool */
    167     uint32  total_size; /* Total size of the pool in MB */
    168     uint32  offset; /* Current offset of the pool in MB */
    169 }_dma_pool_t;
    170 
    171 static _dma_pool_t _dma_pool;
    172 
    173 #define ONE_MB      (1024 * 1024)
    174 
    175 #ifdef KEYSTONE
    176 /*
    177  * Enforce PCIE transaction ordering. Commit the write transaction.
    178  */
    179 
    180 #define SSOC_WRITEL(val, addr)                  \
    181             do {                                \
    182                 writel((val), (addr));          \
    183                 __asm__ __volatile__("sync");   \
    184             } while(0)
    185 
    186 #else
    187 
    188 #define SSOC_WRITEL(val, addr) \
    189             writel((val), (addr))
    190 
    191 #endif
    192 /*
    193  * Function: _interrupt
    194  *
    195  * Purpose:
    196  *    Interrupt Handler.
    197  *    Mask all interrupts on device and wake up interrupt
    198  *    thread. It is assumed that the interrupt thread unmasks
    199  *    interrupts again when interrupt handling is complete.
    200  * Parameters:
    201  *    ctrl - BDE control structure for this device.
    202  * Returns:
    203  *    Nothing
    204  */
    205 static void 
    206 _cmic_interrupt(bde_ctrl_t *ctrl)
    207 {
    208     int d;
    209     uint32_t mask = 0, stat, imask = 0, fmask = 0;
    210     bde_inst_resource_t *res;
    211 
    212     d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
    213     res = &_bde_inst_resource[ctrl->inst];
    214 
    215     /* Check for secondary interrupt handler */
    216     if (lkbde_irq_mask_get(d, &mask, &fmask) < 0) {
    217         fmask = 0;
    218     }
    219 
    220     if (fmask != 0) {
    221         imask = mask & ~fmask;
    222         /* Check for pending user mode interrupts */
    223         stat = user_bde->read(d, CMIC_IRQ_STAT);
    224         if ((stat & imask) == 0) {
    225             /* All handled in kernel mode */
    226             lkbde_irq_mask_set(d, CMIC_IRQ_MASK, imask, 0);
    227             return;
    228         }
    229     }
    230 
    231     lkbde_irq_mask_set(d, CMIC_IRQ_MASK, 0, 0);
    232 
    233     atomic_set(&res->intr, 1);
    234 
    235 #ifdef BDE_LINUX_NON_INTERRUPTIBLE
    236     wake_up(&res->intr_wq);
    237 #else
    238     wake_up_interruptible(&res->intr_wq);
    239 #endif
    240 }
    241 
    242 static void 
    243 _cmicx_interrupt(bde_ctrl_t *ctrl)
    244 {
    245     int d, ind;
    246     uint32 stat, iena, mask, fmask;
    247     bde_inst_resource_t *res;
    248     uint32 intc_intr_status_base = 0, intc_intr_enable_base = 0;
    249 
    250     d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
    251     res = &_bde_inst_resource[ctrl->inst];
    252 
    253     lkbde_irq_mask_get(d, &mask, &fmask);
    254 
    255     if ((ctrl->dev_type & BDE_SWITCH_DEV_TYPE) &&
    256             ((user_bde->get_dev(d)->device == BCM56370_DEVICE_ID) ||
    257              (user_bde->get_dev(d)->device == BCM56371_DEVICE_ID) ||
    258              (user_bde->get_dev(d)->device == BCM56372_DEVICE_ID) ||
    259              (user_bde->get_dev(d)->device == BCM56374_DEVICE_ID) ||
    260              (user_bde->get_dev(d)->device == BCM56375_DEVICE_ID) ||
    261              (user_bde->get_dev(d)->device == BCM56376_DEVICE_ID) ||
    262              (user_bde->get_dev(d)->device == BCM56377_DEVICE_ID) ||
    263              (user_bde->get_dev(d)->device == BCM56577_DEVICE_ID) ||
    264              (user_bde->get_dev(d)->device == BCM56578_DEVICE_ID) ||
    265              (user_bde->get_dev(d)->device == BCM56579_DEVICE_ID))) {
    266         intc_intr_status_base = HX5_INTC_INTR_STATUS_BASE;
    267         intc_intr_enable_base = HX5_INTC_INTR_ENABLE_BASE;
    268     } else {
    269         intc_intr_status_base = INTC_INTR_STATUS_BASE;
    270         intc_intr_enable_base = INTC_INTR_ENABLE_BASE;
    271     }
    272     if (fmask) {
    273         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    274             IHOST_READ_INTR(d, ihost_intr_status_base + INTC_PDMA_INTR_REG_IND, stat);
    275             IHOST_READ_INTR(d, ihost_intr_enable_base + INTC_PDMA_INTR_REG_IND, iena);
    276         } else {
    277             READ_INTC_INTR(d, intc_intr_status_base + 4 * INTC_PDMA_INTR_REG_IND, stat);
    278             READ_INTC_INTR(d, intc_intr_enable_base + 4 * INTC_PDMA_INTR_REG_IND, iena);
    279         }
    280         if (stat & iena) {
    281             if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    282                 IHOST_WRITE_INTR(d, ihost_intr_enable_base + INTC_PDMA_INTR_REG_IND +
    283                     HX5_IHOST_IRQ_MASK_OFFSET, ~0);
    284             } else {
    285                 WRITE_INTC_INTR(d, intc_intr_enable_base + 4 * INTC_PDMA_INTR_REG_IND, 0);
    286             }
    287 
    288             for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) {
    289                 if (ind == INTC_PDMA_INTR_REG_IND) {
    290                     continue;
    291                 }
    292                 if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    293                     if (ind < INTC_LOW_PRIORITY_INTR_REG_IND) {
    294                         continue;
    295                     }
    296                     IHOST_READ_INTR(d, ihost_intr_status_base + ind, stat);
    297                     IHOST_READ_INTR(d, ihost_intr_enable_base + ind, iena);
    298                     if (ind == INTC_LOW_PRIORITY_INTR_REG_IND) {
    299                         stat &= INTR_LOW_PRIORITY_BITPOS;
    300                     }
    301                 } else {
    302                     READ_INTC_INTR(d, intc_intr_status_base + 4 * ind, stat);
    303                     READ_INTC_INTR(d, intc_intr_enable_base + 4 * ind, iena);
    304                 }
    305                 if (stat & iena) {
    306                     break;
    307                 }
    308             }
    309 
    310             if (ind >= INTC_INTR_REG_NUM) {
    311                 return;
    312             }
    313         }
    314     }
    315 
    316     /* Disable all interrupts.. Re-enable unserviced interrupts later
    317      * So as to avoid getting new interrupts until the user level driver
    318      * enumerates the interrupts to be serviced
    319      */
    320     for (ind = 0; ind < INTC_INTR_REG_NUM; ind++) {
    321         if (fmask && ind == INTC_PDMA_INTR_REG_IND) {
    322             continue;
    323         }
    324         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    325             if (ind < INTC_LOW_PRIORITY_INTR_REG_IND) {
    326                 continue;
    327             }
    328             if (ind == INTC_LOW_PRIORITY_INTR_REG_IND) {
    329                 IHOST_WRITE_INTR(d, ihost_intr_enable_base + INTC_LOW_PRIORITY_INTR_REG_IND +
    330                     HX5_IHOST_IRQ_MASK_OFFSET, INTR_LOW_PRIORITY_BITPOS);
    331             } else {
    332                 IHOST_WRITE_INTR(d, ihost_intr_enable_base + ind +
    333                     HX5_IHOST_IRQ_MASK_OFFSET, ~0);
    334             }
    335         } else {
    336             WRITE_INTC_INTR(d, intc_intr_enable_base + 4*ind, 0);
    337         }
    338     }
    339 
    340     /* Notify */
    341     atomic_set(&res->intr, 1);
    342 #ifdef BDE_LINUX_NON_INTERRUPTIBLE
    343     wake_up(&res->intr_wq);
    344 #else
    345     wake_up_interruptible(&res->intr_wq);
    346 #endif
    347 }
    348 
    349 static void
    350 _cmicm_interrupt(bde_ctrl_t *ctrl)
    351 {
    352     int d;
    353     int cmc = BDE_CMICM_PCIE_CMC;
    354     uint32 stat, mask = 0, fmask = 0, imask = 0;
    355     bde_inst_resource_t *res;
    356 
    357     d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
    358     res = &_bde_inst_resource[ctrl->inst];
    359 
    360     lkbde_irq_mask_get(d, &mask, &fmask);
    361 
    362     while (fmask) {
    363         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT0_OFFSET(cmc));
    364         imask = mask & ~fmask;
    365         if (stat & imask) {
    366             break;
    367         }
    368         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT1_OFFSET(cmc));
    369         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    370             mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc));
    371         } else {
    372             mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc));
    373         }
    374         if (stat & mask) {
    375             break;
    376         }
    377         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT2_OFFSET(cmc));
    378         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    379             mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc));
    380         } else {
    381             mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc));
    382         }
    383         if (stat & mask) {
    384             break;
    385         }
    386         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT3_OFFSET(cmc));
    387         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    388             mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc));
    389         } else {
    390             mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc));
    391         }
    392         if (stat & mask) {
    393             break;
    394         }
    395         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT4_OFFSET(cmc));
    396         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    397             mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc));
    398         } else {
    399             mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc));
    400         }
    401         if (stat & mask) {
    402             break;
    403         }
    404         return;
    405     }
    406 
    407     if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    408         lkbde_irq_mask_set(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(cmc), 0, 0);
    409         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc), 0);
    410         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc), 0);
    411         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc), 0);
    412         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc), 0);
    413         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(1), 0);
    414         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(2), 0);
    415     }
    416     else {
    417         lkbde_irq_mask_set(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(cmc), 0, 0);
    418         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc), 0);
    419         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc), 0);
    420         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc), 0);
    421         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc), 0);
    422         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(1), 0);
    423         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(2), 0);
    424     }
    425     atomic_set(&res->intr, 1);
    426 #ifdef BDE_LINUX_NON_INTERRUPTIBLE
    427     wake_up(&res->intr_wq);
    428 #else
    429     wake_up_interruptible(&res->intr_wq);
    430 #endif
    431 }
    432 
    433 /* some device has cmc0 only */
    434 static void
    435 _cmicd_cmc0_interrupt(bde_ctrl_t *ctrl)
    436 {
    437     int d;
    438     int cmc = 0;
    439     uint32 stat, mask = 0, fmask = 0, imask = 0;
    440     bde_inst_resource_t *res;
    441 
    442     d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
    443     res = &_bde_inst_resource[ctrl->inst];
    444     lkbde_irq_mask_get(d, &mask, &fmask);
    445 
    446     while (fmask) {
    447         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT0_OFFSET(cmc));
    448         imask = mask & ~fmask;
    449         if (stat & imask) {
    450             break;
    451         }
    452         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT1_OFFSET(cmc));
    453         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    454             mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc));
    455         } else {
    456             mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc));
    457         }
    458         if (stat & mask) {
    459             break;
    460         }
    461         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT2_OFFSET(cmc));
    462         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    463             mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc));
    464         } else {
    465             mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc));
    466         }
    467         if (stat & mask) {
    468             break;
    469         }
    470         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT3_OFFSET(cmc));
    471         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    472             mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc));
    473         } else {
    474             mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc));
    475         }
    476         if (stat & mask) {
    477             break;
    478         }
    479         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT4_OFFSET(cmc));
    480         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    481             mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc));
    482         } else {
    483             mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc));
    484         }
    485         if (stat & mask) {
    486             break;
    487         }
    488         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT5_OFFSET(cmc));
    489         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    490             mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(cmc));
    491         } else {
    492             mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(cmc));
    493         }
    494         if (stat & mask) {
    495             break;
    496         }
    497         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT6_OFFSET(cmc));
    498         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    499             mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc));
    500         } else {
    501             mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(cmc));
    502         }
    503         if (stat & mask) {
    504             break;
    505         }
    506         return;
    507     }
    508 
    509     if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    510         lkbde_irq_mask_set(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(cmc), 0, 0);
    511         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc), 0);
    512         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc), 0);
    513         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc), 0);
    514         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc), 0);
    515         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(cmc), 0);
    516         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc), 0);
    517     } else {
    518         lkbde_irq_mask_set(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(cmc), 0, 0);
    519         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc), 0);
    520         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc), 0);
    521         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc), 0);
    522         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc), 0);
    523         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(cmc), 0);
    524         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(cmc), 0);
    525     }
    526     atomic_set(&res->intr, 1);
    527 #ifdef BDE_LINUX_NON_INTERRUPTIBLE
    528     wake_up(&res->intr_wq);
    529 #else
    530     wake_up_interruptible(&res->intr_wq);
    531 #endif
    532 }
    533 
    534 static void
    535 _cmicd_interrupt(bde_ctrl_t *ctrl)
    536 {
    537     int d;
    538     int cmc = BDE_CMICD_PCIE_CMC;
    539     uint32 stat, mask = 0, fmask = 0, imask = 0;
    540     bde_inst_resource_t *res;
    541 
    542     d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
    543     res = &_bde_inst_resource[ctrl->inst];
    544     lkbde_irq_mask_get(d, &mask, &fmask);
    545 
    546     while (fmask) {
    547         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT0_OFFSET(cmc));
    548         imask = mask & ~fmask;
    549         if (stat & imask) {
    550             break;
    551         }
    552         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT1_OFFSET(cmc));
    553         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    554             mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc));
    555         } else {
    556             mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc));
    557         }
    558         if (stat & mask) {
    559             break;
    560         }
    561         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT2_OFFSET(cmc));
    562         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    563             mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc));
    564         } else {
    565             mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc));
    566         }
    567         if (stat & mask) {
    568             break;
    569         }
    570         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT3_OFFSET(cmc));
    571         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    572             mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc));
    573         } else {
    574             mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc));
    575         }
    576         if (stat & mask) {
    577             break;
    578         }
    579         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT4_OFFSET(cmc));
    580         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    581             mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc));
    582         } else {
    583             mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc));
    584         }
    585         if (stat & mask) {
    586             break;
    587         }
    588         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT5_OFFSET(cmc));
    589         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    590             mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(cmc));
    591         } else {
    592             mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(cmc));
    593         }
    594         if (stat & mask) {
    595             break;
    596         }
    597         stat = user_bde->read(d, CMIC_CMCx_IRQ_STAT6_OFFSET(cmc));
    598         if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    599             mask = user_bde->read(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc));
    600         } else {
    601             mask = user_bde->read(d, CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(cmc));
    602         }
    603         if (stat & mask) {
    604             break;
    605         }
    606         return;
    607     }
    608 
    609     if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    610         lkbde_irq_mask_set(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(cmc), 0, 0);
    611         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK1_OFFSET(cmc), 0);
    612         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK2_OFFSET(cmc), 0);
    613         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK3_OFFSET(cmc), 0);
    614         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK4_OFFSET(cmc), 0);
    615         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK5_OFFSET(cmc), 0);
    616         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK6_OFFSET(cmc), 0);
    617         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(1), 0);
    618         user_bde->write(d, CMIC_CMCx_UC0_IRQ_MASK0_OFFSET(2), 0);
    619     } else {
    620         lkbde_irq_mask_set(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(cmc), 0, 0);
    621         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK1_OFFSET(cmc), 0);
    622         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK2_OFFSET(cmc), 0);
    623         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK3_OFFSET(cmc), 0);
    624         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK4_OFFSET(cmc), 0);
    625         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK5_OFFSET(cmc), 0);
    626         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK6_OFFSET(cmc), 0);
    627         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(1), 0);
    628         user_bde->write(d, CMIC_CMCx_PCIE_IRQ_MASK0_OFFSET(2), 0);
    629     }
    630     atomic_set(&res->intr, 1);
    631 #ifdef BDE_LINUX_NON_INTERRUPTIBLE
    632     wake_up(&res->intr_wq);
    633 #else
    634     wake_up_interruptible(&res->intr_wq);
    635 #endif
    636 }
    637 
    638 static void 
    639 _bcm88750_interrupt(bde_ctrl_t *ctrl)
    640 {
    641     int d;
    642     bde_inst_resource_t *res;
    643 
    644     d = (((uint8 *)ctrl - (uint8 *)_devices) / sizeof (bde_ctrl_t));
    645     res = &_bde_inst_resource[ctrl->inst];
    646     lkbde_irq_mask_set(d, CMIC_IRQ_MASK, 0, 0);
    647 
    648     lkbde_irq_mask_set(d, CMIC_IRQ_MASK_1, 0, 0); 
    649     lkbde_irq_mask_set(d, CMIC_IRQ_MASK_2, 0, 0);
    650     atomic_set(&res->intr, 1);
    651 #ifdef BDE_LINUX_NON_INTERRUPTIBLE
    652     wake_up(&res->intr_wq);
    653 #else
    654     wake_up_interruptible(&res->intr_wq);
    655 #endif
    656 }
    657 
    658 /* The actual interrupt handler of ethernet devices */
    659 static void 
    660 _ether_interrupt(bde_ctrl_t *ctrl)
    661 {
    662     SSOC_WRITEL(0, ctrl->ba + 0x024/4);
    663 
    664     atomic_set(&_ether_interrupt_has_taken_place, 1);
    665 #ifdef BDE_LINUX_NON_INTERRUPTIBLE
    666     wake_up(&_ether_interrupt_wq);
    667 #else
    668     wake_up_interruptible(&_ether_interrupt_wq);
    669 #endif
    670 }
    671 
    672 
    673 static struct _intr_mode_s {
    674     isr_f isr;
    675     const char *name;
    676 } _intr_mode[] = {
    677     { (isr_f)_cmic_interrupt,       "CMIC/CMICe" },
    678     { (isr_f)_cmicm_interrupt,      "CMICm" },
    679     { (isr_f)_cmicd_interrupt,      "CMICd" },
    680     { (isr_f)_cmicd_cmc0_interrupt, "CMICd CMC0" },
    681     { (isr_f)_bcm88750_interrupt,   "BCM88750" },
    682     { (isr_f)_cmicx_interrupt,      "CMICx" },
    683     { NULL, NULL }
    684 };
    685 
    686 static const char *
    687 _intr_mode_str(void *isr)
    688 {
    689     int imx;
    690 
    691     imx = 0;
    692     while (_intr_mode[imx].isr != NULL) {
    693         if (isr == _intr_mode[imx].isr) {
    694             return _intr_mode[imx].name;
    695         }
    696         imx++;
    697     }
    698     return NULL;
    699 }
    700 
    701 static void
    702 _devices_init(int d)
    703 {
    704     bde_ctrl_t *ctrl;
    705     uint32 ver;
    706     uint16 device_id_mask = 0xFFF0;
    707     uint16 device_id;
    708     uint32 state = 0;
    709 
    710     (void)lkbde_dev_state_get(d, &state);
    711     if (state == BDE_DEV_STATE_REMOVED) {
    712         return;
    713     }
    714 
    715     ctrl = &_devices[d];
    716     /* Initialize our control info */
    717     ctrl->dev_type = user_bde->get_dev_type(d);
    718     ctrl->devid = user_bde->get_dev(d)->device;
    719     ctrl->inst = 0;
    720 
    721     if (BDE_DEV_MEM_MAPPED(ctrl->dev_type)) {
    722         ctrl->enabled = 0;
    723         ctrl->ba = lkbde_get_dev_virt(d);
    724     }
    725     if (ctrl->dev_type & BDE_SWITCH_DEV_TYPE) {
    726         switch (user_bde->get_dev(d)->device) {
    727         case BCM88750_DEVICE_ID:
    728         case BCM88753_DEVICE_ID:
    729         case BCM88754_DEVICE_ID:
    730         case BCM88755_DEVICE_ID:
    731         case BCM88752_DEVICE_ID:
    732             ctrl->isr = (isr_f)_bcm88750_interrupt;
    733             break;
    734         case BCM53540_DEVICE_ID:
    735         case BCM53547_DEVICE_ID:
    736         case BCM53548_DEVICE_ID:
    737         case BCM53549_DEVICE_ID:
    738         case BCM88670_DEVICE_ID:
    739         case BCM88671_DEVICE_ID:
    740         case BCM88671M_DEVICE_ID:
    741         case BCM88672_DEVICE_ID:
    742         case BCM88673_DEVICE_ID:
    743         case BCM88674_DEVICE_ID:
    744         case BCM88675_DEVICE_ID:
    745         case BCM88675M_DEVICE_ID:
    746         case BCM88676_DEVICE_ID:
    747         case BCM88676M_DEVICE_ID:
    748         case BCM88677_DEVICE_ID:
    749         case BCM88678_DEVICE_ID:
    750         case BCM88679_DEVICE_ID:
    751         case BCM88370_DEVICE_ID:
    752         case BCM88371_DEVICE_ID:
    753         case BCM88371M_DEVICE_ID:
    754         case BCM88375_DEVICE_ID:
    755         case BCM88376_DEVICE_ID:
    756         case BCM88376M_DEVICE_ID:
    757         case BCM88377_DEVICE_ID:
    758         case BCM88378_DEVICE_ID:
    759         case BCM88379_DEVICE_ID:
    760         case BCM88681_DEVICE_ID:
    761         case BCM88682_DEVICE_ID:
    762         case BCM88683_DEVICE_ID:
    763         case BCM88684_DEVICE_ID:
    764         case BCM88685_DEVICE_ID:
    765         case BCM88380_DEVICE_ID:
    766         case BCM88381_DEVICE_ID:
    767         case BCM88680_DEVICE_ID:
    768         case BCM88800_DEVICE_ID:
    769         case BCM88770_DEVICE_ID:
    770         case BCM88773_DEVICE_ID:
    771         case BCM88774_DEVICE_ID:
    772         case BCM88775_DEVICE_ID:
    773         case BCM88776_DEVICE_ID:
    774         case BCM88777_DEVICE_ID:
    775         case BCM88470_DEVICE_ID:
    776         case BCM88470P_DEVICE_ID:
    777         case BCM88471_DEVICE_ID:
    778         case BCM88473_DEVICE_ID:
    779         case BCM88474_DEVICE_ID:
    780         case BCM88474H_DEVICE_ID:
    781         case BCM88476_DEVICE_ID:
    782         case BCM88477_DEVICE_ID:
    783         case BCM88270_DEVICE_ID:
    784         case BCM88272_DEVICE_ID:
    785         case BCM88273_DEVICE_ID:
    786         case BCM88274_DEVICE_ID:
    787         case BCM88278_DEVICE_ID:
    788         case BCM88279_DEVICE_ID:
    789         case BCM8206_DEVICE_ID:
    790         case BCM88950_DEVICE_ID:
    791         case BCM88953_DEVICE_ID:
    792         case BCM88954_DEVICE_ID:
    793         case BCM88955_DEVICE_ID:
    794         case BCM88956_DEVICE_ID:
    795         case BCM88772_DEVICE_ID:
    796         case BCM88952_DEVICE_ID:
    797             ctrl->isr = (isr_f)_cmicd_cmc0_interrupt;
    798             break;
    799         case BCM88790_DEVICE_ID:
    800             ctrl->isr = (isr_f)_cmicx_interrupt;
    801             break;
    802         case BCM56370_DEVICE_ID:
    803         case BCM56371_DEVICE_ID:
    804         case BCM56372_DEVICE_ID:
    805         case BCM56374_DEVICE_ID:
    806         case BCM56375_DEVICE_ID:
    807         case BCM56376_DEVICE_ID:
    808         case BCM56377_DEVICE_ID:
    809         case BCM56577_DEVICE_ID:
    810         case BCM56578_DEVICE_ID:
    811         case BCM56579_DEVICE_ID:
    812             ctrl->isr = (isr_f)_cmicx_interrupt;
    813             if (ctrl->dev_type & BDE_AXI_DEV_TYPE) {
    814                 if (!ihost_intr_enable_base) {
    815                     ihost_intr_enable_base = (uint32_t *)IOREMAP(HX5_IHOST_GICD_ISENABLERN_1,
    816                                                                  HX5_IHOST_INTR_MAP_NUM);
    817                 }
    818                 if (!ihost_intr_status_base) {
    819                     ihost_intr_status_base = (uint32_t *)IOREMAP(HX5_INTC_INTR_RAW_STATUS_REG0,
    820                                                                  HX5_IHOST_INTR_STATUS_MAP_NUM);
    821                 }
    822             }
    823             break;
    824         default:
    825             /* Get CMIC version */
    826             if (user_bde->get_cmic_ver(d, &ver) != 0) {
    827                 ver = -1;
    828             }
    829             device_id = ctrl->devid & device_id_mask;
    830             /* TH/TH+/TH2 should use cmicd interrupt handler */
    831             if (BCM56960_DEVICE_ID == device_id ||
    832                 BCM56930_DEVICE_ID == device_id ||
    833                 BCM56970_DEVICE_ID == device_id) {
    834                 ctrl->isr = (isr_f)_cmicd_interrupt;
    835             }
    836             /* check if version is CMICX */
    837             else if (ver == 0x04) {
    838                  ctrl->isr = (isr_f)_cmicx_interrupt;
    839             } else {
    840                 ctrl->isr = (isr_f)_cmic_interrupt;
    841                 if ((ctrl->dev_type & BDE_256K_REG_SPACE) &&
    842 #ifdef BCM_PETRA_SUPPORT 
    843                     ctrl->devid != 0x1234 &&
    844 #endif
    845                     readl(ctrl->ba + CMICE_DEV_REV_ID) == 0) {
    846                     ctrl->isr = (isr_f)_cmicm_interrupt;
    847                 }
    848             }
    849             break;
    850         }
    851 
    852 #ifdef BCM_DNX_SUPPORT
    853         /*All Jericho 2 devices from 0x8690 to 0x869F*/
    854         if (SOC_IS_JERICHO_2_TYPE(user_bde->get_dev(d)->device)) {
    855           ctrl->isr = (isr_f)_cmicx_interrupt;
    856         }
    857 #endif
    858 
    859         /*All Ramon devices from 0x8790 to 0x879F*/
    860         if ((user_bde->get_dev(d)->device & BCM88790_DEVICE_ID) == BCM88790_DEVICE_ID) {
    861             ctrl->isr = (isr_f)_cmicx_interrupt;
    862         }
    863         if (_intr_mode_str(ctrl->isr) == NULL) {
    864             gprintk("Warning: Unknown interrupt mode\n");
    865         }
    866     }
    867 }
    868 /*
    869  * Function: _init
    870  *
    871  * Purpose:
    872  *    Module initialization.
    873  *    Attaches to kernel BDE.
    874  * Parameters:
    875  *    None
    876  * Returns:
    877  *    Always 0
    878  */
    879 static int
    880 _init(void)
    881 {
    882     int i;
    883     phys_addr_t cpu_pbase, dma_pbase;
    884     ssize_t dmasize;
    885     bde_inst_resource_t *res;
    886 
    887     /* Connect to the kernel bde */
    888     if ((linux_bde_create(NULL, &user_bde) < 0) || user_bde == NULL) {
    889         return -ENODEV;
    890     }
    891 
    892     init_waitqueue_head(&_ether_interrupt_wq);
    893 
    894     lkbde_get_dma_info(&cpu_pbase, &dma_pbase, &dmasize);
    895 
    896     memset(&_dma_pool, 0, sizeof(_dma_pool));
    897     _dma_pool.cpu_pbase = cpu_pbase;
    898     _dma_pool.dma_pbase = dma_pbase;
    899     _dma_pool.total_size = dmasize / ONE_MB;
    900 
    901     memset(_devices, 0, sizeof(_devices));
    902 
    903     /* Use _bde_inst_resource[0] as the default resource */
    904     memset(_bde_inst_resource, 0, sizeof(_bde_inst_resource));
    905     res = &_bde_inst_resource[0];
    906     res->dma_offset = 0;
    907     res->dma_size = _dma_pool.total_size;
    908     init_waitqueue_head(&res->intr_wq);
    909     atomic_set(&res->intr, 0);
    910 
    911     ihost_intr_enable_base = NULL;
    912     ihost_intr_status_base = NULL;
    913 
    914     for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
    915         res->inst_id |= (1 << i);
    916         _devices_init(i);
    917     }
    918 
    919     return 0;
    920 }
    921 
    922 /*
    923  * Function: _cleanup
    924  *
    925  * Purpose:
    926  *    Module cleanup function.
    927  * Parameters:
    928  *    None
    929  * Returns:
    930  *    Always 0
    931  */
    932 static int
    933 _cleanup(void)
    934 {
    935     int i;
    936 
    937     if (user_bde) {
    938         for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
    939             if (_devices[i].enabled &&
    940                 BDE_DEV_MEM_MAPPED(_devices[i].dev_type)) {
    941                 user_bde->interrupt_disconnect(i);
    942             }
    943             lkbde_dev_instid_set(i, 0);
    944         }
    945         linux_bde_destroy(user_bde);
    946         user_bde = NULL;
    947     }
    948 
    949     if (ihost_intr_enable_base) {
    950         iounmap(ihost_intr_enable_base);
    951         ihost_intr_enable_base = NULL;
    952     }
    953     if (ihost_intr_status_base) {
    954         iounmap(ihost_intr_status_base);
    955         ihost_intr_status_base = NULL;
    956     }
    957 
    958     return 0;
    959 }
    960 
    961 /*
    962  * Function: _pprint
    963  *
    964  * Purpose:
    965  *    Print proc filesystem information.
    966  * Parameters:
    967  *    None
    968  * Returns:
    969  *    Always 0
    970  */
    971 static int
    972 _pprint(void)
    973 {
    974     int idx;
    975     const char *name;
    976     bde_inst_resource_t *res;
    977     uint32 state, instid;
    978 
    979     pprintf("Broadcom Device Enumerator (%s)\n", LINUX_USER_BDE_NAME);
    980     for (idx = 0; idx < user_bde->num_devices(BDE_ALL_DEVICES); idx++) {
    981         name = _intr_mode_str(_devices[idx].isr);
    982         if (name == NULL) {
    983             name = "unknown";
    984         }
    985         pprintf("\t%d: Interrupt mode  %s ",idx, name);
    986         (void)lkbde_dev_state_get(idx, &state);
    987         if (state == BDE_DEV_STATE_REMOVED) {
    988             pprintf(" Device REMOVED ! \n");
    989         } else {
    990             (void)lkbde_dev_instid_get(idx, &instid);
    991             if (instid) {
    992                 pprintf("Inst id 0x%x\n",instid);
    993             } else {
    994                 pprintf("\n");
    995             }
    996         }
    997     }
    998     pprintf("Instance resource \n");
    999 
   1000     for (idx = 0; idx < user_bde->num_devices(BDE_ALL_DEVICES); idx++) {
   1001         res = &_bde_inst_resource[idx];
   1002         if (res->inst_id) {
   1003             pprintf("\tDev mask 0x%x : "
   1004                     "DMA offset %d size %d MB\n",
   1005                     res->inst_id,
   1006                     res->dma_offset,
   1007                     res->dma_size);
   1008         }
   1009     }
   1010 
   1011     return 0;
   1012 }
   1013 
   1014 /* 
   1015  * Allocate the DMA resource from DMA pool
   1016  * Parameter :
   1017  * dma_size (IN): allocate dma_size in MB
   1018  * dma_offset (OUT): dma offset in MB
   1019  */
   1020 static int
   1021 _dma_resource_alloc(unsigned int dma_size, unsigned int *dma_offset)
   1022 {
   1023     uint32 left;
   1024 
   1025     left = _dma_pool.total_size - _dma_pool.offset;
   1026     if (dma_size > left) {
   1027         gprintk("ERROR: Run out the dma resource!\n");
   1028         return -1;
   1029     }
   1030     *dma_offset = _dma_pool.offset;
   1031     _dma_pool.offset += dma_size;
   1032     return 0;
   1033 }
   1034 
   1035 static int
   1036 _dma_resource_get(int inst_id, phys_addr_t *cpu_pbase, phys_addr_t *dma_pbase, ssize_t* size)
   1037 {
   1038     int i;
   1039     unsigned int dma_size = 0, dma_offset = 0;
   1040     bde_inst_resource_t *res;
   1041 
   1042     for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
   1043         res = &_bde_inst_resource[i];
   1044         if (res->inst_id == inst_id) {
   1045             dma_size = res->dma_size;
   1046             dma_offset = res->dma_offset;
   1047             break;
   1048         }
   1049     }
   1050 
   1051     *cpu_pbase = _dma_pool.cpu_pbase + dma_offset * ONE_MB;
   1052     *dma_pbase = _dma_pool.dma_pbase + dma_offset * ONE_MB;
   1053     *size = dma_size * ONE_MB;
   1054 
   1055     return 0;
   1056 }
   1057 
   1058 static int
   1059 _instance_validate(unsigned int inst_id, unsigned int dmasize)
   1060 {
   1061     int i;
   1062     bde_inst_resource_t *res;
   1063 
   1064     for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
   1065         res = &_bde_inst_resource[i];
   1066         if (res->inst_id == inst_id) {
   1067             if (res->dma_size != dmasize) {
   1068                 if(_devices[i].inst == 0){
   1069                     /* Skip _instance_validate (not init yet) */
   1070                     return LUBDE_SUCCESS;
   1071                 }
   1072                 gprintk("ERROR: dma_size mismatch\n");
   1073                 return LUBDE_FAIL;
   1074             }
   1075             return (1);
   1076         }
   1077     }
   1078     return LUBDE_SUCCESS;
   1079 }
   1080 
   1081 static int
   1082 _device_reprobe(void)
   1083 {
   1084     int i;
   1085 
   1086     for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
   1087         if (_devices[i].devid == 0) {
   1088             _devices_init(i);
   1089         }
   1090     }
   1091     return 0;
   1092 }
   1093 
   1094 static int
   1095 _instance_attach(unsigned int inst_id, unsigned int dma_size)
   1096 {
   1097     unsigned int dma_offset;
   1098     int i, exist;
   1099     bde_inst_resource_t *res;
   1100     int inst_idx = -1;
   1101     uint32 instid;
   1102 
   1103     /* Reprobe the system for hot-plugged device */
   1104     _device_reprobe();
   1105 
   1106     /* Validate the resource with inst_id */
   1107     exist = _instance_validate(inst_id, dma_size);
   1108     if (exist < 0) {
   1109         return LUBDE_FAIL;
   1110     }
   1111     if (exist > 0) {
   1112         return LUBDE_SUCCESS;
   1113     }
   1114     if (_dma_resource_alloc(dma_size, &dma_offset) < 0) {
   1115         return LUBDE_FAIL;
   1116     }
   1117     for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
   1118         res = &_bde_inst_resource[i];
   1119         if ((_bde_multi_inst == 0) || (res->inst_id == 0)) {
   1120             res->inst_id = inst_id;
   1121             res->dma_offset = dma_offset;
   1122             res->dma_size = dma_size;
   1123             _bde_multi_inst++;
   1124             inst_idx = i;
   1125             init_waitqueue_head(&res->intr_wq);
   1126             atomic_set(&res->intr, 0);
   1127             break;
   1128         }
   1129     }
   1130 
   1131     for (i = 0; i < user_bde->num_devices(BDE_ALL_DEVICES); i++) {
   1132         if (inst_id & (1 << i)) {
   1133             _devices[i].inst = inst_idx;
   1134             /* Pass the instid to the kernel BDE */
   1135             if (lkbde_dev_instid_get(i, &instid) == 0) {
   1136                 if (!instid) {
   1137                     lkbde_dev_instid_set(i, inst_id);
   1138                 }
   1139             }
   1140         }
   1141     }
   1142 
   1143     return LUBDE_SUCCESS;
   1144 }
   1145 
   1146 /*
   1147  * Function: _ioctl
   1148  *
   1149  * Purpose:
   1150  *    Handle IOCTL commands from user mode.
   1151  * Parameters:
   1152  *    cmd - IOCTL cmd
   1153  *    arg - IOCTL parameters
   1154  * Returns:
   1155  *    0 on success, <0 on error
   1156  */
   1157 static int 
   1158 _ioctl(unsigned int cmd, unsigned long arg)
   1159 {
   1160     lubde_ioctl_t io;
   1161     phys_addr_t cpu_pbase, dma_pbase;
   1162     ssize_t size;
   1163     const ibde_dev_t *bde_dev;
   1164     int inst_id;
   1165     bde_inst_resource_t *res;
   1166     uint32_t *mapaddr;
   1167 
   1168     if (copy_from_user(&io, (void *)arg, sizeof(io))) {
   1169         return -EFAULT;
   1170     }
   1171   
   1172     io.rc = LUBDE_SUCCESS;
   1173   
   1174     switch(cmd) {
   1175     case LUBDE_VERSION:
   1176         io.d0 = KBDE_VERSION;
   1177         break;
   1178     case LUBDE_GET_NUM_DEVICES:
   1179         io.d0 = user_bde->num_devices(io.dev);
   1180         break;
   1181     case LUBDE_GET_DEVICE:
   1182         if (!VALID_DEVICE(io.dev)) {
   1183             return -EINVAL;
   1184         }
   1185         bde_dev = user_bde->get_dev(io.dev);
   1186         if (bde_dev) {
   1187             io.d0 = bde_dev->device;
   1188             io.d1 = bde_dev->rev;
   1189             if (BDE_DEV_MEM_MAPPED(_devices[io.dev].dev_type)) {
   1190                 /* Get physical address to map */
   1191                 io.d2 = lkbde_get_dev_phys(io.dev);
   1192                 io.d3 = lkbde_get_dev_phys_hi(io.dev);
   1193             }
   1194         } else {
   1195             io.rc = LUBDE_FAIL;
   1196         }
   1197         break;
   1198     case LUBDE_GET_DEVICE_TYPE:
   1199         if (!VALID_DEVICE(io.dev)) {
   1200             return -EINVAL;
   1201         }
   1202         io.d0 = _devices[io.dev].dev_type;
   1203         break;
   1204     case LUBDE_GET_BUS_FEATURES:
   1205         user_bde->pci_bus_features(io.dev, (int *) &io.d0, (int *) &io.d1,
   1206                                    (int *) &io.d2);
   1207         break;
   1208     case LUBDE_PCI_CONFIG_PUT32:
   1209         if (!VALID_DEVICE(io.dev)) {
   1210             return -EINVAL;
   1211         }
   1212         if (_devices[io.dev].dev_type & BDE_PCI_DEV_TYPE) {
   1213             user_bde->pci_conf_write(io.dev, io.d0, io.d1);
   1214         } else {
   1215             io.rc = LUBDE_FAIL;
   1216         }
   1217         break;
   1218     case LUBDE_PCI_CONFIG_GET32:
   1219         if (!VALID_DEVICE(io.dev)) {
   1220             return -EINVAL;
   1221         }
   1222         if (_devices[io.dev].dev_type & BDE_PCI_DEV_TYPE) {
   1223             io.d0 = user_bde->pci_conf_read(io.dev, io.d0);
   1224         } else {
   1225             io.rc = LUBDE_FAIL;
   1226         }
   1227         break;
   1228     case LUBDE_GET_DMA_INFO:
   1229         inst_id = io.dev;
   1230         if (_bde_multi_inst){
   1231             _dma_resource_get(inst_id, &cpu_pbase, &dma_pbase, &size);
   1232         } else {
   1233             lkbde_get_dma_info(&cpu_pbase, &dma_pbase, &size);
   1234         }
   1235         io.d0 = dma_pbase;
   1236         io.d1 = size;
   1237         /* Optionally enable DMA mmap via /dev/linux-kernel-bde */
   1238         io.d2 = USE_LINUX_BDE_MMAP;
   1239         /* Get physical address for mmap */
   1240         io.dx.dw[0] = cpu_pbase;
   1241 #ifdef PHYS_ADDRS_ARE_64BITS
   1242         io.dx.dw[1] = cpu_pbase >> 32;
   1243 #else
   1244         io.dx.dw[1] = 0;
   1245 #endif
   1246         break;
   1247     case LUBDE_ENABLE_INTERRUPTS:
   1248         if (!VALID_DEVICE(io.dev)) {
   1249             return -EINVAL;
   1250         }
   1251         if (_devices[io.dev].dev_type & BDE_SWITCH_DEV_TYPE) {
   1252             if (_devices[io.dev].isr && !_devices[io.dev].enabled) {
   1253                 user_bde->interrupt_connect(io.dev,
   1254                                             _devices[io.dev].isr,
   1255                                             _devices+io.dev);
   1256                 _devices[io.dev].enabled = 1;
   1257             }
   1258         } else {
   1259             /* Process ethernet device interrupt */
   1260             
   1261             if (!_devices[io.dev].enabled) {
   1262                 user_bde->interrupt_connect(io.dev,
   1263                                             (void(*)(void *))_ether_interrupt, 
   1264                                             _devices+io.dev);
   1265                 _devices[io.dev].enabled = 1;
   1266             }
   1267         }
   1268         break;
   1269     case LUBDE_DISABLE_INTERRUPTS:
   1270         if (!VALID_DEVICE(io.dev)) {
   1271             return -EINVAL;
   1272         }
   1273         if (_devices[io.dev].enabled) {
   1274             user_bde->interrupt_disconnect(io.dev);
   1275             _devices[io.dev].enabled = 0;
   1276         }
   1277         break;
   1278     case LUBDE_WAIT_FOR_INTERRUPT:
   1279         if (!VALID_DEVICE(io.dev)) {
   1280             return -EINVAL;
   1281         }
   1282         if (_devices[io.dev].dev_type & BDE_SWITCH_DEV_TYPE) {
   1283             res = &_bde_inst_resource[_devices[io.dev].inst];
   1284 #ifdef BDE_LINUX_NON_INTERRUPTIBLE
   1285             wait_event_timeout(res->intr_wq, 
   1286                                atomic_read(&res->intr) != 0, 100);
   1287 
   1288 #else
   1289             wait_event_interruptible(res->intr_wq,
   1290                                      atomic_read(&res->intr) != 0);
   1291 #endif
   1292             /* 
   1293              * Even if we get multiple interrupts, we 
   1294              * only run the interrupt handler once.
   1295              */
   1296             atomic_set(&res->intr, 0);
   1297         } else {
   1298 #ifdef BDE_LINUX_NON_INTERRUPTIBLE
   1299             wait_event_timeout(_ether_interrupt_wq,     
   1300                                atomic_read(&_ether_interrupt_has_taken_place) != 0, 100);
   1301 #else
   1302             wait_event_interruptible(_ether_interrupt_wq,     
   1303                                      atomic_read(&_ether_interrupt_has_taken_place) != 0);
   1304 #endif
   1305             /* 
   1306              * Even if we get multiple interrupts, we 
   1307              * only run the interrupt handler once.
   1308              */
   1309             atomic_set(&_ether_interrupt_has_taken_place, 0);
   1310         }
   1311         break;
   1312     case LUBDE_USLEEP:
   1313     case LUBDE_UDELAY:
   1314     case LUBDE_SEM_OP:
   1315         return -EINVAL;
   1316     case LUBDE_WRITE_IRQ_MASK:
   1317         io.rc = lkbde_irq_mask_set(io.dev, io.d0, io.d1, 0);
   1318         break;
   1319     case LUBDE_SPI_READ_REG:
   1320         if (user_bde->spi_read(io.dev, io.d0, io.dx.buf, io.d1) == -1) {
   1321             io.rc = LUBDE_FAIL;
   1322         } 
   1323         break;
   1324     case LUBDE_SPI_WRITE_REG:
   1325         if (user_bde->spi_write(io.dev, io.d0, io.dx.buf, io.d1) == -1) {
   1326             io.rc = LUBDE_FAIL;
   1327         }
   1328         break;
   1329     case LUBDE_READ_REG_16BIT_BUS:
   1330         io.d1 = user_bde->read(io.dev, io.d0);
   1331         break;
   1332     case LUBDE_WRITE_REG_16BIT_BUS:
   1333         io.rc = user_bde->write(io.dev, io.d0, io.d1);
   1334         break;
   1335 #ifdef BCM_SAND_SUPPORT
   1336     case LUBDE_CPU_WRITE_REG:
   1337     {
   1338         if (lkbde_cpu_write(io.dev, io.d0, (uint32*)io.dx.buf) == -1) {
   1339             io.rc = LUBDE_FAIL;
   1340         }
   1341         break;
   1342     }
   1343     case LUBDE_CPU_READ_REG:
   1344     {
   1345         if (lkbde_cpu_read(io.dev, io.d0, (uint32*)io.dx.buf) == -1) {
   1346             io.rc = LUBDE_FAIL;
   1347         }
   1348         break;
   1349     }
   1350     case LUBDE_CPU_PCI_REGISTER:
   1351     {
   1352         if (lkbde_cpu_pci_register(io.dev) == -1) {
   1353             io.rc = LUBDE_FAIL;
   1354         }
   1355         break;
   1356     }
   1357 #endif
   1358     case LUBDE_DEV_RESOURCE:
   1359         if (!VALID_DEVICE(io.dev)) {
   1360             return -EINVAL;
   1361         }
   1362         bde_dev = user_bde->get_dev(io.dev);
   1363         if (bde_dev) {
   1364             if (BDE_DEV_MEM_MAPPED(_devices[io.dev].dev_type)) {
   1365                 /* Get physical address to map */
   1366                 io.rc = lkbde_get_dev_resource(io.dev, io.d0,
   1367                                                &io.d1, &io.d2, &io.d3);
   1368             }
   1369         } else {
   1370             io.rc = LUBDE_FAIL;
   1371         }
   1372         break;
   1373     case LUBDE_IPROC_READ_REG:
   1374         if (!VALID_DEVICE(io.dev)) {
   1375             return -EINVAL;
   1376         }
   1377         if (_devices[io.dev].dev_type & BDE_AXI_DEV_TYPE) {
   1378             mapaddr = IOREMAP(io.d0, sizeof(uint32_t));
   1379             if (mapaddr == NULL) {
   1380                 io.rc = LUBDE_FAIL;
   1381                 return -1;
   1382             }
   1383             io.d1 = readl(mapaddr);
   1384             iounmap(mapaddr);
   1385         } else {
   1386             io.d1 = user_bde->iproc_read(io.dev, io.d0);
   1387             if (io.d1 == -1) {
   1388                 io.rc = LUBDE_FAIL;
   1389             }
   1390         }
   1391         break;
   1392     case LUBDE_IPROC_WRITE_REG:
   1393         if (user_bde->iproc_write(io.dev, io.d0, io.d1) == -1) {
   1394             io.rc = LUBDE_FAIL;
   1395         }
   1396         break;
   1397     case LUBDE_ATTACH_INSTANCE:
   1398         io.rc = _instance_attach(io.d0, io.d1);
   1399         break;
   1400     case LUBDE_GET_DEVICE_STATE:
   1401         io.rc = lkbde_dev_state_get(io.dev, &io.d0);
   1402         break;
   1403     case LUBDE_REPROBE:
   1404         io.rc = _device_reprobe();
   1405         break;
   1406     default:
   1407         gprintk("Error: Invalid ioctl (%08x)\n", cmd);
   1408         io.rc = LUBDE_FAIL;
   1409         break;
   1410     }
   1411 
   1412     if (copy_to_user((void *)arg, &io, sizeof(io))) {
   1413         return -EFAULT;
   1414     }
   1415 
   1416     return 0;
   1417 }
   1418 
   1419 /* Workaround for broken Busybox/PPC insmod */
   1420 static char _modname[] = LINUX_USER_BDE_NAME;
   1421 
   1422 static gmodule_t _gmodule = 
   1423 {
   1424     name: LINUX_USER_BDE_NAME, 
   1425     major: LINUX_USER_BDE_MAJOR, 
   1426     init: _init, 
   1427     cleanup: _cleanup, 
   1428     pprint: _pprint, 
   1429     ioctl: _ioctl,
   1430 }; 
   1431 
   1432 gmodule_t*
   1433 gmodule_get(void)
   1434 {
   1435     _gmodule.name = _modname;
   1436     return &_gmodule;
   1437 }