16e747b4bSRussell King /* 26e747b4bSRussell King * linux/arch/arm/kernel/ecard.c 36e747b4bSRussell King * 46e747b4bSRussell King * Copyright 1995-2001 Russell King 56e747b4bSRussell King * 66e747b4bSRussell King * This program is free software; you can redistribute it and/or modify 76e747b4bSRussell King * it under the terms of the GNU General Public License version 2 as 86e747b4bSRussell King * published by the Free Software Foundation. 96e747b4bSRussell King * 106e747b4bSRussell King * Find all installed expansion cards, and handle interrupts from them. 116e747b4bSRussell King * 126e747b4bSRussell King * Created from information from Acorns RiscOS3 PRMs 136e747b4bSRussell King * 146e747b4bSRussell King * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether 156e747b4bSRussell King * podule slot. 166e747b4bSRussell King * 06-May-1997 RMK Added blacklist for cards whose loader doesn't work. 176e747b4bSRussell King * 12-Sep-1997 RMK Created new handling of interrupt enables/disables 186e747b4bSRussell King * - cards can now register their own routine to control 196e747b4bSRussell King * interrupts (recommended). 206e747b4bSRussell King * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled 216e747b4bSRussell King * on reset from Linux. (Caused cards not to respond 226e747b4bSRussell King * under RiscOS without hard reset). 236e747b4bSRussell King * 15-Feb-1998 RMK Added DMA support 246e747b4bSRussell King * 12-Sep-1998 RMK Added EASI support 256e747b4bSRussell King * 10-Jan-1999 RMK Run loaders in a simulated RISC OS environment. 266e747b4bSRussell King * 17-Apr-1999 RMK Support for EASI Type C cycles. 276e747b4bSRussell King */ 286e747b4bSRussell King #define ECARD_C 296e747b4bSRussell King 306e747b4bSRussell King #include <linux/module.h> 316e747b4bSRussell King #include <linux/kernel.h> 326e747b4bSRussell King #include <linux/types.h> 336e747b4bSRussell King #include <linux/sched.h> 346e747b4bSRussell King #include <linux/interrupt.h> 356e747b4bSRussell King #include <linux/completion.h> 366e747b4bSRussell King #include <linux/reboot.h> 376e747b4bSRussell King #include <linux/mm.h> 386e747b4bSRussell King #include <linux/slab.h> 396e747b4bSRussell King #include <linux/proc_fs.h> 406e747b4bSRussell King #include <linux/seq_file.h> 416e747b4bSRussell King #include <linux/device.h> 426e747b4bSRussell King #include <linux/init.h> 436e747b4bSRussell King #include <linux/mutex.h> 446e747b4bSRussell King #include <linux/kthread.h> 456e747b4bSRussell King #include <linux/io.h> 466e747b4bSRussell King 476e747b4bSRussell King #include <asm/dma.h> 486e747b4bSRussell King #include <asm/ecard.h> 496e747b4bSRussell King #include <mach/hardware.h> 506e747b4bSRussell King #include <asm/irq.h> 516e747b4bSRussell King #include <asm/mmu_context.h> 526e747b4bSRussell King #include <asm/mach/irq.h> 536e747b4bSRussell King #include <asm/tlbflush.h> 546e747b4bSRussell King 556e747b4bSRussell King #include "ecard.h" 566e747b4bSRussell King 576e747b4bSRussell King #ifndef CONFIG_ARCH_RPC 586e747b4bSRussell King #define HAVE_EXPMASK 596e747b4bSRussell King #endif 606e747b4bSRussell King 616e747b4bSRussell King struct ecard_request { 626e747b4bSRussell King void (*fn)(struct ecard_request *); 636e747b4bSRussell King ecard_t *ec; 646e747b4bSRussell King unsigned int address; 656e747b4bSRussell King unsigned int length; 666e747b4bSRussell King unsigned int use_loader; 676e747b4bSRussell King void *buffer; 686e747b4bSRussell King struct completion *complete; 696e747b4bSRussell King }; 706e747b4bSRussell King 716e747b4bSRussell King struct expcard_blacklist { 726e747b4bSRussell King unsigned short manufacturer; 736e747b4bSRussell King unsigned short product; 746e747b4bSRussell King const char *type; 756e747b4bSRussell King }; 766e747b4bSRussell King 776e747b4bSRussell King static ecard_t *cards; 786e747b4bSRussell King static ecard_t *slot_to_expcard[MAX_ECARDS]; 796e747b4bSRussell King static unsigned int ectcr; 806e747b4bSRussell King #ifdef HAS_EXPMASK 816e747b4bSRussell King static unsigned int have_expmask; 826e747b4bSRussell King #endif 836e747b4bSRussell King 846e747b4bSRussell King /* List of descriptions of cards which don't have an extended 856e747b4bSRussell King * identification, or chunk directories containing a description. 866e747b4bSRussell King */ 876e747b4bSRussell King static struct expcard_blacklist __initdata blacklist[] = { 886e747b4bSRussell King { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" } 896e747b4bSRussell King }; 906e747b4bSRussell King 916e747b4bSRussell King asmlinkage extern int 926e747b4bSRussell King ecard_loader_reset(unsigned long base, loader_t loader); 936e747b4bSRussell King asmlinkage extern int 946e747b4bSRussell King ecard_loader_read(int off, unsigned long base, loader_t loader); 956e747b4bSRussell King 966e747b4bSRussell King static inline unsigned short ecard_getu16(unsigned char *v) 976e747b4bSRussell King { 986e747b4bSRussell King return v[0] | v[1] << 8; 996e747b4bSRussell King } 1006e747b4bSRussell King 1016e747b4bSRussell King static inline signed long ecard_gets24(unsigned char *v) 1026e747b4bSRussell King { 1036e747b4bSRussell King return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0); 1046e747b4bSRussell King } 1056e747b4bSRussell King 1066e747b4bSRussell King static inline ecard_t *slot_to_ecard(unsigned int slot) 1076e747b4bSRussell King { 1086e747b4bSRussell King return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL; 1096e747b4bSRussell King } 1106e747b4bSRussell King 1116e747b4bSRussell King /* ===================== Expansion card daemon ======================== */ 1126e747b4bSRussell King /* 1136e747b4bSRussell King * Since the loader programs on the expansion cards need to be run 1146e747b4bSRussell King * in a specific environment, create a separate task with this 1156e747b4bSRussell King * environment up, and pass requests to this task as and when we 1166e747b4bSRussell King * need to. 1176e747b4bSRussell King * 1186e747b4bSRussell King * This should allow 99% of loaders to be called from Linux. 1196e747b4bSRussell King * 1206e747b4bSRussell King * From a security standpoint, we trust the card vendors. This 1216e747b4bSRussell King * may be a misplaced trust. 1226e747b4bSRussell King */ 1236e747b4bSRussell King static void ecard_task_reset(struct ecard_request *req) 1246e747b4bSRussell King { 1256e747b4bSRussell King struct expansion_card *ec = req->ec; 1266e747b4bSRussell King struct resource *res; 1276e747b4bSRussell King 1286e747b4bSRussell King res = ec->slot_no == 8 1296e747b4bSRussell King ? &ec->resource[ECARD_RES_MEMC] 1306e747b4bSRussell King : ec->easi 1316e747b4bSRussell King ? &ec->resource[ECARD_RES_EASI] 1326e747b4bSRussell King : &ec->resource[ECARD_RES_IOCSYNC]; 1336e747b4bSRussell King 1346e747b4bSRussell King ecard_loader_reset(res->start, ec->loader); 1356e747b4bSRussell King } 1366e747b4bSRussell King 1376e747b4bSRussell King static void ecard_task_readbytes(struct ecard_request *req) 1386e747b4bSRussell King { 1396e747b4bSRussell King struct expansion_card *ec = req->ec; 1406e747b4bSRussell King unsigned char *buf = req->buffer; 1416e747b4bSRussell King unsigned int len = req->length; 1426e747b4bSRussell King unsigned int off = req->address; 1436e747b4bSRussell King 1446e747b4bSRussell King if (ec->slot_no == 8) { 1456e747b4bSRussell King void __iomem *base = (void __iomem *) 1466e747b4bSRussell King ec->resource[ECARD_RES_MEMC].start; 1476e747b4bSRussell King 1486e747b4bSRussell King /* 1496e747b4bSRussell King * The card maintains an index which increments the address 1506e747b4bSRussell King * into a 4096-byte page on each access. We need to keep 1516e747b4bSRussell King * track of the counter. 1526e747b4bSRussell King */ 1536e747b4bSRussell King static unsigned int index; 1546e747b4bSRussell King unsigned int page; 1556e747b4bSRussell King 1566e747b4bSRussell King page = (off >> 12) * 4; 1576e747b4bSRussell King if (page > 256 * 4) 1586e747b4bSRussell King return; 1596e747b4bSRussell King 1606e747b4bSRussell King off &= 4095; 1616e747b4bSRussell King 1626e747b4bSRussell King /* 1636e747b4bSRussell King * If we are reading offset 0, or our current index is 1646e747b4bSRussell King * greater than the offset, reset the hardware index counter. 1656e747b4bSRussell King */ 1666e747b4bSRussell King if (off == 0 || index > off) { 1676e747b4bSRussell King writeb(0, base); 1686e747b4bSRussell King index = 0; 1696e747b4bSRussell King } 1706e747b4bSRussell King 1716e747b4bSRussell King /* 1726e747b4bSRussell King * Increment the hardware index counter until we get to the 1736e747b4bSRussell King * required offset. The read bytes are discarded. 1746e747b4bSRussell King */ 1756e747b4bSRussell King while (index < off) { 1766e747b4bSRussell King readb(base + page); 1776e747b4bSRussell King index += 1; 1786e747b4bSRussell King } 1796e747b4bSRussell King 1806e747b4bSRussell King while (len--) { 1816e747b4bSRussell King *buf++ = readb(base + page); 1826e747b4bSRussell King index += 1; 1836e747b4bSRussell King } 1846e747b4bSRussell King } else { 1856e747b4bSRussell King unsigned long base = (ec->easi 1866e747b4bSRussell King ? &ec->resource[ECARD_RES_EASI] 1876e747b4bSRussell King : &ec->resource[ECARD_RES_IOCSYNC])->start; 1886e747b4bSRussell King void __iomem *pbase = (void __iomem *)base; 1896e747b4bSRussell King 1906e747b4bSRussell King if (!req->use_loader || !ec->loader) { 1916e747b4bSRussell King off *= 4; 1926e747b4bSRussell King while (len--) { 1936e747b4bSRussell King *buf++ = readb(pbase + off); 1946e747b4bSRussell King off += 4; 1956e747b4bSRussell King } 1966e747b4bSRussell King } else { 1976e747b4bSRussell King while(len--) { 1986e747b4bSRussell King /* 1996e747b4bSRussell King * The following is required by some 2006e747b4bSRussell King * expansion card loader programs. 2016e747b4bSRussell King */ 2026e747b4bSRussell King *(unsigned long *)0x108 = 0; 2036e747b4bSRussell King *buf++ = ecard_loader_read(off++, base, 2046e747b4bSRussell King ec->loader); 2056e747b4bSRussell King } 2066e747b4bSRussell King } 2076e747b4bSRussell King } 2086e747b4bSRussell King 2096e747b4bSRussell King } 2106e747b4bSRussell King 2116e747b4bSRussell King static DECLARE_WAIT_QUEUE_HEAD(ecard_wait); 2126e747b4bSRussell King static struct ecard_request *ecard_req; 2136e747b4bSRussell King static DEFINE_MUTEX(ecard_mutex); 2146e747b4bSRussell King 2156e747b4bSRussell King /* 2166e747b4bSRussell King * Set up the expansion card daemon's page tables. 2176e747b4bSRussell King */ 2186e747b4bSRussell King static void ecard_init_pgtables(struct mm_struct *mm) 2196e747b4bSRussell King { 2206e747b4bSRussell King struct vm_area_struct vma; 2216e747b4bSRussell King 2226e747b4bSRussell King /* We want to set up the page tables for the following mapping: 2236e747b4bSRussell King * Virtual Physical 2246e747b4bSRussell King * 0x03000000 0x03000000 2256e747b4bSRussell King * 0x03010000 unmapped 2266e747b4bSRussell King * 0x03210000 0x03210000 2276e747b4bSRussell King * 0x03400000 unmapped 2286e747b4bSRussell King * 0x08000000 0x08000000 2296e747b4bSRussell King * 0x10000000 unmapped 2306e747b4bSRussell King * 2316e747b4bSRussell King * FIXME: we don't follow this 100% yet. 2326e747b4bSRussell King */ 2336e747b4bSRussell King pgd_t *src_pgd, *dst_pgd; 2346e747b4bSRussell King 2356e747b4bSRussell King src_pgd = pgd_offset(mm, (unsigned long)IO_BASE); 2366e747b4bSRussell King dst_pgd = pgd_offset(mm, IO_START); 2376e747b4bSRussell King 2386e747b4bSRussell King memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (IO_SIZE / PGDIR_SIZE)); 2396e747b4bSRussell King 2406e747b4bSRussell King src_pgd = pgd_offset(mm, (unsigned long)EASI_BASE); 2416e747b4bSRussell King dst_pgd = pgd_offset(mm, EASI_START); 2426e747b4bSRussell King 2436e747b4bSRussell King memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (EASI_SIZE / PGDIR_SIZE)); 2446e747b4bSRussell King 2456e747b4bSRussell King vma.vm_mm = mm; 2466e747b4bSRussell King 2476e747b4bSRussell King flush_tlb_range(&vma, IO_START, IO_START + IO_SIZE); 2486e747b4bSRussell King flush_tlb_range(&vma, EASI_START, EASI_START + EASI_SIZE); 2496e747b4bSRussell King } 2506e747b4bSRussell King 2516e747b4bSRussell King static int ecard_init_mm(void) 2526e747b4bSRussell King { 2536e747b4bSRussell King struct mm_struct * mm = mm_alloc(); 2546e747b4bSRussell King struct mm_struct *active_mm = current->active_mm; 2556e747b4bSRussell King 2566e747b4bSRussell King if (!mm) 2576e747b4bSRussell King return -ENOMEM; 2586e747b4bSRussell King 2596e747b4bSRussell King current->mm = mm; 2606e747b4bSRussell King current->active_mm = mm; 2616e747b4bSRussell King activate_mm(active_mm, mm); 2626e747b4bSRussell King mmdrop(active_mm); 2636e747b4bSRussell King ecard_init_pgtables(mm); 2646e747b4bSRussell King return 0; 2656e747b4bSRussell King } 2666e747b4bSRussell King 2676e747b4bSRussell King static int 2686e747b4bSRussell King ecard_task(void * unused) 2696e747b4bSRussell King { 2706e747b4bSRussell King /* 2716e747b4bSRussell King * Allocate a mm. We're not a lazy-TLB kernel task since we need 2726e747b4bSRussell King * to set page table entries where the user space would be. Note 2736e747b4bSRussell King * that this also creates the page tables. Failure is not an 2746e747b4bSRussell King * option here. 2756e747b4bSRussell King */ 2766e747b4bSRussell King if (ecard_init_mm()) 2776e747b4bSRussell King panic("kecardd: unable to alloc mm\n"); 2786e747b4bSRussell King 2796e747b4bSRussell King while (1) { 2806e747b4bSRussell King struct ecard_request *req; 2816e747b4bSRussell King 2826e747b4bSRussell King wait_event_interruptible(ecard_wait, ecard_req != NULL); 2836e747b4bSRussell King 2846e747b4bSRussell King req = xchg(&ecard_req, NULL); 2856e747b4bSRussell King if (req != NULL) { 2866e747b4bSRussell King req->fn(req); 2876e747b4bSRussell King complete(req->complete); 2886e747b4bSRussell King } 2896e747b4bSRussell King } 2906e747b4bSRussell King } 2916e747b4bSRussell King 2926e747b4bSRussell King /* 2936e747b4bSRussell King * Wake the expansion card daemon to action our request. 2946e747b4bSRussell King * 2956e747b4bSRussell King * FIXME: The test here is not sufficient to detect if the 2966e747b4bSRussell King * kcardd is running. 2976e747b4bSRussell King */ 2986e747b4bSRussell King static void ecard_call(struct ecard_request *req) 2996e747b4bSRussell King { 3006e747b4bSRussell King DECLARE_COMPLETION_ONSTACK(completion); 3016e747b4bSRussell King 3026e747b4bSRussell King req->complete = &completion; 3036e747b4bSRussell King 3046e747b4bSRussell King mutex_lock(&ecard_mutex); 3056e747b4bSRussell King ecard_req = req; 3066e747b4bSRussell King wake_up(&ecard_wait); 3076e747b4bSRussell King 3086e747b4bSRussell King /* 3096e747b4bSRussell King * Now wait for kecardd to run. 3106e747b4bSRussell King */ 3116e747b4bSRussell King wait_for_completion(&completion); 3126e747b4bSRussell King mutex_unlock(&ecard_mutex); 3136e747b4bSRussell King } 3146e747b4bSRussell King 3156e747b4bSRussell King /* ======================= Mid-level card control ===================== */ 3166e747b4bSRussell King 3176e747b4bSRussell King static void 3186e747b4bSRussell King ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld) 3196e747b4bSRussell King { 3206e747b4bSRussell King struct ecard_request req; 3216e747b4bSRussell King 3226e747b4bSRussell King req.fn = ecard_task_readbytes; 3236e747b4bSRussell King req.ec = ec; 3246e747b4bSRussell King req.address = off; 3256e747b4bSRussell King req.length = len; 3266e747b4bSRussell King req.use_loader = useld; 3276e747b4bSRussell King req.buffer = addr; 3286e747b4bSRussell King 3296e747b4bSRussell King ecard_call(&req); 3306e747b4bSRussell King } 3316e747b4bSRussell King 3326e747b4bSRussell King int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num) 3336e747b4bSRussell King { 3346e747b4bSRussell King struct ex_chunk_dir excd; 3356e747b4bSRussell King int index = 16; 3366e747b4bSRussell King int useld = 0; 3376e747b4bSRussell King 3386e747b4bSRussell King if (!ec->cid.cd) 3396e747b4bSRussell King return 0; 3406e747b4bSRussell King 3416e747b4bSRussell King while(1) { 3426e747b4bSRussell King ecard_readbytes(&excd, ec, index, 8, useld); 3436e747b4bSRussell King index += 8; 3446e747b4bSRussell King if (c_id(&excd) == 0) { 3456e747b4bSRussell King if (!useld && ec->loader) { 3466e747b4bSRussell King useld = 1; 3476e747b4bSRussell King index = 0; 3486e747b4bSRussell King continue; 3496e747b4bSRussell King } 3506e747b4bSRussell King return 0; 3516e747b4bSRussell King } 3526e747b4bSRussell King if (c_id(&excd) == 0xf0) { /* link */ 3536e747b4bSRussell King index = c_start(&excd); 3546e747b4bSRussell King continue; 3556e747b4bSRussell King } 3566e747b4bSRussell King if (c_id(&excd) == 0x80) { /* loader */ 3576e747b4bSRussell King if (!ec->loader) { 3586e747b4bSRussell King ec->loader = kmalloc(c_len(&excd), 3596e747b4bSRussell King GFP_KERNEL); 3606e747b4bSRussell King if (ec->loader) 3616e747b4bSRussell King ecard_readbytes(ec->loader, ec, 3626e747b4bSRussell King (int)c_start(&excd), 3636e747b4bSRussell King c_len(&excd), useld); 3646e747b4bSRussell King else 3656e747b4bSRussell King return 0; 3666e747b4bSRussell King } 3676e747b4bSRussell King continue; 3686e747b4bSRussell King } 3696e747b4bSRussell King if (c_id(&excd) == id && num-- == 0) 3706e747b4bSRussell King break; 3716e747b4bSRussell King } 3726e747b4bSRussell King 3736e747b4bSRussell King if (c_id(&excd) & 0x80) { 3746e747b4bSRussell King switch (c_id(&excd) & 0x70) { 3756e747b4bSRussell King case 0x70: 3766e747b4bSRussell King ecard_readbytes((unsigned char *)excd.d.string, ec, 3776e747b4bSRussell King (int)c_start(&excd), c_len(&excd), 3786e747b4bSRussell King useld); 3796e747b4bSRussell King break; 3806e747b4bSRussell King case 0x00: 3816e747b4bSRussell King break; 3826e747b4bSRussell King } 3836e747b4bSRussell King } 3846e747b4bSRussell King cd->start_offset = c_start(&excd); 3856e747b4bSRussell King memcpy(cd->d.string, excd.d.string, 256); 3866e747b4bSRussell King return 1; 3876e747b4bSRussell King } 3886e747b4bSRussell King 3896e747b4bSRussell King /* ======================= Interrupt control ============================ */ 3906e747b4bSRussell King 3916e747b4bSRussell King static void ecard_def_irq_enable(ecard_t *ec, int irqnr) 3926e747b4bSRussell King { 3936e747b4bSRussell King #ifdef HAS_EXPMASK 3946e747b4bSRussell King if (irqnr < 4 && have_expmask) { 3956e747b4bSRussell King have_expmask |= 1 << irqnr; 3966e747b4bSRussell King __raw_writeb(have_expmask, EXPMASK_ENABLE); 3976e747b4bSRussell King } 3986e747b4bSRussell King #endif 3996e747b4bSRussell King } 4006e747b4bSRussell King 4016e747b4bSRussell King static void ecard_def_irq_disable(ecard_t *ec, int irqnr) 4026e747b4bSRussell King { 4036e747b4bSRussell King #ifdef HAS_EXPMASK 4046e747b4bSRussell King if (irqnr < 4 && have_expmask) { 4056e747b4bSRussell King have_expmask &= ~(1 << irqnr); 4066e747b4bSRussell King __raw_writeb(have_expmask, EXPMASK_ENABLE); 4076e747b4bSRussell King } 4086e747b4bSRussell King #endif 4096e747b4bSRussell King } 4106e747b4bSRussell King 4116e747b4bSRussell King static int ecard_def_irq_pending(ecard_t *ec) 4126e747b4bSRussell King { 4136e747b4bSRussell King return !ec->irqmask || readb(ec->irqaddr) & ec->irqmask; 4146e747b4bSRussell King } 4156e747b4bSRussell King 4166e747b4bSRussell King static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr) 4176e747b4bSRussell King { 4186e747b4bSRussell King panic("ecard_def_fiq_enable called - impossible"); 4196e747b4bSRussell King } 4206e747b4bSRussell King 4216e747b4bSRussell King static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr) 4226e747b4bSRussell King { 4236e747b4bSRussell King panic("ecard_def_fiq_disable called - impossible"); 4246e747b4bSRussell King } 4256e747b4bSRussell King 4266e747b4bSRussell King static int ecard_def_fiq_pending(ecard_t *ec) 4276e747b4bSRussell King { 4286e747b4bSRussell King return !ec->fiqmask || readb(ec->fiqaddr) & ec->fiqmask; 4296e747b4bSRussell King } 4306e747b4bSRussell King 4316e747b4bSRussell King static expansioncard_ops_t ecard_default_ops = { 4326e747b4bSRussell King ecard_def_irq_enable, 4336e747b4bSRussell King ecard_def_irq_disable, 4346e747b4bSRussell King ecard_def_irq_pending, 4356e747b4bSRussell King ecard_def_fiq_enable, 4366e747b4bSRussell King ecard_def_fiq_disable, 4376e747b4bSRussell King ecard_def_fiq_pending 4386e747b4bSRussell King }; 4396e747b4bSRussell King 4406e747b4bSRussell King /* 4416e747b4bSRussell King * Enable and disable interrupts from expansion cards. 4426e747b4bSRussell King * (interrupts are disabled for these functions). 4436e747b4bSRussell King * 4446e747b4bSRussell King * They are not meant to be called directly, but via enable/disable_irq. 4456e747b4bSRussell King */ 4466e747b4bSRussell King static void ecard_irq_unmask(struct irq_data *d) 4476e747b4bSRussell King { 4486e747b4bSRussell King ecard_t *ec = slot_to_ecard(d->irq - 32); 4496e747b4bSRussell King 4506e747b4bSRussell King if (ec) { 4516e747b4bSRussell King if (!ec->ops) 4526e747b4bSRussell King ec->ops = &ecard_default_ops; 4536e747b4bSRussell King 4546e747b4bSRussell King if (ec->claimed && ec->ops->irqenable) 4556e747b4bSRussell King ec->ops->irqenable(ec, d->irq); 4566e747b4bSRussell King else 4576e747b4bSRussell King printk(KERN_ERR "ecard: rejecting request to " 4586e747b4bSRussell King "enable IRQs for %d\n", d->irq); 4596e747b4bSRussell King } 4606e747b4bSRussell King } 4616e747b4bSRussell King 4626e747b4bSRussell King static void ecard_irq_mask(struct irq_data *d) 4636e747b4bSRussell King { 4646e747b4bSRussell King ecard_t *ec = slot_to_ecard(d->irq - 32); 4656e747b4bSRussell King 4666e747b4bSRussell King if (ec) { 4676e747b4bSRussell King if (!ec->ops) 4686e747b4bSRussell King ec->ops = &ecard_default_ops; 4696e747b4bSRussell King 4706e747b4bSRussell King if (ec->ops && ec->ops->irqdisable) 4716e747b4bSRussell King ec->ops->irqdisable(ec, d->irq); 4726e747b4bSRussell King } 4736e747b4bSRussell King } 4746e747b4bSRussell King 4756e747b4bSRussell King static struct irq_chip ecard_chip = { 4766e747b4bSRussell King .name = "ECARD", 4776e747b4bSRussell King .irq_ack = ecard_irq_mask, 4786e747b4bSRussell King .irq_mask = ecard_irq_mask, 4796e747b4bSRussell King .irq_unmask = ecard_irq_unmask, 4806e747b4bSRussell King }; 4816e747b4bSRussell King 4826e747b4bSRussell King void ecard_enablefiq(unsigned int fiqnr) 4836e747b4bSRussell King { 4846e747b4bSRussell King ecard_t *ec = slot_to_ecard(fiqnr); 4856e747b4bSRussell King 4866e747b4bSRussell King if (ec) { 4876e747b4bSRussell King if (!ec->ops) 4886e747b4bSRussell King ec->ops = &ecard_default_ops; 4896e747b4bSRussell King 4906e747b4bSRussell King if (ec->claimed && ec->ops->fiqenable) 4916e747b4bSRussell King ec->ops->fiqenable(ec, fiqnr); 4926e747b4bSRussell King else 4936e747b4bSRussell King printk(KERN_ERR "ecard: rejecting request to " 4946e747b4bSRussell King "enable FIQs for %d\n", fiqnr); 4956e747b4bSRussell King } 4966e747b4bSRussell King } 4976e747b4bSRussell King 4986e747b4bSRussell King void ecard_disablefiq(unsigned int fiqnr) 4996e747b4bSRussell King { 5006e747b4bSRussell King ecard_t *ec = slot_to_ecard(fiqnr); 5016e747b4bSRussell King 5026e747b4bSRussell King if (ec) { 5036e747b4bSRussell King if (!ec->ops) 5046e747b4bSRussell King ec->ops = &ecard_default_ops; 5056e747b4bSRussell King 5066e747b4bSRussell King if (ec->ops->fiqdisable) 5076e747b4bSRussell King ec->ops->fiqdisable(ec, fiqnr); 5086e747b4bSRussell King } 5096e747b4bSRussell King } 5106e747b4bSRussell King 5116e747b4bSRussell King static void ecard_dump_irq_state(void) 5126e747b4bSRussell King { 5136e747b4bSRussell King ecard_t *ec; 5146e747b4bSRussell King 5156e747b4bSRussell King printk("Expansion card IRQ state:\n"); 5166e747b4bSRussell King 5176e747b4bSRussell King for (ec = cards; ec; ec = ec->next) { 5186e747b4bSRussell King if (ec->slot_no == 8) 5196e747b4bSRussell King continue; 5206e747b4bSRussell King 5216e747b4bSRussell King printk(" %d: %sclaimed, ", 5226e747b4bSRussell King ec->slot_no, ec->claimed ? "" : "not "); 5236e747b4bSRussell King 5246e747b4bSRussell King if (ec->ops && ec->ops->irqpending && 5256e747b4bSRussell King ec->ops != &ecard_default_ops) 5266e747b4bSRussell King printk("irq %spending\n", 5276e747b4bSRussell King ec->ops->irqpending(ec) ? "" : "not "); 5286e747b4bSRussell King else 5296e747b4bSRussell King printk("irqaddr %p, mask = %02X, status = %02X\n", 5306e747b4bSRussell King ec->irqaddr, ec->irqmask, readb(ec->irqaddr)); 5316e747b4bSRussell King } 5326e747b4bSRussell King } 5336e747b4bSRussell King 5346e747b4bSRussell King static void ecard_check_lockup(struct irq_desc *desc) 5356e747b4bSRussell King { 5366e747b4bSRussell King static unsigned long last; 5376e747b4bSRussell King static int lockup; 5386e747b4bSRussell King 5396e747b4bSRussell King /* 5406e747b4bSRussell King * If the timer interrupt has not run since the last million 5416e747b4bSRussell King * unrecognised expansion card interrupts, then there is 5426e747b4bSRussell King * something seriously wrong. Disable the expansion card 5436e747b4bSRussell King * interrupts so at least we can continue. 5446e747b4bSRussell King * 5456e747b4bSRussell King * Maybe we ought to start a timer to re-enable them some time 5466e747b4bSRussell King * later? 5476e747b4bSRussell King */ 5486e747b4bSRussell King if (last == jiffies) { 5496e747b4bSRussell King lockup += 1; 5506e747b4bSRussell King if (lockup > 1000000) { 5516e747b4bSRussell King printk(KERN_ERR "\nInterrupt lockup detected - " 5526e747b4bSRussell King "disabling all expansion card interrupts\n"); 5536e747b4bSRussell King 5546e747b4bSRussell King desc->irq_data.chip->irq_mask(&desc->irq_data); 5556e747b4bSRussell King ecard_dump_irq_state(); 5566e747b4bSRussell King } 5576e747b4bSRussell King } else 5586e747b4bSRussell King lockup = 0; 5596e747b4bSRussell King 5606e747b4bSRussell King /* 5616e747b4bSRussell King * If we did not recognise the source of this interrupt, 5626e747b4bSRussell King * warn the user, but don't flood the user with these messages. 5636e747b4bSRussell King */ 5646e747b4bSRussell King if (!last || time_after(jiffies, last + 5*HZ)) { 5656e747b4bSRussell King last = jiffies; 5666e747b4bSRussell King printk(KERN_WARNING "Unrecognised interrupt from backplane\n"); 5676e747b4bSRussell King ecard_dump_irq_state(); 5686e747b4bSRussell King } 5696e747b4bSRussell King } 5706e747b4bSRussell King 5716e747b4bSRussell King static void 5726e747b4bSRussell King ecard_irq_handler(unsigned int irq, struct irq_desc *desc) 5736e747b4bSRussell King { 5746e747b4bSRussell King ecard_t *ec; 5756e747b4bSRussell King int called = 0; 5766e747b4bSRussell King 5776e747b4bSRussell King desc->irq_data.chip->irq_mask(&desc->irq_data); 5786e747b4bSRussell King for (ec = cards; ec; ec = ec->next) { 5796e747b4bSRussell King int pending; 5806e747b4bSRussell King 5816e747b4bSRussell King if (!ec->claimed || ec->irq == NO_IRQ || ec->slot_no == 8) 5826e747b4bSRussell King continue; 5836e747b4bSRussell King 5846e747b4bSRussell King if (ec->ops && ec->ops->irqpending) 5856e747b4bSRussell King pending = ec->ops->irqpending(ec); 5866e747b4bSRussell King else 5876e747b4bSRussell King pending = ecard_default_ops.irqpending(ec); 5886e747b4bSRussell King 5896e747b4bSRussell King if (pending) { 5906e747b4bSRussell King generic_handle_irq(ec->irq); 5916e747b4bSRussell King called ++; 5926e747b4bSRussell King } 5936e747b4bSRussell King } 5946e747b4bSRussell King desc->irq_data.chip->irq_unmask(&desc->irq_data); 5956e747b4bSRussell King 5966e747b4bSRussell King if (called == 0) 5976e747b4bSRussell King ecard_check_lockup(desc); 5986e747b4bSRussell King } 5996e747b4bSRussell King 6006e747b4bSRussell King #ifdef HAS_EXPMASK 6016e747b4bSRussell King static unsigned char priority_masks[] = 6026e747b4bSRussell King { 6036e747b4bSRussell King 0xf0, 0xf1, 0xf3, 0xf7, 0xff, 0xff, 0xff, 0xff 6046e747b4bSRussell King }; 6056e747b4bSRussell King 6066e747b4bSRussell King static unsigned char first_set[] = 6076e747b4bSRussell King { 6086e747b4bSRussell King 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 6096e747b4bSRussell King 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00 6106e747b4bSRussell King }; 6116e747b4bSRussell King 6126e747b4bSRussell King static void 6136e747b4bSRussell King ecard_irqexp_handler(unsigned int irq, struct irq_desc *desc) 6146e747b4bSRussell King { 6156e747b4bSRussell King const unsigned int statusmask = 15; 6166e747b4bSRussell King unsigned int status; 6176e747b4bSRussell King 6186e747b4bSRussell King status = __raw_readb(EXPMASK_STATUS) & statusmask; 6196e747b4bSRussell King if (status) { 6206e747b4bSRussell King unsigned int slot = first_set[status]; 6216e747b4bSRussell King ecard_t *ec = slot_to_ecard(slot); 6226e747b4bSRussell King 6236e747b4bSRussell King if (ec->claimed) { 6246e747b4bSRussell King /* 6256e747b4bSRussell King * this ugly code is so that we can operate a 6266e747b4bSRussell King * prioritorising system: 6276e747b4bSRussell King * 6286e747b4bSRussell King * Card 0 highest priority 6296e747b4bSRussell King * Card 1 6306e747b4bSRussell King * Card 2 6316e747b4bSRussell King * Card 3 lowest priority 6326e747b4bSRussell King * 6336e747b4bSRussell King * Serial cards should go in 0/1, ethernet/scsi in 2/3 6346e747b4bSRussell King * otherwise you will lose serial data at high speeds! 6356e747b4bSRussell King */ 6366e747b4bSRussell King generic_handle_irq(ec->irq); 6376e747b4bSRussell King } else { 6386e747b4bSRussell King printk(KERN_WARNING "card%d: interrupt from unclaimed " 6396e747b4bSRussell King "card???\n", slot); 6406e747b4bSRussell King have_expmask &= ~(1 << slot); 6416e747b4bSRussell King __raw_writeb(have_expmask, EXPMASK_ENABLE); 6426e747b4bSRussell King } 6436e747b4bSRussell King } else 6446e747b4bSRussell King printk(KERN_WARNING "Wild interrupt from backplane (masks)\n"); 6456e747b4bSRussell King } 6466e747b4bSRussell King 6476e747b4bSRussell King static int __init ecard_probeirqhw(void) 6486e747b4bSRussell King { 6496e747b4bSRussell King ecard_t *ec; 6506e747b4bSRussell King int found; 6516e747b4bSRussell King 6526e747b4bSRussell King __raw_writeb(0x00, EXPMASK_ENABLE); 6536e747b4bSRussell King __raw_writeb(0xff, EXPMASK_STATUS); 6546e747b4bSRussell King found = (__raw_readb(EXPMASK_STATUS) & 15) == 0; 6556e747b4bSRussell King __raw_writeb(0xff, EXPMASK_ENABLE); 6566e747b4bSRussell King 6576e747b4bSRussell King if (found) { 6586e747b4bSRussell King printk(KERN_DEBUG "Expansion card interrupt " 6596e747b4bSRussell King "management hardware found\n"); 6606e747b4bSRussell King 6616e747b4bSRussell King /* for each card present, set a bit to '1' */ 6626e747b4bSRussell King have_expmask = 0x80000000; 6636e747b4bSRussell King 6646e747b4bSRussell King for (ec = cards; ec; ec = ec->next) 6656e747b4bSRussell King have_expmask |= 1 << ec->slot_no; 6666e747b4bSRussell King 6676e747b4bSRussell King __raw_writeb(have_expmask, EXPMASK_ENABLE); 6686e747b4bSRussell King } 6696e747b4bSRussell King 6706e747b4bSRussell King return found; 6716e747b4bSRussell King } 6726e747b4bSRussell King #else 6736e747b4bSRussell King #define ecard_irqexp_handler NULL 6746e747b4bSRussell King #define ecard_probeirqhw() (0) 6756e747b4bSRussell King #endif 6766e747b4bSRussell King 6776e747b4bSRussell King static void __iomem *__ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) 6786e747b4bSRussell King { 6796e747b4bSRussell King void __iomem *address = NULL; 6806e747b4bSRussell King int slot = ec->slot_no; 6816e747b4bSRussell King 6826e747b4bSRussell King if (ec->slot_no == 8) 6836e747b4bSRussell King return ECARD_MEMC8_BASE; 6846e747b4bSRussell King 6856e747b4bSRussell King ectcr &= ~(1 << slot); 6866e747b4bSRussell King 6876e747b4bSRussell King switch (type) { 6886e747b4bSRussell King case ECARD_MEMC: 6896e747b4bSRussell King if (slot < 4) 6906e747b4bSRussell King address = ECARD_MEMC_BASE + (slot << 14); 6916e747b4bSRussell King break; 6926e747b4bSRussell King 6936e747b4bSRussell King case ECARD_IOC: 6946e747b4bSRussell King if (slot < 4) 6956e747b4bSRussell King address = ECARD_IOC_BASE + (slot << 14); 6966e747b4bSRussell King else 6976e747b4bSRussell King address = ECARD_IOC4_BASE + ((slot - 4) << 14); 6986e747b4bSRussell King if (address) 6996e747b4bSRussell King address += speed << 19; 7006e747b4bSRussell King break; 7016e747b4bSRussell King 7026e747b4bSRussell King case ECARD_EASI: 7036e747b4bSRussell King address = ECARD_EASI_BASE + (slot << 24); 7046e747b4bSRussell King if (speed == ECARD_FAST) 7056e747b4bSRussell King ectcr |= 1 << slot; 7066e747b4bSRussell King break; 7076e747b4bSRussell King 7086e747b4bSRussell King default: 7096e747b4bSRussell King break; 7106e747b4bSRussell King } 7116e747b4bSRussell King 7126e747b4bSRussell King #ifdef IOMD_ECTCR 7136e747b4bSRussell King iomd_writeb(ectcr, IOMD_ECTCR); 7146e747b4bSRussell King #endif 7156e747b4bSRussell King return address; 7166e747b4bSRussell King } 7176e747b4bSRussell King 7186e747b4bSRussell King static int ecard_prints(struct seq_file *m, ecard_t *ec) 7196e747b4bSRussell King { 7206e747b4bSRussell King seq_printf(m, " %d: %s ", ec->slot_no, ec->easi ? "EASI" : " "); 7216e747b4bSRussell King 7226e747b4bSRussell King if (ec->cid.id == 0) { 7236e747b4bSRussell King struct in_chunk_dir incd; 7246e747b4bSRussell King 7256e747b4bSRussell King seq_printf(m, "[%04X:%04X] ", 7266e747b4bSRussell King ec->cid.manufacturer, ec->cid.product); 7276e747b4bSRussell King 7286e747b4bSRussell King if (!ec->card_desc && ec->cid.cd && 7296e747b4bSRussell King ecard_readchunk(&incd, ec, 0xf5, 0)) { 7306e747b4bSRussell King ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL); 7316e747b4bSRussell King 7326e747b4bSRussell King if (ec->card_desc) 7336e747b4bSRussell King strcpy((char *)ec->card_desc, incd.d.string); 7346e747b4bSRussell King } 7356e747b4bSRussell King 7366e747b4bSRussell King seq_printf(m, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*"); 7376e747b4bSRussell King } else 7386e747b4bSRussell King seq_printf(m, "Simple card %d\n", ec->cid.id); 7396e747b4bSRussell King 7406e747b4bSRussell King return 0; 7416e747b4bSRussell King } 7426e747b4bSRussell King 7436e747b4bSRussell King static int ecard_devices_proc_show(struct seq_file *m, void *v) 7446e747b4bSRussell King { 7456e747b4bSRussell King ecard_t *ec = cards; 7466e747b4bSRussell King 7476e747b4bSRussell King while (ec) { 7486e747b4bSRussell King ecard_prints(m, ec); 7496e747b4bSRussell King ec = ec->next; 7506e747b4bSRussell King } 7516e747b4bSRussell King return 0; 7526e747b4bSRussell King } 7536e747b4bSRussell King 7546e747b4bSRussell King static int ecard_devices_proc_open(struct inode *inode, struct file *file) 7556e747b4bSRussell King { 7566e747b4bSRussell King return single_open(file, ecard_devices_proc_show, NULL); 7576e747b4bSRussell King } 7586e747b4bSRussell King 7596e747b4bSRussell King static const struct file_operations bus_ecard_proc_fops = { 7606e747b4bSRussell King .owner = THIS_MODULE, 7616e747b4bSRussell King .open = ecard_devices_proc_open, 7626e747b4bSRussell King .read = seq_read, 7636e747b4bSRussell King .llseek = seq_lseek, 7646e747b4bSRussell King .release = single_release, 7656e747b4bSRussell King }; 7666e747b4bSRussell King 7676e747b4bSRussell King static struct proc_dir_entry *proc_bus_ecard_dir = NULL; 7686e747b4bSRussell King 7696e747b4bSRussell King static void ecard_proc_init(void) 7706e747b4bSRussell King { 7716e747b4bSRussell King proc_bus_ecard_dir = proc_mkdir("bus/ecard", NULL); 7726e747b4bSRussell King proc_create("devices", 0, proc_bus_ecard_dir, &bus_ecard_proc_fops); 7736e747b4bSRussell King } 7746e747b4bSRussell King 7756e747b4bSRussell King #define ec_set_resource(ec,nr,st,sz) \ 7766e747b4bSRussell King do { \ 7776e747b4bSRussell King (ec)->resource[nr].name = dev_name(&ec->dev); \ 7786e747b4bSRussell King (ec)->resource[nr].start = st; \ 7796e747b4bSRussell King (ec)->resource[nr].end = (st) + (sz) - 1; \ 7806e747b4bSRussell King (ec)->resource[nr].flags = IORESOURCE_MEM; \ 7816e747b4bSRussell King } while (0) 7826e747b4bSRussell King 7836e747b4bSRussell King static void __init ecard_free_card(struct expansion_card *ec) 7846e747b4bSRussell King { 7856e747b4bSRussell King int i; 7866e747b4bSRussell King 7876e747b4bSRussell King for (i = 0; i < ECARD_NUM_RESOURCES; i++) 7886e747b4bSRussell King if (ec->resource[i].flags) 7896e747b4bSRussell King release_resource(&ec->resource[i]); 7906e747b4bSRussell King 7916e747b4bSRussell King kfree(ec); 7926e747b4bSRussell King } 7936e747b4bSRussell King 7946e747b4bSRussell King static struct expansion_card *__init ecard_alloc_card(int type, int slot) 7956e747b4bSRussell King { 7966e747b4bSRussell King struct expansion_card *ec; 7976e747b4bSRussell King unsigned long base; 7986e747b4bSRussell King int i; 7996e747b4bSRussell King 8006e747b4bSRussell King ec = kzalloc(sizeof(ecard_t), GFP_KERNEL); 8016e747b4bSRussell King if (!ec) { 8026e747b4bSRussell King ec = ERR_PTR(-ENOMEM); 8036e747b4bSRussell King goto nomem; 8046e747b4bSRussell King } 8056e747b4bSRussell King 8066e747b4bSRussell King ec->slot_no = slot; 8076e747b4bSRussell King ec->easi = type == ECARD_EASI; 8086e747b4bSRussell King ec->irq = NO_IRQ; 8096e747b4bSRussell King ec->fiq = NO_IRQ; 8106e747b4bSRussell King ec->dma = NO_DMA; 8116e747b4bSRussell King ec->ops = &ecard_default_ops; 8126e747b4bSRussell King 8136e747b4bSRussell King dev_set_name(&ec->dev, "ecard%d", slot); 8146e747b4bSRussell King ec->dev.parent = NULL; 8156e747b4bSRussell King ec->dev.bus = &ecard_bus_type; 8166e747b4bSRussell King ec->dev.dma_mask = &ec->dma_mask; 8176e747b4bSRussell King ec->dma_mask = (u64)0xffffffff; 8186e747b4bSRussell King ec->dev.coherent_dma_mask = ec->dma_mask; 8196e747b4bSRussell King 8206e747b4bSRussell King if (slot < 4) { 8216e747b4bSRussell King ec_set_resource(ec, ECARD_RES_MEMC, 8226e747b4bSRussell King PODSLOT_MEMC_BASE + (slot << 14), 8236e747b4bSRussell King PODSLOT_MEMC_SIZE); 8246e747b4bSRussell King base = PODSLOT_IOC0_BASE + (slot << 14); 8256e747b4bSRussell King } else 8266e747b4bSRussell King base = PODSLOT_IOC4_BASE + ((slot - 4) << 14); 8276e747b4bSRussell King 8286e747b4bSRussell King #ifdef CONFIG_ARCH_RPC 8296e747b4bSRussell King if (slot < 8) { 8306e747b4bSRussell King ec_set_resource(ec, ECARD_RES_EASI, 8316e747b4bSRussell King PODSLOT_EASI_BASE + (slot << 24), 8326e747b4bSRussell King PODSLOT_EASI_SIZE); 8336e747b4bSRussell King } 8346e747b4bSRussell King 8356e747b4bSRussell King if (slot == 8) { 8366e747b4bSRussell King ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, NETSLOT_SIZE); 8376e747b4bSRussell King } else 8386e747b4bSRussell King #endif 8396e747b4bSRussell King 8406e747b4bSRussell King for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++) 8416e747b4bSRussell King ec_set_resource(ec, i + ECARD_RES_IOCSLOW, 8426e747b4bSRussell King base + (i << 19), PODSLOT_IOC_SIZE); 8436e747b4bSRussell King 8446e747b4bSRussell King for (i = 0; i < ECARD_NUM_RESOURCES; i++) { 8456e747b4bSRussell King if (ec->resource[i].flags && 8466e747b4bSRussell King request_resource(&iomem_resource, &ec->resource[i])) { 8476e747b4bSRussell King dev_err(&ec->dev, "resource(s) not available\n"); 8486e747b4bSRussell King ec->resource[i].end -= ec->resource[i].start; 8496e747b4bSRussell King ec->resource[i].start = 0; 8506e747b4bSRussell King ec->resource[i].flags = 0; 8516e747b4bSRussell King } 8526e747b4bSRussell King } 8536e747b4bSRussell King 8546e747b4bSRussell King nomem: 8556e747b4bSRussell King return ec; 8566e747b4bSRussell King } 8576e747b4bSRussell King 8586e747b4bSRussell King static ssize_t ecard_show_irq(struct device *dev, struct device_attribute *attr, char *buf) 8596e747b4bSRussell King { 8606e747b4bSRussell King struct expansion_card *ec = ECARD_DEV(dev); 8616e747b4bSRussell King return sprintf(buf, "%u\n", ec->irq); 8626e747b4bSRussell King } 8636e747b4bSRussell King 8646e747b4bSRussell King static ssize_t ecard_show_dma(struct device *dev, struct device_attribute *attr, char *buf) 8656e747b4bSRussell King { 8666e747b4bSRussell King struct expansion_card *ec = ECARD_DEV(dev); 8676e747b4bSRussell King return sprintf(buf, "%u\n", ec->dma); 8686e747b4bSRussell King } 8696e747b4bSRussell King 8706e747b4bSRussell King static ssize_t ecard_show_resources(struct device *dev, struct device_attribute *attr, char *buf) 8716e747b4bSRussell King { 8726e747b4bSRussell King struct expansion_card *ec = ECARD_DEV(dev); 8736e747b4bSRussell King char *str = buf; 8746e747b4bSRussell King int i; 8756e747b4bSRussell King 8766e747b4bSRussell King for (i = 0; i < ECARD_NUM_RESOURCES; i++) 8776e747b4bSRussell King str += sprintf(str, "%08x %08x %08lx\n", 8786e747b4bSRussell King ec->resource[i].start, 8796e747b4bSRussell King ec->resource[i].end, 8806e747b4bSRussell King ec->resource[i].flags); 8816e747b4bSRussell King 8826e747b4bSRussell King return str - buf; 8836e747b4bSRussell King } 8846e747b4bSRussell King 8856e747b4bSRussell King static ssize_t ecard_show_vendor(struct device *dev, struct device_attribute *attr, char *buf) 8866e747b4bSRussell King { 8876e747b4bSRussell King struct expansion_card *ec = ECARD_DEV(dev); 8886e747b4bSRussell King return sprintf(buf, "%u\n", ec->cid.manufacturer); 8896e747b4bSRussell King } 8906e747b4bSRussell King 8916e747b4bSRussell King static ssize_t ecard_show_device(struct device *dev, struct device_attribute *attr, char *buf) 8926e747b4bSRussell King { 8936e747b4bSRussell King struct expansion_card *ec = ECARD_DEV(dev); 8946e747b4bSRussell King return sprintf(buf, "%u\n", ec->cid.product); 8956e747b4bSRussell King } 8966e747b4bSRussell King 8976e747b4bSRussell King static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf) 8986e747b4bSRussell King { 8996e747b4bSRussell King struct expansion_card *ec = ECARD_DEV(dev); 9006e747b4bSRussell King return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC"); 9016e747b4bSRussell King } 9026e747b4bSRussell King 9036e747b4bSRussell King static struct device_attribute ecard_dev_attrs[] = { 9046e747b4bSRussell King __ATTR(device, S_IRUGO, ecard_show_device, NULL), 9056e747b4bSRussell King __ATTR(dma, S_IRUGO, ecard_show_dma, NULL), 9066e747b4bSRussell King __ATTR(irq, S_IRUGO, ecard_show_irq, NULL), 9076e747b4bSRussell King __ATTR(resource, S_IRUGO, ecard_show_resources, NULL), 9086e747b4bSRussell King __ATTR(type, S_IRUGO, ecard_show_type, NULL), 9096e747b4bSRussell King __ATTR(vendor, S_IRUGO, ecard_show_vendor, NULL), 9106e747b4bSRussell King __ATTR_NULL, 9116e747b4bSRussell King }; 9126e747b4bSRussell King 9136e747b4bSRussell King 9146e747b4bSRussell King int ecard_request_resources(struct expansion_card *ec) 9156e747b4bSRussell King { 9166e747b4bSRussell King int i, err = 0; 9176e747b4bSRussell King 9186e747b4bSRussell King for (i = 0; i < ECARD_NUM_RESOURCES; i++) { 9196e747b4bSRussell King if (ecard_resource_end(ec, i) && 9206e747b4bSRussell King !request_mem_region(ecard_resource_start(ec, i), 9216e747b4bSRussell King ecard_resource_len(ec, i), 9226e747b4bSRussell King ec->dev.driver->name)) { 9236e747b4bSRussell King err = -EBUSY; 9246e747b4bSRussell King break; 9256e747b4bSRussell King } 9266e747b4bSRussell King } 9276e747b4bSRussell King 9286e747b4bSRussell King if (err) { 9296e747b4bSRussell King while (i--) 9306e747b4bSRussell King if (ecard_resource_end(ec, i)) 9316e747b4bSRussell King release_mem_region(ecard_resource_start(ec, i), 9326e747b4bSRussell King ecard_resource_len(ec, i)); 9336e747b4bSRussell King } 9346e747b4bSRussell King return err; 9356e747b4bSRussell King } 9366e747b4bSRussell King EXPORT_SYMBOL(ecard_request_resources); 9376e747b4bSRussell King 9386e747b4bSRussell King void ecard_release_resources(struct expansion_card *ec) 9396e747b4bSRussell King { 9406e747b4bSRussell King int i; 9416e747b4bSRussell King 9426e747b4bSRussell King for (i = 0; i < ECARD_NUM_RESOURCES; i++) 9436e747b4bSRussell King if (ecard_resource_end(ec, i)) 9446e747b4bSRussell King release_mem_region(ecard_resource_start(ec, i), 9456e747b4bSRussell King ecard_resource_len(ec, i)); 9466e747b4bSRussell King } 9476e747b4bSRussell King EXPORT_SYMBOL(ecard_release_resources); 9486e747b4bSRussell King 9496e747b4bSRussell King void ecard_setirq(struct expansion_card *ec, const struct expansion_card_ops *ops, void *irq_data) 9506e747b4bSRussell King { 9516e747b4bSRussell King ec->irq_data = irq_data; 9526e747b4bSRussell King barrier(); 9536e747b4bSRussell King ec->ops = ops; 9546e747b4bSRussell King } 9556e747b4bSRussell King EXPORT_SYMBOL(ecard_setirq); 9566e747b4bSRussell King 9576e747b4bSRussell King void __iomem *ecardm_iomap(struct expansion_card *ec, unsigned int res, 9586e747b4bSRussell King unsigned long offset, unsigned long maxsize) 9596e747b4bSRussell King { 9606e747b4bSRussell King unsigned long start = ecard_resource_start(ec, res); 9616e747b4bSRussell King unsigned long end = ecard_resource_end(ec, res); 9626e747b4bSRussell King 9636e747b4bSRussell King if (offset > (end - start)) 9646e747b4bSRussell King return NULL; 9656e747b4bSRussell King 9666e747b4bSRussell King start += offset; 9676e747b4bSRussell King if (maxsize && end - start > maxsize) 9686e747b4bSRussell King end = start + maxsize; 9696e747b4bSRussell King 9706e747b4bSRussell King return devm_ioremap(&ec->dev, start, end - start); 9716e747b4bSRussell King } 9726e747b4bSRussell King EXPORT_SYMBOL(ecardm_iomap); 9736e747b4bSRussell King 9746e747b4bSRussell King /* 9756e747b4bSRussell King * Probe for an expansion card. 9766e747b4bSRussell King * 9776e747b4bSRussell King * If bit 1 of the first byte of the card is set, then the 9786e747b4bSRussell King * card does not exist. 9796e747b4bSRussell King */ 9806e747b4bSRussell King static int __init 9816e747b4bSRussell King ecard_probe(int slot, card_type_t type) 9826e747b4bSRussell King { 9836e747b4bSRussell King ecard_t **ecp; 9846e747b4bSRussell King ecard_t *ec; 9856e747b4bSRussell King struct ex_ecid cid; 9866e747b4bSRussell King void __iomem *addr; 9876e747b4bSRussell King int i, rc; 9886e747b4bSRussell King 9896e747b4bSRussell King ec = ecard_alloc_card(type, slot); 9906e747b4bSRussell King if (IS_ERR(ec)) { 9916e747b4bSRussell King rc = PTR_ERR(ec); 9926e747b4bSRussell King goto nomem; 9936e747b4bSRussell King } 9946e747b4bSRussell King 9956e747b4bSRussell King rc = -ENODEV; 9966e747b4bSRussell King if ((addr = __ecard_address(ec, type, ECARD_SYNC)) == NULL) 9976e747b4bSRussell King goto nodev; 9986e747b4bSRussell King 9996e747b4bSRussell King cid.r_zero = 1; 10006e747b4bSRussell King ecard_readbytes(&cid, ec, 0, 16, 0); 10016e747b4bSRussell King if (cid.r_zero) 10026e747b4bSRussell King goto nodev; 10036e747b4bSRussell King 10046e747b4bSRussell King ec->cid.id = cid.r_id; 10056e747b4bSRussell King ec->cid.cd = cid.r_cd; 10066e747b4bSRussell King ec->cid.is = cid.r_is; 10076e747b4bSRussell King ec->cid.w = cid.r_w; 10086e747b4bSRussell King ec->cid.manufacturer = ecard_getu16(cid.r_manu); 10096e747b4bSRussell King ec->cid.product = ecard_getu16(cid.r_prod); 10106e747b4bSRussell King ec->cid.country = cid.r_country; 10116e747b4bSRussell King ec->cid.irqmask = cid.r_irqmask; 10126e747b4bSRussell King ec->cid.irqoff = ecard_gets24(cid.r_irqoff); 10136e747b4bSRussell King ec->cid.fiqmask = cid.r_fiqmask; 10146e747b4bSRussell King ec->cid.fiqoff = ecard_gets24(cid.r_fiqoff); 10156e747b4bSRussell King ec->fiqaddr = 10166e747b4bSRussell King ec->irqaddr = addr; 10176e747b4bSRussell King 10186e747b4bSRussell King if (ec->cid.is) { 10196e747b4bSRussell King ec->irqmask = ec->cid.irqmask; 10206e747b4bSRussell King ec->irqaddr += ec->cid.irqoff; 10216e747b4bSRussell King ec->fiqmask = ec->cid.fiqmask; 10226e747b4bSRussell King ec->fiqaddr += ec->cid.fiqoff; 10236e747b4bSRussell King } else { 10246e747b4bSRussell King ec->irqmask = 1; 10256e747b4bSRussell King ec->fiqmask = 4; 10266e747b4bSRussell King } 10276e747b4bSRussell King 10286e747b4bSRussell King for (i = 0; i < ARRAY_SIZE(blacklist); i++) 10296e747b4bSRussell King if (blacklist[i].manufacturer == ec->cid.manufacturer && 10306e747b4bSRussell King blacklist[i].product == ec->cid.product) { 10316e747b4bSRussell King ec->card_desc = blacklist[i].type; 10326e747b4bSRussell King break; 10336e747b4bSRussell King } 10346e747b4bSRussell King 10356e747b4bSRussell King /* 10366e747b4bSRussell King * hook the interrupt handlers 10376e747b4bSRussell King */ 10386e747b4bSRussell King if (slot < 8) { 10396e747b4bSRussell King ec->irq = 32 + slot; 10406e747b4bSRussell King irq_set_chip_and_handler(ec->irq, &ecard_chip, 10416e747b4bSRussell King handle_level_irq); 10426e747b4bSRussell King set_irq_flags(ec->irq, IRQF_VALID); 10436e747b4bSRussell King } 10446e747b4bSRussell King 10456e747b4bSRussell King if (slot == 8) 10466e747b4bSRussell King ec->irq = 11; 10476e747b4bSRussell King #ifdef CONFIG_ARCH_RPC 10486e747b4bSRussell King /* On RiscPC, only first two slots have DMA capability */ 10496e747b4bSRussell King if (slot < 2) 10506e747b4bSRussell King ec->dma = 2 + slot; 10516e747b4bSRussell King #endif 10526e747b4bSRussell King 10536e747b4bSRussell King for (ecp = &cards; *ecp; ecp = &(*ecp)->next); 10546e747b4bSRussell King 10556e747b4bSRussell King *ecp = ec; 10566e747b4bSRussell King slot_to_expcard[slot] = ec; 10576e747b4bSRussell King 10586e747b4bSRussell King device_register(&ec->dev); 10596e747b4bSRussell King 10606e747b4bSRussell King return 0; 10616e747b4bSRussell King 10626e747b4bSRussell King nodev: 10636e747b4bSRussell King ecard_free_card(ec); 10646e747b4bSRussell King nomem: 10656e747b4bSRussell King return rc; 10666e747b4bSRussell King } 10676e747b4bSRussell King 10686e747b4bSRussell King /* 10696e747b4bSRussell King * Initialise the expansion card system. 10706e747b4bSRussell King * Locate all hardware - interrupt management and 10716e747b4bSRussell King * actual cards. 10726e747b4bSRussell King */ 10736e747b4bSRussell King static int __init ecard_init(void) 10746e747b4bSRussell King { 10756e747b4bSRussell King struct task_struct *task; 10766e747b4bSRussell King int slot, irqhw; 10776e747b4bSRussell King 10786e747b4bSRussell King task = kthread_run(ecard_task, NULL, "kecardd"); 10796e747b4bSRussell King if (IS_ERR(task)) { 10806e747b4bSRussell King printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n", 10816e747b4bSRussell King PTR_ERR(task)); 10826e747b4bSRussell King return PTR_ERR(task); 10836e747b4bSRussell King } 10846e747b4bSRussell King 10856e747b4bSRussell King printk("Probing expansion cards\n"); 10866e747b4bSRussell King 10876e747b4bSRussell King for (slot = 0; slot < 8; slot ++) { 10886e747b4bSRussell King if (ecard_probe(slot, ECARD_EASI) == -ENODEV) 10896e747b4bSRussell King ecard_probe(slot, ECARD_IOC); 10906e747b4bSRussell King } 10916e747b4bSRussell King 10926e747b4bSRussell King ecard_probe(8, ECARD_IOC); 10936e747b4bSRussell King 10946e747b4bSRussell King irqhw = ecard_probeirqhw(); 10956e747b4bSRussell King 10966e747b4bSRussell King irq_set_chained_handler(IRQ_EXPANSIONCARD, 10976e747b4bSRussell King irqhw ? ecard_irqexp_handler : ecard_irq_handler); 10986e747b4bSRussell King 10996e747b4bSRussell King ecard_proc_init(); 11006e747b4bSRussell King 11016e747b4bSRussell King return 0; 11026e747b4bSRussell King } 11036e747b4bSRussell King 11046e747b4bSRussell King subsys_initcall(ecard_init); 11056e747b4bSRussell King 11066e747b4bSRussell King /* 11076e747b4bSRussell King * ECARD "bus" 11086e747b4bSRussell King */ 11096e747b4bSRussell King static const struct ecard_id * 11106e747b4bSRussell King ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec) 11116e747b4bSRussell King { 11126e747b4bSRussell King int i; 11136e747b4bSRussell King 11146e747b4bSRussell King for (i = 0; ids[i].manufacturer != 65535; i++) 11156e747b4bSRussell King if (ec->cid.manufacturer == ids[i].manufacturer && 11166e747b4bSRussell King ec->cid.product == ids[i].product) 11176e747b4bSRussell King return ids + i; 11186e747b4bSRussell King 11196e747b4bSRussell King return NULL; 11206e747b4bSRussell King } 11216e747b4bSRussell King 11226e747b4bSRussell King static int ecard_drv_probe(struct device *dev) 11236e747b4bSRussell King { 11246e747b4bSRussell King struct expansion_card *ec = ECARD_DEV(dev); 11256e747b4bSRussell King struct ecard_driver *drv = ECARD_DRV(dev->driver); 11266e747b4bSRussell King const struct ecard_id *id; 11276e747b4bSRussell King int ret; 11286e747b4bSRussell King 11296e747b4bSRussell King id = ecard_match_device(drv->id_table, ec); 11306e747b4bSRussell King 11316e747b4bSRussell King ec->claimed = 1; 11326e747b4bSRussell King ret = drv->probe(ec, id); 11336e747b4bSRussell King if (ret) 11346e747b4bSRussell King ec->claimed = 0; 11356e747b4bSRussell King return ret; 11366e747b4bSRussell King } 11376e747b4bSRussell King 11386e747b4bSRussell King static int ecard_drv_remove(struct device *dev) 11396e747b4bSRussell King { 11406e747b4bSRussell King struct expansion_card *ec = ECARD_DEV(dev); 11416e747b4bSRussell King struct ecard_driver *drv = ECARD_DRV(dev->driver); 11426e747b4bSRussell King 11436e747b4bSRussell King drv->remove(ec); 11446e747b4bSRussell King ec->claimed = 0; 11456e747b4bSRussell King 11466e747b4bSRussell King /* 11476e747b4bSRussell King * Restore the default operations. We ensure that the 11486e747b4bSRussell King * ops are set before we change the data. 11496e747b4bSRussell King */ 11506e747b4bSRussell King ec->ops = &ecard_default_ops; 11516e747b4bSRussell King barrier(); 11526e747b4bSRussell King ec->irq_data = NULL; 11536e747b4bSRussell King 11546e747b4bSRussell King return 0; 11556e747b4bSRussell King } 11566e747b4bSRussell King 11576e747b4bSRussell King /* 11586e747b4bSRussell King * Before rebooting, we must make sure that the expansion card is in a 11596e747b4bSRussell King * sensible state, so it can be re-detected. This means that the first 11606e747b4bSRussell King * page of the ROM must be visible. We call the expansion cards reset 11616e747b4bSRussell King * handler, if any. 11626e747b4bSRussell King */ 11636e747b4bSRussell King static void ecard_drv_shutdown(struct device *dev) 11646e747b4bSRussell King { 11656e747b4bSRussell King struct expansion_card *ec = ECARD_DEV(dev); 11666e747b4bSRussell King struct ecard_driver *drv = ECARD_DRV(dev->driver); 11676e747b4bSRussell King struct ecard_request req; 11686e747b4bSRussell King 11696e747b4bSRussell King if (dev->driver) { 11706e747b4bSRussell King if (drv->shutdown) 11716e747b4bSRussell King drv->shutdown(ec); 11726e747b4bSRussell King ec->claimed = 0; 11736e747b4bSRussell King } 11746e747b4bSRussell King 11756e747b4bSRussell King /* 11766e747b4bSRussell King * If this card has a loader, call the reset handler. 11776e747b4bSRussell King */ 11786e747b4bSRussell King if (ec->loader) { 11796e747b4bSRussell King req.fn = ecard_task_reset; 11806e747b4bSRussell King req.ec = ec; 11816e747b4bSRussell King ecard_call(&req); 11826e747b4bSRussell King } 11836e747b4bSRussell King } 11846e747b4bSRussell King 11856e747b4bSRussell King int ecard_register_driver(struct ecard_driver *drv) 11866e747b4bSRussell King { 11876e747b4bSRussell King drv->drv.bus = &ecard_bus_type; 11886e747b4bSRussell King 11896e747b4bSRussell King return driver_register(&drv->drv); 11906e747b4bSRussell King } 11916e747b4bSRussell King 11926e747b4bSRussell King void ecard_remove_driver(struct ecard_driver *drv) 11936e747b4bSRussell King { 11946e747b4bSRussell King driver_unregister(&drv->drv); 11956e747b4bSRussell King } 11966e747b4bSRussell King 11976e747b4bSRussell King static int ecard_match(struct device *_dev, struct device_driver *_drv) 11986e747b4bSRussell King { 11996e747b4bSRussell King struct expansion_card *ec = ECARD_DEV(_dev); 12006e747b4bSRussell King struct ecard_driver *drv = ECARD_DRV(_drv); 12016e747b4bSRussell King int ret; 12026e747b4bSRussell King 12036e747b4bSRussell King if (drv->id_table) { 12046e747b4bSRussell King ret = ecard_match_device(drv->id_table, ec) != NULL; 12056e747b4bSRussell King } else { 12066e747b4bSRussell King ret = ec->cid.id == drv->id; 12076e747b4bSRussell King } 12086e747b4bSRussell King 12096e747b4bSRussell King return ret; 12106e747b4bSRussell King } 12116e747b4bSRussell King 12126e747b4bSRussell King struct bus_type ecard_bus_type = { 12136e747b4bSRussell King .name = "ecard", 12146e747b4bSRussell King .dev_attrs = ecard_dev_attrs, 12156e747b4bSRussell King .match = ecard_match, 12166e747b4bSRussell King .probe = ecard_drv_probe, 12176e747b4bSRussell King .remove = ecard_drv_remove, 12186e747b4bSRussell King .shutdown = ecard_drv_shutdown, 12196e747b4bSRussell King }; 12206e747b4bSRussell King 12216e747b4bSRussell King static int ecard_bus_init(void) 12226e747b4bSRussell King { 12236e747b4bSRussell King return bus_register(&ecard_bus_type); 12246e747b4bSRussell King } 12256e747b4bSRussell King 12266e747b4bSRussell King postcore_initcall(ecard_bus_init); 12276e747b4bSRussell King 12286e747b4bSRussell King EXPORT_SYMBOL(ecard_readchunk); 12296e747b4bSRussell King EXPORT_SYMBOL(ecard_register_driver); 12306e747b4bSRussell King EXPORT_SYMBOL(ecard_remove_driver); 12316e747b4bSRussell King EXPORT_SYMBOL(ecard_bus_type); 1232