/*
* File Name:
* defxx.c
*
* Copyright Information:
* Copyright Digital Equipment Corporation 1996.
*
* This software may be used and distributed according to the terms of
* the GNU General Public License, incorporated herein by reference.
*
* Abstract:
* A Linux device driver supporting the Digital Equipment Corporation
* FDDI TURBOchannel, EISA and PCI controller families. Supported
* adapters include:
*
* DEC FDDIcontroller/TURBOchannel (DEFTA)
* DEC FDDIcontroller/EISA (DEFEA)
* DEC FDDIcontroller/PCI (DEFPA)
*
* The original author:
* LVS Lawrence V. Stefani <lstefani@yahoo.com>
*
* Maintainers:
* macro Maciej W. Rozycki <macro@linux-mips.org>
*
* Credits:
* I'd like to thank Patricia Cross for helping me get started with
* Linux, David Davies for a lot of help upgrading and configuring
* my development system and for answering many OS and driver
* development questions, and Alan Cox for recommendations and
* integration help on getting FDDI support into Linux. LVS
*
* Driver Architecture:
* The driver architecture is largely based on previous driver work
* for other operating systems. The upper edge interface and
* functions were largely taken from existing Linux device drivers
* such as David Davies' DE4X5.C driver and Donald Becker's TULIP.C
* driver.
*
* Adapter Probe -
* The driver scans for supported EISA adapters by reading the
* SLOT ID register for each EISA slot and making a match
* against the expected value.
*
* Bus-Specific Initialization -
* This driver currently supports both EISA and PCI controller
* families. While the custom DMA chip and FDDI logic is similar
* or identical, the bus logic is very different. After
* initialization, the only bus-specific differences is in how the
* driver enables and disables interrupts. Other than that, the
* run-time critical code behaves the same on both families.
* It's important to note that both adapter families are configured
* to I/O map, rather than memory map, the adapter registers.
*
* Driver Open/Close -
* In the driver open routine, the driver ISR (interrupt service
* routine) is registered and the adapter is brought to an
* operational state. In the driver close routine, the opposite
* occurs; the driver ISR is deregistered and the adapter is
* brought to a safe, but closed state. Users may use consecutive
* commands to bring the adapter up and down as in the following
* example:
* ifconfig fddi0 up
* ifconfig fddi0 down
* ifconfig fddi0 up
*
* Driver Shutdown -
* Apparently, there is no shutdown or halt routine support under
* Linux. This routine would be called during "reboot" or
* "shutdown" to allow the driver to place the adapter in a safe
* state before a warm reboot occurs. To be really safe, the user
* should close the adapter before shutdown (eg. ifconfig fddi0 down)
* to ensure that the adapter DMA engine is taken off-line. However,
* the current driver code anticipates this problem and always issues
* a soft reset of the adapter at the beginning of driver initialization.
* A future driver enhancement in this area may occur in 2.1.X where
* Alan indicated that a shutdown handler may be implemented.
*
* Interrupt Service Routine -
* The driver supports shared interrupts, so the ISR is registered for
* each board with the appropriate flag and the pointer to that board's
* device structure. This provides the context during interrupt
* processing to support shared interrupts and multiple boards.
*
* Interrupt enabling/disabling can occur at many levels. At the host
* end, you can disable system interrupts, or disable interrupts at the
* PIC (on Intel systems). Across the bus, both EISA and PCI adapters
* have a bus-logic chip interrupt enable/disable as well as a DMA
* controller interrupt enable/disable.
*
* The driver currently enables and disables adapter interrupts at the
* bus-logic chip and assumes that Linux will take care of clearing or
* acknowledging any host-based interrupt chips.
*
* Control Functions -
* Control functions are those used to support functions such as adding
* or deleting multicast addresses, enabling or disabling packet
* reception filters, or other custom/proprietary commands. Presently,
* the driver supports the "get statistics", "set multicast list", and
* "set mac address" functions defined by Linux. A list of possible
* enhancements include:
*
* - Custom ioctl interface for executing port interface commands
* - Custom ioctl interface for adding unicast addresses to
* adapter CAM (to support bridge functions).
* - Custom ioctl interface for supporting firmware upgrades.
*
* Hardware (port interface) Support Routines -
* The driver function names that start with "dfx_hw_" represent
* low-level port interface routines that are called frequently. They
* include issuing a DMA or port control command to the adapter,
* resetting the adapter, or reading the adapter state. Since the
* driver initialization and run-time code must make calls into the
* port interface, these routines were written to be as generic and
* usable as possible.
*
* Receive Path -
* The adapter DMA engine supports a 256 entry receive descriptor block
* of which up to 255 entries can be used at any given time. The
* architecture is a standard producer, consumer, completion model in
* which the driver "produces" receive buffers to the adapter, the
* adapter "consumes" the receive buffers by DMAing incoming packet data,
* and the driver "completes" the receive buffers by servicing the
* incoming packet, then "produces" a new buffer and starts the cycle
* again. Receive buffers can be fragmented in up to 16 fragments
* (descriptor entries). For simplicity, this driver posts
* single-fragment receive buffers of 4608 bytes, then allocates a
* sk_buff, copies the data, then reposts the buffer. To reduce CPU
* utilization, a better approach would be to pass up the receive
* buffer (no extra copy) then allocate and post a replacement buffer.
* This is a performance enhancement that should be looked into at
* some point.
*
* Transmit Path -
* Like the receive path, the adapter DMA engine supports a 256 entry
* transmit descriptor block of which up to 255 entries can be used at
* any given time. Transmit buffers can be fragmented in up to 255
* fragments (descriptor entries). This driver always posts one
* fragment per transmit packet request.
*
* The fragment contains the entire packet from FC to end of data.
* Before posting the buffer to the adapter, the driver sets a three-byte
* packet request header (PRH) which is required by the Motorola MAC chip
* used on the adapters. The PRH tells the MAC the type of token to
* receive/send, whether or not to generate and append the CRC, whether
* synchronous or asynchronous framing is used, etc. Since the PRH
* definition is not necessarily consistent across all FDDI chipsets,
* the driver, rather than the common FDDI packet handler routines,
* sets these bytes.
*
* To reduce the amount of descriptor fetches needed per transmit request,
* the driver takes advantage of the fact that there are at least three
* bytes available before the skb->data field on the outgoing transmit
* request. This is guaranteed by having fddi_setup() in net_init.c set
* dev->hard_header_len to 24 bytes. 21 bytes accounts for the largest
* header in an 802.2 SNAP frame. The other 3 bytes are the extra "pad"
* bytes which we'll use to store the PRH.
*
* There's a subtle advantage to adding these pad bytes to the
* hard_header_len, it ensures that the data portion of the packet for
* an 802.2 SNAP frame is longword aligned. Other FDDI driver
* implementations may not need the extra padding and can start copying
* or DMAing directly from the FC byte which starts at skb->data. Should
* another driver implementation need ADDITIONAL padding, the net_init.c
* module should be updated and dev->hard_header_len should be increased.
* NOTE: To maintain the alignment on the data portion of the packet,
* dev->hard_header_len should always be evenly divisible by 4 and at
* least 24 bytes in size.
*
* Modification History:
* Date Name Description
* 16-Aug-96 LVS Created.
* 20-Aug-96 LVS Updated dfx_probe so that version information
* string is only displayed if 1 or more cards are
* found. Changed dfx_rcv_queue_process to copy
* 3 NULL bytes before FC to ensure that data is
* longword aligned in receive buffer.
* 09-Sep-96 LVS Updated dfx_ctl_set_multicast_list to enable
* LLC group promiscuous mode if multicast list
* is too large. LLC individual/group promiscuous
* mode is now disabled if IFF_PROMISC flag not set.
* dfx_xmt_queue_pkt no longer checks for NULL skb
* on Alan Cox recommendation. Added node address
* override support.
* 12-Sep-96 LVS Reset current address to factory address during
* device open. Updated transmit path to post a
* single fragment which includes PRH->end of data.
* Mar 2000 AC Did various cleanups for 2.3.x
* Jun 2000 jgarzik PCI and resource alloc cleanups
* Jul 2000 tjeerd Much cleanup and some bug fixes
* Sep 2000 tjeerd Fix leak on unload, cosmetic code cleanup
* Feb 2001 Skb allocation fixes
* Feb 2001 davej PCI enable cleanups.
* 04 Aug 2003 macro Converted to the DMA API.
* 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/bitops.h>
#include <linux/compiler.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/pci.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/tc.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include "defxx.h"
/* Version information string should be updated prior to each new release! */
#define DRV_NAME "defxx"
#define DRV_VERSION "v1.10"
#define DRV_RELDATE "2006/12/14"
static char version[] __devinitdata =
DRV_NAME ": " DRV_VERSION " " DRV_RELDATE
" Lawrence V. Stefani and others\n";
#define DYNAMIC_BUFFERS 1
#define SKBUFF_RX_COPYBREAK 200
/*
* NEW_SKB_SIZE = PI_RCV_DATA_K_SIZE_MAX+128 to allow 128 byte
* alignment for compatibility with old EISA boards.
*/
#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128)
#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,
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);
static int dfx_close(struct net_device *dev);
static void dfx_int_pr_halt_id(DFX_board_t *bp);
static void dfx_int_type_0_process(DFX_board_t *bp);
static void dfx_int_common(struct net_device *dev);
static irqreturn_t dfx_interrupt(int irq, void *dev_id);
static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev);
static void dfx_ctl_set_multicast_list(struct net_device *dev);
static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr);
static int dfx_ctl_update_cam(DFX_board_t *bp);
static int dfx_ctl_update_filters(DFX_board_t *bp);
static int dfx_hw_dma_cmd_req(DFX_board_t *bp);
static int dfx_hw_port_ctrl_req(DFX_board_t *bp, PI_UINT32 command, PI_UINT32 data_a, PI_UINT32 data_b, PI_UINT32 *host_data);
static void dfx_hw_adap_reset(DFX_board_t *bp, PI_UINT32 type);
static int dfx_hw_adap_state_rd(DFX_board_t *bp);
static int dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type);
static int dfx_rcv_init(DFX_board_t *bp, int get_buffers);
static void dfx_rcv_queue_process(DFX_board_t *bp);
static void dfx_rcv_flush(DFX_board_t *bp);
static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb,
struct net_device *dev);
static int dfx_xmt_done(DFX_board_t *bp);
static void dfx_xmt_flush(DFX_board_t *bp);
/* Define module-wide (static) variables */
static struct pci_driver dfx_pci_driver;
static struct eisa_driver dfx_eisa_driver;
static struct tc_driver dfx_tc_driver;
/*
* =======================
* = dfx_port_write_long =
* = dfx_port_read_long =
* =======================
*
* Overview:
* Routines for reading and writing values from/to adapter
*
* Returns:
* None
*
* Arguments:
* 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
* the adapter register.
*
* EISA port block base addresses are based on the slot number in which the
* controller is installed. For example, if the EISA controller is installed
* in slot 4, the port block base address is 0x4000. If the controller is
* installed in slot 2, the port block base address is 0x2000, and so on.
* This port block can be used to access PDQ, ESIC, and DEFEA on-board
* 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
* allows for I/O mapping of both PDQ and PFI registers using the register
* offsets defined in DEFXX.H.
*
* Return Codes:
* None
*
* Assumptions:
* bp->base is a valid base I/O address for this adapter.
* offset is a valid register offset for this adapter.
*
* Side Effects:
* Rather than produce macros for these functions, these routines
* are defined using "inline" to ensure that the compiler will
* generate inline code and not waste a procedure call and return.
* This provides all the benefits of macros, but with the
* advantage of strict data type checking.
*/
static inline void dfx_writel(DFX_board_t *bp, int offset, u32 data)
{
writel(data, bp->base.mem + offset);
mb();
}
static inline void dfx_outl(DFX_board_t *bp, int offset, u32 data)
{
outl(data, bp->base.port + offset);
}
static void dfx_port_write_long(DFX_board_t *bp, int offset, u32 data)
{
struct device __maybe_unused *bdev = bp->bus_dev;
int dfx_bus_tc = DFX_BUS_TC(bdev);
int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
if (dfx_use_mmio)
dfx_writel(bp, offset, data);
else
dfx_outl(bp, offset, data);
}
static inline void dfx_readl(DFX_board_t *bp, int offset, u32 *data)
{
mb();
*data = readl(bp->base.mem + offset);
}
static inline void dfx_inl(DFX_board_t *bp, int offset, u32 *data)
{
*data = inl(bp->base.port + offset);
}
static void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data)
{
struct device __maybe_unused *bdev = bp->bus_dev;
int dfx_bus_tc = DFX_BUS_TC(bdev);
int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
if (dfx_use_mmio)
dfx_readl(bp, offset, data);
else
dfx_inl(bp, offset, data);
}
/*
* ================
* = 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;
}
}
static const struct net_device_ops dfx_netdev_ops = {
.ndo_open = dfx_open,
.ndo_stop = dfx_close,
.ndo_start_xmit = dfx_xmt_queue_pkt,
.ndo_get_stats = dfx_ctl_get_stats,
.ndo_set_multicast_list = dfx_ctl_set_multicast_list,
.ndo_set_mac_address = dfx_ctl_set_mac_address,
};
/*
* ================
* = dfx_register =
* ================
*
* Overview:
* Initializes a supported FDDI controller
*
* Returns:
* Condition code
*
* Arguments:
* bdev - pointer to device information
*
* Functional Description:
*
* Return Codes:
* 0 - This device (fddi0, fddi1, etc) configured successfully
* -EBUSY - Failed to get resources, or dfx_driver_init failed.
*
* Assumptions:
* It compiles so it should work :-( (PCI cards do :-)
*
* Side Effects:
* Device structures for FDDI adapters (fddi0, fddi1, etc) are
* initialized and the board resources are read and stored in
* the device structure.
*/
static int __devinit dfx_register(struct device *bdev)
{
static int version_disp;
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;
const char *print_name = dev_name(bdev);
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 */
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 */
}
dev = alloc_fddidev(sizeof(*bp));
if (!dev) {
printk(KERN_ERR "%s: Unable to allocate fddidev, aborting\n",
print_name);
return -ENOMEM;
}
/* Enable PCI device. */
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_NETDEV_DEV(dev, bdev);
bp = netdev_priv(dev);
bp->bus_dev = bdev;
dev_set_drvdata(bdev, dev);
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%lx @ 0x%lx, aborting\n",
print_name, (long)bar_len, (long)bar_start);
err = -EBUSY;
goto err_out_disable;
}
/* 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);
err = -ENOMEM;
goto err_out_region;
}
} else {
bp->base.port = bar_start;
dev->base_addr = bar_start;
}
/* Initialize new device structure */
dev->netdev_ops = &dfx_netdev_ops;
if (dfx_bus_pci)
pci_set_master(to_pci_dev(bdev));
if (dfx_driver_init(dev, print_name, bar_start) != DFX_K_SUCCESS) {
err = -ENODEV;
goto err_out_unmap;
}
err = register_netdev(dev);
if (err)
goto err_out_kfree;
printk("%s: registered as %s\n", print_name, dev->name);
return 0;
err_out_kfree:
alloc_size = sizeof(PI_DESCR_BLOCK) +
PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX +
#ifndef DYNAMIC_BUFFERS
(bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) +
#endif
sizeof(PI_CONSUMER_BLOCK) +
(PI_ALIGN_K_DESC_BLK - 1);
if (bp->kmalloced)
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:
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;
}
/*
* ================
* = dfx_bus_init =
* ================
*
* Overview:
* Initializes the bus-specific controller logic.
*
* Returns:
* None
*
* Arguments:
* dev - pointer to device information
*
* Functional Description:
* Determine and save adapter IRQ in device table,
* then perform bus-specific logic initialization.
*
* Return Codes:
* None
*
* Assumptions:
* bp->base has already been set with the proper
* base I/O address for this device.
*
* Side Effects:
* Interrupts are enabled at the adapter bus-specific logic.
* Note: Interrupts at the DMA engine (PDQ chip) are not
* enabled yet.
*/
static void __devinit dfx_bus_init(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);
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 a pointer back to the net_device struct */
bp->dev = dev;
/* Initialize adapter based on bus type */
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;
/* 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;
case PI_CONFIG_STAT_0_IRQ_K_10:
dev->irq = 10;
break;
case PI_CONFIG_STAT_0_IRQ_K_11:
dev->irq = 11;
break;
case PI_CONFIG_STAT_0_IRQ_K_15:
dev->irq = 15;
break;
}
/*
* 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);
/*
* 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);
/*
* 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) */
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 */
dev->irq = pdev->irq;
/* 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) {
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_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 __devexit 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);
}
}
/*
* ========================
* = dfx_bus_config_check =
* ========================
*
* Overview:
* Checks the configuration (burst size, full-duplex, etc.) If any parameters
* are illegal, then this routine will set new defaults.
*
* Returns:
* None
*
* Arguments:
* bp - pointer to board information
*
* Functional Description:
* For Revision 1 FDDI EISA, Revision 2 or later FDDI EISA with rev E or later
* PDQ, and all FDDI PCI controllers, all values are legal.
*
* Return Codes:
* None
*
* Assumptions:
* dfx_adap_init has NOT been called yet so burst size and other items have
* not been set.
*
* Side Effects:
* None
*/
static void __devinit dfx_bus_config_check(DFX_board_t *bp)
{
struct device __maybe_unused *bdev = bp->bus_dev;
int dfx_bus_eisa = DFX_BUS_EISA(bdev);
int status; /* return code from adapter port control call */
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 (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
* cards used PDQ revision E, so no workaround needed in this
* 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 (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.
*/
status = dfx_hw_port_ctrl_req(bp,
PI_PCTRL_M_SUB_CMD,
PI_SUB_CMD_K_PDQ_REV_GET,
0,
&host_data);
if ((status != DFX_K_SUCCESS) || (host_data == 2))
{
/*
* Either we couldn't determine the PDQ revision, or
* we determined that it is at revision D. In either case,
* we need to implement the workaround.
*/
/* Ensure that the burst size is set to 8 longwords or less */
switch (bp->burst_size)
{
case PI_PDATA_B_DMA_BURST_SIZE_32:
case PI_PDATA_B_DMA_BURST_SIZE_16:
bp->burst_size = PI_PDATA_B_DMA_BURST_SIZE_8;
break;
default:
break;
}
/* Ensure that full-duplex mode is not enabled */
bp->full_duplex_enb = PI_SNMP_K_FALSE;
}
}
}
}
/*
* ===================
* = dfx_driver_init =
* ===================
*
* Overview:
* Initializes remaining adapter board structure information
* and makes sure adapter is in a safe state prior to dfx_open().
*
* Returns:
* Condition code
*
* Arguments:
* dev - pointer to device information
* print_name - printable device name
*
* Functional Description:
* This function allocates additional resources such as the host memory
* blocks needed by the adapter (eg. descriptor and consumer blocks).
* Remaining bus initialization steps are also completed. The adapter
* is also reset so that it is in the DMA_UNAVAILABLE state. The OS
* must call dfx_open() to open the adapter and bring it on-line.
*
* Return Codes:
* DFX_K_SUCCESS - initialization succeeded
* DFX_K_FAILURE - initialization failed - could not allocate memory
* or read adapter MAC address
*
* Assumptions:
* Memory allocated from pci_alloc_consistent() call is physically
* contiguous, locked memory.
*
* Side Effects:
* Adapter is reset and should be in DMA_UNAVAILABLE state before
* returning from this routine.
*/
static int __devinit dfx_driver_init(struct net_device *dev,
const char *print_name,
resource_size_t bar_start)
{
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 */
__le32 le32;
char *board_name = NULL;
DBG_printk("In dfx_driver_init...\n");
/* Initialize bus-specific hardware registers */
dfx_bus_init(dev);
/*
* Initialize default values for configurable parameters
*
* Note: All of these parameters are ones that a user may
* want to customize. It'd be nice to break these
* out into Space.c or someplace else that's more
* accessible/understandable than this file.
*/
bp->full_duplex_enb = PI_SNMP_K_FALSE;
bp->req_ttrt = 8 * 12500; /* 8ms in 80 nanosec units */
bp->burst_size = PI_PDATA_B_DMA_BURST_SIZE_DEF;
bp->rcv_bufs_to_post = RCV_BUFS_DEF;
/*
* Ensure that HW configuration is OK
*
* Note: Depending on the hardware revision, we may need to modify
* some of the configurable parameters to workaround hardware
* limitations. We'll perform this configuration check AFTER
* setting the parameters to their default values.
*/
dfx_bus_config_check(bp);
/* Disable PDQ interrupts first */
dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS);
/* Place adapter in DMA_UNAVAILABLE state by resetting adapter */
(void) dfx_hw_dma_uninit(bp, PI_PDATA_A_RESET_M_SKIP_ST);
/* Read the factory MAC address from the adapter then save it */
if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_LO, 0,
&data) != DFX_K_SUCCESS) {
printk("%s: Could not read adapter factory MAC address!\n",
print_name);
return(DFX_K_FAILURE);
}
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) {
printk("%s: Could not read adapter factory MAC address!\n",
print_name);
return(DFX_K_FAILURE);
}
le32 = cpu_to_le32(data);
memcpy(&bp->factory_mac_addr[4], &le32, sizeof(u16));
/*
* Set current address to factory address
*
* Note: Node address override support is handled through
* dfx_ctl_set_mac_address.
*/
memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN);
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 = %pMF\n",
print_name, board_name, dfx_use_mmio ? "" : "I/O ",
(long long)bar_start, dev->irq, dev->dev_addr);
/*
* Get memory for descriptor block, consumer block, and other buffers
* that need to be DMA read or written to by the adapter.
*/
alloc_size = sizeof(PI_DESCR_BLOCK) +
PI_CMD_REQ_K_SIZE_MAX +
PI_CMD_RSP_K_SIZE_MAX +
#ifndef DYNAMIC_BUFFERS
(bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) +
#endif
sizeof(PI_CONSUMER_BLOCK) +
(PI_ALIGN_K_DESC_BLK - 1);
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);
return(DFX_K_FAILURE);
}
memset(top_v, 0, alloc_size); /* zero out memory before continuing */
top_p = bp->kmalloced_dma; /* get physical address of buffer */
/*
* To guarantee the 8K alignment required for the descriptor block, 8K - 1
* plus the amount of memory needed was allocated. The physical address
* is now 8K aligned. By carving up the memory in a specific order,
* we'll guarantee the alignment requirements for all other structures.
*
* Note: If the assumptions change regarding the non-paged, non-cached,
* physically contiguous nature of the memory block or the address
* alignments, then we'll need to implement a different algorithm
* for allocating the needed memory.
*/
curr_p = ALIGN(top_p, PI_ALIGN_K_DESC_BLK);
curr_v = top_v + (curr_p - top_p);
/* Reserve space for descriptor block */
bp->descr_block_virt = (PI_DESCR_BLOCK *) curr_v;
bp->descr_block_phys = curr_p;
curr_v += sizeof(PI_DESCR_BLOCK);
curr_p += sizeof(PI_DESCR_BLOCK);
/* Reserve space for command request buffer */
bp->cmd_req_virt = (PI_DMA_CMD_REQ *) curr_v;
bp->cmd_req_phys = curr_p;
curr_v += PI_CMD_REQ_K_SIZE_MAX;
curr_p += PI_CMD_REQ_K_SIZE_MAX;
/* Reserve space for command response buffer */
bp->cmd_rsp_virt = (PI_DMA_CMD_RSP *) curr_v;
bp->cmd_rsp_phys = curr_p;
curr_v += PI_CMD_RSP_K_SIZE_MAX;
curr_p += PI_CMD_RSP_K_SIZE_MAX;
/* Reserve space for the LLC host receive queue buffers */
bp->rcv_block_virt = curr_v;
bp->rcv_block_phys = curr_p;
#ifndef DYNAMIC_BUFFERS
curr_v += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX);
curr_p += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX);
#endif
/* Reserve space for the consumer block */
bp->cons_block_virt = (PI_CONSUMER_BLOCK *) curr_v;
bp->cons_block_phys = curr_p;
/* Display virtual and physical addresses if debug driver */
DBG_printk("%s: Descriptor block virt = %0lX, phys = %0X\n",
print_name,
(long)bp->descr_block_virt, bp->descr_block_phys);
DBG_printk("%s: Command Request buffer virt = %0lX, phys = %0X\n",
print_name, (long)bp->cmd_req_virt, bp->cmd_req_phys);
DBG_printk("%s: Command Response buffer virt = %0lX, phys = %0X\n",
print_name, (long)bp->cmd_rsp_virt, bp->cmd_rsp_phys);
DBG_printk("%s: Receive buffer block virt = %0lX, phys = %0X\n",
print_name, (long)bp->rcv_block_virt, bp->rcv_block_phys);
DBG_printk("%s: Consumer block virt = %0lX, phys = %0X\n",
print_name, (long)bp->cons_block_virt, bp->cons_block_phys);
return(DFX_K_SUCCESS);
}
/*
* =================
* = dfx_adap_init =
* =================
*
* Overview:
* Brings the adapter to the link avail/link unavailable state.
*
* Returns:
* Condition code
*
* Arguments:
* bp - pointer to board information
* get_buffers - non-zero if buffers to be allocated
*
* Functional Description:
* Issues the low-level firmware/hardware calls necessary to bring
* the adapter up, or to properly reset and restore adapter during
* run-time.
*
* Return Codes:
* DFX_K_SUCCESS - Adapter brought up successfully
* DFX_K_FAILURE - Adapter initialization failed
*
* Assumptions:
* bp->reset_type should be set to a valid reset type value before
* calling this routine.
*
* Side Effects:
* Adapter should be in LINK_AVAILABLE or LINK_UNAVAILABLE state
* upon a successful return of this routine.
*/