Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:07

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*  GRLIB PCIF PCI HOST driver.
0004  * 
0005  *  COPYRIGHT (c) 2008.
0006  *  Cobham Gaisler AB.
0007  *
0008  *  Configures the PCIF core and initialize,
0009  *   - the PCI Library (pci.c)
0010  *   - the general part of the PCI Bus driver (pci_bus.c)
0011  *  
0012  *  System interrupt assigned to PCI interrupt (INTA#..INTD#) is by
0013  *  default taken from Plug and Play, but may be overridden by the 
0014  *  driver resources INTA#..INTD#.
0015  *
0016  * Redistribution and use in source and binary forms, with or without
0017  * modification, are permitted provided that the following conditions
0018  * are met:
0019  * 1. Redistributions of source code must retain the above copyright
0020  *    notice, this list of conditions and the following disclaimer.
0021  * 2. Redistributions in binary form must reproduce the above copyright
0022  *    notice, this list of conditions and the following disclaimer in the
0023  *    documentation and/or other materials provided with the distribution.
0024  *
0025  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0026  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0027  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0028  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0029  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0030  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0031  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0032  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0033  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0034  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0035  * POSSIBILITY OF SUCH DAMAGE.
0036  */
0037 
0038 #include <stdio.h>
0039 #include <stdlib.h>
0040 #include <string.h>
0041 #include <libcpu/byteorder.h>
0042 #include <libcpu/access.h>
0043 #include <rtems/bspIo.h>
0044 #include <pci.h>
0045 #include <pci/cfg.h>
0046 
0047 #include <drvmgr/drvmgr.h>
0048 #include <grlib/ambapp_bus.h>
0049 #include <grlib/ambapp.h>
0050 #include <drvmgr/pci_bus.h>
0051 #include <grlib/pcif.h>
0052 
0053 
0054 /* Configuration options */
0055 #define SYSTEM_MAINMEM_START 0x40000000
0056 
0057 /* Interrupt assignment. Set to other value than 0xff in order to 
0058  * override defaults and plug&play information
0059  */
0060 #ifndef PCIF_INTA_SYSIRQ
0061  #define PCIF_INTA_SYSIRQ 0xff
0062 #endif
0063 #ifndef PCIF_INTB_SYSIRQ
0064  #define PCIF_INTB_SYSIRQ 0xff
0065 #endif
0066 #ifndef PCIF_INTC_SYSIRQ
0067  #define PCIF_INTC_SYSIRQ 0xff
0068 #endif
0069 #ifndef PCIF_INTD_SYSIRQ
0070  #define PCIF_INTD_SYSIRQ 0xff
0071 #endif
0072 
0073 /*#define DEBUG 1  */
0074 
0075 #ifdef DEBUG
0076 #define DBG(x...) printk(x)
0077 #else
0078 #define DBG(x...) 
0079 #endif
0080 
0081 /*
0082  * Bit encode for PCI_CONFIG_HEADER_TYPE register
0083  */
0084 struct pcif_regs {
0085     volatile unsigned int bars[4];  /* 0x00-0x10 */
0086     volatile unsigned int bus;      /* 0x10 */
0087     volatile unsigned int map_io;   /* 0x14 */
0088     volatile unsigned int status;   /* 0x18 */
0089     volatile unsigned int intr;     /* 0x1c */
0090     int unused[(0x40-0x20)/4];      /* 0x20-0x40 */
0091     volatile unsigned int maps[(0x80-0x40)/4];   /* 0x40-0x80*/
0092 };
0093 
0094 /* Used internally for accessing the PCI bridge's configuration space itself */
0095 #define HOST_TGT PCI_DEV(0xff, 0, 0)
0096 
0097 struct pcif_priv *pcifpriv = NULL;
0098 static int pcif_minor = 0;
0099 
0100 /* PCI Interrupt assignment. Connects an PCI interrupt pin (INTA#..INTD#)
0101  * to a system interrupt number.
0102  */
0103 unsigned char pcif_pci_irq_table[4] =
0104 {
0105     /* INTA# */ PCIF_INTA_SYSIRQ,
0106     /* INTB# */ PCIF_INTB_SYSIRQ,
0107     /* INTC# */ PCIF_INTC_SYSIRQ,
0108     /* INTD# */ PCIF_INTD_SYSIRQ
0109 };
0110 
0111 /* Driver private data struture */
0112 struct pcif_priv {
0113     struct drvmgr_dev   *dev;
0114     struct pcif_regs        *regs;
0115     int             irq;
0116     int             minor;
0117     int             irq_mask;
0118 
0119     unsigned int            pci_area;
0120     unsigned int            pci_area_end;
0121     unsigned int            pci_io;    
0122     unsigned int            pci_conf;
0123     unsigned int            pci_conf_end;
0124 
0125     uint32_t            devVend; /* Host PCI Vendor/Device ID */
0126     uint32_t            bar1_size;
0127 
0128     struct drvmgr_map_entry     maps_up[2];
0129     struct drvmgr_map_entry     maps_down[2];
0130     struct pcibus_config        config;
0131 };
0132 
0133 int pcif_init1(struct drvmgr_dev *dev);
0134 int pcif_init3(struct drvmgr_dev *dev);
0135 
0136 /* PCIF DRIVER */
0137 
0138 struct drvmgr_drv_ops pcif_ops = 
0139 {
0140     .init = {pcif_init1, NULL, pcif_init3, NULL},
0141     .remove = NULL,
0142     .info = NULL
0143 };
0144 
0145 struct amba_dev_id pcif_ids[] = 
0146 {
0147     {VENDOR_GAISLER, GAISLER_PCIF},
0148     {0, 0}      /* Mark end of table */
0149 };
0150 
0151 struct amba_drv_info pcif_info =
0152 {
0153     {
0154         DRVMGR_OBJ_DRV,         /* Driver */
0155         NULL,               /* Next driver */
0156         NULL,               /* Device list */
0157         DRIVER_AMBAPP_GAISLER_PCIF_ID,  /* Driver ID */
0158         "PCIF_DRV",         /* Driver Name */
0159         DRVMGR_BUS_TYPE_AMBAPP,     /* Bus Type */
0160         &pcif_ops,
0161         NULL,               /* Funcs */
0162         0,              /* No devices yet */
0163         sizeof(struct pcif_priv),   /* Let drvmgr alloc private */
0164     },
0165     &pcif_ids[0]
0166 };
0167 
0168 void pcif_register_drv(void)
0169 {
0170     DBG("Registering PCIF driver\n");
0171     drvmgr_drv_register(&pcif_info.general);
0172 }
0173 
0174 static int pcif_cfg_r32(pci_dev_t dev, int ofs, uint32_t *val)
0175 {
0176     struct pcif_priv *priv = pcifpriv;
0177     volatile uint32_t *pci_conf;
0178     uint32_t devfn;
0179     int retval;
0180     int bus = PCI_DEV_BUS(dev);
0181 
0182     if (ofs & 3)
0183         return PCISTS_EINVAL;
0184 
0185     if (PCI_DEV_SLOT(dev) > 15) {
0186         *val = 0xffffffff;
0187         return PCISTS_OK;
0188     }
0189 
0190     /* PCIF can access "non-standard" devices on bus0 (on AD11.AD16), 
0191      * but we skip them.
0192      */
0193     if (dev == HOST_TGT)
0194         bus = devfn = 0;
0195     else if (bus == 0)
0196         devfn = PCI_DEV_DEVFUNC(dev) + PCI_DEV(0, 6, 0);
0197     else
0198         devfn = PCI_DEV_DEVFUNC(dev);
0199 
0200     /* Select bus */
0201     priv->regs->bus = bus << 16;
0202 
0203     pci_conf = (volatile uint32_t *)(priv->pci_conf | (devfn << 8) | ofs);
0204 
0205     *val = *pci_conf;
0206 
0207     if (priv->regs->status & 0x30000000) {
0208         *val = 0xffffffff;
0209         retval = PCISTS_MSTABRT;
0210     } else
0211         retval = PCISTS_OK;
0212 
0213     DBG("pci_read: [%x:%x:%x] reg: 0x%x => addr: 0x%x, val: 0x%x\n",
0214         PCI_DEV_EXPAND(dev), ofs, pci_conf, *val);
0215 
0216     return retval;
0217 }
0218 
0219 static int pcif_cfg_r16(pci_dev_t dev, int ofs, uint16_t *val)
0220 {
0221     uint32_t v;
0222     int retval;
0223 
0224     if (ofs & 1)
0225         return PCISTS_EINVAL;
0226 
0227     retval = pcif_cfg_r32(dev, ofs & ~0x3, &v);
0228     *val = 0xffff & (v >> (8*(ofs & 0x3)));
0229 
0230     return retval;
0231 }
0232 
0233 static int pcif_cfg_r8(pci_dev_t dev, int ofs, uint8_t *val)
0234 {
0235     uint32_t v;
0236     int retval;
0237 
0238     retval = pcif_cfg_r32(dev, ofs & ~0x3, &v);
0239 
0240     *val = 0xff & (v >> (8*(ofs & 3)));
0241 
0242     return retval;
0243 }
0244 
0245 static int pcif_cfg_w32(pci_dev_t dev, int ofs, uint32_t val)
0246 {
0247     struct pcif_priv *priv = pcifpriv;
0248     volatile uint32_t *pci_conf;
0249     uint32_t devfn;
0250     int bus = PCI_DEV_BUS(dev);
0251 
0252     if (ofs & ~0xfc)
0253         return PCISTS_EINVAL;
0254 
0255     if (PCI_DEV_SLOT(dev) > 15)
0256         return PCISTS_MSTABRT;
0257 
0258     /* PCIF can access "non-standard" devices on bus0 (on AD11.AD16), 
0259      * but we skip them.
0260      */
0261     if (dev == HOST_TGT)
0262         bus = devfn = 0;
0263     else if (bus == 0)
0264         devfn = PCI_DEV_DEVFUNC(dev) + PCI_DEV(0, 6, 0);
0265     else
0266         devfn = PCI_DEV_DEVFUNC(dev);
0267 
0268     /* Select bus */
0269     priv->regs->bus = bus << 16;
0270 
0271     pci_conf = (volatile uint32_t *)(priv->pci_conf | (devfn << 8) | ofs);
0272 
0273     *pci_conf = val;
0274 
0275     DBG("pci_write - [%x:%x:%x] reg: 0x%x => addr: 0x%x, val: 0x%x\n",
0276         PCI_DEV_EXPAND(dev), ofs, pci_conf, value);
0277 
0278     return PCISTS_OK;
0279 }
0280 
0281 static int pcif_cfg_w16(pci_dev_t dev, int ofs, uint16_t val)
0282 {
0283     uint32_t v;
0284     int retval;
0285 
0286     if (ofs & 1)
0287         return PCISTS_EINVAL;
0288 
0289     retval = pcif_cfg_r32(dev, ofs & ~0x3, &v);
0290     if (retval != PCISTS_OK)
0291         return retval;
0292 
0293     v = (v & ~(0xffff << (8*(ofs&3)))) | ((0xffff&val) << (8*(ofs&3)));
0294 
0295     return pcif_cfg_w32(dev, ofs & ~0x3, v);
0296 }
0297 
0298 static int pcif_cfg_w8(pci_dev_t dev, int ofs, uint8_t val)
0299 {
0300     uint32_t v;
0301     int retval;
0302 
0303     retval = pcif_cfg_r32(dev, ofs & ~0x3, &v);
0304     if (retval != PCISTS_OK)
0305         return retval;
0306 
0307     v = (v & ~(0xff << (8*(ofs&3)))) | ((0xff&val) << (8*(ofs&3)));
0308 
0309     return pcif_cfg_w32(dev, ofs & ~0x3, v);
0310 }
0311 
0312 
0313 /* Return the assigned system IRQ number that corresponds to the PCI
0314  * "Interrupt Pin" information from configuration space.
0315  *
0316  * The IRQ information is stored in the pcif_pci_irq_table configurable
0317  * by the user.
0318  *
0319  * Returns the "system IRQ" for the PCI INTA#..INTD# pin in irq_pin. Returns
0320  * 0xff if not assigned.
0321  */
0322 static uint8_t pcif_bus0_irq_map(pci_dev_t dev, int irq_pin)
0323 {
0324     uint8_t sysIrqNr = 0; /* not assigned */
0325     int irq_group;
0326 
0327     if ( (irq_pin >= 1) && (irq_pin <= 4) ) {
0328         /* Use default IRQ decoding on PCI BUS0 according slot numbering */
0329         irq_group = PCI_DEV_SLOT(dev) & 0x3;
0330         irq_pin = ((irq_pin - 1) + irq_group) & 0x3;
0331         /* Valid PCI "Interrupt Pin" number */
0332         sysIrqNr = pcif_pci_irq_table[irq_pin];
0333     }
0334     return sysIrqNr;
0335 }
0336 
0337 static int pcif_translate(uint32_t *address, int type, int dir)
0338 {
0339     /* No address translation implmented at this point */
0340     return 0;
0341 }
0342 
0343 extern struct pci_memreg_ops pci_memreg_sparc_be_ops;
0344 
0345 /* PCIF Big-Endian PCI access routines */
0346 struct pci_access_drv pcif_access_drv = {
0347     .cfg =
0348     {
0349         pcif_cfg_r8,
0350         pcif_cfg_r16,
0351         pcif_cfg_r32,
0352         pcif_cfg_w8,
0353         pcif_cfg_w16,
0354         pcif_cfg_w32,
0355     },
0356     .io =   /* PCIF only supports Big-endian */
0357     {
0358         _ld8,
0359         _ld_be16,
0360         _ld_be32,
0361         _st8,
0362         _st_be16,
0363         _st_be32,
0364     },
0365     .memreg = &pci_memreg_sparc_be_ops,
0366     .translate = pcif_translate,
0367 };
0368 
0369 /* Initializes the PCIF core hardware
0370  *
0371  */
0372 static int pcif_hw_init(struct pcif_priv *priv)
0373 {
0374     struct pcif_regs *regs;
0375     uint32_t data, size;
0376     int mst;
0377     pci_dev_t host = HOST_TGT;
0378 
0379     regs = priv->regs;
0380 
0381     /* Mask PCI interrupts */
0382     regs->intr = 0;
0383 
0384     /* Get the PCIF Host PCI ID */
0385     pcif_cfg_r32(host, PCIR_VENDOR, &priv->devVend);
0386 
0387     /* set 1:1 mapping between AHB -> PCI memory space, for all Master cores */
0388     for ( mst=0; mst<16; mst++) {
0389         regs->maps[mst] = priv->pci_area;
0390 
0391         /* Check if this register is implemented */
0392         if ( regs->maps[mst] != priv->pci_area )
0393             break;
0394     }
0395 
0396     /* and map system RAM at pci address SYSTEM_MAINMEM_START. This way
0397      * PCI targets can do DMA directly into CPU main memory.
0398      */
0399     regs->bars[0] = SYSTEM_MAINMEM_START;
0400     regs->bars[1] = 0;
0401     regs->bars[2] = 0;
0402     regs->bars[3] = 0;
0403 
0404     /* determine size of target BAR1 */
0405     pcif_cfg_w32(host, PCIR_BAR(1), 0xffffffff);
0406     pcif_cfg_r32(host, PCIR_BAR(1), &size);
0407     priv->bar1_size = (~(size & ~0xf)) + 1;
0408 
0409     pcif_cfg_w32(host, PCIR_BAR(0), 0);
0410     pcif_cfg_w32(host, PCIR_BAR(1), SYSTEM_MAINMEM_START);
0411     pcif_cfg_w32(host, PCIR_BAR(2), 0);
0412     pcif_cfg_w32(host, PCIR_BAR(3), 0);
0413     pcif_cfg_w32(host, PCIR_BAR(4), 0);
0414     pcif_cfg_w32(host, PCIR_BAR(5), 0);
0415 
0416     /* set as bus master and enable pci memory responses */  
0417     pcif_cfg_r32(host, PCIR_COMMAND, &data);
0418     data |= (PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
0419     pcif_cfg_w32(host, PCIR_COMMAND, data);
0420 
0421     /* Successful */
0422     return 0;
0423 }
0424 
0425 /* Initializes the PCIF core and driver, must be called before calling init_pci() 
0426  *
0427  * Return values
0428  *  0             Successful initalization
0429  *  -1            Error during initialization, for example "PCI core not found".
0430  *  -2            Error PCI controller not HOST (targets not supported)
0431  *  -3            Error due to PCIF hardware initialization
0432  *  -4            Error registering driver to PCI layer
0433  */
0434 static int pcif_init(struct pcif_priv *priv)
0435 {
0436     struct ambapp_apb_info *apb;
0437     struct ambapp_ahb_info *ahb;
0438     int pin;
0439     union drvmgr_key_value *value;
0440     char keyname[6];
0441     struct amba_dev_info *ainfo = priv->dev->businfo;
0442 
0443     /* Find PCI core from Plug&Play information */
0444     apb = ainfo->info.apb_slv;
0445     ahb = ainfo->info.ahb_slv;
0446 
0447     /* Found PCI core, init private structure */
0448     priv->irq = apb->common.irq;
0449     priv->regs = (struct pcif_regs *)apb->start;
0450 
0451     /* Calculate the PCI windows 
0452      *  AMBA->PCI Window:                       AHB SLAVE AREA0
0453      *  AMBA->PCI I/O cycles Window:            AHB SLAVE AREA1 Lower half
0454      *  AMBA->PCI Configuration cycles Window:  AHB SLAVE AREA1 Upper half
0455      */
0456     priv->pci_area     = ahb->start[0];
0457     priv->pci_area_end = ahb->start[0] + ahb->mask[0];
0458     priv->pci_io       = ahb->start[1];
0459     priv->pci_conf     = ahb->start[1] + (ahb->mask[1] >> 1);
0460     priv->pci_conf_end = ahb->start[1] + ahb->mask[1];
0461 
0462     /* On systems where PCI I/O area and configuration area is apart of the "PCI Window" 
0463      * the PCI Window stops at the start of the PCI I/O area
0464      */
0465     if ( (priv->pci_io > priv->pci_area) && (priv->pci_io < (priv->pci_area_end-1)) ) {
0466         priv->pci_area_end = priv->pci_io;
0467     }
0468 
0469     /* Init PCI interrupt assignment table to all use the interrupt routed through
0470      * the PCIF core.
0471      */
0472     strcpy(keyname, "INTX#");
0473     for (pin=1; pin<5; pin++) {
0474         if ( pcif_pci_irq_table[pin-1] == 0xff ) {
0475             pcif_pci_irq_table[pin-1] = priv->irq;
0476 
0477             /* User may override Plug & Play IRQ */
0478             keyname[3] = 'A' + (pin-1);
0479             value = drvmgr_dev_key_get(priv->dev, keyname, DRVMGR_KT_INT);
0480             if ( value )
0481                 pcif_pci_irq_table[pin-1] = value->i;
0482         }
0483     }
0484 
0485     priv->irq_mask = 0xf;
0486     value = drvmgr_dev_key_get(priv->dev, "", DRVMGR_KT_INT);
0487     if ( value )
0488         priv->irq_mask = value->i & 0xf;
0489 
0490     /* This driver only support HOST systems, we check for HOST */
0491     if ( priv->regs->status & 0x00000001 ) {
0492         /* Target not supported */
0493         return -2;
0494     }
0495 
0496     /* Init the PCI Core */
0497     if ( pcif_hw_init(priv) ) {
0498         return -3;
0499     }
0500 
0501     /* Down streams translation table */
0502     priv->maps_down[0].name = "AMBA -> PCI MEM Window";
0503     priv->maps_down[0].size = priv->pci_area_end - priv->pci_area;
0504     priv->maps_down[0].from_adr = (void *)priv->pci_area;
0505     priv->maps_down[0].to_adr = (void *)priv->pci_area;
0506     /* End table */
0507     priv->maps_down[1].size = 0;
0508 
0509     /* Up streams translation table */
0510     priv->maps_up[0].name = "Target BAR1 -> AMBA";
0511     priv->maps_up[0].size = priv->bar1_size;
0512     priv->maps_up[0].from_adr = (void *)SYSTEM_MAINMEM_START;
0513     priv->maps_up[0].to_adr = (void *)SYSTEM_MAINMEM_START;
0514     /* End table */
0515     priv->maps_up[1].size = 0;
0516 
0517     return 0;
0518 }
0519 
0520 /* Called when a core is found with the AMBA device and vendor ID 
0521  * given in pcif_ids[].
0522  */
0523 int pcif_init1(struct drvmgr_dev *dev)
0524 {
0525     struct pcif_priv *priv;
0526     struct pci_auto_setup pcif_auto_cfg;
0527 
0528     DBG("PCIF[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
0529 
0530     if ( pcif_minor != 0 ) {
0531         printk("Driver only supports one PCI core\n");
0532         return DRVMGR_FAIL;
0533     }
0534 
0535     priv = dev->priv;
0536     if ( !priv )
0537         return DRVMGR_NOMEM;
0538 
0539     dev->priv = priv;
0540     priv->dev = dev;
0541     priv->minor = pcif_minor++;
0542 
0543     pcifpriv = priv;
0544     if ( pcif_init(priv) ) {
0545         printk("Failed to initialize PCIF driver\n");
0546         free(priv);
0547         dev->priv = NULL;
0548         return DRVMGR_FAIL;
0549     }
0550 
0551     /* Host is always Big-Endian */
0552     pci_endian = PCI_BIG_ENDIAN;
0553 
0554     /* Register the PCI core at the PCI layer */
0555 
0556     if (pci_access_drv_register(&pcif_access_drv)) {
0557         /* Access routines registration failed */
0558         return DRVMGR_FAIL;
0559     }
0560 
0561     /* Prepare memory MAP */
0562     pcif_auto_cfg.options = 0;
0563     pcif_auto_cfg.mem_start = 0;
0564     pcif_auto_cfg.mem_size = 0;
0565     pcif_auto_cfg.memio_start = priv->pci_area;
0566     pcif_auto_cfg.memio_size = priv->pci_area_end - priv->pci_area;
0567     pcif_auto_cfg.io_start = priv->pci_io;
0568     pcif_auto_cfg.io_size = priv->pci_conf - priv->pci_io;
0569     pcif_auto_cfg.irq_map = pcif_bus0_irq_map;
0570     pcif_auto_cfg.irq_route = NULL; /* use standard routing */
0571     pci_config_register(&pcif_auto_cfg);
0572 
0573     if (pci_config_init()) {
0574         /* PCI configuration failed */
0575         return DRVMGR_FAIL;
0576     }
0577 
0578     priv->config.maps_down = &priv->maps_down[0];
0579     priv->config.maps_up = &priv->maps_up[0];
0580     return pcibus_register(dev, &priv->config);
0581 }
0582 
0583 int pcif_init3(struct drvmgr_dev *dev)
0584 {
0585     struct pcif_priv *priv = dev->priv;
0586 
0587     /* Unmask all interrupts, on some sytems this 
0588      * might be problematic because all PCI IRQs are
0589      * not connected on the PCB or used for something
0590      * else. The irqMask driver resource can be used to 
0591      * control which PCI IRQs are used to generate the
0592      * PCI system IRQ, example:
0593      *
0594      * 0xf - enable all  (DEFAULT)
0595      * 0x8 - enable one PCI irq
0596      *
0597      * Before unmasking PCI IRQ, all PCI boards must
0598      * have been initialized and IRQ turned off to avoid
0599      * system hang.
0600      */
0601 
0602     priv->regs->intr = priv->irq_mask;
0603 
0604     return DRVMGR_OK;
0605 }