Home | History | Annotate | Line # | Download | only in ebus
icap_ebus.c revision 1.3
      1  1.3      chs /*	$NetBSD: icap_ebus.c,v 1.3 2012/10/27 17:17:45 chs Exp $	*/
      2  1.1    pooka 
      3  1.1    pooka /*-
      4  1.1    pooka  * Copyright (c) 2010 The NetBSD Foundation, Inc.
      5  1.1    pooka  * All rights reserved.
      6  1.1    pooka  *
      7  1.1    pooka  * This code was written by Alessandro Forin and Neil Pittman
      8  1.1    pooka  * at Microsoft Research and contributed to The NetBSD Foundation
      9  1.1    pooka  * by Microsoft Corporation.
     10  1.1    pooka  *
     11  1.1    pooka  * Redistribution and use in source and binary forms, with or without
     12  1.1    pooka  * modification, are permitted provided that the following conditions
     13  1.1    pooka  * are met:
     14  1.1    pooka  * 1. Redistributions of source code must retain the above copyright
     15  1.1    pooka  *    notice, this list of conditions and the following disclaimer.
     16  1.1    pooka  * 2. Redistributions in binary form must reproduce the above copyright
     17  1.1    pooka  *    notice, this list of conditions and the following disclaimer in the
     18  1.1    pooka  *    documentation and/or other materials provided with the distribution.
     19  1.1    pooka  *
     20  1.1    pooka  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21  1.1    pooka  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  1.1    pooka  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  1.1    pooka  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24  1.1    pooka  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  1.1    pooka  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  1.1    pooka  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  1.1    pooka  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  1.1    pooka  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  1.1    pooka  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  1.1    pooka  * POSSIBILITY OF SUCH DAMAGE.
     31  1.1    pooka  */
     32  1.1    pooka 
     33  1.1    pooka #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
     34  1.3      chs __KERNEL_RCSID(0, "$NetBSD: icap_ebus.c,v 1.3 2012/10/27 17:17:45 chs Exp $");
     35  1.1    pooka 
     36  1.1    pooka #include <sys/param.h>
     37  1.1    pooka #include <sys/systm.h>
     38  1.1    pooka #include <sys/buf.h>
     39  1.1    pooka #include <sys/bufq.h>
     40  1.1    pooka #include <sys/proc.h>
     41  1.1    pooka #include <sys/errno.h>
     42  1.1    pooka #include <sys/ioctl.h>
     43  1.1    pooka #include <sys/device.h>
     44  1.1    pooka #include <sys/conf.h>
     45  1.1    pooka #include <uvm/uvm_param.h>
     46  1.1    pooka 
     47  1.1    pooka #include <emips/ebus/ebusvar.h>
     48  1.1    pooka #include <emips/emips/machdep.h>
     49  1.1    pooka #include <machine/emipsreg.h>
     50  1.1    pooka 
     51  1.1    pooka #define DEBUG_INTR   0x01
     52  1.1    pooka #define DEBUG_XFERS  0x02
     53  1.1    pooka #define DEBUG_STATUS 0x04
     54  1.1    pooka #define DEBUG_FUNCS  0x08
     55  1.1    pooka #define DEBUG_PROBE  0x10
     56  1.1    pooka #define DEBUG_WRITES 0x20
     57  1.1    pooka #define DEBUG_READS  0x40
     58  1.1    pooka #define DEBUG_ERRORS 0x80
     59  1.1    pooka #ifdef DEBUG
     60  1.1    pooka int icap_debug = DEBUG_ERRORS;
     61  1.1    pooka #define ICAP_DEBUG(x) (icap_debug & (x))
     62  1.1    pooka #define DBGME(_lev_,_x_) if ((_lev_) & icap_debug) _x_
     63  1.1    pooka #else
     64  1.1    pooka #define ICAP_DEBUG(x) (0)
     65  1.1    pooka #define DBGME(_lev_,_x_)
     66  1.1    pooka #endif
     67  1.1    pooka #define DEBUG_PRINT(_args_,_lev_) DBGME(_lev_,printf _args_)
     68  1.1    pooka 
     69  1.1    pooka /*
     70  1.1    pooka  * Device softc
     71  1.1    pooka  */
     72  1.1    pooka struct icap_softc {
     73  1.1    pooka 	device_t sc_dev;
     74  1.1    pooka 	struct _Icap *sc_dp;
     75  1.1    pooka 	struct bufq_state *sc_buflist;
     76  1.1    pooka 	struct buf *sc_bp;
     77  1.1    pooka 	char *sc_data;
     78  1.1    pooka 	int sc_count;
     79  1.1    pooka };
     80  1.1    pooka 
     81  1.1    pooka /* Required funcs
     82  1.1    pooka  */
     83  1.3      chs static int	icap_ebus_match (device_t, cfdata_t, void *);
     84  1.3      chs static void	icap_ebus_attach (device_t, device_t, void *);
     85  1.1    pooka 
     86  1.1    pooka static dev_type_open(icapopen);
     87  1.1    pooka static dev_type_close(icapclose);
     88  1.1    pooka static dev_type_read(icapread);
     89  1.1    pooka static dev_type_write(icapwrite);
     90  1.1    pooka static dev_type_ioctl(icapioctl);
     91  1.1    pooka static dev_type_strategy(icapstrategy);
     92  1.1    pooka 
     93  1.1    pooka /* Other functions
     94  1.1    pooka  */
     95  1.1    pooka extern paddr_t kvtophys(vaddr_t);
     96  1.1    pooka static void icapstart(struct icap_softc *sc);
     97  1.1    pooka static int  icap_ebus_intr(void *cookie, void *f);
     98  1.1    pooka static void icap_reset(struct icap_softc *sc);
     99  1.1    pooka 
    100  1.1    pooka /* Config stuff
    101  1.1    pooka  */
    102  1.1    pooka extern struct cfdriver icap_cd;
    103  1.1    pooka 
    104  1.1    pooka CFATTACH_DECL_NEW(icap_ebus, sizeof (struct icap_softc),
    105  1.1    pooka     icap_ebus_match, icap_ebus_attach, NULL, NULL);
    106  1.1    pooka 
    107  1.1    pooka static int
    108  1.3      chs icap_ebus_match(device_t parent, cfdata_t match, void *aux)
    109  1.1    pooka {
    110  1.1    pooka 	struct ebus_attach_args *ia = aux;
    111  1.1    pooka     struct _Icap *f = (struct _Icap *)ia->ia_vaddr;
    112  1.1    pooka 
    113  1.1    pooka 	DEBUG_PRINT(("icap_match %x\n", (f) ? f->Tag : 0), DEBUG_PROBE);
    114  1.1    pooka 	if (strcmp("icap", ia->ia_name) != 0)
    115  1.1    pooka 		return (0);
    116  1.1    pooka     if ((f == NULL) ||
    117  1.1    pooka         (! (f->Tag == PMTTAG_ICAP)))
    118  1.1    pooka 		return (0);
    119  1.1    pooka 
    120  1.1    pooka 	return (1);
    121  1.1    pooka }
    122  1.1    pooka 
    123  1.1    pooka static void
    124  1.3      chs icap_ebus_attach(device_t parent, device_t self, void *aux)
    125  1.1    pooka {
    126  1.1    pooka 	struct icap_softc *sc = device_private(self);
    127  1.1    pooka 	struct ebus_attach_args *ia =aux;
    128  1.1    pooka 
    129  1.1    pooka 	DEBUG_PRINT(("icap_attach %p\n", sc), DEBUG_PROBE);
    130  1.1    pooka 
    131  1.1    pooka 	sc->sc_dev = self;
    132  1.1    pooka 	sc->sc_dp = (struct _Icap*)ia->ia_vaddr;
    133  1.1    pooka 	bufq_alloc(&sc->sc_buflist, "fcfs", 0);
    134  1.1    pooka 	sc->sc_bp = NULL;
    135  1.1    pooka 	sc->sc_data = NULL;
    136  1.1    pooka 	sc->sc_count = 0;
    137  1.1    pooka 
    138  1.1    pooka #if DEBUG
    139  1.1    pooka     printf(" virt=%p", (void*)sc->sc_dp);
    140  1.1    pooka #endif
    141  1.1    pooka 	printf(": %s\n", "Internal Configuration Access Port");
    142  1.1    pooka 
    143  1.1    pooka 	ebus_intr_establish(parent, (void*)ia->ia_cookie, IPL_BIO,
    144  1.1    pooka 	    icap_ebus_intr, sc);
    145  1.1    pooka 
    146  1.1    pooka 	icap_reset(sc);
    147  1.1    pooka }
    148  1.1    pooka 
    149  1.1    pooka /* The character device handlers
    150  1.1    pooka  */
    151  1.1    pooka const struct cdevsw icap_cdevsw = {
    152  1.1    pooka 	icapopen,
    153  1.1    pooka 	icapclose,
    154  1.1    pooka 	icapread,
    155  1.1    pooka 	icapwrite,
    156  1.1    pooka 	icapioctl,
    157  1.1    pooka 	nostop,
    158  1.1    pooka 	notty,
    159  1.1    pooka 	nopoll,
    160  1.1    pooka 	nommap,
    161  1.1    pooka 	nokqfilter,
    162  1.1    pooka };
    163  1.1    pooka 
    164  1.1    pooka /*
    165  1.1    pooka  * Handle an open request on the device.
    166  1.1    pooka  */
    167  1.1    pooka static int
    168  1.1    pooka icapopen(dev_t device, int flags, int fmt, struct lwp *process)
    169  1.1    pooka {
    170  1.1    pooka 	struct icap_softc *sc;
    171  1.1    pooka 
    172  1.1    pooka 	DEBUG_PRINT(("icapopen\n"), DEBUG_FUNCS);
    173  1.1    pooka 	sc = device_lookup_private(&icap_cd, minor(device));
    174  1.1    pooka 	if (sc == NULL)
    175  1.1    pooka 		return (ENXIO);
    176  1.1    pooka 
    177  1.1    pooka 	return 0;
    178  1.1    pooka }
    179  1.1    pooka 
    180  1.1    pooka /*
    181  1.1    pooka  * Handle the close request for the device.
    182  1.1    pooka  */
    183  1.1    pooka static int
    184  1.1    pooka icapclose(dev_t device, int flags, int fmt, struct lwp *process)
    185  1.1    pooka {
    186  1.1    pooka 	DEBUG_PRINT(("icapclose\n"), DEBUG_FUNCS);
    187  1.1    pooka 	return 0; /* this always succeeds */
    188  1.1    pooka }
    189  1.1    pooka 
    190  1.1    pooka /*
    191  1.1    pooka  * Handle the read request for the device.
    192  1.1    pooka  */
    193  1.1    pooka static int
    194  1.1    pooka icapread(dev_t dev, struct uio *uio, int flags)
    195  1.1    pooka {
    196  1.1    pooka 	DEBUG_PRINT(("icapread\n"), DEBUG_READS);
    197  1.1    pooka 	return (physio(icapstrategy, NULL, dev, B_READ, minphys, uio));
    198  1.1    pooka }
    199  1.1    pooka 
    200  1.1    pooka /*
    201  1.1    pooka  * Handle the write request for the device.
    202  1.1    pooka  */
    203  1.1    pooka static int
    204  1.1    pooka icapwrite(dev_t dev, struct uio *uio, int flags)
    205  1.1    pooka {
    206  1.1    pooka 	DEBUG_PRINT(("icapwrite\n"), DEBUG_WRITES);
    207  1.1    pooka 	return (physio(icapstrategy, NULL, dev, B_WRITE, minphys, uio));
    208  1.1    pooka }
    209  1.1    pooka 
    210  1.1    pooka /*
    211  1.1    pooka  * Handle the ioctl request for the device.
    212  1.1    pooka  */
    213  1.1    pooka static int
    214  1.1    pooka icapioctl(dev_t dev, u_long xfer, void *addr, int flag, struct lwp *l)
    215  1.1    pooka {
    216  1.1    pooka 
    217  1.1    pooka 	return ENOTTY;
    218  1.1    pooka }
    219  1.1    pooka 
    220  1.1    pooka /*
    221  1.1    pooka  * Strategy function for the device.
    222  1.1    pooka  */
    223  1.1    pooka static void
    224  1.1    pooka icapstrategy(struct buf *bp)
    225  1.1    pooka {
    226  1.1    pooka 	struct icap_softc *sc;
    227  1.1    pooka 	int s;
    228  1.1    pooka 
    229  1.1    pooka 	DEBUG_PRINT(("icapstrategy\n"), DEBUG_FUNCS);
    230  1.1    pooka 
    231  1.1    pooka 	/* We did nothing lest we did */
    232  1.1    pooka 	bp->b_resid = bp->b_bcount;
    233  1.1    pooka 
    234  1.1    pooka 	/* Do we know you.  */
    235  1.1    pooka 	sc = device_lookup_private(&icap_cd, minor(bp->b_dev));
    236  1.1    pooka 	if (sc == NULL) {
    237  1.2  tsutsui 		DEBUG_PRINT(("icapstrategy: nodev %" PRIx64 "\n",bp->b_dev),
    238  1.1    pooka 		    DEBUG_ERRORS);
    239  1.1    pooka 		bp->b_error = ENXIO;
    240  1.1    pooka 		biodone(bp);
    241  1.1    pooka 		return;
    242  1.1    pooka 	    }
    243  1.1    pooka 
    244  1.1    pooka 	/* Add to Q. If Q was empty get it started */
    245  1.1    pooka 	s = splbio();
    246  1.1    pooka 	bufq_put(sc->sc_buflist, bp);
    247  1.1    pooka 	if (bufq_peek(sc->sc_buflist) == bp) {
    248  1.1    pooka 		icapstart(sc);
    249  1.1    pooka 	}
    250  1.1    pooka 	splx(s);
    251  1.1    pooka }
    252  1.1    pooka 
    253  1.1    pooka /*
    254  1.1    pooka  * Get the next I/O request started
    255  1.1    pooka  */
    256  1.1    pooka static void
    257  1.1    pooka icapstart(struct icap_softc *sc)
    258  1.1    pooka {
    259  1.1    pooka 	paddr_t phys, phys2;
    260  1.1    pooka 	vaddr_t virt;
    261  1.1    pooka 	size_t count;
    262  1.1    pooka 	uint32_t fl;
    263  1.1    pooka 	struct buf *bp = sc->sc_bp;
    264  1.1    pooka 
    265  1.1    pooka 	DEBUG_PRINT(("icapstart %p %p\n",sc,bp), DEBUG_FUNCS);
    266  1.1    pooka 
    267  1.1    pooka     /* Were we idle?
    268  1.1    pooka      */
    269  1.1    pooka  recheck:
    270  1.1    pooka     if (bp == NULL) {
    271  1.1    pooka 
    272  1.1    pooka         /* Yes, get the next request if any
    273  1.1    pooka          */
    274  1.1    pooka         bp = bufq_get(sc->sc_buflist);
    275  1.1    pooka         DEBUG_PRINT(("icapnext: %p\n",bp), DEBUG_XFERS);
    276  1.1    pooka         if (bp == NULL)
    277  1.1    pooka             return;
    278  1.1    pooka     }
    279  1.1    pooka 
    280  1.1    pooka     /* Done with this request?
    281  1.1    pooka      */
    282  1.1    pooka     if ((bp->b_resid == 0) || bp->b_error) {
    283  1.1    pooka 
    284  1.1    pooka         /* Yes, complete and move to next, if any
    285  1.1    pooka          */
    286  1.1    pooka         sc->sc_bp = NULL;
    287  1.1    pooka         biodone(bp);
    288  1.1    pooka         DEBUG_PRINT(("icapdone %p\n",bp), DEBUG_XFERS);
    289  1.1    pooka         bp = NULL;
    290  1.1    pooka         goto recheck;
    291  1.1    pooka     }
    292  1.1    pooka 
    293  1.1    pooka     /* If new request init the xfer info
    294  1.1    pooka      */
    295  1.1    pooka     if (sc->sc_bp == NULL) {
    296  1.1    pooka         sc->sc_bp = bp;
    297  1.1    pooka         sc->sc_data = bp->b_data;
    298  1.1    pooka         sc->sc_count = bp->b_resid;
    299  1.1    pooka     }
    300  1.1    pooka 
    301  1.1    pooka     /* Loop filling as many buffers as will fit in the FIFO
    302  1.1    pooka      */
    303  1.1    pooka     fl = (bp->b_flags & B_READ) ? ICAPS_F_RECV : ICAPS_F_XMIT;
    304  1.1    pooka     for (;;) {
    305  1.1    pooka 
    306  1.1    pooka         /* Make sure there's still room in the FIFO, no errors.
    307  1.1    pooka          */
    308  1.1    pooka         if (sc->sc_dp->Control & (ICAPC_IF_FULL|ICAPC_ERROR))
    309  1.1    pooka             break;
    310  1.1    pooka 
    311  1.1    pooka         /* How much data do we xfer and where
    312  1.1    pooka          */
    313  1.1    pooka         virt = (vaddr_t)sc->sc_data;
    314  1.1    pooka         phys = kvtophys(virt);
    315  1.1    pooka         count = round_page(virt) - virt;
    316  1.1    pooka         if (count == 0) count = PAGE_SIZE;/* could(will) be aligned */
    317  1.1    pooka 
    318  1.1    pooka         /* How much of it is contiguous
    319  1.1    pooka          */
    320  1.1    pooka         while (count < sc->sc_count) {
    321  1.1    pooka             phys2 = kvtophys(virt + count);
    322  1.1    pooka             if (phys2 != (phys + count)) {
    323  1.1    pooka 
    324  1.1    pooka                 /* No longer contig, ship it
    325  1.1    pooka                  */
    326  1.1    pooka                 break;
    327  1.1    pooka             }
    328  1.1    pooka             count += PAGE_SIZE;
    329  1.1    pooka         }
    330  1.1    pooka 
    331  1.1    pooka         /* Trim if we went too far
    332  1.1    pooka          */
    333  1.1    pooka         if (count > sc->sc_count)
    334  1.1    pooka             count = sc->sc_count;
    335  1.1    pooka 
    336  1.1    pooka         /* Ship it
    337  1.1    pooka          */
    338  1.2  tsutsui         DEBUG_PRINT(("icapship %" PRIxPADDR " %d\n",phys,count), DEBUG_XFERS);
    339  1.1    pooka         sc->sc_dp->SizeAndFlags = fl | count;
    340  1.1    pooka         sc->sc_dp->BufferAddressHi32 = 0; /* BUGBUG 64bit */
    341  1.1    pooka         sc->sc_dp->BufferAddressLo32 = phys; /* this pushes the fifo */
    342  1.1    pooka 
    343  1.1    pooka         /* Adjust pointers and continue
    344  1.1    pooka          */
    345  1.1    pooka         sc->sc_data  += count;
    346  1.1    pooka         sc->sc_count -= count;
    347  1.1    pooka 
    348  1.1    pooka         if (sc->sc_count <= 0)
    349  1.1    pooka             break;
    350  1.1    pooka     }
    351  1.1    pooka }
    352  1.1    pooka 
    353  1.1    pooka /*
    354  1.1    pooka  * Interrupt handler
    355  1.1    pooka  */
    356  1.1    pooka static int
    357  1.1    pooka icap_ebus_intr(void *cookie, void *f)
    358  1.1    pooka {
    359  1.1    pooka 	struct icap_softc *sc = cookie;
    360  1.1    pooka     struct buf *bp = sc->sc_bp;
    361  1.1    pooka 	u_int32_t isr, saf = 0, hi, lo;
    362  1.1    pooka 
    363  1.1    pooka 	isr = sc->sc_dp->Control;
    364  1.1    pooka 
    365  1.1    pooka 	DEBUG_PRINT(("i %x\n",isr), DEBUG_INTR);
    366  1.1    pooka 
    367  1.1    pooka     /* Make sure there is an interrupt and that we should take it
    368  1.1    pooka      */
    369  1.1    pooka 	if ((isr & (ICAPC_INTEN|ICAPC_DONE)) != (ICAPC_INTEN|ICAPC_DONE))
    370  1.1    pooka 		return (0);
    371  1.1    pooka 
    372  1.1    pooka     /* Pull out all completed buffers
    373  1.1    pooka      */
    374  1.1    pooka     while ((isr & ICAPC_OF_EMPTY) == 0) {
    375  1.1    pooka 
    376  1.1    pooka         if (isr & ICAPC_ERROR) {
    377  1.1    pooka             printf("%s: internal error (%x)\n", device_xname(sc->sc_dev),isr);
    378  1.1    pooka             icap_reset(sc);
    379  1.1    pooka             if (bp) {
    380  1.1    pooka                 bp->b_error = EIO;
    381  1.1    pooka                 icapstart(sc);
    382  1.1    pooka             }
    383  1.1    pooka             return (1);
    384  1.1    pooka         }
    385  1.1    pooka 
    386  1.1    pooka         /* Beware, order matters */
    387  1.1    pooka         saf = sc->sc_dp->SizeAndFlags;
    388  1.1    pooka         hi  = sc->sc_dp->BufferAddressHi32; /* BUGBUG 64bit */
    389  1.1    pooka         lo  = sc->sc_dp->BufferAddressLo32; /* this pops the fifo */
    390  1.1    pooka 
    391  1.1    pooka         /* Say its done that much (and sanity)
    392  1.1    pooka          */
    393  1.1    pooka         if (bp) {
    394  1.1    pooka             size_t count = saf & ICAPS_S_MASK;
    395  1.1    pooka             /* more sanity */
    396  1.1    pooka             if (count > bp->b_resid)
    397  1.1    pooka                 count = bp->b_resid;
    398  1.1    pooka             bp->b_resid -= count;
    399  1.1    pooka         }
    400  1.1    pooka 
    401  1.1    pooka         /* More? */
    402  1.1    pooka         isr = sc->sc_dp->Control;
    403  1.1    pooka     }
    404  1.1    pooka 
    405  1.1    pooka     /* Did we pop at least one */
    406  1.1    pooka     if (saf)
    407  1.1    pooka         icapstart(sc);
    408  1.1    pooka 
    409  1.1    pooka 	return (1);
    410  1.1    pooka }
    411  1.1    pooka 
    412  1.1    pooka /*
    413  1.1    pooka  * HW (re)Initialization
    414  1.1    pooka  */
    415  1.1    pooka static void
    416  1.1    pooka icap_reset(struct icap_softc *sc)
    417  1.1    pooka {
    418  1.1    pooka 	DEBUG_PRINT(("icap_reset %x\n",sc->sc_dp->Control), DEBUG_STATUS);
    419  1.1    pooka     sc->sc_dp->Control = ICAPC_RESET;
    420  1.1    pooka     DELAY(2);
    421  1.1    pooka     sc->sc_dp->Control = ICAPC_INTEN;
    422  1.1    pooka }
    423