Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Access to HP-HIL MLC through HP System Device Controller.
0003  *
0004  * Copyright (c) 2001 Brian S. Julin
0005  * All rights reserved.
0006  *
0007  * Redistribution and use in source and binary forms, with or without
0008  * modification, are permitted provided that the following conditions
0009  * are met:
0010  * 1. Redistributions of source code must retain the above copyright
0011  *    notice, this list of conditions, and the following disclaimer,
0012  *    without modification.
0013  * 2. The name of the author may not be used to endorse or promote products
0014  *    derived from this software without specific prior written permission.
0015  *
0016  * Alternatively, this software may be distributed under the terms of the
0017  * GNU General Public License ("GPL").
0018  *
0019  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
0020  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0021  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0022  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
0023  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0024  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0025  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0026  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0027  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0028  *
0029  * References:
0030  * HP-HIL Technical Reference Manual.  Hewlett Packard Product No. 45918A
0031  * System Device Controller Microprocessor Firmware Theory of Operation
0032  *      for Part Number 1820-4784 Revision B.  Dwg No. A-1820-4784-2
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 /************************* Interrupt context ******************************/
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     /* We know status is 5X */
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     /* No more data will be coming due to an error. */
0133  done:
0134     tasklet_schedule(mlc->tasklet);
0135     up(&mlc->isem);
0136  out:
0137     write_unlock(&mlc->lock);
0138 }
0139 
0140 
0141 /******************** Tasklet or userspace context functions ****************/
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     /* Try to down the semaphore */
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             /* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */
0160             goto wasup;
0161         }
0162         if (time_after(jiffies, mlc->instart + mlc->intimeout)) {
0163             /*  printk("!%i %i",
0164                 tv.tv_usec - mlc->instart.tv_usec,
0165                 mlc->intimeout);
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     /* Try to down the semaphores -- they should be up. */
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     /* Try to down the semaphore -- it should be up. */
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     /* Shouldn't be sending commands when loop may be busy */
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;  /* No timeout */
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     /* we cannot emulate this, it should not be used. */
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     /* Should not send command/data after engaging APE */
0273     BUG_ON(mlc->opacket & HIL_CTRL_APE);
0274 
0275     /* Disengaging APE this way would not be valid either since
0276      * the loop must be allowed to idle.
0277      *
0278      * So, it works out that we really never actually send control
0279      * and data when using SDC, we just send the data.
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     /* priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC; */
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);