defxx.c

来自「linux 内核源代码」· C语言 代码 · 共 2,079 行 · 第 1/5 页

C
2,079
字号
/* * 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 int		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 = * ================ *

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?