fc74a9f93a
struct ifnet or the layer 2 common structure it was embedded in have been replaced with a struct ifnet pointer to be filled by a call to the new function, if_alloc(). The layer 2 common structure is also allocated via if_alloc() based on the interface type. It is hung off the new struct ifnet member, if_l2com. This change removes the size of these structures from the kernel ABI and will allow us to better manage them as interfaces come and go. Other changes of note: - Struct arpcom is no longer referenced in normal interface code. Instead the Ethernet address is accessed via the IFP2ENADDR() macro. To enforce this ac_enaddr has been renamed to _ac_enaddr. - The second argument to ether_ifattach is now always the mac address from driver private storage rather than sometimes being ac_enaddr. Reviewed by: sobomax, sam
641 lines
19 KiB
C
641 lines
19 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 HE driver for NATM
|
|
*/
|
|
|
|
/*
|
|
* Debug statistics of the HE driver
|
|
*/
|
|
struct istats {
|
|
uint32_t tdprq_full;
|
|
uint32_t hbuf_error;
|
|
uint32_t crc_error;
|
|
uint32_t len_error;
|
|
uint32_t flow_closed;
|
|
uint32_t flow_drop;
|
|
uint32_t tpd_no_mem;
|
|
uint32_t rx_seg;
|
|
uint32_t empty_hbuf;
|
|
uint32_t short_aal5;
|
|
uint32_t badlen_aal5;
|
|
uint32_t bug_bad_isw;
|
|
uint32_t bug_no_irq_upd;
|
|
uint32_t itype_tbrq;
|
|
uint32_t itype_tpd;
|
|
uint32_t itype_rbps;
|
|
uint32_t itype_rbpl;
|
|
uint32_t itype_rbrq;
|
|
uint32_t itype_rbrqt;
|
|
uint32_t itype_unknown;
|
|
uint32_t itype_phys;
|
|
uint32_t itype_err;
|
|
uint32_t defrag;
|
|
uint32_t mcc;
|
|
uint32_t oec;
|
|
uint32_t dcc;
|
|
uint32_t cec;
|
|
uint32_t no_rcv_mbuf;
|
|
};
|
|
|
|
/* Card memory layout parameters */
|
|
#define HE_CONFIG_MEM_LAYOUT { \
|
|
{ /* 155 */ \
|
|
20, /* cells_per_row */ \
|
|
1024, /* bytes_per_row */ \
|
|
512, /* r0_numrows */ \
|
|
1018, /* tx_numrows */ \
|
|
512, /* r1_numrows */ \
|
|
6, /* r0_startrow */ \
|
|
2 /* cells_per_lbuf */ \
|
|
}, { /* 622 */ \
|
|
40, /* cells_per_row */ \
|
|
2048, /* bytes_per_row */ \
|
|
256, /* r0_numrows */ \
|
|
512, /* tx_numrows */ \
|
|
256, /* r1_numrows */ \
|
|
0, /* r0_startrow */ \
|
|
4 /* cells_per_lbuf */ \
|
|
} \
|
|
}
|
|
|
|
/*********************************************************************/
|
|
struct hatm_softc;
|
|
|
|
/*
|
|
* A chunk of DMA-able memory
|
|
*/
|
|
struct dmamem {
|
|
u_int size; /* in bytes */
|
|
u_int align; /* alignement */
|
|
bus_dma_tag_t tag; /* DMA tag */
|
|
void *base; /* the memory */
|
|
bus_addr_t paddr; /* physical address */
|
|
bus_dmamap_t map; /* the MAP */
|
|
};
|
|
|
|
/*
|
|
* RBP (Receive Buffer Pool) queue entry and queue.
|
|
*/
|
|
struct herbp {
|
|
u_int size; /* RBP number of entries (power of two) */
|
|
u_int thresh; /* interrupt treshold */
|
|
uint32_t bsize; /* buffer size in bytes */
|
|
u_int offset; /* free space at start for small bufs */
|
|
uint32_t mask; /* mask for index */
|
|
struct dmamem mem; /* the queue area */
|
|
struct he_rbpen *rbp;
|
|
uint32_t head, tail; /* head and tail */
|
|
};
|
|
|
|
/*
|
|
* RBRQ (Receive Buffer Return Queue) entry and queue.
|
|
*/
|
|
struct herbrq {
|
|
u_int size; /* number of entries */
|
|
u_int thresh; /* interrupt threshold */
|
|
u_int tout; /* timeout value */
|
|
u_int pcnt; /* packet count threshold */
|
|
struct dmamem mem; /* memory */
|
|
struct he_rbrqen *rbrq;
|
|
uint32_t head; /* driver end */
|
|
};
|
|
|
|
/*
|
|
* TPDRQ (Transmit Packet Descriptor Ready Queue) entry and queue
|
|
*/
|
|
struct hetpdrq {
|
|
u_int size; /* number of entries */
|
|
struct dmamem mem; /* memory */
|
|
struct he_tpdrqen *tpdrq;
|
|
u_int head; /* head (copy of adapter) */
|
|
u_int tail; /* written back to adapter */
|
|
};
|
|
|
|
/*
|
|
* TBRQ (Transmit Buffer Return Queue) entry and queue
|
|
*/
|
|
struct hetbrq {
|
|
u_int size; /* number of entries */
|
|
u_int thresh; /* interrupt threshold */
|
|
struct dmamem mem; /* memory */
|
|
struct he_tbrqen *tbrq;
|
|
u_int head; /* adapter end */
|
|
};
|
|
|
|
/*==================================================================*/
|
|
|
|
/*
|
|
* TPDs are 32 byte and must be aligned on 64 byte boundaries. That means,
|
|
* that half of the space is free. We use this space to plug in a link for
|
|
* the list of free TPDs. Note, that the m_act member of the mbufs contain
|
|
* a pointer to the dmamap.
|
|
*
|
|
* The maximum number of TDPs is the size of the common transmit packet
|
|
* descriptor ready queue plus the sizes of the transmit buffer return queues
|
|
* (currently only queue 0). We allocate and map these TPD when initializing
|
|
* the card. We also allocate on DMA map for each TPD. Only the map in the
|
|
* last TPD of a packets is used when a packet is transmitted.
|
|
* This is signalled by having the mbuf member of this TPD non-zero and
|
|
* pointing to the mbuf.
|
|
*/
|
|
#define HE_TPD_SIZE 64
|
|
struct tpd {
|
|
struct he_tpd tpd; /* at beginning */
|
|
SLIST_ENTRY(tpd) link; /* free cid list link */
|
|
struct mbuf *mbuf; /* the buf chain */
|
|
bus_dmamap_t map; /* map */
|
|
uint32_t cid; /* CID */
|
|
uint16_t no; /* number of this tpd */
|
|
};
|
|
SLIST_HEAD(tpd_list, tpd);
|
|
|
|
#define TPD_SET_USED(SC, I) do { \
|
|
(SC)->tpd_used[(I) / 8] |= (1 << ((I) % 8)); \
|
|
} while (0)
|
|
|
|
#define TPD_CLR_USED(SC, I) do { \
|
|
(SC)->tpd_used[(I) / 8] &= ~(1 << ((I) % 8)); \
|
|
} while (0)
|
|
|
|
#define TPD_TST_USED(SC, I) ((SC)->tpd_used[(I) / 8] & (1 << ((I) % 8)))
|
|
|
|
#define TPD_ADDR(SC, I) ((struct tpd *)((char *)sc->tpds.base + \
|
|
(I) * HE_TPD_SIZE))
|
|
|
|
/*==================================================================*/
|
|
|
|
/*
|
|
* External MBUFs. The card needs a lot of mbufs in the pools for high
|
|
* performance. The problem with using mbufs directly is that we would need
|
|
* a dmamap for each of the mbufs. This can exhaust iommu space on the sparc
|
|
* and it eats also a lot of processing time. So we use external mbufs
|
|
* for the small buffers and clusters for the large buffers.
|
|
* For receive group 0 we use 5 ATM cells, for group 1 one (52 byte) ATM
|
|
* cell. The mbuf storage is allocated pagewise and one dmamap is used per
|
|
* page.
|
|
*
|
|
* The handle we give to the card for the small buffers is a word combined
|
|
* of the page number and the number of the chunk in the page. This restricts
|
|
* the number of chunks per page to 256 (8 bit) and the number of pages to
|
|
* 65536 (16 bits).
|
|
*
|
|
* A chunk may be in one of three states: free, on the card and floating around
|
|
* in the system. If it is free, it is on one of the two free lists and
|
|
* start with a struct mbufx_free. Each page has a bitmap that tracks where
|
|
* its chunks are.
|
|
*
|
|
* For large buffers we use mbuf clusters. Here we have two problems: we need
|
|
* to track the buffers on the card (in the case we want to stop it) and
|
|
* we need to map the 64bit mbuf address to a 26bit handle for 64-bit machines.
|
|
* The card uses the buffers in the order we give it to the card. Therefor
|
|
* we can use a private array holding pointers to the mbufs as a circular
|
|
* queue for both tasks. This is done with the lbufs member of softc. The
|
|
* handle for these buffer is the lbufs index ored with a flag.
|
|
*/
|
|
|
|
/* data space in each external mbuf */
|
|
#define MBUF0_SIZE (5 * 48) /* 240 */
|
|
#define MBUF1_SIZE (52) /* 1 raw cell */
|
|
|
|
/* size of the buffer. Must fit data, offset and header */
|
|
#define MBUF0_CHUNK 256 /* 16 free bytes */
|
|
#define MBUF1_CHUNK 96 /* 44 free bytes */
|
|
|
|
/* start of actual data in buffer */
|
|
#define MBUF0_OFFSET 0
|
|
#define MBUF1_OFFSET 16
|
|
|
|
#define MBUFL_OFFSET 16 /* two pointers for HARP */
|
|
|
|
#if PAGE_SIZE > 8192
|
|
#define MBUF_ALLOC_SIZE (8192)
|
|
#else
|
|
#define MBUF_ALLOC_SIZE (PAGE_SIZE)
|
|
#endif
|
|
|
|
/* each allocated page has one of these structures at its very end. */
|
|
struct mbuf_page_hdr {
|
|
uint16_t nchunks; /* chunks on this page */
|
|
bus_dmamap_t map; /* the DMA MAP */
|
|
uint32_t phys; /* physical base address */
|
|
uint32_t hdroff; /* chunk header offset */
|
|
uint32_t chunksize; /* chunk size */
|
|
u_int pool; /* pool number */
|
|
};
|
|
struct mbuf_page {
|
|
char storage[MBUF_ALLOC_SIZE - sizeof(struct mbuf_page_hdr)];
|
|
struct mbuf_page_hdr hdr;
|
|
};
|
|
|
|
/* numbers per page */
|
|
#define MBUF0_PER_PAGE ((MBUF_ALLOC_SIZE - sizeof(struct mbuf_page_hdr)) / \
|
|
MBUF0_CHUNK)
|
|
#define MBUF1_PER_PAGE ((MBUF_ALLOC_SIZE - sizeof(struct mbuf_page_hdr)) / \
|
|
MBUF1_CHUNK)
|
|
|
|
/*
|
|
* Convert to/from handles
|
|
*/
|
|
/* small buffers */
|
|
#define MBUF_MAKE_HANDLE(PAGENO, CHUNKNO) \
|
|
((((PAGENO) << 10) | (CHUNKNO)) << HE_REGS_RBRQ_ADDR)
|
|
#define MBUF_MAKE_LHANDLE(INDEX) \
|
|
(MBUF_LARGE_FLAG | ((INDEX) << HE_REGS_RBRQ_ADDR))
|
|
|
|
/* large buffers */
|
|
#define MBUF_PARSE_HANDLE(HANDLE, PAGENO, CHUNKNO) do { \
|
|
(CHUNKNO) = ((HANDLE) >> HE_REGS_RBRQ_ADDR) & 0x3ff; \
|
|
(PAGENO) = (((HANDLE) >> 10) >> HE_REGS_RBRQ_ADDR) & 0x3fff; \
|
|
} while (0)
|
|
#define MBUF_PARSE_LHANDLE(HANDLE, INDEX) do { \
|
|
(INDEX) = ((HANDLE) >> HE_REGS_RBRQ_ADDR) & 0xffffff; \
|
|
} while (0)
|
|
|
|
#define MBUF_LARGE_FLAG 0x80000000
|
|
|
|
/* chunks have the following structure at the end (8 byte) */
|
|
struct mbuf_chunk_hdr {
|
|
uint16_t pageno;
|
|
uint8_t chunkno;
|
|
uint8_t flags;
|
|
u_int ref_cnt;
|
|
};
|
|
#define MBUF_CARD 0x01 /* buffer is on card */
|
|
#define MBUF_USED 0x02 /* buffer is somewhere in the system */
|
|
|
|
#define MBUFX_STORAGE_SIZE(X) (MBUF##X##_CHUNK \
|
|
- sizeof(struct mbuf_chunk_hdr))
|
|
|
|
struct mbuf0_chunk {
|
|
char storage[MBUFX_STORAGE_SIZE(0)];
|
|
struct mbuf_chunk_hdr hdr;
|
|
};
|
|
|
|
struct mbuf1_chunk {
|
|
char storage[MBUFX_STORAGE_SIZE(1)];
|
|
struct mbuf_chunk_hdr hdr;
|
|
};
|
|
|
|
struct mbufx_free {
|
|
struct mbufx_free *link;
|
|
};
|
|
|
|
/*==================================================================*/
|
|
|
|
/*
|
|
* Interrupt queue
|
|
*/
|
|
struct heirq {
|
|
u_int size; /* number of entries */
|
|
u_int thresh; /* re-interrupt threshold */
|
|
u_int line; /* interrupt line to use */
|
|
struct dmamem mem; /* interrupt queues */
|
|
uint32_t * irq; /* interrupt queue */
|
|
uint32_t head; /* head index */
|
|
uint32_t * tailp; /* pointer to tail */
|
|
struct hatm_softc *sc; /* back pointer */
|
|
u_int group; /* interrupt group */
|
|
};
|
|
|
|
/*
|
|
* This structure describes all information for a VCC open on the card.
|
|
* The array of these structures is indexed by the compressed connection ID
|
|
* (CID). This structure must begin with the atmio_vcc.
|
|
*/
|
|
struct hevcc {
|
|
struct atmio_vcc param; /* traffic parameters */
|
|
void * rxhand; /* NATM protocol block */
|
|
u_int vflags; /* private flags */
|
|
uint32_t ipackets;
|
|
uint32_t opackets;
|
|
uint32_t ibytes;
|
|
uint32_t obytes;
|
|
|
|
u_int rc; /* rate control group for CBR */
|
|
struct mbuf * chain; /* partial received PDU */
|
|
struct mbuf * last; /* last mbuf in chain */
|
|
u_int ntpds; /* number of active TPDs */
|
|
};
|
|
#define HE_VCC_OPEN 0x000f0000
|
|
#define HE_VCC_RX_OPEN 0x00010000
|
|
#define HE_VCC_RX_CLOSING 0x00020000
|
|
#define HE_VCC_TX_OPEN 0x00040000
|
|
#define HE_VCC_TX_CLOSING 0x00080000
|
|
#define HE_VCC_FLOW_CTRL 0x00100000
|
|
|
|
/*
|
|
* CBR rate groups
|
|
*/
|
|
struct herg {
|
|
u_int refcnt; /* how many connections reference this group */
|
|
u_int rate; /* the value */
|
|
};
|
|
|
|
/*
|
|
* Softc
|
|
*/
|
|
struct hatm_softc {
|
|
struct ifnet *ifp;
|
|
struct mtx mtx; /* lock */
|
|
struct ifmedia media; /* media */
|
|
device_t dev; /* device */
|
|
int memid; /* resoure id for memory */
|
|
struct resource * memres; /* memory resource */
|
|
bus_space_handle_t memh; /* handle */
|
|
bus_space_tag_t memt; /* ... and tag */
|
|
bus_dma_tag_t parent_tag; /* global restriction */
|
|
struct cv vcc_cv; /* condition variable */
|
|
int irqid; /* resource id */
|
|
struct resource * irqres; /* resource */
|
|
void * ih; /* interrupt handle */
|
|
struct utopia utopia; /* utopia state */
|
|
|
|
/* rest has to be reset by stop */
|
|
int he622; /* this is a HE622 */
|
|
int pci64; /* 64bit bus */
|
|
char prod_id[HE_EEPROM_PROD_ID_LEN + 1];
|
|
char rev[HE_EEPROM_REV_LEN + 1];
|
|
struct heirq irq_0; /* interrupt queues 0 */
|
|
|
|
/* generic network controller state */
|
|
u_int cells_per_row;
|
|
u_int bytes_per_row;
|
|
u_int r0_numrows;
|
|
u_int tx_numrows;
|
|
u_int r1_numrows;
|
|
u_int r0_startrow;
|
|
u_int tx_startrow;
|
|
u_int r1_startrow;
|
|
u_int cells_per_lbuf;
|
|
u_int r0_numbuffs;
|
|
u_int r1_numbuffs;
|
|
u_int tx_numbuffs;
|
|
|
|
/* HSP */
|
|
struct he_hsp *hsp;
|
|
struct dmamem hsp_mem;
|
|
|
|
/*** TX ***/
|
|
struct hetbrq tbrq; /* TBRQ 0 */
|
|
struct hetpdrq tpdrq; /* TPDRQ */
|
|
struct tpd_list tpd_free; /* Free TPDs */
|
|
u_int tpd_nfree; /* number of free TPDs */
|
|
u_int tpd_total; /* total TPDs */
|
|
uint8_t *tpd_used; /* bitmap of used TPDs */
|
|
struct dmamem tpds; /* TPD memory */
|
|
bus_dma_tag_t tx_tag; /* DMA tag for all tx mbufs */
|
|
|
|
/*** RX ***/
|
|
/* receive/transmit groups */
|
|
struct herbp rbp_s0; /* RBPS0 */
|
|
struct herbp rbp_l0; /* RBPL0 */
|
|
struct herbp rbp_s1; /* RBPS1 */
|
|
struct herbrq rbrq_0; /* RBRQ0 */
|
|
struct herbrq rbrq_1; /* RBRQ1 */
|
|
|
|
/* list of external mbuf storage */
|
|
bus_dma_tag_t mbuf_tag;
|
|
struct mbuf_page **mbuf_pages;
|
|
u_int mbuf_npages;
|
|
u_int mbuf_max_pages;
|
|
struct mbufx_free *mbuf_list[2];
|
|
|
|
/* mbuf cluster tracking and mapping for group 0 */
|
|
struct mbuf **lbufs; /* mbufs */
|
|
bus_dmamap_t *rmaps; /* DMA maps */
|
|
u_int lbufs_size;
|
|
u_int lbufs_next;
|
|
|
|
/* VCCs */
|
|
struct hevcc *vccs[HE_MAX_VCCS];
|
|
u_int cbr_bw; /* BW allocated to CBR */
|
|
u_int max_tpd; /* per VCC */
|
|
u_int open_vccs;
|
|
uma_zone_t vcc_zone;
|
|
|
|
/* rate groups */
|
|
struct herg rate_ctrl[HE_REGN_CS_STPER];
|
|
|
|
/* memory offsets */
|
|
u_int tsrb, tsrc, tsrd;
|
|
u_int rsrb;
|
|
|
|
struct cv cv_rcclose; /* condition variable */
|
|
uint32_t rate_grid[16][16]; /* our copy */
|
|
|
|
/* sysctl support */
|
|
struct sysctl_ctx_list sysctl_ctx;
|
|
struct sysctl_oid *sysctl_tree;
|
|
|
|
/* internal statistics */
|
|
struct istats istats;
|
|
|
|
u_int mpsafe;
|
|
|
|
#ifdef HATM_DEBUG
|
|
/* debugging */
|
|
u_int debug;
|
|
|
|
/* transmit mbuf count */
|
|
int txmbuf;
|
|
#endif
|
|
};
|
|
|
|
#define READ4(SC,OFF) bus_space_read_4(SC->memt, SC->memh, (OFF))
|
|
#define READ2(SC,OFF) bus_space_read_2(SC->memt, SC->memh, (OFF))
|
|
#define READ1(SC,OFF) bus_space_read_1(SC->memt, SC->memh, (OFF))
|
|
|
|
#define WRITE4(SC,OFF,VAL) bus_space_write_4(SC->memt, SC->memh, (OFF), (VAL))
|
|
#define WRITE2(SC,OFF,VAL) bus_space_write_2(SC->memt, SC->memh, (OFF), (VAL))
|
|
#define WRITE1(SC,OFF,VAL) bus_space_write_1(SC->memt, SC->memh, (OFF), (VAL))
|
|
|
|
#define BARRIER_R(SC) bus_space_barrier(SC->memt, SC->memh, 0, HE_REGO_END, \
|
|
BUS_SPACE_BARRIER_READ)
|
|
#define BARRIER_W(SC) bus_space_barrier(SC->memt, SC->memh, 0, HE_REGO_END, \
|
|
BUS_SPACE_BARRIER_WRITE)
|
|
#define BARRIER_RW(SC) bus_space_barrier(SC->memt, SC->memh, 0, HE_REGO_END, \
|
|
BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)
|
|
|
|
#define READ_SUNI(SC,OFF) READ4(SC, HE_REGO_SUNI + 4 * (OFF))
|
|
#define WRITE_SUNI(SC,OFF,VAL) WRITE4(SC, HE_REGO_SUNI + 4 * (OFF), (VAL))
|
|
|
|
#define READ_LB4(SC,OFF) \
|
|
({ \
|
|
WRITE4(SC, HE_REGO_LB_MEM_ADDR, (OFF)); \
|
|
WRITE4(SC, HE_REGO_LB_MEM_ACCESS, \
|
|
(HE_REGM_LB_MEM_HNDSHK | HE_REGM_LB_MEM_READ)); \
|
|
while((READ4(SC, HE_REGO_LB_MEM_ACCESS) & HE_REGM_LB_MEM_HNDSHK))\
|
|
; \
|
|
READ4(SC, HE_REGO_LB_MEM_DATA); \
|
|
})
|
|
#define WRITE_LB4(SC,OFF,VAL) \
|
|
do { \
|
|
WRITE4(SC, HE_REGO_LB_MEM_ADDR, (OFF)); \
|
|
WRITE4(SC, HE_REGO_LB_MEM_DATA, (VAL)); \
|
|
WRITE4(SC, HE_REGO_LB_MEM_ACCESS, \
|
|
(HE_REGM_LB_MEM_HNDSHK | HE_REGM_LB_MEM_WRITE)); \
|
|
while((READ4(SC, HE_REGO_LB_MEM_ACCESS) & HE_REGM_LB_MEM_HNDSHK))\
|
|
; \
|
|
} while(0)
|
|
|
|
#define WRITE_MEM4(SC,OFF,VAL,SPACE) \
|
|
do { \
|
|
WRITE4(SC, HE_REGO_CON_DAT, (VAL)); \
|
|
WRITE4(SC, HE_REGO_CON_CTL, \
|
|
(SPACE | HE_REGM_CON_WE | HE_REGM_CON_STATUS | (OFF))); \
|
|
while((READ4(SC, HE_REGO_CON_CTL) & HE_REGM_CON_STATUS) != 0) \
|
|
; \
|
|
} while(0)
|
|
|
|
#define READ_MEM4(SC,OFF,SPACE) \
|
|
({ \
|
|
WRITE4(SC, HE_REGO_CON_CTL, \
|
|
(SPACE | HE_REGM_CON_STATUS | (OFF))); \
|
|
while((READ4(SC, HE_REGO_CON_CTL) & HE_REGM_CON_STATUS) != 0) \
|
|
; \
|
|
READ4(SC, HE_REGO_CON_DAT); \
|
|
})
|
|
|
|
#define WRITE_TCM4(SC,OFF,VAL) WRITE_MEM4(SC,(OFF),(VAL),HE_REGM_CON_TCM)
|
|
#define WRITE_RCM4(SC,OFF,VAL) WRITE_MEM4(SC,(OFF),(VAL),HE_REGM_CON_RCM)
|
|
#define WRITE_MBOX4(SC,OFF,VAL) WRITE_MEM4(SC,(OFF),(VAL),HE_REGM_CON_MBOX)
|
|
|
|
#define READ_TCM4(SC,OFF) READ_MEM4(SC,(OFF),HE_REGM_CON_TCM)
|
|
#define READ_RCM4(SC,OFF) READ_MEM4(SC,(OFF),HE_REGM_CON_RCM)
|
|
#define READ_MBOX4(SC,OFF) READ_MEM4(SC,(OFF),HE_REGM_CON_MBOX)
|
|
|
|
#define WRITE_TCM(SC,OFF,BYTES,VAL) \
|
|
WRITE_MEM4(SC,(OFF) | ((~(BYTES) & 0xf) << HE_REGS_CON_DIS), \
|
|
(VAL), HE_REGM_CON_TCM)
|
|
#define WRITE_RCM(SC,OFF,BYTES,VAL) \
|
|
WRITE_MEM4(SC,(OFF) | ((~(BYTES) & 0xf) << HE_REGS_CON_DIS), \
|
|
(VAL), HE_REGM_CON_RCM)
|
|
|
|
#define READ_TSR(SC,CID,NR) \
|
|
({ \
|
|
uint32_t _v; \
|
|
if((NR) <= 7) { \
|
|
_v = READ_TCM4(SC, HE_REGO_TSRA(0,CID,NR)); \
|
|
} else if((NR) <= 11) { \
|
|
_v = READ_TCM4(SC, HE_REGO_TSRB((SC)->tsrb,CID,(NR-8)));\
|
|
} else if((NR) <= 13) { \
|
|
_v = READ_TCM4(SC, HE_REGO_TSRC((SC)->tsrc,CID,(NR-12)));\
|
|
} else { \
|
|
_v = READ_TCM4(SC, HE_REGO_TSRD((SC)->tsrd,CID)); \
|
|
} \
|
|
_v; \
|
|
})
|
|
|
|
#define WRITE_TSR(SC,CID,NR,BEN,VAL) \
|
|
do { \
|
|
if((NR) <= 7) { \
|
|
WRITE_TCM(SC, HE_REGO_TSRA(0,CID,NR),BEN,VAL); \
|
|
} else if((NR) <= 11) { \
|
|
WRITE_TCM(SC, HE_REGO_TSRB((SC)->tsrb,CID,(NR-8)),BEN,VAL);\
|
|
} else if((NR) <= 13) { \
|
|
WRITE_TCM(SC, HE_REGO_TSRC((SC)->tsrc,CID,(NR-12)),BEN,VAL);\
|
|
} else { \
|
|
WRITE_TCM(SC, HE_REGO_TSRD((SC)->tsrd,CID),BEN,VAL); \
|
|
} \
|
|
} while(0)
|
|
|
|
#define READ_RSR(SC,CID,NR) \
|
|
({ \
|
|
uint32_t _v; \
|
|
if((NR) <= 7) { \
|
|
_v = READ_RCM4(SC, HE_REGO_RSRA(0,CID,NR)); \
|
|
} else { \
|
|
_v = READ_RCM4(SC, HE_REGO_RSRB((SC)->rsrb,CID,(NR-8)));\
|
|
} \
|
|
_v; \
|
|
})
|
|
|
|
#define WRITE_RSR(SC,CID,NR,BEN,VAL) \
|
|
do { \
|
|
if((NR) <= 7) { \
|
|
WRITE_RCM(SC, HE_REGO_RSRA(0,CID,NR),BEN,VAL); \
|
|
} else { \
|
|
WRITE_RCM(SC, HE_REGO_RSRB((SC)->rsrb,CID,(NR-8)),BEN,VAL);\
|
|
} \
|
|
} while(0)
|
|
|
|
#ifdef HATM_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)
|
|
|
|
enum {
|
|
DBG_DUMMY = 0x0001, /* default value for -DHATM_DEBUG */
|
|
DBG_RX = 0x0002,
|
|
DBG_TX = 0x0004,
|
|
DBG_VCC = 0x0008,
|
|
DBG_IOCTL = 0x0010,
|
|
DBG_ATTACH = 0x0020,
|
|
DBG_INTR = 0x0040,
|
|
DBG_DMA = 0x0080,
|
|
DBG_DMAH = 0x0100,
|
|
DBG_DUMP = 0x0200,
|
|
|
|
DBG_ALL = 0x03ff
|
|
};
|
|
|
|
#else
|
|
#define DBG(SC, FL, PRINT)
|
|
#endif
|
|
|
|
u_int hatm_cps2atmf(uint32_t);
|
|
u_int hatm_atmf2cps(uint32_t);
|
|
|
|
void hatm_intr(void *);
|
|
int hatm_ioctl(struct ifnet *, u_long, caddr_t);
|
|
void hatm_initialize(struct hatm_softc *);
|
|
void hatm_stop(struct hatm_softc *sc);
|
|
void hatm_start(struct ifnet *);
|
|
|
|
void hatm_rx(struct hatm_softc *sc, u_int cid, u_int flags, struct mbuf *m,
|
|
u_int len);
|
|
void hatm_tx_complete(struct hatm_softc *sc, struct tpd *tpd, uint32_t);
|
|
|
|
int hatm_tx_vcc_can_open(struct hatm_softc *sc, u_int cid, struct hevcc *);
|
|
void hatm_tx_vcc_open(struct hatm_softc *sc, u_int cid);
|
|
void hatm_rx_vcc_open(struct hatm_softc *sc, u_int cid);
|
|
void hatm_tx_vcc_close(struct hatm_softc *sc, u_int cid);
|
|
void hatm_rx_vcc_close(struct hatm_softc *sc, u_int cid);
|
|
void hatm_tx_vcc_closed(struct hatm_softc *sc, u_int cid);
|
|
void hatm_vcc_closed(struct hatm_softc *sc, u_int cid);
|
|
void hatm_load_vc(struct hatm_softc *sc, u_int cid, int reopen);
|
|
|
|
void hatm_ext_free(struct mbufx_free **, struct mbufx_free *);
|