Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-tc
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Fri, 9 Feb 2007 17:22:36 +0000 (09:22 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Fri, 9 Feb 2007 17:22:36 +0000 (09:22 -0800)
* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-tc:
  [EISA] EISA registration with !CONFIG_EISA
  [TC] pmagb-b-fb: Convert to the driver model
  [TC] dec_esp: Driver model for the PMAZ-A
  [TC] mips: pmag-ba-fb: Convert to the driver model
  [TC] defxx: TURBOchannel support
  [TC] TURBOchannel support for the DECstation
  [TC] MIPS: TURBOchannel resources off-by-one fix
  [TC] MIPS: TURBOchannel update to the driver model

33 files changed:
MAINTAINERS
arch/mips/dec/Makefile
arch/mips/dec/prom/identify.c
arch/mips/dec/setup.c
arch/mips/dec/tc.c [new file with mode: 0644]
drivers/net/Kconfig
drivers/net/defxx.c
drivers/net/defxx.h
drivers/scsi/NCR53C9x.c
drivers/scsi/NCR53C9x.h
drivers/scsi/blz1230.c
drivers/scsi/blz2060.c
drivers/scsi/cyberstorm.c
drivers/scsi/cyberstormII.c
drivers/scsi/dec_esp.c
drivers/scsi/fastlane.c
drivers/scsi/jazz_esp.c
drivers/scsi/mac_esp.c
drivers/scsi/mca_53c9x.c
drivers/scsi/oktagon_esp.c
drivers/scsi/sun3x_esp.c
drivers/tc/Makefile
drivers/tc/tc-driver.c [new file with mode: 0644]
drivers/tc/tc.c
drivers/video/Kconfig
drivers/video/pmag-ba-fb.c
drivers/video/pmagb-b-fb.c
include/asm-mips/dec/system.h
include/asm-mips/dec/tc.h [deleted file]
include/asm-mips/dec/tcinfo.h [deleted file]
include/asm-mips/dec/tcmodule.h [deleted file]
include/linux/eisa.h
include/linux/tc.h [new file with mode: 0644]

index f2a79481f1c1904479a8f105924e496003cba4d0..a6c1ebd18d0f801e685e5625ca052aa98eea7d88 100644 (file)
@@ -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
index ed181fdc3ac9f1f9214ddc2a925a965410135569..8b790c2900d5b5c84af4d30479eddfc61507bc8c 100644 (file)
@@ -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)
index 81d5e878ddce8d409cfafd326454dc6eab0fcae3..c4e3c1ea0d48946f0c84b315817c43dab0f1aef6 100644 (file)
@@ -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);
index 1058e2f409bb9ec6a3fed658103affd4d5b338d1..b8a5e75ba0ab4b6bce2bc979a8c7527f050c571d 100644 (file)
@@ -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 (file)
index 0000000..732027c
--- /dev/null
@@ -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;
+       }
+}
index 4f2ffbd81dc156366b4d2a5790997b566df6aea3..38f41a593b1269961e8ce8040751c644a46fa9f6 100644 (file)
@@ -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"
index dc3ab3b5c8cb8ef48aca9a586e86b566bde0c9b9..07d2731c1aa8f45e04b0c86a9c20744603b5fc50 100644 (file)
  *
  * 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>
  *             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>
 
 /* 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");
 
index 2ce8f97253ebb2106745b7a0ad6dc637a775e0d9..19a6f64df1984b77d85046895fb39d92e584b1b5 100644 (file)
@@ -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) */
index 3c912ee29da0e1fa24091849d682bab5c164bfc3..8b5334c56f0a9668fb1f132b7a657cae329104e4 100644 (file)
@@ -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;
index 521e3f842cfd526e98fc451993f4080df00a4e06..d85cb73a9f69f217cdcf9e9c779bde8dc3da3947 100644 (file)
@@ -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 *);
index 329a8f297b318fa1c76594e90e2dcf6e6d746f54..23f7c24ab8093124ab795d32f16e7210515fe700 100644 (file)
@@ -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);
index b6c137b9735056985820216ce397a9e914f8d08b..b6203ec00961e3c1306631a29ecf1346afaffad5 100644 (file)
@@ -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;
index 7c7cfb54e8976a9f1070ca412309798d3c2b8214..c6b98a42e89d837d4288979fcdb8258a71ee3a69 100644 (file)
@@ -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;
index d88cb9cf091e4a880b8e5e22daa419a4613326f4..e336e853e66fb03affd5524e6f37a74519ad401c 100644 (file)
@@ -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);
index c29ccbc44693ab46079b652c617c2f72c147291b..d42ad663ffee83a60d7956854e6b493b00f42a61 100644 (file)
@@ -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);
index 2a1c5c22b9e0a9baa2f6ccf8e49e127576a38ecf..4266a2139b5fb25f02bf46966ffe94966fd98ec4 100644 (file)
@@ -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;
index bfac4441d89fdcad18132a6e9e8720774697d364..19dd4b962e18c140d78511b0b516a07db696b1b7 100644 (file)
@@ -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;
index 3586fac9be9a03d2ff2cac73210348d8b75631ac..bcb49021b7e204acbbc432e4cb9cace197ca37af 100644 (file)
@@ -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;
index 998a8bbc1a4b748962f9787967bfebb647212883..d693d0f213956bb2a5d9f9bfd4c0e4791a63d95a 100644 (file)
@@ -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);
index c116a6ae3c54f21caa66f3ca26b69cbdae92b3e1..26a6d55faf3ec03a86b480687cceb00872f5365e 100644 (file)
@@ -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;
index 6b60536ac92b4bb11278eb2f8b9ae37519f649e4..80fb3f88af2edd937ebdf2df51e8f4efcca67ee3 100644 (file)
@@ -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;
index 83b5bd75ce2639a8747dfaabacb57402cda6bc94..9673426922114cacb1c70dcdda0f565955711d84 100644 (file)
@@ -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 (file)
index 0000000..16b5bae
--- /dev/null
@@ -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);
index 4a51e56f85b6b0a3d362bdd44317c2c484c84319..f77f62a4b325d3bb3c898efe42d397a17238114a 100644 (file)
 /*
- * 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);
index 4e83f01e894efe30b9cca2da83b6ff35b007e61b..45fe65d8d7a03d91de405314f052ac377fae2cb5 100644 (file)
@@ -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
index f5361cd8ccce1359cd706d0e081a873b77235955..264d37243fadfde02a2952839d77cdd53697cb1f 100644 (file)
@@ -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
 #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);
 }
 
 
index a06a064ad7575bf6cd9e0126d9f8312f95689d79..7a0ce7d5af6bf2c150d1d12cbe8760d5ba19e9be 100644 (file)
@@ -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
 #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);
 }
 
 
index 78af51fbc797b247b67d0a8e3c3ee5f8af009382..b2afaccd68314c650cc8edfec35f55b1f5645480 100644 (file)
@@ -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 (file)
index 9cb51f2..0000000
+++ /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 (file)
index cc23509..0000000
+++ /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 (file)
index 6268e89..0000000
+++ /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 */
index 1ff7c1392525884b0f7ee005ae21ff822b01ae56..fe806b6f030dfb2d7583751cc33d96f36a8b7d90 100644 (file)
@@ -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 (file)
index 0000000..f92511e
--- /dev/null
@@ -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 */