diff options
33 files changed, 1537 insertions, 906 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index f2a79481f1c1..a6c1ebd18d0f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3293,6 +3293,11 @@ L: vtun@office.satix.net W: http://vtun.sourceforge.net/tun S: Maintained +TURBOCHANNEL SUBSYSTEM +P: Maciej W. Rozycki +M: macro@linux-mips.org +S: Maintained + U14-34F SCSI DRIVER P: Dario Ballabio M: ballabio_dario@emc.com diff --git a/arch/mips/dec/Makefile b/arch/mips/dec/Makefile index ed181fdc3ac9..8b790c2900d5 100644 --- a/arch/mips/dec/Makefile +++ b/arch/mips/dec/Makefile @@ -6,6 +6,7 @@ obj-y := ecc-berr.o int-handler.o ioasic-irq.o kn01-berr.o \ kn02-irq.o kn02xa-berr.o reset.o setup.o time.o obj-$(CONFIG_PROM_CONSOLE) += promcon.o +obj-$(CONFIG_TC) += tc.o obj-$(CONFIG_CPU_HAS_WB) += wbflush.o EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/dec/prom/identify.c b/arch/mips/dec/prom/identify.c index 81d5e878ddce..c4e3c1ea0d48 100644 --- a/arch/mips/dec/prom/identify.c +++ b/arch/mips/dec/prom/identify.c @@ -88,6 +88,7 @@ static inline void prom_init_kn02(void) { dec_kn_slot_base = KN02_SLOT_BASE; dec_kn_slot_size = KN02_SLOT_SIZE; + dec_tc_bus = 1; dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + KN02_RTC); } @@ -96,6 +97,7 @@ static inline void prom_init_kn02xa(void) { dec_kn_slot_base = KN02XA_SLOT_BASE; dec_kn_slot_size = IOASIC_SLOT_SIZE; + dec_tc_bus = 1; ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL); dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY); @@ -105,6 +107,7 @@ static inline void prom_init_kn03(void) { dec_kn_slot_base = KN03_SLOT_BASE; dec_kn_slot_size = IOASIC_SLOT_SIZE; + dec_tc_bus = 1; ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL); dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY); diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c index 1058e2f409bb..b8a5e75ba0ab 100644 --- a/arch/mips/dec/setup.c +++ b/arch/mips/dec/setup.c @@ -53,6 +53,8 @@ unsigned long dec_kn_slot_base, dec_kn_slot_size; EXPORT_SYMBOL(dec_kn_slot_base); EXPORT_SYMBOL(dec_kn_slot_size); +int dec_tc_bus; + spinlock_t ioasic_ssr_lock; volatile u32 *ioasic_base; diff --git a/arch/mips/dec/tc.c b/arch/mips/dec/tc.c new file mode 100644 index 000000000000..732027c79834 --- /dev/null +++ b/arch/mips/dec/tc.c @@ -0,0 +1,95 @@ +/* + * TURBOchannel architecture calls. + * + * Copyright (c) Harald Koerfgen, 1998 + * Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki + * Copyright (c) 2005 James Simmons + * + * This file is subject to the terms and conditions of the GNU + * General Public License. See the file "COPYING" in the main + * directory of this archive for more details. + */ +#include <linux/compiler.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/string.h> +#include <linux/tc.h> +#include <linux/types.h> + +#include <asm/addrspace.h> +#include <asm/bootinfo.h> +#include <asm/paccess.h> + +#include <asm/dec/interrupts.h> +#include <asm/dec/prom.h> +#include <asm/dec/system.h> + +/* + * Protected read byte from TURBOchannel slot space. + */ +int tc_preadb(u8 *valp, void __iomem *addr) +{ + return get_dbe(*valp, (u8 *)addr); +} + +/* + * Get TURBOchannel bus information as specified by the spec, plus + * the slot space base address and the number of slots. + */ +int __init tc_bus_get_info(struct tc_bus *tbus) +{ + if (!dec_tc_bus) + return -ENXIO; + + memcpy(&tbus->info, rex_gettcinfo(), sizeof(tbus->info)); + tbus->slot_base = CPHYSADDR((long)rex_slot_address(0)); + + switch (mips_machtype) { + case MACH_DS5000_200: + tbus->num_tcslots = 7; + break; + case MACH_DS5000_2X0: + case MACH_DS5900: + tbus->ext_slot_base = 0x20000000; + tbus->ext_slot_size = 0x20000000; + /* fall through */ + case MACH_DS5000_1XX: + tbus->num_tcslots = 3; + break; + case MACH_DS5000_XX: + tbus->num_tcslots = 2; + default: + break; + } + return 0; +} + +/* + * Get the IRQ for the specified slot. + */ +void __init tc_device_get_irq(struct tc_dev *tdev) +{ + switch (tdev->slot) { + case 0: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC0]; + break; + case 1: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC1]; + break; + case 2: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC2]; + break; + /* + * Yuck! DS5000/200 onboard devices + */ + case 5: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC5]; + break; + case 6: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC6]; + break; + default: + tdev->interrupt = -1; + break; + } +} diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 4f2ffbd81dc1..38f41a593b12 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2545,7 +2545,7 @@ config RIONET_RX_SIZE config FDDI bool "FDDI driver support" - depends on (PCI || EISA) + depends on (PCI || EISA || TC) help Fiber Distributed Data Interface is a high speed local area network design; essentially a replacement for high speed Ethernet. FDDI can @@ -2555,11 +2555,31 @@ config FDDI will say N. config DEFXX - tristate "Digital DEFEA and DEFPA adapter support" - depends on FDDI && (PCI || EISA) - help - This is support for the DIGITAL series of EISA (DEFEA) and PCI - (DEFPA) controllers which can connect you to a local FDDI network. + tristate "Digital DEFTA/DEFEA/DEFPA adapter support" + depends on FDDI && (PCI || EISA || TC) + ---help--- + This is support for the DIGITAL series of TURBOchannel (DEFTA), + EISA (DEFEA) and PCI (DEFPA) controllers which can connect you + to a local FDDI network. + + To compile this driver as a module, choose M here: the module + will be called defxx. If unsure, say N. + +config DEFXX_MMIO + bool + prompt "Use MMIO instead of PIO" if PCI || EISA + depends on DEFXX + default n if PCI || EISA + default y + ---help--- + This instructs the driver to use EISA or PCI memory-mapped I/O + (MMIO) as appropriate instead of programmed I/O ports (PIO). + Enabling this gives an improvement in processing time in parts + of the driver, but it may cause problems with EISA (DEFEA) + adapters. TURBOchannel does not have the concept of I/O ports, + so MMIO is always used for these (DEFTA) adapters. + + If unsure, say N. config SKFP tristate "SysKonnect FDDI PCI support" diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index dc3ab3b5c8cb..07d2731c1aa8 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -10,10 +10,12 @@ * * Abstract: * A Linux device driver supporting the Digital Equipment Corporation - * FDDI EISA and PCI controller families. Supported adapters include: + * FDDI TURBOchannel, EISA and PCI controller families. Supported + * adapters include: * - * DEC FDDIcontroller/EISA (DEFEA) - * DEC FDDIcontroller/PCI (DEFPA) + * DEC FDDIcontroller/TURBOchannel (DEFTA) + * DEC FDDIcontroller/EISA (DEFEA) + * DEC FDDIcontroller/PCI (DEFPA) * * The original author: * LVS Lawrence V. Stefani <lstefani@yahoo.com> @@ -193,24 +195,27 @@ * 14 Aug 2004 macro Fix device names reported. * 14 Jun 2005 macro Use irqreturn_t. * 23 Oct 2006 macro Big-endian host support. + * 14 Dec 2006 macro TURBOchannel support. */ /* Include files */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/pci.h> +#include <linux/bitops.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/eisa.h> +#include <linux/errno.h> +#include <linux/fddidevice.h> #include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/netdevice.h> -#include <linux/fddidevice.h> +#include <linux/pci.h> #include <linux/skbuff.h> -#include <linux/bitops.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/tc.h> #include <asm/byteorder.h> #include <asm/io.h> @@ -219,8 +224,8 @@ /* Version information string should be updated prior to each new release! */ #define DRV_NAME "defxx" -#define DRV_VERSION "v1.09" -#define DRV_RELDATE "2006/10/23" +#define DRV_VERSION "v1.10" +#define DRV_RELDATE "2006/12/14" static char version[] __devinitdata = DRV_NAME ": " DRV_VERSION " " DRV_RELDATE @@ -235,12 +240,41 @@ static char version[] __devinitdata = */ #define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128) +#define __unused __attribute__ ((unused)) + +#ifdef CONFIG_PCI +#define DFX_BUS_PCI(dev) (dev->bus == &pci_bus_type) +#else +#define DFX_BUS_PCI(dev) 0 +#endif + +#ifdef CONFIG_EISA +#define DFX_BUS_EISA(dev) (dev->bus == &eisa_bus_type) +#else +#define DFX_BUS_EISA(dev) 0 +#endif + +#ifdef CONFIG_TC +#define DFX_BUS_TC(dev) (dev->bus == &tc_bus_type) +#else +#define DFX_BUS_TC(dev) 0 +#endif + +#ifdef CONFIG_DEFXX_MMIO +#define DFX_MMIO 1 +#else +#define DFX_MMIO 0 +#endif + /* Define module-wide (static) routines */ static void dfx_bus_init(struct net_device *dev); +static void dfx_bus_uninit(struct net_device *dev); static void dfx_bus_config_check(DFX_board_t *bp); -static int dfx_driver_init(struct net_device *dev, const char *print_name); +static int dfx_driver_init(struct net_device *dev, + const char *print_name, + resource_size_t bar_start); static int dfx_adap_init(DFX_board_t *bp, int get_buffers); static int dfx_open(struct net_device *dev); @@ -273,13 +307,13 @@ static void dfx_xmt_flush(DFX_board_t *bp); /* Define module-wide (static) variables */ -static struct net_device *root_dfx_eisa_dev; +static struct pci_driver dfx_pci_driver; +static struct eisa_driver dfx_eisa_driver; +static struct tc_driver dfx_tc_driver; /* * ======================= - * = dfx_port_write_byte = - * = dfx_port_read_byte = * = dfx_port_write_long = * = dfx_port_read_long = * ======================= @@ -291,12 +325,11 @@ static struct net_device *root_dfx_eisa_dev; * None * * Arguments: - * bp - pointer to board information - * offset - register offset from base I/O address - * data - for dfx_port_write_byte and dfx_port_write_long, this - * is a value to write. - * for dfx_port_read_byte and dfx_port_read_byte, this - * is a pointer to store the read value. + * bp - pointer to board information + * offset - register offset from base I/O address + * data - for dfx_port_write_long, this is a value to write; + * for dfx_port_read_long, this is a pointer to store + * the read value * * Functional Description: * These routines perform the correct operation to read or write @@ -310,7 +343,7 @@ static struct net_device *root_dfx_eisa_dev; * registers using the register offsets defined in DEFXX.H. * * PCI port block base addresses are assigned by the PCI BIOS or system - * firmware. There is one 128 byte port block which can be accessed. It + * firmware. There is one 128 byte port block which can be accessed. It * allows for I/O mapping of both PDQ and PFI registers using the register * offsets defined in DEFXX.H. * @@ -318,7 +351,7 @@ static struct net_device *root_dfx_eisa_dev; * None * * Assumptions: - * bp->base_addr is a valid base I/O address for this adapter. + * bp->base is a valid base I/O address for this adapter. * offset is a valid register offset for this adapter. * * Side Effects: @@ -329,69 +362,135 @@ static struct net_device *root_dfx_eisa_dev; * advantage of strict data type checking. */ -static inline void dfx_port_write_byte( - DFX_board_t *bp, - int offset, - u8 data - ) +static inline void dfx_writel(DFX_board_t *bp, int offset, u32 data) +{ + writel(data, bp->base.mem + offset); + mb(); +} - { - u16 port = bp->base_addr + offset; +static inline void dfx_outl(DFX_board_t *bp, int offset, u32 data) +{ + outl(data, bp->base.port + offset); +} - outb(data, port); - } +static void dfx_port_write_long(DFX_board_t *bp, int offset, u32 data) +{ + struct device __unused *bdev = bp->bus_dev; + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; -static inline void dfx_port_read_byte( - DFX_board_t *bp, - int offset, - u8 *data - ) + if (dfx_use_mmio) + dfx_writel(bp, offset, data); + else + dfx_outl(bp, offset, data); +} - { - u16 port = bp->base_addr + offset; - *data = inb(port); - } +static inline void dfx_readl(DFX_board_t *bp, int offset, u32 *data) +{ + mb(); + *data = readl(bp->base.mem + offset); +} -static inline void dfx_port_write_long( - DFX_board_t *bp, - int offset, - u32 data - ) +static inline void dfx_inl(DFX_board_t *bp, int offset, u32 *data) +{ + *data = inl(bp->base.port + offset); +} - { - u16 port = bp->base_addr + offset; +static void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data) +{ + struct device __unused *bdev = bp->bus_dev; + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; - outl(data, port); - } + if (dfx_use_mmio) + dfx_readl(bp, offset, data); + else + dfx_inl(bp, offset, data); +} -static inline void dfx_port_read_long( - DFX_board_t *bp, - int offset, - u32 *data - ) - { - u16 port = bp->base_addr + offset; +/* + * ================ + * = dfx_get_bars = + * ================ + * + * Overview: + * Retrieves the address range used to access control and status + * registers. + * + * Returns: + * None + * + * Arguments: + * bdev - pointer to device information + * bar_start - pointer to store the start address + * bar_len - pointer to store the length of the area + * + * Assumptions: + * I am sure there are some. + * + * Side Effects: + * None + */ +static void dfx_get_bars(struct device *bdev, + resource_size_t *bar_start, resource_size_t *bar_len) +{ + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; - *data = inl(port); - } + if (dfx_bus_pci) { + int num = dfx_use_mmio ? 0 : 1; + *bar_start = pci_resource_start(to_pci_dev(bdev), num); + *bar_len = pci_resource_len(to_pci_dev(bdev), num); + } + if (dfx_bus_eisa) { + unsigned long base_addr = to_eisa_device(bdev)->base_addr; + resource_size_t bar; + + if (dfx_use_mmio) { + bar = inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_2); + bar <<= 8; + bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_1); + bar <<= 8; + bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_0); + bar <<= 16; + *bar_start = bar; + bar = inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_2); + bar <<= 8; + bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_1); + bar <<= 8; + bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_0); + bar <<= 16; + *bar_len = (bar | PI_MEM_ADD_MASK_M) + 1; + } else { + *bar_start = base_addr; + *bar_len = PI_ESIC_K_CSR_IO_LEN; + } + } + if (dfx_bus_tc) { + *bar_start = to_tc_dev(bdev)->resource.start + + PI_TC_K_CSR_OFFSET; + *bar_len = PI_TC_K_CSR_LEN; + } +} /* - * ============= - * = dfx_init_one_pci_or_eisa = - * ============= + * ================ + * = dfx_register = + * ================ * * Overview: - * Initializes a supported FDDI EISA or PCI controller + * Initializes a supported FDDI controller * * Returns: * Condition code * * Arguments: - * pdev - pointer to pci device information (NULL for EISA) - * ioaddr - pointer to port (NULL for PCI) + * bdev - pointer to device information * * Functional Description: * @@ -407,56 +506,74 @@ static inline void dfx_port_read_long( * initialized and the board resources are read and stored in * the device structure. */ -static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr) +static int __devinit dfx_register(struct device *bdev) { static int version_disp; - char *print_name = DRV_NAME; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + char *print_name = bdev->bus_id; struct net_device *dev; DFX_board_t *bp; /* board pointer */ + resource_size_t bar_start = 0; /* pointer to port */ + resource_size_t bar_len = 0; /* resource length */ int alloc_size; /* total buffer size used */ - int err; + struct resource *region; + int err = 0; if (!version_disp) { /* display version info if adapter is found */ version_disp = 1; /* set display flag to TRUE so that */ printk(version); /* we only display this string ONCE */ } - if (pdev != NULL) - print_name = pci_name(pdev); - dev = alloc_fddidev(sizeof(*bp)); if (!dev) { - printk(KERN_ERR "%s: unable to allocate fddidev, aborting\n", + printk(KERN_ERR "%s: Unable to allocate fddidev, aborting\n", print_name); return -ENOMEM; } /* Enable PCI device. */ - if (pdev != NULL) { - err = pci_enable_device (pdev); - if (err) goto err_out; - ioaddr = pci_resource_start (pdev, 1); + if (dfx_bus_pci && pci_enable_device(to_pci_dev(bdev))) { + printk(KERN_ERR "%s: Cannot enable PCI device, aborting\n", + print_name); + goto err_out; } SET_MODULE_OWNER(dev); - if (pdev != NULL) - SET_NETDEV_DEV(dev, &pdev->dev); + SET_NETDEV_DEV(dev, bdev); + + bp = netdev_priv(dev); + bp->bus_dev = bdev; + dev_set_drvdata(bdev, dev); - bp = dev->priv; + dfx_get_bars(bdev, &bar_start, &bar_len); - if (!request_region(ioaddr, - pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, - print_name)) { + if (dfx_use_mmio) + region = request_mem_region(bar_start, bar_len, print_name); + else + region = request_region(bar_start, bar_len, print_name); + if (!region) { printk(KERN_ERR "%s: Cannot reserve I/O resource " - "0x%x @ 0x%lx, aborting\n", print_name, - pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, ioaddr); + "0x%lx @ 0x%lx, aborting\n", + print_name, (long)bar_len, (long)bar_start); err = -EBUSY; - goto err_out; + goto err_out_disable; } - /* Initialize new device structure */ + /* Set up I/O base address. */ + if (dfx_use_mmio) { + bp->base.mem = ioremap_nocache(bar_start, bar_len); + if (!bp->base.mem) { + printk(KERN_ERR "%s: Cannot map MMIO\n", print_name); + goto err_out_region; + } + } else { + bp->base.port = bar_start; + dev->base_addr = bar_start; + } - dev->base_addr = ioaddr; /* save port (I/O) base address */ + /* Initialize new device structure */ dev->get_stats = dfx_ctl_get_stats; dev->open = dfx_open; @@ -465,22 +582,12 @@ static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr) dev->set_multicast_list = dfx_ctl_set_multicast_list; dev->set_mac_address = dfx_ctl_set_mac_address; - if (pdev == NULL) { - /* EISA board */ - bp->bus_type = DFX_BUS_TYPE_EISA; - bp->next = root_dfx_eisa_dev; - root_dfx_eisa_dev = dev; - } else { - /* PCI board */ - bp->bus_type = DFX_BUS_TYPE_PCI; - bp->pci_dev = pdev; - pci_set_drvdata (pdev, dev); - pci_set_master (pdev); - } + if (dfx_bus_pci) + pci_set_master(to_pci_dev(bdev)); - if (dfx_driver_init(dev, print_name) != DFX_K_SUCCESS) { + if (dfx_driver_init(dev, print_name, bar_start) != DFX_K_SUCCESS) { err = -ENODEV; - goto err_out_region; + goto err_out_unmap; } err = register_netdev(dev); @@ -499,44 +606,28 @@ err_out_kfree: sizeof(PI_CONSUMER_BLOCK) + (PI_ALIGN_K_DESC_BLK - 1); if (bp->kmalloced) - pci_free_consistent(pdev, alloc_size, - bp->kmalloced, bp->kmalloced_dma); + dma_free_coherent(bdev, alloc_size, + bp->kmalloced, bp->kmalloced_dma); + +err_out_unmap: + if (dfx_use_mmio) + iounmap(bp->base.mem); + err_out_region: - release_region(ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN); + if (dfx_use_mmio) + release_mem_region(bar_start, bar_len); + else + release_region(bar_start, bar_len); + +err_out_disable: + if (dfx_bus_pci) + pci_disable_device(to_pci_dev(bdev)); + err_out: free_netdev(dev); return err; } -static int __devinit dfx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - return dfx_init_one_pci_or_eisa(pdev, 0); -} - -static int __init dfx_eisa_init(void) -{ - int rc = -ENODEV; - int i; /* used in for loops */ - u16 port; /* temporary I/O (port) address */ - u32 slot_id; /* EISA hardware (slot) ID read from adapter */ - - DBG_printk("In dfx_eisa_init...\n"); - - /* Scan for FDDI EISA controllers */ - - for (i=0; i < DFX_MAX_EISA_SLOTS; i++) /* only scan for up to 16 EISA slots */ - { - port = (i << 12) + PI_ESIC_K_SLOT_ID; /* port = I/O address for reading slot ID */ - slot_id = inl(port); /* read EISA HW (slot) ID */ - if ((slot_id & 0xF0FFFFFF) == DEFEA_PRODUCT_ID) - { - port = (i << 12); /* recalc base addr */ - - if (dfx_init_one_pci_or_eisa(NULL, port) == 0) rc = 0; - } - } - return rc; -} /* * ================ @@ -544,7 +635,7 @@ static int __init dfx_eisa_init(void) * ================ * * Overview: - * Initializes EISA and PCI controller bus-specific logic. + * Initializes the bus-specific controller logic. * * Returns: * None @@ -560,7 +651,7 @@ static int __init dfx_eisa_init(void) * None * * Assumptions: - * dev->base_addr has already been set with the proper + * bp->base has already been set with the proper * base I/O address for this device. * * Side Effects: @@ -571,87 +662,103 @@ static int __init dfx_eisa_init(void) static void __devinit dfx_bus_init(struct net_device *dev) { - DFX_board_t *bp = dev->priv; - u8 val; /* used for I/O read/writes */ + DFX_board_t *bp = netdev_priv(dev); + struct device *bdev = bp->bus_dev; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + u8 val; DBG_printk("In dfx_bus_init...\n"); - /* - * Initialize base I/O address field in bp structure - * - * Note: bp->base_addr is the same as dev->base_addr. - * It's useful because often we'll need to read - * or write registers where we already have the - * bp pointer instead of the dev pointer. Having - * the base address in the bp structure will - * save a pointer dereference. - * - * IMPORTANT!! This field must be defined before - * any of the dfx_port_* inline functions are - * called. - */ - - bp->base_addr = dev->base_addr; - - /* And a pointer back to the net_device struct */ + /* Initialize a pointer back to the net_device struct */ bp->dev = dev; /* Initialize adapter based on bus type */ - if (bp->bus_type == DFX_BUS_TYPE_EISA) - { - /* Get the interrupt level from the ESIC chip */ - - dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val); - switch ((val & PI_CONFIG_STAT_0_M_IRQ) >> PI_CONFIG_STAT_0_V_IRQ) - { - case PI_CONFIG_STAT_0_IRQ_K_9: - dev->irq = 9; - break; - - case PI_CONFIG_STAT_0_IRQ_K_10: - dev->irq = 10; - break; + if (dfx_bus_tc) + dev->irq = to_tc_dev(bdev)->interrupt; + if (dfx_bus_eisa) { + unsigned long base_addr = to_eisa_device(bdev)->base_addr; - case PI_CONFIG_STAT_0_IRQ_K_11: - dev->irq = 11; - break; + /* Get the interrupt level from the ESIC chip. */ + val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); + val &= PI_CONFIG_STAT_0_M_IRQ; + val >>= PI_CONFIG_STAT_0_V_IRQ; - case PI_CONFIG_STAT_0_IRQ_K_15: - dev->irq = 15; - break; - } - - /* Enable access to I/O on the board by writing 0x03 to Function Control Register */ + switch (val) { + case PI_CONFIG_STAT_0_IRQ_K_9: + dev->irq = 9; + break; - dfx_port_write_byte(bp, PI_ESIC_K_FUNCTION_CNTRL, PI_ESIC_K_FUNCTION_CNTRL_IO_ENB); + case PI_CONFIG_STAT_0_IRQ_K_10: + dev->irq = 10; + break; - /* Set the I/O decode range of the board */ + case PI_CONFIG_STAT_0_IRQ_K_11: + dev->irq = 11; + break; - val = ((dev->base_addr >> 12) << PI_IO_CMP_V_SLOT); - dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_0_1, val); - dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_1_1, val); + case PI_CONFIG_STAT_0_IRQ_K_15: + dev->irq = 15; + break; + } - /* Enable access to rest of module (including PDQ and packet memory) */ + /* + * Enable memory decoding (MEMCS0) and/or port decoding + * (IOCS1/IOCS0) as appropriate in Function Control + * Register. One of the port chip selects seems to be + * used for the Burst Holdoff register, but this bit of + * documentation is missing and as yet it has not been + * determined which of the two. This is also the reason + * the size of the decoded port range is twice as large + * as one required by the PDQ. + */ - dfx_port_write_byte(bp, PI_ESIC_K_SLOT_CNTRL, PI_SLOT_CNTRL_M_ENB); + /* Set the decode range of the board. */ + val = ((bp->base.port >> 12) << PI_IO_CMP_V_SLOT); + outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_1, val); + outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_0, 0); + outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_1, val); + outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_0, 0); + val = PI_ESIC_K_CSR_IO_LEN - 1; + outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_1, (val >> 8) & 0xff); + outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_0, val & 0xff); + outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_1, (val >> 8) & 0xff); + outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_0, val & 0xff); + + /* Enable the decoders. */ + val = PI_FUNCTION_CNTRL_M_IOCS1 | PI_FUNCTION_CNTRL_M_IOCS0; + if (dfx_use_mmio) + val |= PI_FUNCTION_CNTRL_M_MEMCS0; + outb(base_addr + PI_ESIC_K_FUNCTION_CNTRL, val); /* - * Map PDQ registers into I/O space. This is done by clearing a bit - * in Burst Holdoff register. + * Enable access to the rest of the module + * (including PDQ and packet memory). */ + val = PI_SLOT_CNTRL_M_ENB; + outb(base_addr + PI_ESIC_K_SLOT_CNTRL, val); - dfx_port_read_byte(bp, PI_ESIC_K_BURST_HOLDOFF, &val); - dfx_port_write_byte(bp, PI_ESIC_K_BURST_HOLDOFF, (val & ~PI_BURST_HOLDOFF_M_MEM_MAP)); + /* + * Map PDQ registers into memory or port space. This is + * done with a bit in the Burst Holdoff register. + */ + val = inb(base_addr + PI_DEFEA_K_BURST_HOLDOFF); + if (dfx_use_mmio) + val |= PI_BURST_HOLDOFF_V_MEM_MAP; + else + val &= ~PI_BURST_HOLDOFF_V_MEM_MAP; + outb(base_addr + PI_DEFEA_K_BURST_HOLDOFF, val); /* Enable interrupts at EISA bus interface chip (ESIC) */ - - dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val); - dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, (val | PI_CONFIG_STAT_0_M_INT_ENB)); - } - else - { - struct pci_dev *pdev = bp->pci_dev; + val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); + val |= PI_CONFIG_STAT_0_M_INT_ENB; + outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val); + } + if (dfx_bus_pci) { + struct pci_dev *pdev = to_pci_dev(bdev); /* Get the interrupt level from the PCI Configuration Table */ @@ -660,17 +767,70 @@ static void __devinit dfx_bus_init(struct net_device *dev) /* Check Latency Timer and set if less than minimal */ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &val); - if (val < PFI_K_LAT_TIMER_MIN) /* if less than min, override with default */ - { + if (val < PFI_K_LAT_TIMER_MIN) { val = PFI_K_LAT_TIMER_DEF; pci_write_config_byte(pdev, PCI_LATENCY_TIMER, val); - } + } /* Enable interrupts at PCI bus interface chip (PFI) */ + val = PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB; + dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, val); + } +} - dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, (PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB)); - } +/* + * ================== + * = dfx_bus_uninit = + * ================== + * + * Overview: + * Uninitializes the bus-specific controller logic. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * Perform bus-specific logic uninitialization. + * + * Return Codes: + * None + * + * Assumptions: + * bp->base has already been set with the proper + * base I/O address for this device. + * + * Side Effects: + * Interrupts are disabled at the adapter bus-specific logic. + */ + +static void __devinit dfx_bus_uninit(struct net_device *dev) +{ + DFX_board_t *bp = netdev_priv(dev); + struct device *bdev = bp->bus_dev; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + u8 val; + + DBG_printk("In dfx_bus_uninit...\n"); + + /* Uninitialize adapter based on bus type */ + + if (dfx_bus_eisa) { + unsigned long base_addr = to_eisa_device(bdev)->base_addr; + + /* Disable interrupts at EISA bus interface chip (ESIC) */ + val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); + val &= ~PI_CONFIG_STAT_0_M_INT_ENB; + outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val); + } + if (dfx_bus_pci) { + /* Disable interrupts at PCI bus interface chip (PFI) */ + dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, 0); } +} /* @@ -705,18 +865,16 @@ static void __devinit dfx_bus_init(struct net_device *dev) static void __devinit dfx_bus_config_check(DFX_board_t *bp) { + struct device __unused *bdev = bp->bus_dev; + int dfx_bus_eisa = DFX_BUS_EISA(bdev); int status; /* return code from adapter port control call */ - u32 slot_id; /* EISA-bus hardware id (DEC3001, DEC3002,...) */ u32 host_data; /* LW data returned from port control call */ DBG_printk("In dfx_bus_config_check...\n"); /* Configuration check only valid for EISA adapter */ - if (bp->bus_type == DFX_BUS_TYPE_EISA) - { - dfx_port_read_long(bp, PI_ESIC_K_SLOT_ID, &slot_id); - + if (dfx_bus_eisa) { /* * First check if revision 2 EISA controller. Rev. 1 cards used * PDQ revision B, so no workaround needed in this case. Rev. 3 @@ -724,14 +882,11 @@ static void __devinit dfx_bus_config_check(DFX_board_t *bp) * case, either. Only Rev. 2 cards used either Rev. D or E * chips, so we must verify the chip revision on Rev. 2 cards. */ - - if (slot_id == DEFEA_PROD_ID_2) - { + if (to_eisa_device(bdev)->id.driver_data == DEFEA_PROD_ID_2) { /* - * Revision 2 FDDI EISA controller found, so let's check PDQ - * revision of adapter. + * Revision 2 FDDI EISA controller found, + * so let's check PDQ revision of adapter. */ - status = dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_SUB_CMD, PI_SUB_CMD_K_PDQ_REV_GET, @@ -805,13 +960,20 @@ static void __devinit dfx_bus_config_check(DFX_board_t *bp) */ static int __devinit dfx_driver_init(struct net_device *dev, - const char *print_name) + const char *print_name, + resource_size_t bar_start) { - DFX_board_t *bp = dev->priv; - int alloc_size; /* total buffer size needed */ - char *top_v, *curr_v; /* virtual addrs into memory block */ - dma_addr_t top_p, curr_p; /* physical addrs into memory block */ - u32 data; /* host data register value */ + DFX_board_t *bp = netdev_priv(dev); + struct device *bdev = bp->bus_dev; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + int alloc_size; /* total buffer size needed */ + char *top_v, *curr_v; /* virtual addrs into memory block */ + dma_addr_t top_p, curr_p; /* physical addrs into memory block */ + u32 data, le32; /* host data register value */ + char *board_name = NULL; DBG_printk("In dfx_driver_init...\n"); @@ -860,8 +1022,8 @@ static int __devinit dfx_driver_init(struct net_device *dev, print_name); return(DFX_K_FAILURE); } - data = cpu_to_le32(data); - memcpy(&bp->factory_mac_addr[0], &data, sizeof(u32)); + le32 = cpu_to_le32(data); + memcpy(&bp->factory_mac_addr[0], &le32, sizeof(u32)); if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_HI, 0, &data) != DFX_K_SUCCESS) { @@ -869,8 +1031,8 @@ static int __devinit dfx_driver_init(struct net_device *dev, print_name); return(DFX_K_FAILURE); } - data = cpu_to_le32(data); - memcpy(&bp->factory_mac_addr[4], &data, sizeof(u16)); + le32 = cpu_to_le32(data); + memcpy(&bp->factory_mac_addr[4], &le32, sizeof(u16)); /* * Set current address to factory address @@ -880,20 +1042,18 @@ static int __devinit dfx_driver_init(struct net_device *dev, */ memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN); - if (bp->bus_type == DFX_BUS_TYPE_EISA) - printk("%s: DEFEA at I/O addr = 0x%lX, IRQ = %d, " - "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n", - print_name, dev->base_addr, dev->irq, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); - else - printk("%s: DEFPA at I/O addr = 0x%lX, IRQ = %d, " - "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n", - print_name, dev->base_addr, dev->irq, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); + if (dfx_bus_tc) + board_name = "DEFTA"; + if (dfx_bus_eisa) + board_name = "DEFEA"; + if (dfx_bus_pci) + board_name = "DEFPA"; + pr_info("%s: %s at %saddr = 0x%llx, IRQ = %d, " + "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n", + print_name, board_name, dfx_use_mmio ? "" : "I/O ", + (long long)bar_start, dev->irq, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); /* * Get memory for descriptor block, consumer block, and other buffers @@ -908,8 +1068,9 @@ static int __devinit dfx_driver_init(struct net_device *dev, #endif sizeof(PI_CONSUMER_BLOCK) + (PI_ALIGN_K_DESC_BLK - 1); - bp->kmalloced = top_v = pci_alloc_consistent(bp->pci_dev, alloc_size, - &bp->kmalloced_dma); + bp->kmalloced = top_v = dma_alloc_coherent(bp->bus_dev, alloc_size, + &bp->kmalloced_dma, + GFP_ATOMIC); if (top_v == NULL) { printk("%s: Could not allocate memory for host buffers " "and structures!\n", print_name); @@ -1219,14 +1380,15 @@ static int dfx_adap_init(DFX_board_t *bp, int get_buffers) static int dfx_open(struct net_device *dev) { + DFX_board_t *bp = netdev_priv(dev); int ret; - DFX_board_t *bp = dev->priv; DBG_printk("In dfx_open...\n"); /* Register IRQ - support shared interrupts by passing device ptr */ - ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name, dev); + ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name, + dev); if (ret) { printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq); return ret; @@ -1309,7 +1471,7 @@ static int dfx_open(struct net_device *dev) static int dfx_close(struct net_device *dev) { - DFX_board_t *bp = dev->priv; + DFX_board_t *bp = netdev_priv(dev); DBG_printk("In dfx_close...\n"); @@ -1645,7 +1807,7 @@ static void dfx_int_type_0_process(DFX_board_t *bp) static void dfx_int_common(struct net_device *dev) { - DFX_board_t *bp = dev->priv; + DFX_board_t *bp = netdev_priv(dev); PI_UINT32 port_status; /* Port Status register */ /* Process xmt interrupts - frequent case, so always call this routine */ @@ -1715,18 +1877,16 @@ static void dfx_int_common(struct net_device *dev) static irqreturn_t dfx_interrupt(int irq, void *dev_id) { - struct net_device *dev = dev_id; - DFX_board_t *bp; /* private board structure pointer */ - - /* Get board pointer only if device structure is valid */ - - bp = dev->priv; - - /* See if we're already servicing an interrupt */ + struct net_device *dev = dev_id; + DFX_board_t *bp = netdev_priv(dev); + struct device *bdev = bp->bus_dev; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); /* Service adapter interrupts */ - if (bp->bus_type == DFX_BUS_TYPE_PCI) { + if (dfx_bus_pci) { u32 status; dfx_port_read_long(bp, PFI_K_REG_STATUS, &status); @@ -1750,10 +1910,12 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id) PFI_MODE_M_DMA_ENB)); spin_unlock(&bp->lock); - } else { + } + if (dfx_bus_eisa) { + unsigned long base_addr = to_eisa_device(bdev)->base_addr; u8 status; - dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status); + status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); if (!(status & PI_CONFIG_STAT_0_M_PEND)) return IRQ_NONE; @@ -1761,15 +1923,35 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id) /* Disable interrupts at the ESIC */ status &= ~PI_CONFIG_STAT_0_M_INT_ENB; - dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status); + outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status); /* Call interrupt service routine for this adapter */ dfx_int_common(dev); /* Reenable interrupts at the ESIC */ - dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status); + status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); status |= PI_CONFIG_STAT_0_M_INT_ENB; - dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status); + outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status); + + spin_unlock(&bp->lock); + } + if (dfx_bus_tc) { + u32 status; + + dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &status); + if (!(status & (PI_PSTATUS_M_RCV_DATA_PENDING | + PI_PSTATUS_M_XMT_DATA_PENDING | + PI_PSTATUS_M_SMT_HOST_PENDING | + PI_PSTATUS_M_UNSOL_PENDING | + PI_PSTATUS_M_CMD_RSP_PENDING | + PI_PSTATUS_M_CMD_REQ_PENDING | + PI_PSTATUS_M_TYPE_0_PENDING))) + return IRQ_NONE; + + spin_lock(&bp->lock); + + /* Call interrupt service routine for this adapter */ + dfx_int_common(dev); spin_unlock(&bp->lock); } @@ -1823,7 +2005,7 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id) static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev) { - DFX_board_t *bp = dev->priv; + DFX_board_t *bp = netdev_priv(dev); /* Fill the bp->stats structure with driver-maintained counters */ @@ -2009,8 +2191,8 @@ static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev) */ static void dfx_ctl_set_multicast_list(struct net_device *dev) - { - DFX_board_t *bp = dev->priv; +{ + DFX_board_t *bp = netdev_priv(dev); int i; /* used as index in for loop */ struct dev_mc_list *dmi; /* ptr to multicast addr entry */ @@ -2124,8 +2306,8 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev) static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr) { - DFX_board_t *bp = dev->priv; struct sockaddr *p_sockaddr = (struct sockaddr *)addr; + DFX_board_t *bp = netdev_priv(dev); /* Copy unicast address to driver-maintained structs and update count */ @@ -2764,9 +2946,9 @@ static int dfx_rcv_init(DFX_board_t *bp, int get_buffers) my_skb_align(newskb, 128); bp->descr_block_virt->rcv_data[i + j].long_1 = - (u32)pci_map_single(bp->pci_dev, newskb->data, + (u32)dma_map_single(bp->bus_dev, newskb->data, NEW_SKB_SIZE, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); /* * p_rcv_buff_va is only used inside the * kernel so we put the skb pointer here. @@ -2880,17 +3062,17 @@ static void dfx_rcv_queue_process( my_skb_align(newskb, 128); skb = (struct sk_buff *)bp->p_rcv_buff_va[entry]; - pci_unmap_single(bp->pci_dev, + dma_unmap_single(bp->bus_dev, bp->descr_block_virt->rcv_data[entry].long_1, NEW_SKB_SIZE, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); skb_reserve(skb, RCV_BUFF_K_PADDING); bp->p_rcv_buff_va[entry] = (char *)newskb; bp->descr_block_virt->rcv_data[entry].long_1 = - (u32)pci_map_single(bp->pci_dev, + (u32)dma_map_single(bp->bus_dev, newskb->data, NEW_SKB_SIZE, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); } else skb = NULL; } else @@ -3010,7 +3192,7 @@ static int dfx_xmt_queue_pkt( ) { - DFX_board_t *bp = dev->priv; + DFX_board_t *bp = netdev_priv(dev); u8 prod; /* local transmit producer index */ PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */ XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ @@ -3116,8 +3298,8 @@ static int dfx_xmt_queue_pkt( */ p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len) << PI_XMT_DESCR_V_SEG_LEN)); - p_xmt_descr->long_1 = (u32)pci_map_single(bp->pci_dev, skb->data, - skb->len, PCI_DMA_TODEVICE); + p_xmt_descr->long_1 = (u32)dma_map_single(bp->bus_dev, skb->data, + skb->len, DMA_TO_DEVICE); /* * Verify that descriptor is actually available @@ -3220,10 +3402,10 @@ static int dfx_xmt_done(DFX_board_t *bp) /* Return skb to operating system */ comp = bp->rcv_xmt_reg.index.xmt_comp; - pci_unmap_single(bp->pci_dev, + dma_unmap_single(bp->bus_dev, bp->descr_block_virt->xmt_data[comp].long_1, p_xmt_drv_descr->p_skb->len, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); dev_kfree_skb_irq(p_xmt_drv_descr->p_skb); /* @@ -3344,10 +3526,10 @@ static void dfx_xmt_flush( DFX_board_t *bp ) /* Return skb to operating system */ comp = bp->rcv_xmt_reg.index.xmt_comp; - pci_unmap_single(bp->pci_dev, + dma_unmap_single(bp->bus_dev, bp->descr_block_virt->xmt_data[comp].long_1, p_xmt_drv_descr->p_skb->len, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); dev_kfree_skb(p_xmt_drv_descr->p_skb); /* Increment transmit error counter */ @@ -3375,13 +3557,44 @@ static void dfx_xmt_flush( DFX_board_t *bp ) bp->cons_block_virt->xmt_rcv_data = prod_cons; } -static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct net_device *dev) +/* + * ================== + * = dfx_unregister = + * ================== + * + * Overview: + * Shuts down an FDDI controller + * + * Returns: + * Condition code + * + * Arguments: + * bdev - pointer to device information + * + * Functional Description: + * + * Return Codes: + * None + * + * Assumptions: + * It compiles so it should work :-( (PCI cards do :-) + * + * Side Effects: + * Device structures for FDDI adapters (fddi0, fddi1, etc) are + * freed. + */ +static void __devexit dfx_unregister(struct device *bdev) { - DFX_board_t *bp = dev->priv; + struct net_device *dev = dev_get_drvdata(bdev); + DFX_board_t *bp = netdev_priv(dev); + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + resource_size_t bar_start = 0; /* pointer to port */ + resource_size_t bar_len = 0; /* resource length */ int alloc_size; /* total buffer size used */ unregister_netdev(dev); - release_region(dev->base_addr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN ); alloc_size = sizeof(PI_DESCR_BLOCK) + PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX + @@ -3391,78 +3604,141 @@ static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct ne sizeof(PI_CONSUMER_BLOCK) + (PI_ALIGN_K_DESC_BLK - 1); if (bp->kmalloced) - pci_free_consistent(pdev, alloc_size, bp->kmalloced, - bp->kmalloced_dma); + dma_free_coherent(bdev, alloc_size, + bp->kmalloced, bp->kmalloced_dma); + + dfx_bus_uninit(dev); + + dfx_get_bars(bdev, &bar_start, &bar_len); + if (dfx_use_mmio) { + iounmap(bp->base.mem); + release_mem_region(bar_start, bar_len); + } else + release_region(bar_start, bar_len); + + if (dfx_bus_pci) + pci_disable_device(to_pci_dev(bdev)); + free_netdev(dev); } -static void __devexit dfx_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - dfx_remove_one_pci_or_eisa(pdev, dev); - pci_set_drvdata(pdev, NULL); -} +static int __devinit __unused dfx_dev_register(struct device *); +static int __devexit __unused dfx_dev_unregister(struct device *); -static struct pci_device_id dfx_pci_tbl[] = { - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, } +#ifdef CONFIG_PCI +static int __devinit dfx_pci_register(struct pci_dev *, + const struct pci_device_id *); +static void __devexit dfx_pci_unregister(struct pci_dev *); + +static struct pci_device_id dfx_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI) }, + { } }; -MODULE_DEVICE_TABLE(pci, dfx_pci_tbl); +MODULE_DEVICE_TABLE(pci, dfx_pci_table); -static struct pci_driver dfx_driver = { +static struct pci_driver dfx_pci_driver = { .name = "defxx", - .probe = dfx_init_one, - .remove = __devexit_p(dfx_remove_one), - .id_table = dfx_pci_tbl, + .id_table = dfx_pci_table, + .probe = dfx_pci_register, + .remove = __devexit_p(dfx_pci_unregister), }; -static int dfx_have_pci; -static int dfx_have_eisa; - +static __devinit int dfx_pci_register(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + return dfx_register(&pdev->dev); +} -static void __exit dfx_eisa_cleanup(void) +static void __devexit dfx_pci_unregister(struct pci_dev *pdev) { - struct net_device *dev = root_dfx_eisa_dev; + dfx_unregister(&pdev->dev); +} +#endif /* CONFIG_PCI */ + +#ifdef CONFIG_EISA +static struct eisa_device_id dfx_eisa_table[] = { + { "DEC3001", DEFEA_PROD_ID_1 }, + { "DEC3002", DEFEA_PROD_ID_2 }, + { "DEC3003", DEFEA_PROD_ID_3 }, + { "DEC3004", DEFEA_PROD_ID_4 }, + { } +}; +MODULE_DEVICE_TABLE(eisa, dfx_eisa_table); + +static struct eisa_driver dfx_eisa_driver = { + .id_table = dfx_eisa_table, + .driver = { + .name = "defxx", + .bus = &eisa_bus_type, + .probe = dfx_dev_register, + .remove = __devexit_p(dfx_dev_unregister), + }, +}; +#endif /* CONFIG_EISA */ + +#ifdef CONFIG_TC +static struct tc_device_id const dfx_tc_table[] = { + { "DEC ", "PMAF-FA " }, + { "DEC ", "PMAF-FD " }, + { "DEC ", "PMAF-FS " }, + { "DEC ", "PMAF-FU " }, + { } +}; +MODULE_DEVICE_TABLE(tc, dfx_tc_table); + +static struct tc_driver dfx_tc_driver = { + .id_table = dfx_tc_table, + .driver = { + .name = "defxx", + .bus = &tc_bus_type, + .probe = dfx_dev_register, + .remove = __devexit_p(dfx_dev_unregister), + }, +}; +#endif /* CONFIG_TC */ - while (dev) - { - struct net_device *tmp; - DFX_board_t *bp; +static int __devinit __unused dfx_dev_register(struct device *dev) +{ + int status; - bp = (DFX_board_t*)dev->priv; - tmp = bp->next; - dfx_remove_one_pci_or_eisa(NULL, dev); - dev = tmp; - } + status = dfx_register(dev); + if (!status) + get_device(dev); + return status; } -static int __init dfx_init(void) +static int __devexit __unused dfx_dev_unregister(struct device *dev) { - int rc_pci, rc_eisa; - - rc_pci = pci_register_driver(&dfx_driver); - if (rc_pci >= 0) dfx_have_pci = 1; + put_device(dev); + dfx_unregister(dev); + return 0; +} - rc_eisa = dfx_eisa_init(); - if (rc_eisa >= 0) dfx_have_eisa = 1; - return ((rc_eisa < 0) ? 0 : rc_eisa) + ((rc_pci < 0) ? 0 : rc_pci); +static int __devinit dfx_init(void) +{ + int status; + + status = pci_register_driver(&dfx_pci_driver); + if (!status) + status = eisa_driver_register(&dfx_eisa_driver); + if (!status) + status = tc_register_driver(&dfx_tc_driver); + return status; } -static void __exit dfx_cleanup(void) +static void __devexit dfx_cleanup(void) { - if (dfx_have_pci) - pci_unregister_driver(&dfx_driver); - if (dfx_have_eisa) - dfx_eisa_cleanup(); - + tc_unregister_driver(&dfx_tc_driver); + eisa_driver_unregister(&dfx_eisa_driver); + pci_unregister_driver(&dfx_pci_driver); } module_init(dfx_init); module_exit(dfx_cleanup); MODULE_AUTHOR("Lawrence V. Stefani"); -MODULE_DESCRIPTION("DEC FDDIcontroller EISA/PCI (DEFEA/DEFPA) driver " +MODULE_DESCRIPTION("DEC FDDIcontroller TC/EISA/PCI (DEFTA/DEFEA/DEFPA) driver " DRV_VERSION " " DRV_RELDATE); MODULE_LICENSE("GPL"); diff --git a/drivers/net/defxx.h b/drivers/net/defxx.h index 2ce8f97253eb..19a6f64df198 100644 --- a/drivers/net/defxx.h +++ b/drivers/net/defxx.h @@ -26,6 +26,7 @@ * 12-Sep-96 LVS Removed packet request header pointers. * 04 Aug 2003 macro Converted to the DMA API. * 23 Oct 2006 macro Big-endian host support. + * 14 Dec 2006 macro TURBOchannel support. */ #ifndef _DEFXX_H_ @@ -1471,9 +1472,17 @@ typedef union #endif /* __BIG_ENDIAN */ +/* Define TC PDQ CSR offset and length */ + +#define PI_TC_K_CSR_OFFSET 0x100000 +#define PI_TC_K_CSR_LEN 0x40 /* 64 bytes */ + /* Define EISA controller register offsets */ -#define PI_ESIC_K_BURST_HOLDOFF 0x040 +#define PI_ESIC_K_CSR_IO_LEN 0x80 /* 128 bytes */ + +#define PI_DEFEA_K_BURST_HOLDOFF 0x040 + #define PI_ESIC_K_SLOT_ID 0xC80 #define PI_ESIC_K_SLOT_CNTRL 0xC84 #define PI_ESIC_K_MEM_ADD_CMP_0 0xC85 @@ -1488,14 +1497,14 @@ typedef union #define PI_ESIC_K_MEM_ADD_LO_CMP_0 0xC8E #define PI_ESIC_K_MEM_ADD_LO_CMP_1 0xC8F #define PI_ESIC_K_MEM_ADD_LO_CMP_2 0xC90 -#define PI_ESIC_K_IO_CMP_0_0 0xC91 -#define PI_ESIC_K_IO_CMP_0_1 0xC92 -#define PI_ESIC_K_IO_CMP_1_0 0xC93 -#define PI_ESIC_K_IO_CMP_1_1 0xC94 -#define PI_ESIC_K_IO_CMP_2_0 0xC95 -#define PI_ESIC_K_IO_CMP_2_1 0xC96 -#define PI_ESIC_K_IO_CMP_3_0 0xC97 -#define PI_ESIC_K_IO_CMP_3_1 0xC98 +#define PI_ESIC_K_IO_ADD_CMP_0_0 0xC91 +#define PI_ESIC_K_IO_ADD_CMP_0_1 0xC92 +#define PI_ESIC_K_IO_ADD_CMP_1_0 0xC93 +#define PI_ESIC_K_IO_ADD_CMP_1_1 0xC94 +#define PI_ESIC_K_IO_ADD_CMP_2_0 0xC95 +#define PI_ESIC_K_IO_ADD_CMP_2_1 0xC96 +#define PI_ESIC_K_IO_ADD_CMP_3_0 0xC97 +#define PI_ESIC_K_IO_ADD_CMP_3_1 0xC98 #define PI_ESIC_K_IO_ADD_MASK_0_0 0xC99 #define PI_ESIC_K_IO_ADD_MASK_0_1 0xC9A #define PI_ESIC_K_IO_ADD_MASK_1_0 0xC9B @@ -1518,11 +1527,16 @@ typedef union #define PI_ESIC_K_INPUT_PORT 0xCAC #define PI_ESIC_K_OUTPUT_PORT 0xCAD #define PI_ESIC_K_FUNCTION_CNTRL 0xCAE -#define PI_ESIC_K_CSR_IO_LEN PI_ESIC_K_FUNCTION_CNTRL+1 /* always last reg + 1 */ -/* Define the value all drivers must write to the function control register. */ +/* Define the bits in the function control register. */ -#define PI_ESIC_K_FUNCTION_CNTRL_IO_ENB 0x03 +#define PI_FUNCTION_CNTRL_M_IOCS0 0x01 +#define PI_FUNCTION_CNTRL_M_IOCS1 0x02 +#define PI_FUNCTION_CNTRL_M_IOCS2 0x04 +#define PI_FUNCTION_CNTRL_M_IOCS3 0x08 +#define PI_FUNCTION_CNTRL_M_MEMCS0 0x10 +#define PI_FUNCTION_CNTRL_M_MEMCS1 0x20 +#define PI_FUNCTION_CNTRL_M_DMA 0x80 /* Define the bits in the slot control register. */ @@ -1540,6 +1554,10 @@ typedef union #define PI_BURST_HOLDOFF_V_RESERVED 1 #define PI_BURST_HOLDOFF_V_MEM_MAP 0 +/* Define the implicit mask of the Memory Address Mask Register. */ + +#define PI_MEM_ADD_MASK_M 0x3ff + /* * Define the fields in the IO Compare registers. * The driver must initialize the slot field with the slot ID shifted by the @@ -1577,6 +1595,7 @@ typedef union #define DEFEA_PROD_ID_1 0x0130A310 /* DEC product 300, rev 1 */ #define DEFEA_PROD_ID_2 0x0230A310 /* DEC product 300, rev 2 */ #define DEFEA_PROD_ID_3 0x0330A310 /* DEC product 300, rev 3 */ +#define DEFEA_PROD_ID_4 0x0430A310 /* DEC product 300, rev 4 */ /**********************************************/ /* Digital PFI Specification v1.0 Definitions */ @@ -1633,12 +1652,6 @@ typedef union #define PFI_STATUS_V_FIFO_EMPTY 1 #define PFI_STATUS_V_DMA_IN_PROGRESS 0 -#define DFX_MAX_EISA_SLOTS 16 /* maximum number of EISA slots to scan */ -#define DFX_MAX_NUM_BOARDS 8 /* maximum number of adapters supported */ - -#define DFX_BUS_TYPE_PCI 0 /* type code for DEC FDDIcontroller/PCI */ -#define DFX_BUS_TYPE_EISA 1 /* type code for DEC FDDIcontroller/EISA */ - #define DFX_FC_PRH2_PRH1_PRH0 0x54003820 /* Packet Request Header bytes + FC */ #define DFX_PRH0_BYTE 0x20 /* Packet Request Header byte 0 */ #define DFX_PRH1_BYTE 0x38 /* Packet Request Header byte 1 */ @@ -1756,10 +1769,11 @@ typedef struct DFX_board_tag /* Store device, bus-specific, and parameter information for this adapter */ struct net_device *dev; /* pointer to device structure */ - struct net_device *next; - u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */ - u16 base_addr; /* base I/O address (same as dev->base_addr) */ - struct pci_dev * pci_dev; + union { + void __iomem *mem; + int port; + } base; /* base address */ + struct device *bus_dev; u32 full_duplex_enb; /* FDDI Full Duplex enable (1 == on, 2 == off) */ u32 req_ttrt; /* requested TTRT value (in 80ns units) */ u32 burst_size; /* adapter burst size (enumerated) */ diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c index 3c912ee29da0..8b5334c56f0a 100644 --- a/drivers/scsi/NCR53C9x.c +++ b/drivers/scsi/NCR53C9x.c @@ -528,12 +528,16 @@ void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs) /* Allocate structure and insert basic data such as SCSI chip frequency * data and a pointer to the device */ -struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev) +struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev, + int hotplug) { struct NCR_ESP *esp, *elink; struct Scsi_Host *esp_host; - esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP)); + if (hotplug) + esp_host = scsi_host_alloc(tpnt, sizeof(struct NCR_ESP)); + else + esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP)); if(!esp_host) panic("Cannot register ESP SCSI host"); esp = (struct NCR_ESP *) esp_host->hostdata; diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h index 521e3f842cfd..d85cb73a9f69 100644 --- a/drivers/scsi/NCR53C9x.h +++ b/drivers/scsi/NCR53C9x.h @@ -652,7 +652,7 @@ extern int nesps, esps_in_use, esps_running; /* External functions */ extern void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs); -extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *); +extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *, int); extern void esp_deallocate(struct NCR_ESP *); extern void esp_release(void); extern void esp_initialize(struct NCR_ESP *); diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c index 329a8f297b31..23f7c24ab809 100644 --- a/drivers/scsi/blz1230.c +++ b/drivers/scsi/blz1230.c @@ -121,7 +121,8 @@ int __init blz1230_esp_detect(struct scsi_host_template *tpnt) */ address = ZTWO_VADDR(board); eregs = (struct ESP_regs *)(address + REAL_BLZ1230_ESP_ADDR); - esp = esp_allocate(tpnt, (void *)board+REAL_BLZ1230_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + REAL_BLZ1230_ESP_ADDR, + 0); esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7)); udelay(5); diff --git a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c index b6c137b97350..b6203ec00961 100644 --- a/drivers/scsi/blz2060.c +++ b/drivers/scsi/blz2060.c @@ -100,7 +100,7 @@ int __init blz2060_esp_detect(struct scsi_host_template *tpnt) unsigned long board = z->resource.start; if (request_mem_region(board+BLZ2060_ESP_ADDR, sizeof(struct ESP_regs), "NCR53C9x")) { - esp = esp_allocate(tpnt, (void *)board+BLZ2060_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + BLZ2060_ESP_ADDR, 0); /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; diff --git a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c index 7c7cfb54e897..c6b98a42e89d 100644 --- a/drivers/scsi/cyberstorm.c +++ b/drivers/scsi/cyberstorm.c @@ -126,7 +126,7 @@ int __init cyber_esp_detect(struct scsi_host_template *tpnt) sizeof(struct ESP_regs)); return 0; } - esp = esp_allocate(tpnt, (void *)board+CYBER_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + CYBER_ESP_ADDR, 0); /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; diff --git a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c index d88cb9cf091e..e336e853e66f 100644 --- a/drivers/scsi/cyberstormII.c +++ b/drivers/scsi/cyberstormII.c @@ -98,7 +98,7 @@ int __init cyberII_esp_detect(struct scsi_host_template *tpnt) address = (unsigned long)ZTWO_VADDR(board); eregs = (struct ESP_regs *)(address + CYBERII_ESP_ADDR); - esp = esp_allocate(tpnt, (void *)board+CYBERII_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + CYBERII_ESP_ADDR, 0); esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7)); udelay(5); diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c index c29ccbc44693..d42ad663ffee 100644 --- a/drivers/scsi/dec_esp.c +++ b/drivers/scsi/dec_esp.c @@ -18,7 +18,7 @@ * 20001005 - Initialization fixes for 2.4.0-test9 * Florian Lohoff <flo@rfc822.org> * - * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki + * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki */ #include <linux/kernel.h> @@ -30,6 +30,7 @@ #include <linux/proc_fs.h> #include <linux/spinlock.h> #include <linux/stat.h> +#include <linux/tc.h> #include <asm/dma.h> #include <asm/irq.h> @@ -42,7 +43,6 @@ #include <asm/dec/ioasic_ints.h> #include <asm/dec/machtype.h> #include <asm/dec/system.h> -#include <asm/dec/tc.h> #define DEC_SCSI_SREG 0 #define DEC_SCSI_DMAREG 0x40000 @@ -98,51 +98,33 @@ static irqreturn_t scsi_dma_merr_int(int, void *); static irqreturn_t scsi_dma_err_int(int, void *); static irqreturn_t scsi_dma_int(int, void *); -static int dec_esp_detect(struct scsi_host_template * tpnt); - -static int dec_esp_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, NULL); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); - return 0; -} - -static struct scsi_host_template driver_template = { - .proc_name = "dec_esp", - .proc_info = esp_proc_info, +static struct scsi_host_template dec_esp_template = { + .module = THIS_MODULE, .name = "NCR53C94", - .detect = dec_esp_detect, - .slave_alloc = esp_slave_alloc, - .slave_destroy = esp_slave_destroy, - .release = dec_esp_release, .info = esp_info, .queuecommand = esp_queue, .eh_abort_handler = esp_abort, .eh_bus_reset_handler = esp_reset, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .proc_info = esp_proc_info, + .proc_name = "dec_esp", .can_queue = 7, - .this_id = 7, .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = DISABLE_CLUSTERING, }; - -#include "scsi_module.c" +static struct NCR_ESP *dec_esp_platform; /***************************************************************** Detection */ -static int dec_esp_detect(struct scsi_host_template * tpnt) +static int dec_esp_platform_probe(void) { struct NCR_ESP *esp; - struct ConfigDev *esp_dev; - int slot; - unsigned long mem_start; + int err = 0; if (IOASIC) { - esp_dev = 0; - esp = esp_allocate(tpnt, (void *) esp_dev); + esp = esp_allocate(&dec_esp_template, NULL, 1); /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; @@ -200,112 +182,175 @@ static int dec_esp_detect(struct scsi_host_template * tpnt) /* Check for differential SCSI-bus */ esp->diff = 0; + err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, + "ncr53c94", esp->ehost); + if (err) + goto err_alloc; + err = request_irq(dec_interrupt[DEC_IRQ_ASC_MERR], + scsi_dma_merr_int, IRQF_DISABLED, + "ncr53c94 error", esp->ehost); + if (err) + goto err_irq; + err = request_irq(dec_interrupt[DEC_IRQ_ASC_ERR], + scsi_dma_err_int, IRQF_DISABLED, + "ncr53c94 overrun", esp->ehost); + if (err) + goto err_irq_merr; + err = request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], scsi_dma_int, + IRQF_DISABLED, "ncr53c94 dma", esp->ehost); + if (err) + goto err_irq_err; + esp_initialize(esp); - if (request_irq(esp->irq, esp_intr, IRQF_DISABLED, - "ncr53c94", esp->ehost)) - goto err_dealloc; - if (request_irq(dec_interrupt[DEC_IRQ_ASC_MERR], - scsi_dma_merr_int, IRQF_DISABLED, - "ncr53c94 error", esp->ehost)) - goto err_free_irq; - if (request_irq(dec_interrupt[DEC_IRQ_ASC_ERR], - scsi_dma_err_int, IRQF_DISABLED, - "ncr53c94 overrun", esp->ehost)) - goto err_free_irq_merr; - if (request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], - scsi_dma_int, IRQF_DISABLED, - "ncr53c94 dma", esp->ehost)) - goto err_free_irq_err; + err = scsi_add_host(esp->ehost, NULL); + if (err) { + printk(KERN_ERR "ESP: Unable to register adapter\n"); + goto err_irq_dma; + } + + scsi_scan_host(esp->ehost); + dec_esp_platform = esp; } - if (TURBOCHANNEL) { - while ((slot = search_tc_card("PMAZ-AA")) >= 0) { - claim_tc_card(slot); - - esp_dev = 0; - esp = esp_allocate(tpnt, (void *) esp_dev); - - mem_start = get_tc_base_addr(slot); - - /* Store base addr into esp struct */ - esp->slot = CPHYSADDR(mem_start); - - esp->dregs = 0; - esp->eregs = (void *)CKSEG1ADDR(mem_start + - DEC_SCSI_SREG); - esp->do_pio_cmds = 1; - - /* Set the command buffer */ - esp->esp_command = (volatile unsigned char *) pmaz_cmd_buffer; - - /* get virtual dma address for command buffer */ - esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer); - - esp->cfreq = get_tc_speed(); - - esp->irq = get_tc_irq_nr(slot); - - /* Required functions */ - esp->dma_bytes_sent = &dma_bytes_sent; - esp->dma_can_transfer = &dma_can_transfer; - esp->dma_dump_state = &dma_dump_state; - esp->dma_init_read = &pmaz_dma_init_read; - esp->dma_init_write = &pmaz_dma_init_write; - esp->dma_ints_off = &pmaz_dma_ints_off; - esp->dma_ints_on = &pmaz_dma_ints_on; - esp->dma_irq_p = &dma_irq_p; - esp->dma_ports_p = &dma_ports_p; - esp->dma_setup = &pmaz_dma_setup; - - /* Optional functions */ - esp->dma_barrier = 0; - esp->dma_drain = &pmaz_dma_drain; - esp->dma_invalidate = 0; - esp->dma_irq_entry = 0; - esp->dma_irq_exit = 0; - esp->dma_poll = 0; - esp->dma_reset = 0; - esp->dma_led_off = 0; - esp->dma_led_on = 0; - - esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one; - esp->dma_mmu_get_scsi_sgl = 0; - esp->dma_mmu_release_scsi_one = 0; - esp->dma_mmu_release_scsi_sgl = 0; - esp->dma_advance_sg = 0; - - if (request_irq(esp->irq, esp_intr, IRQF_DISABLED, - "PMAZ_AA", esp->ehost)) { - esp_deallocate(esp); - release_tc_card(slot); - continue; - } - esp->scsi_id = 7; - esp->diff = 0; - esp_initialize(esp); - } + return 0; + +err_irq_dma: + free_irq(dec_interrupt[DEC_IRQ_ASC_DMA], esp->ehost); +err_irq_err: + free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], esp->ehost); +err_irq_merr: + free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], esp->ehost); +err_irq: + free_irq(esp->irq, esp->ehost); +err_alloc: + esp_deallocate(esp); + scsi_host_put(esp->ehost); + return err; +} + +static int __init dec_esp_probe(struct device *dev) +{ + struct NCR_ESP *esp; + resource_size_t start, len; + int err; + + esp = esp_allocate(&dec_esp_template, NULL, 1); + + dev_set_drvdata(dev, esp); + + start = to_tc_dev(dev)->resource.start; + len = to_tc_dev(dev)->resource.end - start + 1; + + if (!request_mem_region(start, len, dev->bus_id)) { + printk(KERN_ERR "%s: Unable to reserve MMIO resource\n", + dev->bus_id); + err = -EBUSY; + goto err_alloc; } - if(nesps) { - printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); - esps_running = esps_in_use; - return esps_in_use; + /* Store base addr into esp struct. */ + esp->slot = start; + + esp->dregs = 0; + esp->eregs = (void *)CKSEG1ADDR(start + DEC_SCSI_SREG); + esp->do_pio_cmds = 1; + + /* Set the command buffer. */ + esp->esp_command = (volatile unsigned char *)pmaz_cmd_buffer; + + /* Get virtual dma address for command buffer. */ + esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer); + + esp->cfreq = tc_get_speed(to_tc_dev(dev)->bus); + + esp->irq = to_tc_dev(dev)->interrupt; + + /* Required functions. */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &pmaz_dma_init_read; + esp->dma_init_write = &pmaz_dma_init_write; + esp->dma_ints_off = &pmaz_dma_ints_off; + esp->dma_ints_on = &pmaz_dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &pmaz_dma_setup; + + /* Optional functions. */ + esp->dma_barrier = 0; + esp->dma_drain = &pmaz_dma_drain; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_poll = 0; + esp->dma_reset = 0; + esp->dma_led_off = 0; + esp->dma_led_on = 0; + + esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one; + esp->dma_mmu_get_scsi_sgl = 0; + esp->dma_mmu_release_scsi_one = 0; + esp->dma_mmu_release_scsi_sgl = 0; + esp->dma_advance_sg = 0; + + err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, "PMAZ_AA", + esp->ehost); + if (err) { + printk(KERN_ERR "%s: Unable to get IRQ %d\n", + dev->bus_id, esp->irq); + goto err_resource; + } + + esp->scsi_id = 7; + esp->diff = 0; + esp_initialize(esp); + + err = scsi_add_host(esp->ehost, dev); + if (err) { + printk(KERN_ERR "%s: Unable to register adapter\n", + dev->bus_id); + goto err_irq; } + + scsi_scan_host(esp->ehost); + return 0; -err_free_irq_err: - free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], scsi_dma_err_int); -err_free_irq_merr: - free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], scsi_dma_merr_int); -err_free_irq: - free_irq(esp->irq, esp_intr); -err_dealloc: +err_irq: + free_irq(esp->irq, esp->ehost); + +err_resource: + release_mem_region(start, len); + +err_alloc: esp_deallocate(esp); - return 0; + scsi_host_put(esp->ehost); + return err; +} + +static void __exit dec_esp_platform_remove(void) +{ + struct NCR_ESP *esp = dec_esp_platform; + + free_irq(esp->irq, esp->ehost); + esp_deallocate(esp); + scsi_host_put(esp->ehost); + dec_esp_platform = NULL; } +static void __exit dec_esp_remove(struct device *dev) +{ + struct NCR_ESP *esp = dev_get_drvdata(dev); + + free_irq(esp->irq, esp->ehost); + esp_deallocate(esp); + scsi_host_put(esp->ehost); +} + + /************************************************************* DMA Functions */ static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id) { @@ -576,3 +621,67 @@ static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp { sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer); } + + +#ifdef CONFIG_TC +static int __init dec_esp_tc_probe(struct device *dev); +static int __exit dec_esp_tc_remove(struct device *dev); + +static const struct tc_device_id dec_esp_tc_table[] = { + { "DEC ", "PMAZ-AA " }, + { } +}; +MODULE_DEVICE_TABLE(tc, dec_esp_tc_table); + +static struct tc_driver dec_esp_tc_driver = { + .id_table = dec_esp_tc_table, + .driver = { + .name = "dec_esp", + .bus = &tc_bus_type, + .probe = dec_esp_tc_probe, + .remove = __exit_p(dec_esp_tc_remove), + }, +}; + +static int __init dec_esp_tc_probe(struct device *dev) +{ + int status = dec_esp_probe(dev); + if (!status) + get_device(dev); + return status; +} + +static int __exit dec_esp_tc_remove(struct device *dev) +{ + put_device(dev); + dec_esp_remove(dev); + return 0; +} +#endif + +static int __init dec_esp_init(void) +{ + int status; + + status = tc_register_driver(&dec_esp_tc_driver); + if (!status) + dec_esp_platform_probe(); + + if (nesps) { + pr_info("ESP: Total of %d ESP hosts found, " + "%d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + } + + return status; +} + +static void __exit dec_esp_exit(void) +{ + dec_esp_platform_remove(); + tc_unregister_driver(&dec_esp_tc_driver); +} + + +module_init(dec_esp_init); +module_exit(dec_esp_exit); diff --git a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c index 2a1c5c22b9e0..4266a2139b5f 100644 --- a/drivers/scsi/fastlane.c +++ b/drivers/scsi/fastlane.c @@ -142,7 +142,7 @@ int __init fastlane_esp_detect(struct scsi_host_template *tpnt) if (board < 0x1000000) { goto err_release; } - esp = esp_allocate(tpnt, (void *)board+FASTLANE_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + FASTLANE_ESP_ADDR, 0); /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index bfac4441d89f..19dd4b962e18 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -75,7 +75,7 @@ static int jazz_esp_detect(struct scsi_host_template *tpnt) */ if (1) { esp_dev = NULL; - esp = esp_allocate(tpnt, (void *) esp_dev); + esp = esp_allocate(tpnt, esp_dev, 0); /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 3586fac9be9a..bcb49021b7e2 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -351,7 +351,7 @@ int mac_esp_detect(struct scsi_host_template * tpnt) for (chipnum = 0; chipnum < chipspresent; chipnum ++) { struct NCR_ESP * esp; - esp = esp_allocate(tpnt, (void *) NULL); + esp = esp_allocate(tpnt, NULL, 0); esp->eregs = (struct ESP_regs *) get_base(chipnum); esp->dma_irq_p = &esp_dafb_dma_irq_p; diff --git a/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c index 998a8bbc1a4b..d693d0f21395 100644 --- a/drivers/scsi/mca_53c9x.c +++ b/drivers/scsi/mca_53c9x.c @@ -122,7 +122,7 @@ static int mca_esp_detect(struct scsi_host_template *tpnt) if ((slot = mca_find_adapter(*id_to_check, 0)) != MCA_NOTFOUND) { - esp = esp_allocate(tpnt, (void *) NULL); + esp = esp_allocate(tpnt, NULL, 0); pos[0] = mca_read_stored_pos(slot, 2); pos[1] = mca_read_stored_pos(slot, 3); diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c index c116a6ae3c54..26a6d55faf3e 100644 --- a/drivers/scsi/oktagon_esp.c +++ b/drivers/scsi/oktagon_esp.c @@ -133,7 +133,7 @@ int oktagon_esp_detect(struct scsi_host_template *tpnt) eregs = (struct ESP_regs *)(address + OKTAGON_ESP_ADDR); /* This line was 5 lines lower */ - esp = esp_allocate(tpnt, (void *)board+OKTAGON_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + OKTAGON_ESP_ADDR, 0); /* we have to shift the registers only one bit for oktagon */ esp->shift = 1; diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index 6b60536ac92b..80fb3f88af2e 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c @@ -53,7 +53,7 @@ int sun3x_esp_detect(struct scsi_host_template *tpnt) struct ConfigDev *esp_dev; esp_dev = 0; - esp = esp_allocate(tpnt, (void *) esp_dev); + esp = esp_allocate(tpnt, esp_dev, 0); /* Do command transfer with DMA */ esp->do_pio_cmds = 0; diff --git a/drivers/tc/Makefile b/drivers/tc/Makefile index 83b5bd75ce26..967342692211 100644 --- a/drivers/tc/Makefile +++ b/drivers/tc/Makefile @@ -4,7 +4,7 @@ # Object file lists. -obj-$(CONFIG_TC) += tc.o +obj-$(CONFIG_TC) += tc.o tc-driver.o obj-$(CONFIG_ZS) += zs.o obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o diff --git a/drivers/tc/tc-driver.c b/drivers/tc/tc-driver.c new file mode 100644 index 000000000000..16b5bae63c74 --- /dev/null +++ b/drivers/tc/tc-driver.c @@ -0,0 +1,110 @@ +/* + * TURBOchannel driver services. + * + * Copyright (c) 2005 James Simmons + * Copyright (c) 2006 Maciej W. Rozycki + * + * Loosely based on drivers/dio/dio-driver.c and + * drivers/pci/pci-driver.c. + * + * This file is subject to the terms and conditions of the GNU + * General Public License. See the file "COPYING" in the main + * directory of this archive for more details. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/tc.h> + +/** + * tc_register_driver - register a new TC driver + * @drv: the driver structure to register + * + * Adds the driver structure to the list of registered drivers + * Returns a negative value on error, otherwise 0. + * If no error occurred, the driver remains registered even if + * no device was claimed during registration. + */ +int tc_register_driver(struct tc_driver *tdrv) +{ + return driver_register(&tdrv->driver); +} +EXPORT_SYMBOL(tc_register_driver); + +/** + * tc_unregister_driver - unregister a TC driver + * @drv: the driver structure to unregister + * + * Deletes the driver structure from the list of registered TC drivers, + * gives it a chance to clean up by calling its remove() function for + * each device it was responsible for, and marks those devices as + * driverless. + */ +void tc_unregister_driver(struct tc_driver *tdrv) +{ + driver_unregister(&tdrv->driver); +} +EXPORT_SYMBOL(tc_unregister_driver); + +/** + * tc_match_device - tell if a TC device structure has a matching + * TC device ID structure + * @tdrv: the TC driver to earch for matching TC device ID strings + * @tdev: the TC device structure to match against + * + * Used by a driver to check whether a TC device present in the + * system is in its list of supported devices. Returns the matching + * tc_device_id structure or %NULL if there is no match. + */ +const struct tc_device_id *tc_match_device(struct tc_driver *tdrv, + struct tc_dev *tdev) +{ + const struct tc_device_id *id = tdrv->id_table; + + if (id) { + while (id->name[0] || id->vendor[0]) { + if (strcmp(tdev->name, id->name) == 0 && + strcmp(tdev->vendor, id->vendor) == 0) + return id; + id++; + } + } + return NULL; +} +EXPORT_SYMBOL(tc_match_device); + +/** + * tc_bus_match - Tell if a device structure has a matching + * TC device ID structure + * @dev: the device structure to match against + * @drv: the device driver to search for matching TC device ID strings + * + * Used by a driver to check whether a TC device present in the + * system is in its list of supported devices. Returns 1 if there + * is a match or 0 otherwise. + */ +static int tc_bus_match(struct device *dev, struct device_driver *drv) +{ + struct tc_dev *tdev = to_tc_dev(dev); + struct tc_driver *tdrv = to_tc_driver(drv); + const struct tc_device_id *id; + + id = tc_match_device(tdrv, tdev); + if (id) + return 1; + + return 0; +} + +struct bus_type tc_bus_type = { + .name = "tc", + .match = tc_bus_match, +}; +EXPORT_SYMBOL(tc_bus_type); + +static int __init tc_driver_init(void) +{ + return bus_register(&tc_bus_type); +} + +postcore_initcall(tc_driver_init); diff --git a/drivers/tc/tc.c b/drivers/tc/tc.c index 4a51e56f85b6..f77f62a4b325 100644 --- a/drivers/tc/tc.c +++ b/drivers/tc/tc.c @@ -1,254 +1,193 @@ /* - * tc-init: We assume the TURBOchannel to be up and running so - * just probe for Modules and fill in the global data structure - * tc_bus. + * TURBOchannel bus services. * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. + * Copyright (c) Harald Koerfgen, 1998 + * Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki + * Copyright (c) 2005 James Simmons * - * Copyright (c) Harald Koerfgen, 1998 - * Copyright (c) 2001, 2003, 2005 Maciej W. Rozycki + * This file is subject to the terms and conditions of the GNU + * General Public License. See the file "COPYING" in the main + * directory of this archive for more details. */ +#include <linux/compiler.h> +#include <linux/errno.h> #include <linux/init.h> +#include <linux/ioport.h> #include <linux/kernel.h> +#include <linux/list.h> #include <linux/module.h> #include <linux/string.h> +#include <linux/tc.h> #include <linux/types.h> -#include <asm/addrspace.h> -#include <asm/errno.h> #include <asm/io.h> -#include <asm/paccess.h> -#include <asm/dec/machtype.h> -#include <asm/dec/prom.h> -#include <asm/dec/tcinfo.h> -#include <asm/dec/tcmodule.h> -#include <asm/dec/interrupts.h> - -MODULE_LICENSE("GPL"); -slot_info tc_bus[MAX_SLOT]; -static int num_tcslots; -static tcinfo *info; +static struct tc_bus tc_bus = { + .name = "TURBOchannel", +}; /* - * Interface to the world. Read comment in include/asm-mips/tc.h. + * Probing for TURBOchannel modules. */ - -int search_tc_card(const char *name) -{ - int slot; - slot_info *sip; - - for (slot = 0; slot < num_tcslots; slot++) { - sip = &tc_bus[slot]; - if ((sip->flags & FREE) && - (strncmp(sip->name, name, strlen(name)) == 0)) { - return slot; - } - } - - return -ENODEV; -} - -void claim_tc_card(int slot) -{ - if (tc_bus[slot].flags & IN_USE) { - printk("claim_tc_card: attempting to claim a card already in use\n"); - return; - } - tc_bus[slot].flags &= ~FREE; - tc_bus[slot].flags |= IN_USE; -} - -void release_tc_card(int slot) +static void __init tc_bus_add_devices(struct tc_bus *tbus) { - if (tc_bus[slot].flags & FREE) { - printk("release_tc_card: " - "attempting to release a card already free\n"); - return; - } - tc_bus[slot].flags &= ~IN_USE; - tc_bus[slot].flags |= FREE; -} - -unsigned long get_tc_base_addr(int slot) -{ - return tc_bus[slot].base_addr; -} - -unsigned long get_tc_irq_nr(int slot) -{ - return tc_bus[slot].interrupt; -} - -unsigned long get_tc_speed(void) -{ - return 100000 * (10000 / (unsigned long)info->clk_period); -} - -/* - * Probing for TURBOchannel modules - */ -static void __init tc_probe(unsigned long startaddr, unsigned long size, - int slots) -{ - unsigned long slotaddr; + resource_size_t slotsize = tbus->info.slot_size << 20; + resource_size_t extslotsize = tbus->ext_slot_size; + resource_size_t slotaddr; + resource_size_t extslotaddr; + resource_size_t devsize; + void __iomem *module; + struct tc_dev *tdev; int i, slot, err; - long offset; u8 pattern[4]; - volatile u8 *module; + long offset; - for (slot = 0; slot < slots; slot++) { - slotaddr = startaddr + slot * size; - module = ioremap_nocache(slotaddr, size); + for (slot = 0; slot < tbus->num_tcslots; slot++) { + slotaddr = tbus->slot_base + slot * slotsize; + extslotaddr = tbus->ext_slot_base + slot * extslotsize; + module = ioremap_nocache(slotaddr, slotsize); BUG_ON(!module); - offset = OLDCARD; + offset = TC_OLDCARD; err = 0; - err |= get_dbe(pattern[0], module + OLDCARD + TC_PATTERN0); - err |= get_dbe(pattern[1], module + OLDCARD + TC_PATTERN1); - err |= get_dbe(pattern[2], module + OLDCARD + TC_PATTERN2); - err |= get_dbe(pattern[3], module + OLDCARD + TC_PATTERN3); - if (err) { - iounmap(module); - continue; - } + err |= tc_preadb(pattern + 0, module + offset + TC_PATTERN0); + err |= tc_preadb(pattern + 1, module + offset + TC_PATTERN1); + err |= tc_preadb(pattern + 2, module + offset + TC_PATTERN2); + err |= tc_preadb(pattern + 3, module + offset + TC_PATTERN3); + if (err) + goto out_err; if (pattern[0] != 0x55 || pattern[1] != 0x00 || pattern[2] != 0xaa || pattern[3] != 0xff) { - offset = NEWCARD; + offset = TC_NEWCARD; err = 0; - err |= get_dbe(pattern[0], module + TC_PATTERN0); - err |= get_dbe(pattern[1], module + TC_PATTERN1); - err |= get_dbe(pattern[2], module + TC_PATTERN2); - err |= get_dbe(pattern[3], module + TC_PATTERN3); - if (err) { - iounmap(module); - continue; - } + err |= tc_preadb(pattern + 0, + module + offset + TC_PATTERN0); + err |= tc_preadb(pattern + 1, + module + offset + TC_PATTERN1); + err |= tc_preadb(pattern + 2, + module + offset + TC_PATTERN2); + err |= tc_preadb(pattern + 3, + module + offset + TC_PATTERN3); + if (err) + goto out_err; } if (pattern[0] != 0x55 || pattern[1] != 0x00 || - pattern[2] != 0xaa || pattern[3] != 0xff) { - iounmap(module); - continue; + pattern[2] != 0xaa || pattern[3] != 0xff) + goto out_err; + + /* Found a board, allocate it an entry in the list */ + tdev = kzalloc(sizeof(*tdev), GFP_KERNEL); + if (!tdev) { + printk(KERN_ERR "tc%x: unable to allocate tc_dev\n", + slot); + goto out_err; } + sprintf(tdev->dev.bus_id, "tc%x", slot); + tdev->bus = tbus; + tdev->dev.parent = &tbus->dev; + tdev->dev.bus = &tc_bus_type; + tdev->slot = slot; - tc_bus[slot].base_addr = slotaddr; for (i = 0; i < 8; i++) { - tc_bus[slot].firmware[i] = - module[TC_FIRM_VER + offset + 4 * i]; - tc_bus[slot].vendor[i] = - module[TC_VENDOR + offset + 4 * i]; - tc_bus[slot].name[i] = - module[TC_MODULE + offset + 4 * i]; + tdev->firmware[i] = + readb(module + offset + TC_FIRM_VER + 4 * i); + tdev->vendor[i] = + readb(module + offset + TC_VENDOR + 4 * i); + tdev->name[i] = + readb(module + offset + TC_MODULE + 4 * i); } - tc_bus[slot].firmware[8] = 0; - tc_bus[slot].vendor[8] = 0; - tc_bus[slot].name[8] = 0; - /* - * Looks unneccesary, but we may change - * TC? in the future - */ - switch (slot) { - case 0: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC0]; - break; - case 1: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC1]; - break; - case 2: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC2]; - break; - /* - * Yuck! DS5000/200 onboard devices - */ - case 5: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC5]; - break; - case 6: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC6]; - break; - default: - tc_bus[slot].interrupt = -1; - break; + tdev->firmware[8] = 0; + tdev->vendor[8] = 0; + tdev->name[8] = 0; + + pr_info("%s: %s %s %s\n", tdev->dev.bus_id, tdev->vendor, + tdev->name, tdev->firmware); + + devsize = readb(module + offset + TC_SLOT_SIZE); + devsize <<= 22; + if (devsize <= slotsize) { + tdev->resource.start = slotaddr; + tdev->resource.end = slotaddr + devsize - 1; + } else if (devsize <= extslotsize) { + tdev->resource.start = extslotaddr; + tdev->resource.end = extslotaddr + devsize - 1; + } else { + printk(KERN_ERR "%s: Cannot provide slot space " + "(%dMiB required, up to %dMiB supported)\n", + tdev->dev.bus_id, devsize >> 20, + max(slotsize, extslotsize) >> 20); + kfree(tdev); + goto out_err; } + tdev->resource.name = tdev->name; + tdev->resource.flags = IORESOURCE_MEM; + + tc_device_get_irq(tdev); + device_register(&tdev->dev); + list_add_tail(&tdev->node, &tbus->devices); + +out_err: iounmap(module); } } /* - * the main entry + * The main entry. */ static int __init tc_init(void) { - int tc_clock; - int i; - unsigned long slot0addr; - unsigned long slot_size; - - if (!TURBOCHANNEL) + /* Initialize the TURBOchannel bus */ + if (tc_bus_get_info(&tc_bus)) return 0; - for (i = 0; i < MAX_SLOT; i++) { - tc_bus[i].base_addr = 0; - tc_bus[i].name[0] = 0; - tc_bus[i].vendor[0] = 0; - tc_bus[i].firmware[0] = 0; - tc_bus[i].interrupt = -1; - tc_bus[i].flags = FREE; - } - - info = rex_gettcinfo(); - slot0addr = CPHYSADDR((long)rex_slot_address(0)); - - switch (mips_machtype) { - case MACH_DS5000_200: - num_tcslots = 7; - break; - case MACH_DS5000_1XX: - case MACH_DS5000_2X0: - case MACH_DS5900: - num_tcslots = 3; - break; - case MACH_DS5000_XX: - default: - num_tcslots = 2; - break; - } - - tc_clock = 10000 / info->clk_period; - - if (info->slot_size && slot0addr) { - pr_info("TURBOchannel rev. %d at %d.%d MHz (with%s parity)\n", - info->revision, tc_clock / 10, tc_clock % 10, - info->parity ? "" : "out"); - - slot_size = info->slot_size << 20; - - tc_probe(slot0addr, slot_size, num_tcslots); - - for (i = 0; i < num_tcslots; i++) { - if (!tc_bus[i].base_addr) - continue; - pr_info(" slot %d: %s %s %s\n", i, tc_bus[i].vendor, - tc_bus[i].name, tc_bus[i].firmware); + INIT_LIST_HEAD(&tc_bus.devices); + strcpy(tc_bus.dev.bus_id, "tc"); + device_register(&tc_bus.dev); + + if (tc_bus.info.slot_size) { + unsigned int tc_clock = tc_get_speed(&tc_bus) / 100000; + + pr_info("tc: TURBOchannel rev. %d at %d.%d MHz " + "(with%s parity)\n", tc_bus.info.revision, + tc_clock / 10, tc_clock % 10, + tc_bus.info.parity ? "" : "out"); + + tc_bus.resource[0].start = tc_bus.slot_base; + tc_bus.resource[0].end = tc_bus.slot_base + + (tc_bus.info.slot_size << 20) * + tc_bus.num_tcslots - 1; + tc_bus.resource[0].name = tc_bus.name; + tc_bus.resource[0].flags = IORESOURCE_MEM; + if (request_resource(&iomem_resource, + &tc_bus.resource[0]) < 0) { + printk(KERN_ERR "tc: Cannot reserve resource\n"); + return 0; + } + if (tc_bus.ext_slot_size) { + tc_bus.resource[1].start = tc_bus.ext_slot_base; + tc_bus.resource[1].end = tc_bus.ext_slot_base + + tc_bus.ext_slot_size * + tc_bus.num_tcslots - 1; + tc_bus.resource[1].name = tc_bus.name; + tc_bus.resource[1].flags = IORESOURCE_MEM; + if (request_resource(&iomem_resource, + &tc_bus.resource[1]) < 0) { + printk(KERN_ERR + "tc: Cannot reserve resource\n"); + release_resource(&tc_bus.resource[0]); + return 0; + } } + + tc_bus_add_devices(&tc_bus); } return 0; } subsys_initcall(tc_init); - -EXPORT_SYMBOL(search_tc_card); -EXPORT_SYMBOL(claim_tc_card); -EXPORT_SYMBOL(release_tc_card); -EXPORT_SYMBOL(get_tc_base_addr); -EXPORT_SYMBOL(get_tc_irq_nr); -EXPORT_SYMBOL(get_tc_speed); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 4e83f01e894e..45fe65d8d7a0 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1444,8 +1444,8 @@ config FB_PMAG_AA used mainly in the MIPS-based DECstation series. config FB_PMAG_BA - bool "PMAG-BA TURBOchannel framebuffer support" - depends on (FB = y) && TC + tristate "PMAG-BA TURBOchannel framebuffer support" + depends on FB && TC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -1454,8 +1454,8 @@ config FB_PMAG_BA used mainly in the MIPS-based DECstation series. config FB_PMAGB_B - bool "PMAGB-B TURBOchannel framebuffer support" - depends on (FB = y) && TC + tristate "PMAGB-B TURBOchannel framebuffer support" + depends on TC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c index f5361cd8ccce..264d37243fad 100644 --- a/drivers/video/pmag-ba-fb.c +++ b/drivers/video/pmag-ba-fb.c @@ -15,7 +15,8 @@ * Michael Engel <engel@unix-ag.org>, * Karsten Merker <merker@linuxtag.org> and * Harald Koerfgen. - * Copyright (c) 2005 Maciej W. Rozycki + * Copyright (c) 2005, 2006 Maciej W. Rozycki + * Copyright (c) 2005 James Simmons * * This file is subject to the terms and conditions of the GNU General * Public License. See the file COPYING in the main directory of this @@ -28,26 +29,21 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/tc.h> #include <linux/types.h> #include <asm/io.h> #include <asm/system.h> -#include <asm/dec/tc.h> - #include <video/pmag-ba-fb.h> struct pmagbafb_par { - struct fb_info *next; volatile void __iomem *mmio; volatile u32 __iomem *dac; - int slot; }; -static struct fb_info *root_pmagbafb_dev; - static struct fb_var_screeninfo pmagbafb_defined __initdata = { .xres = 1024, .yres = 864, @@ -145,24 +141,19 @@ static void __init pmagbafb_erase_cursor(struct fb_info *info) } -static int __init pmagbafb_init_one(int slot) +static int __init pmagbafb_probe(struct device *dev) { + struct tc_dev *tdev = to_tc_dev(dev); + resource_size_t start, len; struct fb_info *info; struct pmagbafb_par *par; - unsigned long base_addr; - info = framebuffer_alloc(sizeof(struct pmagbafb_par), NULL); + info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev); if (!info) return -ENOMEM; par = info->par; - par->slot = slot; - claim_tc_card(par->slot); - - base_addr = get_tc_base_addr(par->slot); - - par->next = root_pmagbafb_dev; - root_pmagbafb_dev = info; + dev_set_drvdata(dev, info); if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) goto err_alloc; @@ -172,15 +163,21 @@ static int __init pmagbafb_init_one(int slot) info->var = pmagbafb_defined; info->flags = FBINFO_DEFAULT; + /* Request the I/O MEM resource. */ + start = tdev->resource.start; + len = tdev->resource.end - start + 1; + if (!request_mem_region(start, len, dev->bus_id)) + goto err_cmap; + /* MMIO mapping setup. */ - info->fix.mmio_start = base_addr; + info->fix.mmio_start = start; par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len); if (!par->mmio) - goto err_cmap; + goto err_resource; par->dac = par->mmio + PMAG_BA_BT459; /* Frame buffer mapping setup. */ - info->fix.smem_start = base_addr + PMAG_BA_FBMEM; + info->fix.smem_start = start + PMAG_BA_FBMEM; info->screen_base = ioremap_nocache(info->fix.smem_start, info->fix.smem_len); if (!info->screen_base) @@ -192,8 +189,10 @@ static int __init pmagbafb_init_one(int slot) if (register_framebuffer(info) < 0) goto err_smem_map; - pr_info("fb%d: %s frame buffer device in slot %d\n", - info->node, info->fix.id, par->slot); + get_device(dev); + + pr_info("fb%d: %s frame buffer device at %s\n", + info->node, info->fix.id, dev->bus_id); return 0; @@ -204,54 +203,68 @@ err_smem_map: err_mmio_map: iounmap(par->mmio); +err_resource: + release_mem_region(start, len); + err_cmap: fb_dealloc_cmap(&info->cmap); err_alloc: - root_pmagbafb_dev = par->next; - release_tc_card(par->slot); framebuffer_release(info); return -ENXIO; } -static void __exit pmagbafb_exit_one(void) +static int __exit pmagbafb_remove(struct device *dev) { - struct fb_info *info = root_pmagbafb_dev; + struct tc_dev *tdev = to_tc_dev(dev); + struct fb_info *info = dev_get_drvdata(dev); struct pmagbafb_par *par = info->par; + resource_size_t start, len; + put_device(dev); unregister_framebuffer(info); iounmap(info->screen_base); iounmap(par->mmio); + start = tdev->resource.start; + len = tdev->resource.end - start + 1; + release_mem_region(start, len); fb_dealloc_cmap(&info->cmap); - root_pmagbafb_dev = par->next; - release_tc_card(par->slot); framebuffer_release(info); + return 0; } /* - * Initialise the framebuffer. + * Initialize the framebuffer. */ +static const struct tc_device_id pmagbafb_tc_table[] = { + { "DEC ", "PMAG-BA " }, + { } +}; +MODULE_DEVICE_TABLE(tc, pmagbafb_tc_table); + +static struct tc_driver pmagbafb_driver = { + .id_table = pmagbafb_tc_table, + .driver = { + .name = "pmagbafb", + .bus = &tc_bus_type, + .probe = pmagbafb_probe, + .remove = __exit_p(pmagbafb_remove), + }, +}; + static int __init pmagbafb_init(void) { - int count = 0; - int slot; - +#ifndef MODULE if (fb_get_options("pmagbafb", NULL)) return -ENXIO; - - while ((slot = search_tc_card("PMAG-BA")) >= 0) { - if (pmagbafb_init_one(slot) < 0) - break; - count++; - } - return (count > 0) ? 0 : -ENXIO; +#endif + return tc_register_driver(&pmagbafb_driver); } static void __exit pmagbafb_exit(void) { - while (root_pmagbafb_dev) - pmagbafb_exit_one(); + tc_unregister_driver(&pmagbafb_driver); } diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c index a06a064ad757..7a0ce7d5af6b 100644 --- a/drivers/video/pmagb-b-fb.c +++ b/drivers/video/pmagb-b-fb.c @@ -11,7 +11,7 @@ * Michael Engel <engel@unix-ag.org>, * Karsten Merker <merker@linuxtag.org> and * Harald Koerfgen. - * Copyright (c) 2005 Maciej W. Rozycki + * Copyright (c) 2005, 2006 Maciej W. Rozycki * * This file is subject to the terms and conditions of the GNU General * Public License. See the file COPYING in the main directory of this @@ -25,18 +25,16 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/tc.h> #include <linux/types.h> #include <asm/io.h> #include <asm/system.h> -#include <asm/dec/tc.h> - #include <video/pmagb-b-fb.h> struct pmagbbfb_par { - struct fb_info *next; volatile void __iomem *mmio; volatile void __iomem *smem; volatile u32 __iomem *sfb; @@ -47,8 +45,6 @@ struct pmagbbfb_par { }; -static struct fb_info *root_pmagbbfb_dev; - static struct fb_var_screeninfo pmagbbfb_defined __initdata = { .bits_per_pixel = 8, .red.length = 8, @@ -190,8 +186,9 @@ static void __init pmagbbfb_osc_setup(struct fb_info *info) 69197, 66000, 65000, 50350, 36000, 32000, 25175 }; struct pmagbbfb_par *par = info->par; + struct tc_bus *tbus = to_tc_dev(info->device)->bus; u32 count0 = 8, count1 = 8, counttc = 16 * 256 + 8; - u32 freq0, freq1, freqtc = get_tc_speed() / 250; + u32 freq0, freq1, freqtc = tc_get_speed(tbus) / 250; int i, j; gp0_write(par, 0); /* select Osc0 */ @@ -249,26 +246,21 @@ static void __init pmagbbfb_osc_setup(struct fb_info *info) }; -static int __init pmagbbfb_init_one(int slot) +static int __init pmagbbfb_probe(struct device *dev) { - char freq0[12], freq1[12]; + struct tc_dev *tdev = to_tc_dev(dev); + resource_size_t start, len; struct fb_info *info; struct pmagbbfb_par *par; - unsigned long base_addr; + char freq0[12], freq1[12]; u32 vid_base; - info = framebuffer_alloc(sizeof(struct pmagbbfb_par), NULL); + info = framebuffer_alloc(sizeof(struct pmagbbfb_par), dev); if (!info) return -ENOMEM; par = info->par; - par->slot = slot; - claim_tc_card(par->slot); - - base_addr = get_tc_base_addr(par->slot); - - par->next = root_pmagbbfb_dev; - root_pmagbbfb_dev = info; + dev_set_drvdata(dev, info); if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) goto err_alloc; @@ -278,16 +270,22 @@ static int __init pmagbbfb_init_one(int slot) info->var = pmagbbfb_defined; info->flags = FBINFO_DEFAULT; + /* Request the I/O MEM resource. */ + start = tdev->resource.start; + len = tdev->resource.end - start + 1; + if (!request_mem_region(start, len, dev->bus_id)) + goto err_cmap; + /* MMIO mapping setup. */ - info->fix.mmio_start = base_addr; + info->fix.mmio_start = start; par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len); if (!par->mmio) - goto err_cmap; + goto err_resource; par->sfb = par->mmio + PMAGB_B_SFB; par->dac = par->mmio + PMAGB_B_BT459; /* Frame buffer mapping setup. */ - info->fix.smem_start = base_addr + PMAGB_B_FBMEM; + info->fix.smem_start = start + PMAGB_B_FBMEM; par->smem = ioremap_nocache(info->fix.smem_start, info->fix.smem_len); if (!par->smem) goto err_mmio_map; @@ -302,13 +300,15 @@ static int __init pmagbbfb_init_one(int slot) if (register_framebuffer(info) < 0) goto err_smem_map; + get_device(dev); + snprintf(freq0, sizeof(freq0), "%u.%03uMHz", par->osc0 / 1000, par->osc0 % 1000); snprintf(freq1, sizeof(freq1), "%u.%03uMHz", par->osc1 / 1000, par->osc1 % 1000); - pr_info("fb%d: %s frame buffer device in slot %d\n", - info->node, info->fix.id, par->slot); + pr_info("fb%d: %s frame buffer device at %s\n", + info->node, info->fix.id, dev->bus_id); pr_info("fb%d: Osc0: %s, Osc1: %s, Osc%u selected\n", info->node, freq0, par->osc1 ? freq1 : "disabled", par->osc1 != 0); @@ -322,54 +322,68 @@ err_smem_map: err_mmio_map: iounmap(par->mmio); +err_resource: + release_mem_region(start, len); + err_cmap: fb_dealloc_cmap(&info->cmap); err_alloc: - root_pmagbbfb_dev = par->next; - release_tc_card(par->slot); framebuffer_release(info); return -ENXIO; } -static void __exit pmagbbfb_exit_one(void) +static int __exit pmagbbfb_remove(struct device *dev) { - struct fb_info *info = root_pmagbbfb_dev; + struct tc_dev *tdev = to_tc_dev(dev); + struct fb_info *info = dev_get_drvdata(dev); struct pmagbbfb_par *par = info->par; + resource_size_t start, len; + put_device(dev); unregister_framebuffer(info); iounmap(par->smem); iounmap(par->mmio); + start = tdev->resource.start; + len = tdev->resource.end - start + 1; + release_mem_region(start, len); fb_dealloc_cmap(&info->cmap); - root_pmagbbfb_dev = par->next; - release_tc_card(par->slot); framebuffer_release(info); + return 0; } /* - * Initialise the framebuffer. + * Initialize the framebuffer. */ +static const struct tc_device_id pmagbbfb_tc_table[] = { + { "DEC ", "PMAGB-BA" }, + { } +}; +MODULE_DEVICE_TABLE(tc, pmagbbfb_tc_table); + +static struct tc_driver pmagbbfb_driver = { + .id_table = pmagbbfb_tc_table, + .driver = { + .name = "pmagbbfb", + .bus = &tc_bus_type, + .probe = pmagbbfb_probe, + .remove = __exit_p(pmagbbfb_remove), + }, +}; + static int __init pmagbbfb_init(void) { - int count = 0; - int slot; - +#ifndef MODULE if (fb_get_options("pmagbbfb", NULL)) return -ENXIO; - - while ((slot = search_tc_card("PMAGB-BA")) >= 0) { - if (pmagbbfb_init_one(slot) < 0) - break; - count++; - } - return (count > 0) ? 0 : -ENXIO; +#endif + return tc_register_driver(&pmagbbfb_driver); } static void __exit pmagbbfb_exit(void) { - while (root_pmagbbfb_dev) - pmagbbfb_exit_one(); + tc_unregister_driver(&pmagbbfb_driver); } diff --git a/include/asm-mips/dec/system.h b/include/asm-mips/dec/system.h index 78af51fbc797..b2afaccd6831 100644 --- a/include/asm-mips/dec/system.h +++ b/include/asm-mips/dec/system.h @@ -3,7 +3,7 @@ * * Generic DECstation/DECsystem bits. * - * Copyright (C) 2005 Maciej W. Rozycki + * Copyright (C) 2005, 2006 Maciej W. Rozycki * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -14,5 +14,6 @@ #define __ASM_DEC_SYSTEM_H extern unsigned long dec_kn_slot_base, dec_kn_slot_size; +extern int dec_tc_bus; #endif /* __ASM_DEC_SYSTEM_H */ diff --git a/include/asm-mips/dec/tc.h b/include/asm-mips/dec/tc.h deleted file mode 100644 index 9cb51f24d42c..000000000000 --- a/include/asm-mips/dec/tc.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Interface to the TURBOchannel related routines - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 1998 Harald Koerfgen - */ -#ifndef __ASM_DEC_TC_H -#define __ASM_DEC_TC_H - -/* - * Search for a TURBOchannel Option Module - * with a certain name. Returns slot number - * of the first card not in use or -ENODEV - * if none found. - */ -extern int search_tc_card(const char *); -/* - * Marks the card in slot as used - */ -extern void claim_tc_card(int); -/* - * Marks the card in slot as free - */ -extern void release_tc_card(int); -/* - * Return base address of card in slot - */ -extern unsigned long get_tc_base_addr(int); -/* - * Return interrupt number of slot - */ -extern unsigned long get_tc_irq_nr(int); -/* - * Return TURBOchannel clock frequency in Hz - */ -extern unsigned long get_tc_speed(void); - -#endif /* __ASM_DEC_TC_H */ diff --git a/include/asm-mips/dec/tcinfo.h b/include/asm-mips/dec/tcinfo.h deleted file mode 100644 index cc23509ee77a..000000000000 --- a/include/asm-mips/dec/tcinfo.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Various TURBOchannel related stuff - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Information obtained through the get_tcinfo prom call - * created from: - * - * TURBOchannel Firmware Specification - * - * EK-TCAAD-FS-004 - * from Digital Equipment Corporation - * - * Copyright (c) 1998 Harald Koerfgen - */ - -typedef struct { - int revision; - int clk_period; - int slot_size; - int io_timeout; - int dma_range; - int max_dma_burst; - int parity; - int reserved[4]; -} tcinfo; - -#define MAX_SLOT 7 - -typedef struct { - unsigned long base_addr; - unsigned char name[9]; - unsigned char vendor[9]; - unsigned char firmware[9]; - int interrupt; - int flags; -} slot_info; - -/* - * Values for flags - */ -#define FREE 1<<0 -#define IN_USE 1<<1 - - diff --git a/include/asm-mips/dec/tcmodule.h b/include/asm-mips/dec/tcmodule.h deleted file mode 100644 index 6268e8915d87..000000000000 --- a/include/asm-mips/dec/tcmodule.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Offsets for the ROM header locations for - * TURBOchannel cards - * - * created from: - * - * TURBOchannel Firmware Specification - * - * EK-TCAAD-FS-004 - * from Digital Equipment Corporation - * - * Jan.1998 Harald Koerfgen - */ -#ifndef __ASM_DEC_TCMODULE_H -#define __ASM_DEC_TCMODULE_H - -#define OLDCARD 0x3c0000 -#define NEWCARD 0x000000 - -#define TC_ROM_WIDTH 0x3e0 -#define TC_ROM_STRIDE 0x3e4 -#define TC_ROM_SIZE 0x3e8 -#define TC_SLOT_SIZE 0x3ec -#define TC_PATTERN0 0x3f0 -#define TC_PATTERN1 0x3f4 -#define TC_PATTERN2 0x3f8 -#define TC_PATTERN3 0x3fc -#define TC_FIRM_VER 0x400 -#define TC_VENDOR 0x420 -#define TC_MODULE 0x440 -#define TC_FIRM_TYPE 0x460 -#define TC_FLAGS 0x470 -#define TC_ROM_OBJECTS 0x480 - -#endif /* __ASM_DEC_TCMODULE_H */ diff --git a/include/linux/eisa.h b/include/linux/eisa.h index 1ff7c1392525..fe806b6f030d 100644 --- a/include/linux/eisa.h +++ b/include/linux/eisa.h @@ -61,10 +61,20 @@ struct eisa_driver { #define to_eisa_driver(drv) container_of(drv,struct eisa_driver, driver) +/* These external functions are only available when EISA support is enabled. */ +#ifdef CONFIG_EISA + extern struct bus_type eisa_bus_type; int eisa_driver_register (struct eisa_driver *edrv); void eisa_driver_unregister (struct eisa_driver *edrv); +#else /* !CONFIG_EISA */ + +static inline int eisa_driver_register (struct eisa_driver *edrv) { return 0; } +static inline void eisa_driver_unregister (struct eisa_driver *edrv) { } + +#endif /* !CONFIG_EISA */ + /* Mimics pci.h... */ static inline void *eisa_get_drvdata (struct eisa_device *edev) { diff --git a/include/linux/tc.h b/include/linux/tc.h new file mode 100644 index 000000000000..f92511e57cdb --- /dev/null +++ b/include/linux/tc.h @@ -0,0 +1,141 @@ +/* + * Interface to the TURBOchannel related routines. + * + * Copyright (c) 1998 Harald Koerfgen + * Copyright (c) 2005 James Simmons + * Copyright (c) 2006 Maciej W. Rozycki + * + * Based on: + * + * "TURBOchannel Firmware Specification", EK-TCAAD-FS-004 + * + * from Digital Equipment Corporation. + * + * This file is subject to the terms and conditions of the GNU + * General Public License. See the file "COPYING" in the main + * directory of this archive for more details. + */ +#ifndef _LINUX_TC_H +#define _LINUX_TC_H + +#include <linux/compiler.h> +#include <linux/device.h> +#include <linux/ioport.h> +#include <linux/types.h> + +/* + * Offsets for the ROM header locations for TURBOchannel cards. + */ +#define TC_OLDCARD 0x3c0000 +#define TC_NEWCARD 0x000000 + +#define TC_ROM_WIDTH 0x3e0 +#define TC_ROM_STRIDE 0x3e4 +#define TC_ROM_SIZE 0x3e8 +#define TC_SLOT_SIZE 0x3ec +#define TC_PATTERN0 0x3f0 +#define TC_PATTERN1 0x3f4 +#define TC_PATTERN2 0x3f8 +#define TC_PATTERN3 0x3fc +#define TC_FIRM_VER 0x400 +#define TC_VENDOR 0x420 +#define TC_MODULE 0x440 +#define TC_FIRM_TYPE 0x460 +#define TC_FLAGS 0x470 +#define TC_ROM_OBJECTS 0x480 + +/* + * Information obtained through the get_tcinfo() PROM call. + */ +struct tcinfo { + s32 revision; /* Hardware revision level. */ + s32 clk_period; /* Clock period in nanoseconds. */ + s32 slot_size; /* Slot size in megabytes. */ + s32 io_timeout; /* I/O timeout in cycles. */ + s32 dma_range; /* DMA address range in megabytes. */ + s32 max_dma_burst; /* Maximum DMA burst length. */ + s32 parity; /* System module supports TC parity. */ + s32 reserved[4]; +}; + +/* + * TURBOchannel bus. + */ +struct tc_bus { + struct list_head devices; /* List of devices on this bus. */ + struct resource resource[2]; /* Address space routed to this bus. */ + + struct device dev; + char name[13]; + resource_size_t slot_base; + resource_size_t ext_slot_base; + resource_size_t ext_slot_size; + int num_tcslots; + struct tcinfo info; +}; + +/* + * TURBOchannel device. + */ +struct tc_dev { + struct list_head node; /* Node in list of all TC devices. */ + struct tc_bus *bus; /* Bus this device is on. */ + struct tc_driver *driver; /* Which driver has allocated this + device. */ + struct device dev; /* Generic device interface. */ + struct resource resource; /* Address space of this device. */ + char vendor[9]; + char name[9]; + char firmware[9]; + int interrupt; + int slot; +}; + +#define to_tc_dev(n) container_of(n, struct tc_dev, dev) + +struct tc_device_id { + char vendor[9]; + char name[9]; +}; + +/* + * TURBOchannel driver. + */ +struct tc_driver { + struct list_head node; + const struct tc_device_id *id_table; + struct device_driver driver; +}; + +#define to_tc_driver(drv) container_of(drv, struct tc_driver, driver) + +/* + * Return TURBOchannel clock frequency in Hz. + */ +static inline unsigned long tc_get_speed(struct tc_bus *tbus) +{ + return 100000 * (10000 / (unsigned long)tbus->info.clk_period); +} + +#ifdef CONFIG_TC + +extern struct bus_type tc_bus_type; + +extern int tc_register_driver(struct tc_driver *tdrv); +extern void tc_unregister_driver(struct tc_driver *tdrv); + +#else /* !CONFIG_TC */ + +static inline int tc_register_driver(struct tc_driver *tdrv) { return 0; } +static inline void tc_unregister_driver(struct tc_driver *tdrv) { } + +#endif /* CONFIG_TC */ + +/* + * These have to be provided by the architecture. + */ +extern int tc_preadb(u8 *valp, void __iomem *addr); +extern int tc_bus_get_info(struct tc_bus *tbus); +extern void tc_device_get_irq(struct tc_dev *tdev); + +#endif /* _LINUX_TC_H */ |