mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-28 11:57:28 +00:00
7cf545d0a1
if_watchdog and if_timer. - Fix some issues in detach for sn(4), ste(4), and ti(4). Primarily this means calling ether_ifdetach() before anything else.
396 lines
12 KiB
C
396 lines
12 KiB
C
/*-
|
|
* Copyright (c) 2001-2003
|
|
* Fraunhofer Institute for Open Communication Systems (FhG Fokus).
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* Author: Hartmut Brandt <harti@freebsd.org>
|
|
*
|
|
* $FreeBSD$
|
|
*
|
|
* Fore PCA200E driver definitions.
|
|
*/
|
|
/*
|
|
* Debug statistics of the PCA200 driver
|
|
*/
|
|
struct istats {
|
|
uint32_t cmd_queue_full;
|
|
uint32_t get_stat_errors;
|
|
uint32_t clr_stat_errors;
|
|
uint32_t get_prom_errors;
|
|
uint32_t suni_reg_errors;
|
|
uint32_t tx_queue_full;
|
|
uint32_t tx_queue_almost_full;
|
|
uint32_t tx_pdu2big;
|
|
uint32_t tx_too_many_segs;
|
|
uint32_t tx_retry;
|
|
uint32_t fix_empty;
|
|
uint32_t fix_addr_copy;
|
|
uint32_t fix_addr_noext;
|
|
uint32_t fix_addr_ext;
|
|
uint32_t fix_len_noext;
|
|
uint32_t fix_len_copy;
|
|
uint32_t fix_len;
|
|
uint32_t rx_badvc;
|
|
uint32_t rx_closed;
|
|
};
|
|
|
|
/*
|
|
* Addresses on the on-board RAM are expressed as offsets to the
|
|
* start of that RAM.
|
|
*/
|
|
typedef uint32_t cardoff_t;
|
|
|
|
/*
|
|
* The card uses a number of queues for communication with the host.
|
|
* Parts of the queue are located on the card (pointers to the status
|
|
* word and the ioblk and the command blocks), the rest in host memory.
|
|
* Each of these queues forms a ring, where the head and tail pointers are
|
|
* managed * either by the card or the host. For the receive queue the
|
|
* head is managed by the card (and not used altogether by the host) and the
|
|
* tail by the host - for all other queues its the other way around.
|
|
* The host resident parts of the queue entries contain pointers to
|
|
* the host resident status and the host resident ioblk (the latter not for
|
|
* the command queue) as well as DMA addresses for supply to the card.
|
|
*/
|
|
struct fqelem {
|
|
cardoff_t card; /* corresponding element on card */
|
|
bus_addr_t card_ioblk; /* ioblk address to supply to card */
|
|
volatile uint32_t *statp; /* host status pointer */
|
|
void *ioblk; /* host ioblk (not for commands) */
|
|
};
|
|
|
|
struct fqueue {
|
|
struct fqelem *chunk; /* pointer to the element array */
|
|
int head; /* queue head */
|
|
int tail; /* queue tail */
|
|
};
|
|
|
|
/*
|
|
* Queue manipulation macros
|
|
*/
|
|
#define NEXT_QUEUE_ENTRY(HEAD,LEN) ((HEAD) = ((HEAD) + 1) % LEN)
|
|
#define GET_QUEUE(Q,TYPE,IDX) (&((TYPE *)(Q).chunk)[(IDX)])
|
|
|
|
/*
|
|
* Now define structures for the different queues. Each of these structures
|
|
* must start with a struct fqelem.
|
|
*/
|
|
struct txqueue { /* transmit queue element */
|
|
struct fqelem q;
|
|
struct mbuf *m; /* the chain we are transmitting */
|
|
bus_dmamap_t map; /* map for the packet */
|
|
};
|
|
|
|
struct rxqueue { /* receive queue element */
|
|
struct fqelem q;
|
|
};
|
|
|
|
struct supqueue { /* supply queue element */
|
|
struct fqelem q;
|
|
};
|
|
|
|
struct cmdqueue;
|
|
struct fatm_softc;
|
|
|
|
typedef void (*completion_cb)(struct fatm_softc *, struct cmdqueue *);
|
|
|
|
struct cmdqueue { /* command queue element */
|
|
struct fqelem q;
|
|
completion_cb cb; /* call on command completion */
|
|
int error; /* set if error occured */
|
|
};
|
|
|
|
/*
|
|
* Card-DMA-able memory is managed by means of the bus_dma* functions.
|
|
* To allocate a chunk of memory with a specific size and alignment one
|
|
* has to:
|
|
* 1. create a DMA tag
|
|
* 2. allocate the memory
|
|
* 3. load the memory into a map.
|
|
* This finally gives the physical address that can be given to the card.
|
|
* The card can DMA the entire 32-bit space without boundaries. We assume,
|
|
* that all the allocations can be mapped in one contiguous segment. This
|
|
* may be wrong in the future if we have more than 32 bit addresses.
|
|
* Allocation is done at attach time and managed by the following structure.
|
|
*
|
|
* This could be done easier with the NetBSD bus_dma* functions. They appear
|
|
* to be more useful and consistent.
|
|
*/
|
|
struct fatm_mem {
|
|
u_int size; /* size */
|
|
u_int align; /* alignment */
|
|
bus_dma_tag_t dmat; /* DMA tag */
|
|
void *mem; /* memory block */
|
|
bus_addr_t paddr; /* pysical address */
|
|
bus_dmamap_t map; /* map */
|
|
};
|
|
|
|
/*
|
|
* Each of these structures describes one receive buffer while the buffer
|
|
* is on the card or in the receive return queue. These structures are
|
|
* allocated at initialisation time together with the DMA maps. The handle that
|
|
* is given to the card is the index into the array of these structures.
|
|
*/
|
|
struct rbuf {
|
|
struct mbuf *m; /* the mbuf while we are on the card */
|
|
bus_dmamap_t map; /* the map */
|
|
LIST_ENTRY(rbuf) link; /* the free list link */
|
|
};
|
|
LIST_HEAD(rbuf_list, rbuf);
|
|
|
|
/*
|
|
* The driver maintains a list of all open VCCs. Because we
|
|
* use only VPI=0 and a maximum VCI of 1024, the list is rather an array
|
|
* than a list. We also store the atm pseudoheader flags here and the
|
|
* rxhand (aka. protocol block).
|
|
*/
|
|
struct card_vcc {
|
|
struct atmio_vcc param; /* traffic parameters */
|
|
void *rxhand;
|
|
u_int vflags;
|
|
uint32_t ipackets;
|
|
uint32_t opackets;
|
|
uint32_t ibytes;
|
|
uint32_t obytes;
|
|
};
|
|
|
|
#define FATM_VCC_OPEN 0x00010000 /* is open */
|
|
#define FATM_VCC_TRY_OPEN 0x00020000 /* is currently opening */
|
|
#define FATM_VCC_TRY_CLOSE 0x00040000 /* is currently closing */
|
|
#define FATM_VCC_BUSY 0x00070000 /* one of the above */
|
|
#define FATM_VCC_REOPEN 0x00080000 /* reopening during init */
|
|
|
|
/*
|
|
* Finally the softc structure
|
|
*/
|
|
struct fatm_softc {
|
|
struct ifnet *ifp; /* common part */
|
|
struct mtx mtx; /* lock this structure */
|
|
struct ifmedia media; /* media */
|
|
struct callout watchdog_timer;
|
|
|
|
int init_state; /* initialisation step */
|
|
int memid; /* resource id for card memory */
|
|
struct resource *memres; /* resource for card memory */
|
|
bus_space_handle_t memh; /* handle for card memory */
|
|
bus_space_tag_t memt; /* tag for card memory */
|
|
int irqid; /* resource id for interrupt */
|
|
struct resource *irqres; /* resource for interrupt */
|
|
void *ih; /* interrupt handler */
|
|
|
|
bus_dma_tag_t parent_dmat; /* parent DMA tag */
|
|
struct fatm_mem stat_mem; /* memory for status blocks */
|
|
struct fatm_mem txq_mem; /* TX descriptor queue */
|
|
struct fatm_mem rxq_mem; /* RX descriptor queue */
|
|
struct fatm_mem s1q_mem; /* Small buffer 1 queue */
|
|
struct fatm_mem l1q_mem; /* Large buffer 1 queue */
|
|
struct fatm_mem prom_mem; /* PROM memory */
|
|
|
|
struct fqueue txqueue; /* transmission queue */
|
|
struct fqueue rxqueue; /* receive queue */
|
|
struct fqueue s1queue; /* SMALL S1 queue */
|
|
struct fqueue l1queue; /* LARGE S1 queue */
|
|
struct fqueue cmdqueue; /* command queue */
|
|
|
|
/* fields for access to the SUNI registers */
|
|
struct fatm_mem reg_mem; /* DMAable memory for readregs */
|
|
struct cv cv_regs; /* to serialize access to reg_mem */
|
|
|
|
/* fields for access to statistics */
|
|
struct fatm_mem sadi_mem; /* sadistics memory */
|
|
struct cv cv_stat; /* to serialize access to sadi_mem */
|
|
|
|
u_int flags;
|
|
#define FATM_STAT_INUSE 0x0001
|
|
#define FATM_REGS_INUSE 0x0002
|
|
u_int txcnt; /* number of used transmit desc */
|
|
int retry_tx; /* keep mbufs in queue if full */
|
|
|
|
struct card_vcc **vccs; /* table of vccs */
|
|
int open_vccs; /* number of vccs in use */
|
|
int small_cnt; /* number of buffers owned by card */
|
|
int large_cnt; /* number of buffers owned by card */
|
|
uma_zone_t vcc_zone; /* allocator for VCCs */
|
|
|
|
/* receiving */
|
|
struct rbuf *rbufs; /* rbuf array */
|
|
struct rbuf_list rbuf_free; /* free rbufs list */
|
|
struct rbuf_list rbuf_used; /* used rbufs list */
|
|
u_int rbuf_total; /* total number of buffs */
|
|
bus_dma_tag_t rbuf_tag; /* tag for rbuf mapping */
|
|
|
|
/* transmission */
|
|
bus_dma_tag_t tx_tag; /* transmission tag */
|
|
|
|
uint32_t heartbeat; /* last heartbeat */
|
|
u_int stop_cnt; /* how many times checked */
|
|
|
|
struct istats istats; /* internal statistics */
|
|
|
|
/* SUNI state */
|
|
struct utopia utopia;
|
|
|
|
/* sysctl support */
|
|
struct sysctl_ctx_list sysctl_ctx;
|
|
struct sysctl_oid *sysctl_tree;
|
|
|
|
#ifdef FATM_DEBUG
|
|
/* debugging */
|
|
u_int debug;
|
|
#endif
|
|
};
|
|
|
|
#ifndef FATM_DEBUG
|
|
#define FATM_LOCK(SC) mtx_lock(&(SC)->mtx)
|
|
#define FATM_UNLOCK(SC) mtx_unlock(&(SC)->mtx)
|
|
#else
|
|
#define FATM_LOCK(SC) do { \
|
|
DBG(SC, LOCK, ("locking in line %d", __LINE__)); \
|
|
mtx_lock(&(SC)->mtx); \
|
|
} while (0)
|
|
#define FATM_UNLOCK(SC) do { \
|
|
DBG(SC, LOCK, ("unlocking in line %d", __LINE__)); \
|
|
mtx_unlock(&(SC)->mtx); \
|
|
} while (0)
|
|
#endif
|
|
#define FATM_CHECKLOCK(SC) mtx_assert(&sc->mtx, MA_OWNED)
|
|
|
|
/*
|
|
* Macros to access host memory fields that are also access by the card.
|
|
* These fields need to little-endian always.
|
|
*/
|
|
#define H_GETSTAT(STATP) (le32toh(*(STATP)))
|
|
#define H_SETSTAT(STATP, S) do { *(STATP) = htole32(S); } while (0)
|
|
#define H_SETDESC(DESC, D) do { (DESC) = htole32(D); } while (0)
|
|
|
|
#ifdef notyet
|
|
#define H_SYNCSTAT_POSTREAD(SC, P) \
|
|
bus_dmamap_sync_size((SC)->stat_mem.dmat, \
|
|
(SC)->stat_mem.map, \
|
|
(volatile char *)(P) - (volatile char *)(SC)->stat_mem.mem, \
|
|
sizeof(volatile uint32_t), BUS_DMASYNC_POSTREAD)
|
|
|
|
#define H_SYNCSTAT_PREWRITE(SC, P) \
|
|
bus_dmamap_sync_size((SC)->stat_mem.dmat, \
|
|
(SC)->stat_mem.map, \
|
|
(volatile char *)(P) - (volatile char *)(SC)->stat_mem.mem, \
|
|
sizeof(volatile uint32_t), BUS_DMASYNC_PREWRITE)
|
|
|
|
#define H_SYNCQ_PREWRITE(M, P, SZ) \
|
|
bus_dmamap_sync_size((M)->dmat, (M)->map, \
|
|
(volatile char *)(P) - (volatile char *)(M)->mem, (SZ), \
|
|
BUS_DMASYNC_PREWRITE)
|
|
|
|
#define H_SYNCQ_POSTREAD(M, P, SZ) \
|
|
bus_dmamap_sync_size((M)->dmat, (M)->map, \
|
|
(volatile char *)(P) - (volatile char *)(M)->mem, (SZ), \
|
|
BUS_DMASYNC_POSTREAD)
|
|
#else
|
|
#define H_SYNCSTAT_POSTREAD(SC, P) do { } while (0)
|
|
#define H_SYNCSTAT_PREWRITE(SC, P) do { } while (0)
|
|
#define H_SYNCQ_PREWRITE(M, P, SZ) do { } while (0)
|
|
#define H_SYNCQ_POSTREAD(M, P, SZ) do { } while (0)
|
|
#endif
|
|
|
|
/*
|
|
* Macros to manipulate VPVCs
|
|
*/
|
|
#define MKVPVC(VPI,VCI) (((VPI) << 16) | (VCI))
|
|
#define GETVPI(VPVC) (((VPVC) >> 16) & 0xff)
|
|
#define GETVCI(VPVC) ((VPVC) & 0xffff)
|
|
|
|
/*
|
|
* These macros encapsulate the bus_space functions for better readabiliy.
|
|
*/
|
|
#define WRITE4(SC, OFF, VAL) bus_space_write_4(SC->memt, SC->memh, OFF, VAL)
|
|
#define WRITE1(SC, OFF, VAL) bus_space_write_1(SC->memt, SC->memh, OFF, VAL)
|
|
|
|
#define READ4(SC, OFF) bus_space_read_4(SC->memt, SC->memh, OFF)
|
|
#define READ1(SC, OFF) bus_space_read_1(SC->memt, SC->memh, OFF)
|
|
|
|
#define BARRIER_R(SC) \
|
|
bus_space_barrier(SC->memt, SC->memh, 0, FATMO_END, \
|
|
BUS_SPACE_BARRIER_READ)
|
|
#define BARRIER_W(SC) \
|
|
bus_space_barrier(SC->memt, SC->memh, 0, FATMO_END, \
|
|
BUS_SPACE_BARRIER_WRITE)
|
|
#define BARRIER_RW(SC) \
|
|
bus_space_barrier(SC->memt, SC->memh, 0, FATMO_END, \
|
|
BUS_SPACE_BARRIER_WRITE|BUS_SPACE_BARRIER_READ)
|
|
|
|
#ifdef FATM_DEBUG
|
|
#define DBG(SC, FL, PRINT) do { \
|
|
if ((SC)->debug & DBG_##FL) { \
|
|
if_printf(&(SC)->ifatm.ifnet, "%s: ", __func__); \
|
|
printf PRINT; \
|
|
printf("\n"); \
|
|
} \
|
|
} while (0)
|
|
#define DBGC(SC, FL, PRINT) do { \
|
|
if ((SC)->debug & DBG_##FL) \
|
|
printf PRINT; \
|
|
} while (0)
|
|
|
|
enum {
|
|
DBG_RCV = 0x0001,
|
|
DBG_XMIT = 0x0002,
|
|
DBG_VCC = 0x0004,
|
|
DBG_IOCTL = 0x0008,
|
|
DBG_ATTACH = 0x0010,
|
|
DBG_INIT = 0x0020,
|
|
DBG_DMA = 0x0040,
|
|
DBG_BEAT = 0x0080,
|
|
DBG_UART = 0x0100,
|
|
DBG_LOCK = 0x0200,
|
|
|
|
DBG_ALL = 0xffff
|
|
};
|
|
|
|
#else
|
|
#define DBG(SC, FL, PRINT)
|
|
#define DBGC(SC, FL, PRINT)
|
|
#endif
|
|
|
|
/*
|
|
* Configuration.
|
|
*
|
|
* This section contains tunable parameters and dependend defines.
|
|
*/
|
|
#define FATM_CMD_QLEN 16 /* command queue length */
|
|
#ifndef TEST_DMA_SYNC
|
|
#define FATM_TX_QLEN 128 /* transmit queue length */
|
|
#define FATM_RX_QLEN 64 /* receive queue length */
|
|
#else
|
|
#define FATM_TX_QLEN 8 /* transmit queue length */
|
|
#define FATM_RX_QLEN 8 /* receive queue length */
|
|
#endif
|
|
|
|
#define SMALL_SUPPLY_QLEN 16
|
|
#define SMALL_POOL_SIZE 256
|
|
#define SMALL_SUPPLY_BLKSIZE 8
|
|
|
|
#define LARGE_SUPPLY_QLEN 16
|
|
#define LARGE_POOL_SIZE 128
|
|
#define LARGE_SUPPLY_BLKSIZE 8
|