Commit 68a696a0 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-tc

* '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
parents dcb92f88 f85da084
......@@ -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
......
......@@ -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)
......@@ -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);
......
......@@ -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;
......
/*
* 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;
}
}
......@@ -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"
......
......@@ -10,8 +10,10 @@
*
* 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/TURBOchannel (DEFTA)
* DEC FDDIcontroller/EISA (DEFEA)
* DEC FDDIcontroller/PCI (DEFPA)
*
......@@ -193,24 +195,27 @@
* 14 Aug 2004 macro Fix device names reported.
* 14 Jun 2005 macro Use irqreturn_t.
* 23 Oct 2006 macro Big-endian host support.
* 14 Dec 2006 macro TURBOchannel support.
*/
/* Include files */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/eisa.h>
#include <linux/errno.h>
#include <linux/fddidevice.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/fddidevice.h>
#include <linux/pci.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/tc.h>
#include <asm/byteorder.h>
#include <asm/io.h>
......@@ -219,8 +224,8 @@
/* Version information string should be updated prior to each new release! */
#define DRV_NAME "defxx"
#define DRV_VERSION "v1.09"
#define DRV_RELDATE "2006/10/23"
#define DRV_VERSION "v1.10"
#define DRV_RELDATE "2006/12/14"
static char version[] __devinitdata =
DRV_NAME ": " DRV_VERSION " " DRV_RELDATE
......@@ -235,12 +240,41 @@ static char version[] __devinitdata =
*/
#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128)
#define __unused __attribute__ ((unused))
#ifdef CONFIG_PCI
#define DFX_BUS_PCI(dev) (dev->bus == &pci_bus_type)
#else
#define DFX_BUS_PCI(dev) 0
#endif
#ifdef CONFIG_EISA
#define DFX_BUS_EISA(dev) (dev->bus == &eisa_bus_type)
#else
#define DFX_BUS_EISA(dev) 0
#endif
#ifdef CONFIG_TC
#define DFX_BUS_TC(dev) (dev->bus == &tc_bus_type)
#else
#define DFX_BUS_TC(dev) 0
#endif
#ifdef CONFIG_DEFXX_MMIO
#define DFX_MMIO 1
#else
#define DFX_MMIO 0
#endif
/* Define module-wide (static) routines */
static void dfx_bus_init(struct net_device *dev);
static void dfx_bus_uninit(struct net_device *dev);
static void dfx_bus_config_check(DFX_board_t *bp);
static int dfx_driver_init(struct net_device *dev, const char *print_name);
static int dfx_driver_init(struct net_device *dev,
const char *print_name,
resource_size_t bar_start);
static int dfx_adap_init(DFX_board_t *bp, int get_buffers);
static int dfx_open(struct net_device *dev);
......@@ -273,13 +307,13 @@ static void dfx_xmt_flush(DFX_board_t *bp);
/* Define module-wide (static) variables */
static struct net_device *root_dfx_eisa_dev;
static struct pci_driver dfx_pci_driver;
static struct eisa_driver dfx_eisa_driver;
static struct tc_driver dfx_tc_driver;
/*
* =======================
* = dfx_port_write_byte =
* = dfx_port_read_byte =
* = dfx_port_write_long =
* = dfx_port_read_long =
* =======================
......@@ -293,10 +327,9 @@ static struct net_device *root_dfx_eisa_dev;
* 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.
* 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
......@@ -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
)
{
u16 port = bp->base_addr + offset;
static inline void dfx_writel(DFX_board_t *bp, int offset, u32 data)
{
writel(data, bp->base.mem + offset);
mb();
}
outb(data, port);
}
static inline void dfx_outl(DFX_board_t *bp, int offset, u32 data)
{
outl(data, bp->base.port + offset);
}
static inline void dfx_port_read_byte(
DFX_board_t *bp,
int offset,
u8 *data
)
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;
{
u16 port = bp->base_addr + offset;
if (dfx_use_mmio)
dfx_writel(bp, offset, data);
else
dfx_outl(bp, offset, data);
}
*data = inb(port);
}
static inline void dfx_port_write_long(
DFX_board_t *bp,
int offset,
u32 data
)
static inline void dfx_readl(DFX_board_t *bp, int offset, u32 *data)
{
mb();
*data = readl(bp->base.mem + offset);
}
{
u16 port = bp->base_addr + offset;
static inline void dfx_inl(DFX_board_t *bp, int offset, u32 *data)
{
*data = inl(bp->base.port + offset);
}
outl(data, port);
}
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;
static inline void dfx_port_read_long(
DFX_board_t *bp,
int offset,
u32 *data
)
if (dfx_use_mmio)
dfx_readl(bp, offset, data);
else
dfx_inl(bp, offset, data);
}
{
u16 port = bp->base_addr + offset;
*data = inl(port);
/*
* ================
* = 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;
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 = dev->priv;
bp = netdev_priv(dev);
bp->bus_dev = bdev;
dev_set_drvdata(bdev, dev);
if (!request_region(ioaddr,
pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN,
print_name)) {
dfx_get_bars(bdev, &bar_start, &bar_len);
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,
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,40 +662,32 @@ 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 */
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;
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)
{
/* 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;
switch (val) {
case PI_CONFIG_STAT_0_IRQ_K_9:
dev->irq = 9;
break;
......@@ -622,36 +705,60 @@ static void __devinit dfx_bus_init(struct net_device *dev)
break;
}
/* Enable access to I/O on the board by writing 0x03 to Function Control Register */
dfx_port_write_byte(bp, PI_ESIC_K_FUNCTION_CNTRL, PI_ESIC_K_FUNCTION_CNTRL_IO_ENB);
/* Set the I/O decode range of the board */
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);
/* Enable access to rest of module (including PDQ and packet memory) */
dfx_port_write_byte(bp, PI_ESIC_K_SLOT_CNTRL, PI_SLOT_CNTRL_M_ENB);
/*
* 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.
*/
/* 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));
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);
}
else
{
struct pci_dev *pdev = bp->pci_dev;
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;
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; /* host data register value */
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, "
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, 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]);
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 */
......@@ -1716,17 +1878,15 @@ 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 */
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);
while (dev)
{
struct net_device *tmp;
DFX_board_t *bp;
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);
bp = (DFX_board_t*)dev->priv;
tmp = bp->next;
dfx_remove_one_pci_or_eisa(NULL, dev);
dev = tmp;
}
}
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 */
static int __init dfx_init(void)
static int __devinit __unused dfx_dev_register(struct device *dev)
{
int rc_pci, rc_eisa;
int status;
rc_pci = pci_register_driver(&dfx_driver);
if (rc_pci >= 0) dfx_have_pci = 1;
rc_eisa = dfx_eisa_init();
if (rc_eisa >= 0) dfx_have_eisa = 1;
status = dfx_register(dev);
if (!status)
get_device(dev);
return status;
}
return ((rc_eisa < 0) ? 0 : rc_eisa) + ((rc_pci < 0) ? 0 : rc_pci);
static int __devexit __unused dfx_dev_unregister(struct device *dev)
{
put_device(dev);
dfx_unregister(dev);
return 0;
}
static void __exit dfx_cleanup(void)
static int __devinit dfx_init(void)
{
if (dfx_have_pci)
pci_unregister_driver(&dfx_driver);
if (dfx_have_eisa)
dfx_eisa_cleanup();
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 __devexit dfx_cleanup(void)
{
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");
......
......@@ -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) */
......
......@@ -528,11 +528,15 @@ 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;
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");
......
......@@ -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 *);
......
......@@ -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);
......
......@@ -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;
......
......@@ -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;
......
......@@ -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);
......
......@@ -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,54 +182,92 @@ static int dec_esp_detect(struct scsi_host_template * tpnt)
/* Check for differential SCSI-bus */
esp->diff = 0;
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],
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))
goto err_free_irq;
if (request_irq(dec_interrupt[DEC_IRQ_ASC_ERR],
"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))
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;
"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);
err = scsi_add_host(esp->ehost, NULL);
if (err) {
printk(KERN_ERR "ESP: Unable to register adapter\n");
goto err_irq_dma;
}
if (TURBOCHANNEL) {
while ((slot = search_tc_card("PMAZ-AA")) >= 0) {
claim_tc_card(slot);
scsi_scan_host(esp->ehost);
esp_dev = 0;
esp = esp_allocate(tpnt, (void *) esp_dev);
dec_esp_platform = esp;
}
mem_start = get_tc_base_addr(slot);
return 0;
/* Store base addr into esp struct */
esp->slot = CPHYSADDR(mem_start);
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;
}
/* Store base addr into esp struct. */
esp->slot = start;
esp->dregs = 0;
esp->eregs = (void *)CKSEG1ADDR(mem_start +
DEC_SCSI_SREG);
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;
/* Set the command buffer. */
esp->esp_command = (volatile unsigned char *)pmaz_cmd_buffer;
/* get virtual dma address for command buffer */
/* Get virtual dma address for command buffer. */
esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer);
esp->cfreq = get_tc_speed();
esp->cfreq = tc_get_speed(to_tc_dev(dev)->bus);
esp->irq = get_tc_irq_nr(slot);
esp->irq = to_tc_dev(dev)->interrupt;
/* Required functions */
/* Required functions. */
esp->dma_bytes_sent = &dma_bytes_sent;
esp->dma_can_transfer = &dma_can_transfer;
esp->dma_dump_state = &dma_dump_state;
......@@ -259,7 +279,7 @@ static int dec_esp_detect(struct scsi_host_template * tpnt)
esp->dma_ports_p = &dma_ports_p;
esp->dma_setup = &pmaz_dma_setup;
/* Optional functions */
/* Optional functions. */
esp->dma_barrier = 0;
esp->dma_drain = &pmaz_dma_drain;
esp->dma_invalidate = 0;
......@@ -276,36 +296,61 @@ static int dec_esp_detect(struct scsi_host_template * tpnt)
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;
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);
}
}
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;
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);
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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);
......
......@@ -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;
......
......@@ -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;
......
......@@ -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
......
/*
* 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);
/*
* 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.
*
* 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.
* TURBOchannel bus services.
*
* Copyright (c) Harald Koerfgen, 1998
* Copyright (c) 2001, 2003, 2005 Maciej W. Rozycki
* 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/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;
/*
* Interface to the world. Read comment in include/asm-mips/tc.h.
*/
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)
{
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);
}
static struct tc_bus tc_bus = {
.name = "TURBOchannel",
};
/*
* Probing for TURBOchannel modules
* Probing for TURBOchannel modules.
*/
static void __init tc_probe(unsigned long startaddr, unsigned long size,
int slots)
static void __init tc_bus_add_devices(struct tc_bus *tbus)
{
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;
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;
}
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;
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_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);
}
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);
......@@ -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
......
......@@ -15,7 +15,8 @@
* Michael Engel <engel@unix-ag.org>,
* Karsten Merker <merker@linuxtag.org> and
* Harald Koerfgen.
* Copyright (c) 2005 Maciej W. Rozycki
* Copyright (c) 2005, 2006 Maciej W. Rozycki
* Copyright (c) 2005 James Simmons
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
......@@ -28,26 +29,21 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/tc.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/dec/tc.h>
#include <video/pmag-ba-fb.h>
struct pmagbafb_par {
struct fb_info *next;
volatile void __iomem *mmio;
volatile u32 __iomem *dac;
int slot;
};
static struct fb_info *root_pmagbafb_dev;
static struct fb_var_screeninfo pmagbafb_defined __initdata = {
.xres = 1024,
.yres = 864,
......@@ -145,24 +141,19 @@ static void __init pmagbafb_erase_cursor(struct fb_info *info)
}
static int __init pmagbafb_init_one(int slot)
static int __init pmagbafb_probe(struct device *dev)
{
struct tc_dev *tdev = to_tc_dev(dev);
resource_size_t start, len;
struct fb_info *info;
struct pmagbafb_par *par;
unsigned long base_addr;
info = framebuffer_alloc(sizeof(struct pmagbafb_par), NULL);
info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev);
if (!info)
return -ENOMEM;
par = info->par;
par->slot = slot;
claim_tc_card(par->slot);
base_addr = get_tc_base_addr(par->slot);
par->next = root_pmagbafb_dev;
root_pmagbafb_dev = info;
dev_set_drvdata(dev, info);
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
goto err_alloc;
......@@ -172,15 +163,21 @@ static int __init pmagbafb_init_one(int slot)
info->var = pmagbafb_defined;
info->flags = FBINFO_DEFAULT;
/* Request the I/O MEM resource. */
start = tdev->resource.start;
len = tdev->resource.end - start + 1;
if (!request_mem_region(start, len, dev->bus_id))
goto err_cmap;
/* MMIO mapping setup. */
info->fix.mmio_start = base_addr;
info->fix.mmio_start = start;
par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
if (!par->mmio)
goto err_cmap;
goto err_resource;
par->dac = par->mmio + PMAG_BA_BT459;
/* Frame buffer mapping setup. */
info->fix.smem_start = base_addr + PMAG_BA_FBMEM;
info->fix.smem_start = start + PMAG_BA_FBMEM;
info->screen_base = ioremap_nocache(info->fix.smem_start,
info->fix.smem_len);
if (!info->screen_base)
......@@ -192,8 +189,10 @@ static int __init pmagbafb_init_one(int slot)
if (register_framebuffer(info) < 0)
goto err_smem_map;
pr_info("fb%d: %s frame buffer device in slot %d\n",
info->node, info->fix.id, par->slot);
get_device(dev);
pr_info("fb%d: %s frame buffer device at %s\n",
info->node, info->fix.id, dev->bus_id);
return 0;
......@@ -204,54 +203,68 @@ err_smem_map:
err_mmio_map:
iounmap(par->mmio);
err_resource:
release_mem_region(start, len);
err_cmap:
fb_dealloc_cmap(&info->cmap);
err_alloc:
root_pmagbafb_dev = par->next;
release_tc_card(par->slot);
framebuffer_release(info);
return -ENXIO;
}
static void __exit pmagbafb_exit_one(void)
static int __exit pmagbafb_remove(struct device *dev)
{
struct fb_info *info = root_pmagbafb_dev;
struct tc_dev *tdev = to_tc_dev(dev);
struct fb_info *info = dev_get_drvdata(dev);
struct pmagbafb_par *par = info->par;
resource_size_t start, len;
put_device(dev);
unregister_framebuffer(info);
iounmap(info->screen_base);
iounmap(par->mmio);
start = tdev->resource.start;
len = tdev->resource.end - start + 1;
release_mem_region(start, len);
fb_dealloc_cmap(&info->cmap);
root_pmagbafb_dev = par->next;
release_tc_card(par->slot);
framebuffer_release(info);
return 0;
}
/*
* Initialise the framebuffer.
* Initialize the framebuffer.
*/
static const struct tc_device_id pmagbafb_tc_table[] = {
{ "DEC ", "PMAG-BA " },
{ }
};
MODULE_DEVICE_TABLE(tc, pmagbafb_tc_table);
static struct tc_driver pmagbafb_driver = {
.id_table = pmagbafb_tc_table,
.driver = {
.name = "pmagbafb",
.bus = &tc_bus_type,
.probe = pmagbafb_probe,
.remove = __exit_p(pmagbafb_remove),
},
};
static int __init pmagbafb_init(void)
{
int count = 0;
int slot;
#ifndef MODULE
if (fb_get_options("pmagbafb", NULL))
return -ENXIO;
while ((slot = search_tc_card("PMAG-BA")) >= 0) {
if (pmagbafb_init_one(slot) < 0)
break;
count++;
}
return (count > 0) ? 0 : -ENXIO;
#endif
return tc_register_driver(&pmagbafb_driver);
}
static void __exit pmagbafb_exit(void)
{
while (root_pmagbafb_dev)
pmagbafb_exit_one();
tc_unregister_driver(&pmagbafb_driver);
}
......
......@@ -11,7 +11,7 @@
* Michael Engel <engel@unix-ag.org>,
* Karsten Merker <merker@linuxtag.org> and
* Harald Koerfgen.
* Copyright (c) 2005 Maciej W. Rozycki
* Copyright (c) 2005, 2006 Maciej W. Rozycki
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
......@@ -25,18 +25,16 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/tc.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/dec/tc.h>
#include <video/pmagb-b-fb.h>
struct pmagbbfb_par {
struct fb_info *next;
volatile void __iomem *mmio;
volatile void __iomem *smem;
volatile u32 __iomem *sfb;
......@@ -47,8 +45,6 @@ struct pmagbbfb_par {
};
static struct fb_info *root_pmagbbfb_dev;
static struct fb_var_screeninfo pmagbbfb_defined __initdata = {
.bits_per_pixel = 8,
.red.length = 8,
......@@ -190,8 +186,9 @@ static void __init pmagbbfb_osc_setup(struct fb_info *info)
69197, 66000, 65000, 50350, 36000, 32000, 25175
};
struct pmagbbfb_par *par = info->par;
struct tc_bus *tbus = to_tc_dev(info->device)->bus;
u32 count0 = 8, count1 = 8, counttc = 16 * 256 + 8;
u32 freq0, freq1, freqtc = get_tc_speed() / 250;
u32 freq0, freq1, freqtc = tc_get_speed(tbus) / 250;
int i, j;
gp0_write(par, 0); /* select Osc0 */
......@@ -249,26 +246,21 @@ static void __init pmagbbfb_osc_setup(struct fb_info *info)
};
static int __init pmagbbfb_init_one(int slot)
static int __init pmagbbfb_probe(struct device *dev)
{
char freq0[12], freq1[12];
struct tc_dev *tdev = to_tc_dev(dev);
resource_size_t start, len;
struct fb_info *info;
struct pmagbbfb_par *par;
unsigned long base_addr;
char freq0[12], freq1[12];
u32 vid_base;
info = framebuffer_alloc(sizeof(struct pmagbbfb_par), NULL);
info = framebuffer_alloc(sizeof(struct pmagbbfb_par), dev);
if (!info)
return -ENOMEM;
par = info->par;
par->slot = slot;
claim_tc_card(par->slot);
base_addr = get_tc_base_addr(par->slot);
par->next = root_pmagbbfb_dev;
root_pmagbbfb_dev = info;
dev_set_drvdata(dev, info);
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
goto err_alloc;
......@@ -278,16 +270,22 @@ static int __init pmagbbfb_init_one(int slot)
info->var = pmagbbfb_defined;
info->flags = FBINFO_DEFAULT;
/* Request the I/O MEM resource. */
start = tdev->resource.start;
len = tdev->resource.end - start + 1;
if (!request_mem_region(start, len, dev->bus_id))
goto err_cmap;
/* MMIO mapping setup. */
info->fix.mmio_start = base_addr;
info->fix.mmio_start = start;
par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
if (!par->mmio)
goto err_cmap;
goto err_resource;
par->sfb = par->mmio + PMAGB_B_SFB;
par->dac = par->mmio + PMAGB_B_BT459;
/* Frame buffer mapping setup. */
info->fix.smem_start = base_addr + PMAGB_B_FBMEM;
info->fix.smem_start = start + PMAGB_B_FBMEM;
par->smem = ioremap_nocache(info->fix.smem_start, info->fix.smem_len);
if (!par->smem)
goto err_mmio_map;
......@@ -302,13 +300,15 @@ static int __init pmagbbfb_init_one(int slot)
if (register_framebuffer(info) < 0)
goto err_smem_map;
get_device(dev);
snprintf(freq0, sizeof(freq0), "%u.%03uMHz",
par->osc0 / 1000, par->osc0 % 1000);
snprintf(freq1, sizeof(freq1), "%u.%03uMHz",
par->osc1 / 1000, par->osc1 % 1000);
pr_info("fb%d: %s frame buffer device in slot %d\n",
info->node, info->fix.id, par->slot);
pr_info("fb%d: %s frame buffer device at %s\n",
info->node, info->fix.id, dev->bus_id);
pr_info("fb%d: Osc0: %s, Osc1: %s, Osc%u selected\n",
info->node, freq0, par->osc1 ? freq1 : "disabled",
par->osc1 != 0);
......@@ -322,54 +322,68 @@ err_smem_map:
err_mmio_map:
iounmap(par->mmio);
err_resource:
release_mem_region(start, len);
err_cmap:
fb_dealloc_cmap(&info->cmap);
err_alloc:
root_pmagbbfb_dev = par->next;
release_tc_card(par->slot);
framebuffer_release(info);
return -ENXIO;
}
static void __exit pmagbbfb_exit_one(void)
static int __exit pmagbbfb_remove(struct device *dev)
{
struct fb_info *info = root_pmagbbfb_dev;
struct tc_dev *tdev = to_tc_dev(dev);
struct fb_info *info = dev_get_drvdata(dev);
struct pmagbbfb_par *par = info->par;
resource_size_t start, len;
put_device(dev);
unregister_framebuffer(info);
iounmap(par->smem);
iounmap(par->mmio);
start = tdev->resource.start;
len = tdev->resource.end - start + 1;
release_mem_region(start, len);
fb_dealloc_cmap(&info->cmap);
root_pmagbbfb_dev = par->next;
release_tc_card(par->slot);
framebuffer_release(info);
return 0;
}
/*
* Initialise the framebuffer.
* Initialize the framebuffer.
*/
static const struct tc_device_id pmagbbfb_tc_table[] = {
{ "DEC ", "PMAGB-BA" },
{ }
};
MODULE_DEVICE_TABLE(tc, pmagbbfb_tc_table);
static struct tc_driver pmagbbfb_driver = {
.id_table = pmagbbfb_tc_table,
.driver = {
.name = "pmagbbfb",
.bus = &tc_bus_type,
.probe = pmagbbfb_probe,
.remove = __exit_p(pmagbbfb_remove),
},
};
static int __init pmagbbfb_init(void)
{
int count = 0;
int slot;
#ifndef MODULE
if (fb_get_options("pmagbbfb", NULL))
return -ENXIO;
while ((slot = search_tc_card("PMAGB-BA")) >= 0) {
if (pmagbbfb_init_one(slot) < 0)
break;
count++;
}
return (count > 0) ? 0 : -ENXIO;
#endif
return tc_register_driver(&pmagbbfb_driver);
}
static void __exit pmagbbfb_exit(void)
{
while (root_pmagbbfb_dev)
pmagbbfb_exit_one();
tc_unregister_driver(&pmagbbfb_driver);
}
......
......@@ -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 */
/*
* 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 */
/*
* 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
/*
* 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 */
......@@ -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)
{
......
/*
* 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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment