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
0031
0032
0033
0034
0035
0036 #include <linux/hil_mlc.h>
0037 #include <linux/hp_sdc.h>
0038 #include <linux/errno.h>
0039 #include <linux/kernel.h>
0040 #include <linux/module.h>
0041 #include <linux/init.h>
0042 #include <linux/string.h>
0043 #include <linux/semaphore.h>
0044
0045 #define PREFIX "HP SDC MLC: "
0046
0047 static hil_mlc hp_sdc_mlc;
0048
0049 MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
0050 MODULE_DESCRIPTION("Glue for onboard HIL MLC in HP-PARISC machines");
0051 MODULE_LICENSE("Dual BSD/GPL");
0052
0053 static struct hp_sdc_mlc_priv_s {
0054 int emtestmode;
0055 hp_sdc_transaction trans;
0056 u8 tseq[16];
0057 int got5x;
0058 } hp_sdc_mlc_priv;
0059
0060
0061 static void hp_sdc_mlc_isr (int irq, void *dev_id,
0062 uint8_t status, uint8_t data)
0063 {
0064 int idx;
0065 hil_mlc *mlc = &hp_sdc_mlc;
0066
0067 write_lock(&mlc->lock);
0068 if (mlc->icount < 0) {
0069 printk(KERN_WARNING PREFIX "HIL Overflow!\n");
0070 up(&mlc->isem);
0071 goto out;
0072 }
0073 idx = 15 - mlc->icount;
0074 if ((status & HP_SDC_STATUS_IRQMASK) == HP_SDC_STATUS_HILDATA) {
0075 mlc->ipacket[idx] |= data | HIL_ERR_INT;
0076 mlc->icount--;
0077 if (hp_sdc_mlc_priv.got5x || !idx)
0078 goto check;
0079 if ((mlc->ipacket[idx - 1] & HIL_PKT_ADDR_MASK) !=
0080 (mlc->ipacket[idx] & HIL_PKT_ADDR_MASK)) {
0081 mlc->ipacket[idx] &= ~HIL_PKT_ADDR_MASK;
0082 mlc->ipacket[idx] |= (mlc->ipacket[idx - 1]
0083 & HIL_PKT_ADDR_MASK);
0084 }
0085 goto check;
0086 }
0087
0088 if (data & HP_SDC_HIL_ISERR)
0089 goto err;
0090 mlc->ipacket[idx] =
0091 (data & HP_SDC_HIL_R1MASK) << HIL_PKT_ADDR_SHIFT;
0092 hp_sdc_mlc_priv.got5x = 1;
0093 goto out;
0094
0095 check:
0096 hp_sdc_mlc_priv.got5x = 0;
0097 if (mlc->imatch == 0)
0098 goto done;
0099 if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
0100 && (mlc->ipacket[idx] == (mlc->imatch | idx)))
0101 goto done;
0102 if (mlc->ipacket[idx] == mlc->imatch)
0103 goto done;
0104 goto out;
0105
0106 err:
0107 printk(KERN_DEBUG PREFIX "err code %x\n", data);
0108
0109 switch (data) {
0110 case HP_SDC_HIL_RC_DONE:
0111 printk(KERN_WARNING PREFIX "Bastard SDC reconfigured loop!\n");
0112 break;
0113
0114 case HP_SDC_HIL_ERR:
0115 mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR |
0116 HIL_ERR_FERR | HIL_ERR_FOF;
0117 break;
0118
0119 case HP_SDC_HIL_TO:
0120 mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_LERR;
0121 break;
0122
0123 case HP_SDC_HIL_RC:
0124 printk(KERN_WARNING PREFIX "Bastard SDC decided to reconfigure loop!\n");
0125 break;
0126
0127 default:
0128 printk(KERN_WARNING PREFIX "Unknown HIL Error status (%x)!\n", data);
0129 break;
0130 }
0131
0132
0133 done:
0134 tasklet_schedule(mlc->tasklet);
0135 up(&mlc->isem);
0136 out:
0137 write_unlock(&mlc->lock);
0138 }
0139
0140
0141
0142
0143 static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout)
0144 {
0145 struct hp_sdc_mlc_priv_s *priv;
0146 int rc = 2;
0147
0148 priv = mlc->priv;
0149
0150
0151 if (down_trylock(&mlc->isem)) {
0152 if (priv->emtestmode) {
0153 mlc->ipacket[0] =
0154 HIL_ERR_INT | (mlc->opacket &
0155 (HIL_PKT_CMD |
0156 HIL_PKT_ADDR_MASK |
0157 HIL_PKT_DATA_MASK));
0158 mlc->icount = 14;
0159
0160 goto wasup;
0161 }
0162 if (time_after(jiffies, mlc->instart + mlc->intimeout)) {
0163
0164
0165
0166
0167 rc = 1;
0168 up(&mlc->isem);
0169 }
0170 goto done;
0171 }
0172 wasup:
0173 up(&mlc->isem);
0174 rc = 0;
0175 done:
0176 return rc;
0177 }
0178
0179 static int hp_sdc_mlc_cts(hil_mlc *mlc)
0180 {
0181 struct hp_sdc_mlc_priv_s *priv;
0182
0183 priv = mlc->priv;
0184
0185
0186 BUG_ON(down_trylock(&mlc->isem));
0187 BUG_ON(down_trylock(&mlc->osem));
0188
0189 up(&mlc->isem);
0190 up(&mlc->osem);
0191
0192 if (down_trylock(&mlc->csem)) {
0193 if (priv->trans.act.semaphore != &mlc->csem)
0194 goto poll;
0195 else
0196 goto busy;
0197 }
0198
0199 if (!(priv->tseq[4] & HP_SDC_USE_LOOP))
0200 goto done;
0201
0202 poll:
0203 priv->trans.act.semaphore = &mlc->csem;
0204 priv->trans.actidx = 0;
0205 priv->trans.idx = 1;
0206 priv->trans.endidx = 5;
0207 priv->tseq[0] =
0208 HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
0209 priv->tseq[1] = HP_SDC_CMD_READ_USE;
0210 priv->tseq[2] = 1;
0211 priv->tseq[3] = 0;
0212 priv->tseq[4] = 0;
0213 return __hp_sdc_enqueue_transaction(&priv->trans);
0214 busy:
0215 return 1;
0216 done:
0217 priv->trans.act.semaphore = &mlc->osem;
0218 up(&mlc->csem);
0219 return 0;
0220 }
0221
0222 static int hp_sdc_mlc_out(hil_mlc *mlc)
0223 {
0224 struct hp_sdc_mlc_priv_s *priv;
0225
0226 priv = mlc->priv;
0227
0228
0229 BUG_ON(down_trylock(&mlc->osem));
0230
0231 if (mlc->opacket & HIL_DO_ALTER_CTRL)
0232 goto do_control;
0233
0234 do_data:
0235 if (priv->emtestmode) {
0236 up(&mlc->osem);
0237 return 0;
0238 }
0239
0240 BUG_ON(down_trylock(&mlc->csem));
0241 up(&mlc->csem);
0242
0243 priv->trans.actidx = 0;
0244 priv->trans.idx = 1;
0245 priv->trans.act.semaphore = &mlc->osem;
0246 priv->trans.endidx = 6;
0247 priv->tseq[0] =
0248 HP_SDC_ACT_DATAREG | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_SEMAPHORE;
0249 priv->tseq[1] = 0x7;
0250 priv->tseq[2] =
0251 (mlc->opacket &
0252 (HIL_PKT_ADDR_MASK | HIL_PKT_CMD))
0253 >> HIL_PKT_ADDR_SHIFT;
0254 priv->tseq[3] =
0255 (mlc->opacket & HIL_PKT_DATA_MASK)
0256 >> HIL_PKT_DATA_SHIFT;
0257 priv->tseq[4] = 0;
0258 if (priv->tseq[3] == HIL_CMD_DHR)
0259 priv->tseq[4] = 1;
0260 priv->tseq[5] = HP_SDC_CMD_DO_HIL;
0261 goto enqueue;
0262
0263 do_control:
0264 priv->emtestmode = mlc->opacket & HIL_CTRL_TEST;
0265
0266
0267 BUG_ON((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE);
0268
0269 if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY)
0270 goto control_only;
0271
0272
0273 BUG_ON(mlc->opacket & HIL_CTRL_APE);
0274
0275
0276
0277
0278
0279
0280
0281 goto do_data;
0282
0283 control_only:
0284 priv->trans.actidx = 0;
0285 priv->trans.idx = 1;
0286 priv->trans.act.semaphore = &mlc->osem;
0287 priv->trans.endidx = 4;
0288 priv->tseq[0] =
0289 HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
0290 priv->tseq[1] = HP_SDC_CMD_SET_LPC;
0291 priv->tseq[2] = 1;
0292
0293 priv->tseq[3] = 0;
0294 if (mlc->opacket & HIL_CTRL_APE) {
0295 priv->tseq[3] |= HP_SDC_LPC_APE_IPF;
0296 BUG_ON(down_trylock(&mlc->csem));
0297 }
0298 enqueue:
0299 return hp_sdc_enqueue_transaction(&priv->trans);
0300 }
0301
0302 static int __init hp_sdc_mlc_init(void)
0303 {
0304 hil_mlc *mlc = &hp_sdc_mlc;
0305 int err;
0306
0307 #ifdef __mc68000__
0308 if (!MACH_IS_HP300)
0309 return -ENODEV;
0310 #endif
0311
0312 printk(KERN_INFO PREFIX "Registering the System Domain Controller's HIL MLC.\n");
0313
0314 hp_sdc_mlc_priv.emtestmode = 0;
0315 hp_sdc_mlc_priv.trans.seq = hp_sdc_mlc_priv.tseq;
0316 hp_sdc_mlc_priv.trans.act.semaphore = &mlc->osem;
0317 hp_sdc_mlc_priv.got5x = 0;
0318
0319 mlc->cts = &hp_sdc_mlc_cts;
0320 mlc->in = &hp_sdc_mlc_in;
0321 mlc->out = &hp_sdc_mlc_out;
0322 mlc->priv = &hp_sdc_mlc_priv;
0323
0324 err = hil_mlc_register(mlc);
0325 if (err) {
0326 printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n");
0327 return err;
0328 }
0329
0330 if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) {
0331 printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n");
0332 if (hil_mlc_unregister(mlc))
0333 printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
0334 "This is bad. Could cause an oops.\n");
0335 return -EBUSY;
0336 }
0337
0338 return 0;
0339 }
0340
0341 static void __exit hp_sdc_mlc_exit(void)
0342 {
0343 hil_mlc *mlc = &hp_sdc_mlc;
0344
0345 if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr))
0346 printk(KERN_ERR PREFIX "Failed to release the raw HIL ISR hook.\n"
0347 "This is bad. Could cause an oops.\n");
0348
0349 if (hil_mlc_unregister(mlc))
0350 printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
0351 "This is bad. Could cause an oops.\n");
0352 }
0353
0354 module_init(hp_sdc_mlc_init);
0355 module_exit(hp_sdc_mlc_exit);