File indexing completed on 2025-05-11 08:24:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 #include <inttypes.h>
0031 #include <string.h>
0032 #include <rtems.h>
0033 #include <rtems/bspIo.h>
0034 #include <drvmgr/drvmgr.h>
0035 #include <grlib/ambapp_bus.h>
0036
0037 #include <grlib/ahbstat.h>
0038
0039 #include <grlib/grlib_impl.h>
0040
0041 #define REG_WRITE(addr, val) (*(volatile uint32_t *)(addr) = (uint32_t)(val))
0042 #define REG_READ(addr) (*(volatile uint32_t *)(addr))
0043
0044 void ahbstat_isr(void *arg);
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061 int (*ahbstat_error)(
0062 int minor,
0063 struct ahbstat_regs *regs,
0064 uint32_t status,
0065 uint32_t failing_address
0066 ) __attribute__((weak)) = NULL;
0067
0068 #define AHBSTAT_STS_ME_BIT 13
0069 #define AHBSTAT_STS_FW_BIT 12
0070 #define AHBSTAT_STS_CF_BIT 11
0071 #define AHBSTAT_STS_AF_BIT 10
0072 #define AHBSTAT_STS_CE_BIT 9
0073 #define AHBSTAT_STS_NE_BIT 8
0074 #define AHBSTAT_STS_HW_BIT 7
0075 #define AHBSTAT_STS_HM_BIT 3
0076 #define AHBSTAT_STS_HS_BIT 0
0077
0078 #define AHBSTAT_STS_ME (1 << AHBSTAT_STS_ME_BIT)
0079 #define AHBSTAT_STS_FW (1 << AHBSTAT_STS_FW_BIT)
0080 #define AHBSTAT_STS_CF (1 << AHBSTAT_STS_CF_BIT)
0081 #define AHBSTAT_STS_AF (1 << AHBSTAT_STS_AF_BIT)
0082 #define AHBSTAT_STS_CE (1 << AHBSTAT_STS_CE_BIT)
0083 #define AHBSTAT_STS_NE (1 << AHBSTAT_STS_NE_BIT)
0084 #define AHBSTAT_STS_HW (1 << AHBSTAT_STS_HW_BIT)
0085 #define AHBSTAT_STS_HM (0xf << AHBSTAT_STS_HM_BIT)
0086 #define AHBSTAT_STS_HS (0x7 << AHBSTAT_STS_HS_BIT)
0087
0088 enum { DEVNAME_LEN = 9 };
0089 struct ahbstat_priv {
0090 struct drvmgr_dev *dev;
0091 struct ahbstat_regs *regs;
0092 char devname[DEVNAME_LEN];
0093 int minor;
0094
0095 uint32_t last_status;
0096 uint32_t last_address;
0097
0098 SPIN_DECLARE(devlock);
0099 };
0100
0101 static int ahbstat_init2(struct drvmgr_dev *dev);
0102
0103 struct drvmgr_drv_ops ahbstat_ops =
0104 {
0105 .init = {NULL, ahbstat_init2, NULL, NULL},
0106 .remove = NULL,
0107 .info = NULL
0108 };
0109
0110 struct amba_dev_id ahbstat_ids[] =
0111 {
0112 {VENDOR_GAISLER, GAISLER_AHBSTAT},
0113 {0, 0}
0114 };
0115
0116 struct amba_drv_info ahbstat_drv_info =
0117 {
0118 {
0119 DRVMGR_OBJ_DRV,
0120 NULL,
0121 NULL,
0122 DRIVER_AMBAPP_GAISLER_AHBSTAT_ID,
0123 "AHBSTAT_DRV",
0124 DRVMGR_BUS_TYPE_AMBAPP,
0125 &ahbstat_ops,
0126 NULL,
0127 0,
0128 sizeof(struct ahbstat_priv),
0129 },
0130 &ahbstat_ids[0]
0131 };
0132
0133 void ahbstat_register_drv (void)
0134 {
0135 drvmgr_drv_register(&ahbstat_drv_info.general);
0136 }
0137
0138 static int ahbstat_init2(struct drvmgr_dev *dev)
0139 {
0140 struct ahbstat_priv *priv;
0141 struct amba_dev_info *ambadev;
0142
0143 priv = dev->priv;
0144 if (!priv)
0145 return DRVMGR_NOMEM;
0146 priv->dev = dev;
0147
0148
0149 ambadev = (struct amba_dev_info *)dev->businfo;
0150 if (ambadev == NULL)
0151 return DRVMGR_FAIL;
0152 priv->regs = (struct ahbstat_regs *)ambadev->info.apb_slv->start;
0153 priv->minor = dev->minor_drv;
0154
0155 strncpy(&priv->devname[0], "ahbstat0", DEVNAME_LEN);
0156 priv->devname[7] += priv->minor;
0157
0158
0159
0160
0161 SPIN_INIT(&priv->devlock, priv->devname);
0162
0163
0164 REG_WRITE(&priv->regs->status, 0);
0165
0166
0167 drvmgr_interrupt_register(dev, 0, priv->devname, ahbstat_isr, priv);
0168
0169 return DRVMGR_OK;
0170 }
0171
0172 void ahbstat_isr(void *arg)
0173 {
0174 struct ahbstat_priv *priv = arg;
0175 uint32_t fadr, status;
0176 int rc;
0177 SPIN_ISR_IRQFLAGS(lock_context);
0178
0179
0180 status = REG_READ(&priv->regs->status);
0181 if ((status & AHBSTAT_STS_NE) == 0)
0182 return;
0183
0184
0185
0186
0187 fadr = REG_READ(&priv->regs->failing);
0188
0189 SPIN_LOCK(&priv->devlock, lock_context);
0190 priv->last_status = status;
0191 priv->last_address = fadr;
0192 SPIN_UNLOCK(&priv->devlock, lock_context);
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202 rc = 0;
0203 if (ahbstat_error != NULL)
0204 rc = ahbstat_error(priv->minor, priv->regs, status, fadr);
0205
0206 if ((rc & 0x1) == 0) {
0207 printk("\n### AHBSTAT: %s %s error of size %" PRId32
0208 " by master %" PRId32 " at 0x%08" PRIx32 "\n",
0209 status & AHBSTAT_STS_CE ? "single" : "non-correctable",
0210 status & AHBSTAT_STS_HW ? "write" : "read",
0211 (status & AHBSTAT_STS_HS) >> AHBSTAT_STS_HS_BIT,
0212 (status & AHBSTAT_STS_HM) >> AHBSTAT_STS_HM_BIT,
0213 fadr);
0214 }
0215
0216 if ((rc & 0x2) == 0) {
0217
0218 REG_WRITE(&priv->regs->status, 0);
0219 }
0220 }
0221
0222
0223
0224
0225
0226
0227
0228
0229 int ahbstat_last_error(int minor, uint32_t *status, uint32_t *address)
0230 {
0231 struct drvmgr_dev *dev;
0232 struct ahbstat_priv *priv;
0233 uint32_t last_status;
0234 uint32_t last_address;
0235 SPIN_IRQFLAGS(lock_context);
0236
0237 if (drvmgr_get_dev(&ahbstat_drv_info.general, minor, &dev)) {
0238 return -1;
0239 }
0240 priv = (struct ahbstat_priv *)dev->priv;
0241
0242
0243 SPIN_LOCK_IRQ(&priv->devlock, lock_context);
0244 last_status = REG_READ(&priv->last_status);
0245 last_address = REG_READ(&priv->last_address);
0246 SPIN_UNLOCK_IRQ(&priv->devlock, lock_context);
0247
0248 *status = last_status;
0249 *address = last_address;
0250
0251 return (last_status & AHBSTAT_STS_NE) >> AHBSTAT_STS_NE_BIT;
0252 }
0253
0254
0255 struct ahbstat_regs *ahbstat_get_regs(int minor)
0256 {
0257 struct drvmgr_dev *dev;
0258 struct ahbstat_priv *priv;
0259
0260 if (drvmgr_get_dev(&ahbstat_drv_info.general, minor, &dev)) {
0261 return NULL;
0262 }
0263 priv = (struct ahbstat_priv *)dev->priv;
0264
0265 return priv->regs;
0266 }