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 }