diff options
author | Can Erkin Acar <canacar@cvs.openbsd.org> | 2005-11-08 20:23:43 +0000 |
---|---|---|
committer | Can Erkin Acar <canacar@cvs.openbsd.org> | 2005-11-08 20:23:43 +0000 |
commit | 54acae808a4b1ba4d3c4a749c2b76e13f868d108 (patch) | |
tree | 436a684f1ff7e262102b49cb799e39ccbb0ba851 /sys/dev/pci | |
parent | 060f79aa9651e40c6acf3089c2223bce1b15243c (diff) |
Use bus_dma(9) in san(4). Now works on amd64. Still works on i386
as tested extensively by Greg Mortensen, many thanks. ok brad@
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/if_san_common.c | 10 | ||||
-rw-r--r-- | sys/dev/pci/if_san_common.h | 4 | ||||
-rw-r--r-- | sys/dev/pci/if_san_xilinx.c | 484 |
3 files changed, 305 insertions, 193 deletions
diff --git a/sys/dev/pci/if_san_common.c b/sys/dev/pci/if_san_common.c index bbdf75d0c3c..6fc69e2d1ff 100644 --- a/sys/dev/pci/if_san_common.c +++ b/sys/dev/pci/if_san_common.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_san_common.c,v 1.10 2005/09/14 05:08:05 canacar Exp $ */ +/* $OpenBSD: if_san_common.c,v 1.11 2005/11/08 20:23:42 canacar Exp $ */ /*- * Copyright (c) 2001-2004 Sangoma Technologies (SAN) @@ -397,8 +397,8 @@ wan_mbuf_alloc(int len) if (m == NULL || len <= MHLEN) return (m); - m->m_pkthdr.len = 0; - m->m_len = 0; + m->m_pkthdr.len = len; + m->m_len = len; MCLGET(m, M_DONTWAIT); if ((m->m_flags & M_EXT) == 0) { @@ -447,8 +447,8 @@ wan_mbuf_to_buffer(struct mbuf **m_org) buffer += 16; /* make sure the buffer is aligned to a 4-byte boundary */ - if (mtod(m, u_int32_t) & 0x03) { - unsigned int inc = 4 - (mtod(m, u_int32_t) & 0x03); + if (ADDR_MASK(buffer, 0x03)) { + unsigned int inc = 4 - ADDR_MASK(buffer, 0x03); buffer += inc; len -= inc; } diff --git a/sys/dev/pci/if_san_common.h b/sys/dev/pci/if_san_common.h index cc449b0547f..762969f42fd 100644 --- a/sys/dev/pci/if_san_common.h +++ b/sys/dev/pci/if_san_common.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_san_common.h,v 1.7 2005/04/01 21:42:36 canacar Exp $ */ +/* $OpenBSD: if_san_common.h,v 1.8 2005/11/08 20:23:42 canacar Exp $ */ /*- * Copyright (c) 2001-2004 Sangoma Technologies (SAN) @@ -38,6 +38,8 @@ # include <dev/pci/if_san_te1.h> # include <dev/pci/if_sandrv.h> +#define ADDR_MASK(x,y) (((caddr_t)(x) - (caddr_t)0) & (y)) + #define WANPIPE_LITE_VERSION "1.1.1" #define WAN_OPENBSD_PLATFORM 0x06 #define WAN_PLATFORM_ID WAN_OPENBSD_PLATFORM diff --git a/sys/dev/pci/if_san_xilinx.c b/sys/dev/pci/if_san_xilinx.c index 994a2135158..5bd51d76fbd 100644 --- a/sys/dev/pci/if_san_xilinx.c +++ b/sys/dev/pci/if_san_xilinx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_san_xilinx.c,v 1.14 2005/09/17 15:10:31 canacar Exp $ */ +/* $OpenBSD: if_san_xilinx.c,v 1.15 2005/11/08 20:23:42 canacar Exp $ */ /*- * Copyright (c) 2001-2004 Sangoma Technologies (SAN) @@ -97,6 +97,15 @@ enum { static int aft_rx_copyback = MHLEN; +struct xilinx_rx_buffer { + SIMPLEQ_ENTRY(xilinx_rx_buffer) entry; + struct mbuf *mbuf; + bus_dmamap_t dma_map; + wp_rx_element_t rx_el; +}; + +SIMPLEQ_HEAD(xilinx_rx_head, xilinx_rx_buffer); + /* * This structure is placed in the private data area of the device structure. * The card structure used to occupy the private area but now the following @@ -106,17 +115,19 @@ static int aft_rx_copyback = MHLEN; typedef struct { wanpipe_common_t common; - struct ifqueue wp_tx_free_list; struct ifqueue wp_tx_pending_list; struct ifqueue wp_tx_complete_list; - struct ifqueue wp_rx_free_list; - struct ifqueue wp_rx_complete_list; - + struct xilinx_rx_head wp_rx_free_list; + struct xilinx_rx_head wp_rx_complete_list; + struct xilinx_rx_buffer *wp_rx_buffers; + struct xilinx_rx_buffer *wp_rx_buffer_last; + struct xilinx_rx_buffer *rx_dma_buf; + + bus_dma_tag_t dmatag; + bus_dmamap_t tx_dmamap; struct mbuf *tx_dma_mbuf; u_int8_t tx_dma_cnt; - struct mbuf *rx_dma_mbuf; - unsigned long time_slot_map; unsigned char num_of_time_slots; long logic_ch_num; @@ -150,7 +161,6 @@ typedef struct { int first_time_slot; - struct mbuf *tx_idle_mbuf; unsigned long tx_dma_addr; unsigned int tx_dma_len; unsigned char rx_dma; @@ -231,7 +241,7 @@ static int xilinx_init_tx_dev_fifo(sdla_t *, xilinx_softc_t *, static void xilinx_tx_post_complete(sdla_t *, xilinx_softc_t *, struct mbuf *); static void xilinx_rx_post_complete(sdla_t *, xilinx_softc_t *, - struct mbuf *, struct mbuf **, unsigned char *); + struct xilinx_rx_buffer *, struct mbuf **, u_char *); static char request_xilinx_logical_channel_num(sdla_t *, xilinx_softc_t *, @@ -262,9 +272,15 @@ static int free_fifo_baddr_and_size(sdla_t *, xilinx_softc_t *); static void aft_red_led_ctrl(sdla_t *, int); static void aft_led_timer(void *); -static int aft_alloc_rx_dma_buff(sdla_t *, xilinx_softc_t *, int); -static int aft_init_requeue_free_m(xilinx_softc_t *, struct mbuf *); static int aft_core_ready(sdla_t *); +static int aft_alloc_rx_buffers(xilinx_softc_t *); +static void aft_release_rx_buffers(xilinx_softc_t *); +static int aft_alloc_rx_dma_buff(xilinx_softc_t *, int); +static void aft_reload_rx_dma_buff(xilinx_softc_t *, + struct xilinx_rx_buffer *); +static void aft_release_rx_dma_buff(xilinx_softc_t *, + struct xilinx_rx_buffer *); + /* TE1 Control registers */ static WRITE_FRONT_END_REG_T write_front_end_reg; @@ -343,17 +359,14 @@ wan_xilinx_init(sdla_t *card) strlcpy(sc->if_name, ifp->if_xname, IFNAMSIZ); sc->first_time_slot = -1; sc->time_slot_map = 0; + sdla_getcfg(card->hw, SDLA_DMATAG, &sc->dmatag); - IFQ_SET_MAXLEN(&sc->wp_tx_free_list, MAX_TX_BUF); - sc->wp_tx_free_list.ifq_len = 0; IFQ_SET_MAXLEN(&sc->wp_tx_pending_list, MAX_TX_BUF); sc->wp_tx_pending_list.ifq_len = 0; IFQ_SET_MAXLEN(&sc->wp_tx_complete_list, MAX_TX_BUF); sc->wp_tx_complete_list.ifq_len = 0; - IFQ_SET_MAXLEN(&sc->wp_rx_free_list, MAX_RX_BUF); - sc->wp_rx_free_list.ifq_len = 0; - IFQ_SET_MAXLEN(&sc->wp_rx_complete_list, MAX_RX_BUF); - sc->wp_rx_complete_list.ifq_len = 0; + + aft_alloc_rx_buffers(sc); xilinx_delay(1); @@ -389,9 +402,6 @@ wan_xilinx_release(sdla_t* card, struct ifnet* ifp) { xilinx_softc_t *sc = ifp->if_softc; - IF_PURGE(&sc->wp_rx_free_list); - IF_PURGE(&sc->wp_rx_complete_list); - IF_PURGE(&sc->wp_tx_free_list); IF_PURGE(&sc->wp_tx_pending_list); if (sc->tx_dma_addr && sc->tx_dma_len) { @@ -401,20 +411,21 @@ wan_xilinx_release(sdla_t* card, struct ifnet* ifp) if (sc->tx_dma_mbuf) { log(LOG_INFO, "freeing tx dma mbuf\n"); + bus_dmamap_unload(sc->dmatag, sc->tx_dmamap); m_freem(sc->tx_dma_mbuf); sc->tx_dma_mbuf = NULL; } - if (sc->tx_idle_mbuf) { - log(LOG_INFO, "freeing idle tx dma mbuf\n"); - m_freem(sc->tx_idle_mbuf); - sc->tx_idle_mbuf = NULL; +#if 0 + bus_dmamap_destroy(sc->dmatag, sc->tx_dmamap); +#endif + if (sc->rx_dma_buf) { + SIMPLEQ_INSERT_TAIL(&sc->wp_rx_free_list, + sc->rx_dma_buf, entry); + sc->rx_dma_buf = NULL; } - if (sc->rx_dma_mbuf) { - m_freem(sc->rx_dma_mbuf); - sc->rx_dma_mbuf = NULL; - } + aft_release_rx_buffers(sc); wanpipe_generic_unregister(ifp); ifp->if_softc = NULL; @@ -483,9 +494,15 @@ wan_xilinx_up(struct ifnet *ifp) log(LOG_INFO, "%s: Allocating %d dma mbuf len=%d\n", card->devname, card->u.xilinx.dma_per_ch, sc->dma_mtu); #endif - err = aft_alloc_rx_dma_buff(card, sc, card->u.xilinx.dma_per_ch); - if (err) - return (EINVAL); + if (aft_alloc_rx_dma_buff(sc, card->u.xilinx.dma_per_ch) == 0) + return (ENOMEM); + + if (bus_dmamap_create(sc->dmatag, sc->dma_mtu, 1, sc->dma_mtu, + 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->tx_dmamap)) { + log(LOG_INFO, "%s: Failed to allocate tx dmamap\n", + sc->if_name); + return (ENOMEM); + } err = xilinx_chip_configure(card); if (err) @@ -521,7 +538,7 @@ wan_xilinx_down(struct ifnet *ifp) { xilinx_softc_t *sc = ifp->if_softc; sdla_t *card = (sdla_t *)sc->common.card; - struct mbuf *m; + struct xilinx_rx_buffer *buf; int s; if (card->state == WAN_DISCONNECTED) @@ -552,30 +569,29 @@ wan_xilinx_down(struct ifnet *ifp) } if (sc->tx_dma_mbuf) { + bus_dmamap_unload(sc->dmatag, sc->tx_dmamap); m_freem(sc->tx_dma_mbuf); sc->tx_dma_mbuf = NULL; } - if (sc->tx_idle_mbuf) { - m_freem(sc->tx_idle_mbuf); - sc->tx_idle_mbuf = NULL; + bus_dmamap_destroy(sc->dmatag, sc->tx_dmamap); + + /* If there is something left in rx_dma_buf, then move it to + * rx_free_list. + */ + if (sc->rx_dma_buf) { + aft_reload_rx_dma_buff(sc, sc->rx_dma_buf); + sc->rx_dma_buf = NULL; } - /* If there is something left in rx_dma_buf, then - ** move it to rx_free_list. */ - if (sc->rx_dma_mbuf) { - m = sc->rx_dma_mbuf; - aft_init_requeue_free_m(sc, m); - sc->rx_dma_mbuf = NULL; + while ((buf = SIMPLEQ_FIRST(&sc->wp_rx_free_list)) != NULL) { + SIMPLEQ_REMOVE_HEAD(&sc->wp_rx_free_list, entry); + aft_release_rx_dma_buff(sc, buf); } - /* If there is something in rx_complete_list, then - ** move evething to rx_free_list. */ - for (;;) { - IF_DEQUEUE(&sc->wp_rx_complete_list, m); - if (m == NULL) - break; - IF_ENQUEUE(&sc->wp_rx_free_list, m); + while ((buf = SIMPLEQ_FIRST(&sc->wp_rx_complete_list)) != NULL) { + SIMPLEQ_REMOVE_HEAD(&sc->wp_rx_complete_list, entry); + aft_release_rx_dma_buff(sc, buf); } splx(s); @@ -1653,30 +1669,32 @@ xilinx_dma_rx(sdla_t *card, xilinx_softc_t *sc) } #endif - if (sc->rx_dma_mbuf) { + if (sc->rx_dma_buf) { log(LOG_INFO, "%s: Critial Error: Rx Dma Buf busy!\n", sc->if_name); return (EINVAL); } - IF_DEQUEUE(&sc->wp_rx_free_list, sc->rx_dma_mbuf); + sc->rx_dma_buf = SIMPLEQ_FIRST(&sc->wp_rx_free_list); - if (!sc->rx_dma_mbuf) { - log(LOG_INFO, "%s: Critical Error no rx dma buf " - "Free=%d Comp=%d!\n", sc->if_name, - sc->wp_rx_free_list.ifq_len, - sc->wp_rx_complete_list.ifq_len); - return (ENOMEM); + if (sc->rx_dma_buf == NULL) { + if (aft_alloc_rx_dma_buff(sc, 1) == 0) { + log(LOG_INFO, "%s: Critical Error no rx dma buf!", + sc->if_name); + return (ENOMEM); + } + sc->rx_dma_buf = SIMPLEQ_FIRST(&sc->wp_rx_free_list); } - rx_el = mtod(sc->rx_dma_mbuf, wp_rx_element_t *); - sc->rx_dma_mbuf->m_len = sizeof(wp_rx_element_t); - sc->rx_dma_mbuf->m_pkthdr.len = sc->rx_dma_mbuf->m_len; - memset(rx_el, 0, sizeof(wp_rx_element_t)); + SIMPLEQ_REMOVE_HEAD(&sc->wp_rx_free_list, entry); - bus_addr = kvtop(mtod(sc->rx_dma_mbuf, caddr_t) + - sc->rx_dma_mbuf->m_len); + bus_dmamap_sync(sc->dmatag, sc->rx_dma_buf->dma_map, 0, sc->dma_mtu, + BUS_DMASYNC_PREREAD); + rx_el = &sc->rx_dma_buf->rx_el; + memset(rx_el, 0, sizeof(*rx_el)); + + bus_addr = sc->rx_dma_buf->dma_map->dm_segs[0].ds_addr; rx_el->dma_addr = bus_addr; /* Write the pointer of the data packet to the @@ -1768,8 +1786,7 @@ xilinx_dma_tx(sdla_t *card, xilinx_softc_t *sc) * minimize tx isr, the previously transmitted * packet is deallocated here */ if (sc->tx_dma_mbuf) { - log(LOG_INFO, "%s: Deallocating tx_dma_mbuf in %s\n", - sc->if_name, __FUNCTION__); + bus_dmamap_unload(sc->dmatag, sc->tx_dmamap); m_freem(sc->tx_dma_mbuf); sc->tx_dma_mbuf = NULL; } @@ -1798,39 +1815,45 @@ xilinx_dma_tx(sdla_t *card, xilinx_softc_t *sc) if (!m) { bit_clear((u_int8_t *)&sc->dma_status, TX_BUSY); return (ENOBUFS); - } else { - len = m->m_len; - if (len > MAX_XILINX_TX_DMA_SIZE) { - /* FIXME: We need to split this frame into - * multiple parts. For now though - * just drop it :) */ - log(LOG_INFO, "%s: Tx len %d > %d (MAX TX DMA LEN)\n", - sc->if_name, len, MAX_XILINX_TX_DMA_SIZE); - m_freem(m); - bit_clear((u_int8_t *)&sc->dma_status, TX_BUSY); - return (EINVAL); - } + } - if (mtod(m, u_int32_t) & 0x03) { - /* The mbuf should already be aligned */ - log(LOG_INFO, "%s: TX packet not aligned!\n", - sc->if_name, MAX_XILINX_TX_DMA_SIZE); - m_freem(m); - bit_clear((u_int8_t *)&sc->dma_status, TX_BUSY); - return (EINVAL); - } - - sc->tx_dma_addr = kvtop(mtod(m, caddr_t)); - sc->tx_dma_len = len; + len = m->m_len; + if (len > MAX_XILINX_TX_DMA_SIZE) { + /* FIXME: We need to split this frame into + * multiple parts. For now though + * just drop it :) */ + log(LOG_INFO, "%s: Tx len %d > %d (MAX TX DMA LEN)\n", + sc->if_name, len, MAX_XILINX_TX_DMA_SIZE); + m_freem(m); + bit_clear((u_int8_t *)&sc->dma_status, TX_BUSY); + return (EINVAL); + } + + if (ADDR_MASK(mtod(m, caddr_t), 0x03)) { + /* The mbuf should already be aligned */ + log(LOG_INFO, "%s: TX packet not aligned!\n", + sc->if_name, MAX_XILINX_TX_DMA_SIZE); + m_freem(m); + bit_clear((u_int8_t *)&sc->dma_status, TX_BUSY); + return (EINVAL); } + if (bus_dmamap_load(sc->dmatag, sc->tx_dmamap, + mtod(m, void *), len, NULL, BUS_DMA_NOWAIT | BUS_DMA_WRITE)) { + log(LOG_INFO, "%s: Failed to load TX mbuf for DMA!\n", + sc->if_name); + m_freem(m); + bit_clear((u_int8_t *)&sc->dma_status, TX_BUSY); + return (EINVAL); + } + + sc->tx_dma_addr = sc->tx_dmamap->dm_segs[0].ds_addr; + sc->tx_dma_len = len; + if (sc->tx_dma_addr & 0x03) { log(LOG_INFO, "%s: Error: Tx Ptr not aligned " "to 32bit boundary!\n", card->devname); - - if (m) - m_freem(m); - + m_freem(m); bit_clear((u_int8_t *)&sc->dma_status, TX_BUSY); return (EINVAL); } @@ -1847,6 +1870,9 @@ xilinx_dma_tx(sdla_t *card, xilinx_softc_t *sc) * DMA address register */ reg = sc->tx_dma_addr; + bus_dmamap_sync(sc->dmatag, sc->tx_dmamap, 0, len, + BUS_DMASYNC_PREWRITE); + /* Set the 32bit alignment of the data length. * Used to pad the tx packet to the 32 bit * boundary */ @@ -1913,50 +1939,52 @@ xilinx_dma_tx_complete(sdla_t *card, xilinx_softc_t *sc) dma_descr = (sc->logic_ch_num << 4) + XILINX_TxDMA_DESCRIPTOR_HI; sdla_bus_read_4(card->hw, dma_descr, ®); - if (!sc->tx_dma_mbuf) { + if (sc->tx_dma_mbuf == NULL) { log(LOG_INFO, "%s: Critical Error: Tx DMA intr: no tx mbuf !\n", card->devname); bit_clear((u_int8_t *)&sc->dma_status, TX_BUSY); return; - } else { - sc->tx_dma_addr = 0; - sc->tx_dma_len = 0; + } + bus_dmamap_sync(sc->dmatag, sc->tx_dmamap, 0, sc->tx_dma_len, + BUS_DMASYNC_POSTWRITE); - /* Do not free the packet here, - * copy the packet dma info into csum - * field and let the bh handler analyze - * the transmitted packet. - */ + sc->tx_dma_addr = 0; + sc->tx_dma_len = 0; - if (reg & TxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT) { - log(LOG_INFO, "%s:%s: PCI Error: 'Retry' " - "exceeds maximum (64k): Reg=0x%X!\n", - card->devname, sc->if_name, reg); + /* Do not free the packet here, + * copy the packet dma info into csum + * field and let the bh handler analyze + * the transmitted packet. + */ - if (++sc->pci_retry < 3) { - bit_set((u_int8_t *)®, - TxDMA_HI_DMA_GO_READY_BIT); + if (reg & TxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT) { + log(LOG_INFO, "%s:%s: PCI Error: 'Retry' " + "exceeds maximum (64k): Reg=0x%X!\n", + card->devname, sc->if_name, reg); - log(LOG_INFO, "%s: Retry: TXDMA_HI=0x%X " - "DmaDescr=0x%lX (%s)\n", - sc->if_name, reg, dma_descr, __FUNCTION__); + if (++sc->pci_retry < 3) { + bit_set((u_int8_t *)®, + TxDMA_HI_DMA_GO_READY_BIT); - sdla_bus_write_4(card->hw, dma_descr, reg); - return; - } + log(LOG_INFO, "%s: Retry: TXDMA_HI=0x%X " + "DmaDescr=0x%lX (%s)\n", + sc->if_name, reg, dma_descr, __FUNCTION__); + + sdla_bus_write_4(card->hw, dma_descr, reg); + return; } + } - sc->pci_retry = 0; - sc->tx_dma_mbuf->m_pkthdr.csum_flags = reg; - IF_ENQUEUE(&sc->wp_tx_complete_list, sc->tx_dma_mbuf); - sc->tx_dma_mbuf = NULL; + sc->pci_retry = 0; + sc->tx_dma_mbuf->m_pkthdr.csum_flags = reg; + IF_ENQUEUE(&sc->wp_tx_complete_list, sc->tx_dma_mbuf); + sc->tx_dma_mbuf = NULL; - bit_clear((u_int8_t *)&sc->dma_status, TX_BUSY); + bit_clear((u_int8_t *)&sc->dma_status, TX_BUSY); - xilinx_process_packet(sc); - } + xilinx_process_packet(sc); } static void @@ -2040,19 +2068,19 @@ tx_post_exit: static void xilinx_dma_rx_complete(sdla_t *card, xilinx_softc_t *sc) { + struct xilinx_rx_buffer *buf; unsigned long dma_descr; - struct mbuf *m; wp_rx_element_t *rx_el; bit_clear((u_int8_t *)&sc->rx_dma, 0); - if (!sc->rx_dma_mbuf) { + if (sc->rx_dma_buf == NULL) { log(LOG_INFO, "%s: Critical Error: rx_dma_mbuf\n", sc->if_name); return; } - rx_el = mtod(sc->rx_dma_mbuf, wp_rx_element_t *); + rx_el = &sc->rx_dma_buf->rx_el; /* Reading Rx DMA descriptor information */ dma_descr=(sc->logic_ch_num << 4) + XILINX_RxDMA_DESCRIPTOR_LO; @@ -2071,12 +2099,12 @@ xilinx_dma_rx_complete(sdla_t *card, xilinx_softc_t *sc) __FUNCTION__, __LINE__); #endif - m = sc->rx_dma_mbuf; - sc->rx_dma_mbuf = NULL; + buf = sc->rx_dma_buf; + sc->rx_dma_buf = NULL; xilinx_dma_rx(card, sc); - IF_ENQUEUE(&sc->wp_rx_complete_list, m); + SIMPLEQ_INSERT_TAIL(&sc->wp_rx_complete_list, buf, entry); xilinx_process_packet(sc); @@ -2086,11 +2114,12 @@ xilinx_dma_rx_complete(sdla_t *card, xilinx_softc_t *sc) static void xilinx_rx_post_complete(sdla_t *card, xilinx_softc_t *sc, - struct mbuf *m, struct mbuf **new_m, unsigned char *pkt_error) + struct xilinx_rx_buffer *buf, struct mbuf **new_m, u_char *pkt_error) { struct ifnet *ifp; unsigned int len, data_error = 0; - wp_rx_element_t *rx_el = mtod(m, wp_rx_element_t *); + wp_rx_element_t *rx_el = &buf->rx_el; + struct mbuf *m = buf->mbuf; WAN_ASSERT1(sc == NULL); ifp = (struct ifnet *)&sc->common.ifp; /*m->m_pkthdr.rcvif;*/ @@ -2114,7 +2143,7 @@ xilinx_rx_post_complete(sdla_t *card, xilinx_softc_t *sc, } /* Checking Rx DMA PCI error status. Has to be '0's */ - if (rx_el->reg&RxDMA_HI_DMA_PCI_ERROR_MASK) { + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_MASK) { #ifdef DEBUG_ERR if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_M_ABRT) log(LOG_INFO, "%s: Rx Error: Abort from Master: " @@ -2225,42 +2254,34 @@ xilinx_rx_post_complete(sdla_t *card, xilinx_softc_t *sc, } } + bus_dmamap_sync(sc->dmatag, sc->rx_dma_buf->dma_map, 0, len, + BUS_DMASYNC_POSTREAD); + + m->m_len = m->m_pkthdr.len = len; + if (len > aft_rx_copyback) { /* The rx size is big enough, thus * send this buffer up the stack * and allocate another one */ - memset(mtod(m, caddr_t), 0, sizeof(wp_rx_element_t)); - m->m_len += len; - m->m_pkthdr.len = m->m_len; - m_adj(m, sizeof(wp_rx_element_t)); *new_m = m; - - aft_alloc_rx_dma_buff(card, sc, 1); + buf->mbuf = NULL; } else { - struct mbuf *m0; + struct mbuf *m0; /* The rx packet is very * small thus, allocate a new * buffer and pass it up */ - m0 = wan_mbuf_alloc(len); - if (m0 == NULL) { + if ((m0 = m_copym2(m, 0, len, M_NOWAIT)) == NULL) { log(LOG_INFO, "%s: Failed to allocate mbuf!\n", sc->if_name); if (ifp) ifp->if_ierrors++; - goto rx_comp_error; - } - - m0->m_len = m0->m_pkthdr.len = len; - memcpy(mtod(m0, caddr_t), mtod(m, caddr_t) + m->m_len, len); - *new_m = m0; - aft_init_requeue_free_m(sc, m); + } else + *new_m = m0; } - return; - -rx_comp_error: + rx_comp_error: + aft_reload_rx_dma_buff(sc, buf); - aft_init_requeue_free_m(sc, m); return; } @@ -2363,36 +2384,131 @@ xilinx_dma_max_logic_ch(sdla_t *card) } static int -aft_init_requeue_free_m(xilinx_softc_t *sc, struct mbuf *m) +aft_alloc_rx_buffers(xilinx_softc_t *sc) { - int err; + struct xilinx_rx_buffer *buf; - m->m_data = (m->m_flags & M_EXT) ? m->m_ext.ext_buf : m->m_pktdat; - m->m_pkthdr.len = m->m_len = 0; + SIMPLEQ_INIT(&sc->wp_rx_free_list); + SIMPLEQ_INIT(&sc->wp_rx_complete_list); - memset(mtod(m, caddr_t), 0, sizeof(wp_rx_element_t)); - IF_ENQUEUE(&sc->wp_rx_free_list, m); + /* allocate receive buffers in one cluster */ + buf = malloc(sizeof(*buf) * MAX_RX_BUF, M_DEVBUF, M_NOWAIT); + if (buf == NULL) + return (1); - return (err); + bzero(buf, sizeof(*buf) * MAX_RX_BUF); + sc->wp_rx_buffers = buf; + sc->wp_rx_buffer_last = buf; + + return (0); } +static void +aft_release_rx_buffers(xilinx_softc_t *sc) +{ + struct xilinx_rx_buffer *buf; + + if (sc->wp_rx_buffers == NULL) { + printf("%s: release_rx_buffers called with no buffers!\n", + sc->if_name, MAX_RX_BUF, sizeof(*buf), (void *)buf); + return; + } + + while ((buf = SIMPLEQ_FIRST(&sc->wp_rx_free_list)) != NULL) { + SIMPLEQ_REMOVE_HEAD(&sc->wp_rx_free_list, entry); + aft_release_rx_dma_buff(sc, buf); + } + + while ((buf = SIMPLEQ_FIRST(&sc->wp_rx_complete_list)) != NULL) { + SIMPLEQ_REMOVE_HEAD(&sc->wp_rx_complete_list, entry); + aft_release_rx_dma_buff(sc, buf); + } + + free(sc->wp_rx_buffers, M_DEVBUF); + + sc->wp_rx_buffers = NULL; + sc->wp_rx_buffer_last = NULL; +} + +/* Allocate an mbuf and setup dma_map. */ static int -aft_alloc_rx_dma_buff(sdla_t *card, xilinx_softc_t *sc, int num) +aft_alloc_rx_dma_buff(xilinx_softc_t *sc, int num) { - int i; - struct mbuf *m; + struct xilinx_rx_buffer *buf, *ebuf; + int n; - for (i = 0; i < num; i++) { - m = wan_mbuf_alloc(sc->dma_mtu); - if (m == NULL) { - log(LOG_INFO, "%s: %s no memory\n", - sc->if_name, __FUNCTION__); - return (ENOMEM); + ebuf = sc->wp_rx_buffers + MAX_RX_BUF; + buf = sc->wp_rx_buffer_last; + + for (n = 0; n < num; n++) { + int i; + for (i = 0; i < MAX_RX_BUF; i++) { + if (buf->mbuf == NULL) + break; + if (++buf == ebuf) + buf = sc->wp_rx_buffers; } - IF_ENQUEUE(&sc->wp_rx_free_list, m); + + if (buf->mbuf != NULL) + break; + + sc->wp_rx_buffer_last = buf; + + buf->mbuf = wan_mbuf_alloc(sc->dma_mtu); + if (buf->mbuf == NULL) + break; + + if (bus_dmamap_create(sc->dmatag, sc->dma_mtu, 1, sc->dma_mtu, + 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &buf->dma_map)) { + m_freem(buf->mbuf); + buf->mbuf = NULL; + break; + } + + if (bus_dmamap_load(sc->dmatag, buf->dma_map, + mtod(buf->mbuf, void *), sc->dma_mtu, NULL, + BUS_DMA_NOWAIT | BUS_DMA_READ)) { + aft_release_rx_dma_buff(sc, buf); + break; + } + + SIMPLEQ_INSERT_TAIL(&sc->wp_rx_free_list, buf, entry); } - return (0); + return (n); +} + +static void +aft_reload_rx_dma_buff(xilinx_softc_t *sc, struct xilinx_rx_buffer *buf) +{ + bus_dmamap_unload(sc->dmatag, buf->dma_map); + if (buf->mbuf == NULL) { + buf->mbuf = wan_mbuf_alloc(sc->dma_mtu); + if (buf->mbuf == NULL) { + bus_dmamap_destroy(sc->dmatag, buf->dma_map); + return; + } + } + if (bus_dmamap_load(sc->dmatag, buf->dma_map, mtod(buf->mbuf, void *), + sc->dma_mtu, NULL, BUS_DMA_NOWAIT | BUS_DMA_READ)) { + aft_release_rx_dma_buff(sc, buf); + return; + } + + SIMPLEQ_INSERT_TAIL(&sc->wp_rx_free_list, buf, entry); +} + +static void +aft_release_rx_dma_buff(xilinx_softc_t *sc, struct xilinx_rx_buffer *buf) +{ + if (buf->mbuf == NULL) { + printf("%s: Error, buffer already free!\n"); + return; + } + + bus_dmamap_destroy(sc->dmatag, buf->dma_map); + m_freem(buf->mbuf); + buf->mbuf = NULL; } static void @@ -2417,19 +2533,17 @@ xilinx_process_packet(xilinx_softc_t *sc) WAN_ASSERT1(sc == NULL); for (;;) { - IF_DEQUEUE(&sc->wp_rx_complete_list, m); - if (m == NULL) + struct xilinx_rx_buffer *buf; + buf = SIMPLEQ_FIRST(&sc->wp_rx_complete_list); + if (buf == NULL) break; + SIMPLEQ_REMOVE_HEAD(&sc->wp_rx_complete_list, entry); + new_m = NULL; pkt_error = 0; - /* - * The post function will take care of the skb and new_skb - * buffer. If new_skb buffer exists, driver must pass it up - * the stack, or free it - */ - xilinx_rx_post_complete(sc->common.card, sc, m, &new_m, + xilinx_rx_post_complete(sc->common.card, sc, buf, &new_m, &pkt_error); if (new_m) { ifp = (struct ifnet *)&sc->common.ifp; @@ -2556,11 +2670,9 @@ fifo_error_interrupt(sdla_t *card, unsigned long reg) #ifdef DEBUG_ERR log(LOG_INFO, "%s:%s: Warning RX Fifo Error " - "on LCh=%ld Slot=%d RxCL=%d RxFL=%d " - "RxDMA=%d\n", card->devname, sc->if_name, + "on LCh=%ld Slot=%d RxDMA=%d\n", + card->devname, sc->if_name, sc->logic_ch_num, i, - sc->wp_rx_complete_list.ifq_len, - sc->wp_rx_free_list.ifq_len, sc->rx_dma); #endif @@ -2791,7 +2903,8 @@ port_set_state(sdla_t *card, int state) * handle_front_end_state */ -static void handle_front_end_state(void *card_id) +static void +handle_front_end_state(void *card_id) { sdla_t *card = (sdla_t *)card_id; @@ -3008,13 +3121,9 @@ enable_data_error_intr(sdla_t *card) sc->if_name, __FUNCTION__); #endif - if (sc->rx_dma_mbuf) { - wp_rx_element_t *rx_el; - struct mbuf *m = sc->rx_dma_mbuf; - - sc->rx_dma_mbuf = NULL; - rx_el = mtod(m, wp_rx_element_t *); - aft_init_requeue_free_m(sc, m); + if (sc->rx_dma_buf) { + aft_reload_rx_dma_buff(sc, sc->rx_dma_buf); + sc->rx_dma_buf = NULL; } xilinx_dma_rx(card, sc); @@ -3025,6 +3134,7 @@ enable_data_error_intr(sdla_t *card) } if (sc->tx_dma_mbuf) { + bus_dmamap_unload(sc->dmatag, sc->tx_dmamap); m_freem(sc->tx_dma_mbuf); sc->tx_dma_mbuf = NULL; } |