- Bus DMA'fy the driver

- Use htole* macros where appropriate so that the driver could work on non-x86 architectures
- Use m_getcl() instead of MGETHDR/MCLGET macros
Submitted by:	sam (Sam Leffler)
This commit is contained in:
pdeuskar 2003-05-02 21:17:08 +00:00
parent 6b35b9cda0
commit 1163149bb1
2 changed files with 457 additions and 235 deletions

View File

@ -155,6 +155,9 @@ static int em_82547_fifo_workaround(struct adapter *, int);
static void em_82547_update_fifo_head(struct adapter *, int); static void em_82547_update_fifo_head(struct adapter *, int);
static int em_82547_tx_fifo_reset(struct adapter *); static int em_82547_tx_fifo_reset(struct adapter *);
static void em_82547_move_tail(void *arg); static void em_82547_move_tail(void *arg);
static int em_dma_malloc(struct adapter *, bus_size_t,
struct em_dma_alloc *, int);
static void em_dma_free(struct adapter *, struct em_dma_alloc *);
/********************************************************************* /*********************************************************************
* FreeBSD Device Interface Entry Points * FreeBSD Device Interface Entry Points
@ -329,36 +332,36 @@ em_attach(device_t dev)
sizeof(struct em_tx_desc), 4096); sizeof(struct em_tx_desc), 4096);
/* Allocate Transmit Descriptor ring */ /* Allocate Transmit Descriptor ring */
if (!(adapter->tx_desc_base = (struct em_tx_desc *) if (em_dma_malloc(adapter, tsize, &adapter->txdma, BUS_DMA_NOWAIT)) {
contigmalloc(tsize, M_DEVBUF, M_NOWAIT, 0, ~0, PAGE_SIZE, 0))) { printf("em%d: Unable to allocate tx_desc memory\n",
printf("em%d: Unable to allocate TxDescriptor memory\n", adapter->unit);
adapter->unit); em_free_pci_resources(adapter);
em_free_pci_resources(adapter); splx(s);
splx(s); return(ENOMEM);
return(ENOMEM); }
} adapter->tx_desc_base = (struct em_tx_desc *) adapter->txdma.dma_vaddr;
rsize = EM_ROUNDUP(adapter->num_rx_desc * rsize = EM_ROUNDUP(adapter->num_rx_desc *
sizeof(struct em_rx_desc), 4096); sizeof(struct em_rx_desc), 4096);
/* Allocate Receive Descriptor ring */ /* Allocate Receive Descriptor ring */
if (!(adapter->rx_desc_base = (struct em_rx_desc *) if (em_dma_malloc(adapter, rsize, &adapter->rxdma, BUS_DMA_NOWAIT)) {
contigmalloc(rsize, M_DEVBUF, M_NOWAIT, 0, ~0, PAGE_SIZE, 0))) { printf("em%d: Unable to allocate rx_desc memory\n",
printf("em%d: Unable to allocate rx_desc memory\n", adapter->unit);
adapter->unit); em_free_pci_resources(adapter);
em_free_pci_resources(adapter); em_dma_free(adapter, &adapter->txdma);
contigfree(adapter->tx_desc_base, tsize, M_DEVBUF); splx(s);
splx(s); return(ENOMEM);
return(ENOMEM); }
} adapter->rx_desc_base = (struct em_rx_desc *) adapter->rxdma.dma_vaddr;
/* Initialize the hardware */ /* Initialize the hardware */
if (em_hardware_init(adapter)) { if (em_hardware_init(adapter)) {
printf("em%d: Unable to initialize the hardware\n", printf("em%d: Unable to initialize the hardware\n",
adapter->unit); adapter->unit);
em_free_pci_resources(adapter); em_free_pci_resources(adapter);
contigfree(adapter->tx_desc_base, tsize, M_DEVBUF); em_dma_free(adapter, &adapter->txdma);
contigfree(adapter->rx_desc_base, rsize, M_DEVBUF); em_dma_free(adapter, &adapter->rxdma);
splx(s); splx(s);
return(EIO); return(EIO);
} }
@ -368,8 +371,8 @@ em_attach(device_t dev)
printf("em%d: EEPROM read error while reading mac address\n", printf("em%d: EEPROM read error while reading mac address\n",
adapter->unit); adapter->unit);
em_free_pci_resources(adapter); em_free_pci_resources(adapter);
contigfree(adapter->tx_desc_base, tsize, M_DEVBUF); em_dma_free(adapter, &adapter->txdma);
contigfree(adapter->rx_desc_base, rsize, M_DEVBUF); em_dma_free(adapter, &adapter->rxdma);
splx(s); splx(s);
return(EIO); return(EIO);
} }
@ -418,7 +421,6 @@ em_detach(device_t dev)
struct adapter * adapter = device_get_softc(dev); struct adapter * adapter = device_get_softc(dev);
struct ifnet *ifp = &adapter->interface_data.ac_if; struct ifnet *ifp = &adapter->interface_data.ac_if;
int s; int s;
int size;
INIT_DEBUGOUT("em_detach: begin"); INIT_DEBUGOUT("em_detach: begin");
s = splimp(); s = splimp();
@ -431,24 +433,18 @@ em_detach(device_t dev)
ether_ifdetach(&adapter->interface_data.ac_if); ether_ifdetach(&adapter->interface_data.ac_if);
#endif #endif
em_free_pci_resources(adapter); em_free_pci_resources(adapter);
size = EM_ROUNDUP(adapter->num_tx_desc *
sizeof(struct em_tx_desc), 4096);
/* Free Transmit Descriptor ring */ /* Free Transmit Descriptor ring */
if (adapter->tx_desc_base) { if (adapter->tx_desc_base) {
contigfree(adapter->tx_desc_base, size, M_DEVBUF); em_dma_free(adapter, &adapter->txdma);
adapter->tx_desc_base = NULL; adapter->tx_desc_base = NULL;
} }
size = EM_ROUNDUP(adapter->num_rx_desc * /* Free Receive Descriptor ring */
sizeof(struct em_rx_desc), 4096); if (adapter->rx_desc_base) {
em_dma_free(adapter, &adapter->rxdma);
/* Free Receive Descriptor ring */ adapter->rx_desc_base = NULL;
if (adapter->rx_desc_base) { }
contigfree(adapter->rx_desc_base, size, M_DEVBUF);
adapter->rx_desc_base = NULL;
}
/* Remove from the adapter list */ /* Remove from the adapter list */
if (em_adapter_list == adapter) if (em_adapter_list == adapter)
@ -947,6 +943,19 @@ em_media_change(struct ifnet *ifp)
return(0); return(0);
} }
static void
em_tx_cb(void *arg, bus_dma_segment_t *seg, int nsegs, bus_size_t mapsize, int error)
{
struct em_q *q = arg;
if (error)
return;
KASSERT(nsegs <= EM_MAX_SCATTER,
("Too many DMA segments returned when mapping tx packet"));
q->nsegs = nsegs;
bcopy(seg, q->segs, nsegs * sizeof(seg[0]));
}
#define EM_FIFO_HDR 0x10 #define EM_FIFO_HDR 0x10
#define EM_82547_PKT_THRESH 0x3e0 #define EM_82547_PKT_THRESH 0x3e0
#define EM_82547_TX_FIFO_SIZE 0x2800 #define EM_82547_TX_FIFO_SIZE 0x2800
@ -957,43 +966,63 @@ em_media_change(struct ifnet *ifp)
* *
* return 0 on success, positive on failure * return 0 on success, positive on failure
**********************************************************************/ **********************************************************************/
static int
static int
em_encap(struct adapter *adapter, struct mbuf *m_head) em_encap(struct adapter *adapter, struct mbuf *m_head)
{ {
vm_offset_t virtual_addr;
u_int32_t txd_upper; u_int32_t txd_upper;
u_int32_t txd_lower; u_int32_t txd_lower;
int txd_used, i, txd_saved; int i, j, error;
struct mbuf *mp;
#if __FreeBSD_version < 500000 #if __FreeBSD_version < 500000
struct ifvlan *ifv = NULL; struct ifvlan *ifv = NULL;
#else #else
struct m_tag *mtag; struct m_tag *mtag;
#endif #endif
struct em_q q;
struct em_buffer *tx_buffer = NULL; struct em_buffer *tx_buffer = NULL;
struct em_tx_desc *current_tx_desc = NULL; struct em_tx_desc *current_tx_desc = NULL;
struct ifnet *ifp = &adapter->interface_data.ac_if; struct ifnet *ifp = &adapter->interface_data.ac_if;
/* /*
* Force a cleanup if number of TX descriptors * Force a cleanup if number of TX descriptors
* available hits the threshold * available hits the threshold
*/ */
if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
em_clean_transmit_interrupts(adapter); em_clean_transmit_interrupts(adapter);
if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
adapter->no_tx_desc_avail1++;
return(ENOBUFS);
}
}
if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) { /*
adapter->no_tx_desc_avail1++; * Map the packet for DMA.
return (ENOBUFS); */
} if (bus_dmamap_create(adapter->txtag, BUS_DMA_NOWAIT, &q.map)) {
adapter->no_tx_map_avail++;
return (ENOMEM);
}
error = bus_dmamap_load_mbuf(adapter->txtag, q.map,
m_head, em_tx_cb, &q, BUS_DMA_NOWAIT);
if (error != 0) {
adapter->no_tx_dma_setup++;
bus_dmamap_destroy(adapter->txtag, q.map);
return (error);
}
KASSERT(q.nsegs != 0, ("em_encap: empty packet"));
if (ifp->if_hwassist > 0) { if (q.nsegs > adapter->num_tx_desc_avail) {
em_transmit_checksum_setup(adapter, m_head, adapter->no_tx_desc_avail2++;
&txd_upper, &txd_lower); bus_dmamap_destroy(adapter->txtag, q.map);
} return (ENOBUFS);
else }
txd_upper = txd_lower = 0;
if (ifp->if_hwassist > 0) {
em_transmit_checksum_setup(adapter, m_head,
&txd_upper, &txd_lower);
} else
txd_upper = txd_lower = 0;
/* Find out if we are in vlan mode */ /* Find out if we are in vlan mode */
@ -1003,80 +1032,68 @@ em_encap(struct adapter *adapter, struct mbuf *m_head)
m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN) m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN)
ifv = m_head->m_pkthdr.rcvif->if_softc; ifv = m_head->m_pkthdr.rcvif->if_softc;
#else #else
mtag = VLAN_OUTPUT_TAG(ifp, m_head); mtag = VLAN_OUTPUT_TAG(ifp, m_head);
#endif #endif
i = adapter->next_avail_tx_desc; i = adapter->next_avail_tx_desc;
txd_saved = i; for (j = 0; j < q.nsegs; j++) {
txd_used = 0; tx_buffer = &adapter->tx_buffer_area[i];
for (mp = m_head; mp != NULL; mp = mp->m_next) { current_tx_desc = &adapter->tx_desc_base[i];
if (mp->m_len == 0)
continue;
if (txd_used == adapter->num_tx_desc_avail) { current_tx_desc->buffer_addr = htole64(q.segs[j].ds_addr);
adapter->next_avail_tx_desc = txd_saved; current_tx_desc->lower.data = htole32(
adapter->no_tx_desc_avail2++; adapter->txd_cmd | txd_lower | q.segs[j].ds_len);
return (ENOBUFS); current_tx_desc->upper.data = htole32(txd_upper);
}
tx_buffer = &adapter->tx_buffer_area[i]; if (++i == adapter->num_tx_desc)
current_tx_desc = &adapter->tx_desc_base[i]; i = 0;
virtual_addr = mtod(mp, vm_offset_t);
current_tx_desc->buffer_addr = vtophys(virtual_addr);
current_tx_desc->lower.data = (adapter->txd_cmd | txd_lower | mp->m_len); tx_buffer->m_head = NULL;
current_tx_desc->upper.data = (txd_upper); }
if (++i == adapter->num_tx_desc) adapter->num_tx_desc_avail -= q.nsegs;
i = 0; adapter->next_avail_tx_desc = i;
tx_buffer->m_head = NULL;
txd_used++;
}
adapter->num_tx_desc_avail -= txd_used;
adapter->next_avail_tx_desc = i;
#if __FreeBSD_version < 500000 #if __FreeBSD_version < 500000
if (ifv != NULL) { if (ifv != NULL) {
/* Set the vlan id */ /* Set the vlan id */
current_tx_desc->upper.fields.special = ifv->ifv_tag; current_tx_desc->upper.fields.special = htole16(ifv->ifv_tag);
#else #else
if (mtag != NULL) { if (mtag != NULL) {
/* Set the vlan id */ /* Set the vlan id */
current_tx_desc->upper.fields.special = VLAN_TAG_VALUE(mtag); current_tx_desc->upper.fields.special = htole16(VLAN_TAG_VALUE(mtag));
#endif #endif
/* Tell hardware to add tag */ /* Tell hardware to add tag */
current_tx_desc->lower.data |= E1000_TXD_CMD_VLE; current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_VLE);
} }
tx_buffer->m_head = m_head; tx_buffer->m_head = m_head;
tx_buffer->map = q.map;
/* bus_dmamap_sync(adapter->txtag, q.map, BUS_DMASYNC_PREWRITE);
* Last Descriptor of Packet needs End Of Packet (EOP)
*/
current_tx_desc->lower.data |= (E1000_TXD_CMD_EOP);
/* /*
* Advance the Transmit Descriptor Tail (Tdt), this tells the E1000 * Last Descriptor of Packet needs End Of Packet (EOP)
* that this frame is available to transmit. */
*/ current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_EOP);
if (adapter->hw.mac_type == em_82547 &&
adapter->link_duplex == HALF_DUPLEX) {
em_82547_move_tail(adapter);
}
else {
E1000_WRITE_REG(&adapter->hw, TDT, i);
if (adapter->hw.mac_type == em_82547) {
em_82547_update_fifo_head(adapter, m_head->m_pkthdr.len);
}
}
return (0); /*
* Advance the Transmit Descriptor Tail (Tdt), this tells the E1000
* that this frame is available to transmit.
*/
if (adapter->hw.mac_type == em_82547 &&
adapter->link_duplex == HALF_DUPLEX) {
em_82547_move_tail(adapter);
} else {
E1000_WRITE_REG(&adapter->hw, TDT, i);
if (adapter->hw.mac_type == em_82547) {
em_82547_update_fifo_head(adapter, m_head->m_pkthdr.len);
}
}
return(0);
} }
/********************************************************************* /*********************************************************************
* *
* 82547 workaround to avoid controller hang in half-duplex environment. * 82547 workaround to avoid controller hang in half-duplex environment.
@ -1715,6 +1732,92 @@ em_smartspeed(struct adapter *adapter)
} }
/*
* Manage DMA'able memory.
*/
static void
em_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
if (error)
return;
*(bus_addr_t*) arg = segs->ds_addr;
return;
}
static int
em_dma_malloc(struct adapter *adapter, bus_size_t size,
struct em_dma_alloc *dma, int mapflags)
{
int r;
r = bus_dma_tag_create(NULL, /* parent */
PAGE_SIZE, 0, /* alignment, bounds */
BUS_SPACE_MAXADDR, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
size, /* maxsize */
1, /* nsegments */
size, /* maxsegsize */
BUS_DMA_ALLOCNOW, /* flags */
&dma->dma_tag);
if (r != 0) {
printf("em%d: em_dma_malloc: bus_dma_tag_create failed; "
"error %u\n", adapter->unit, r);
goto fail_0;
}
r = bus_dmamap_create(dma->dma_tag, BUS_DMA_NOWAIT, &dma->dma_map);
if (r != 0) {
printf("em%d: em_dma_malloc: bus_dmamap_create failed; "
"error %u\n", adapter->unit, r);
goto fail_1;
}
r = bus_dmamem_alloc(dma->dma_tag, (void**) &dma->dma_vaddr,
BUS_DMA_NOWAIT, &dma->dma_map);
if (r != 0) {
printf("em%d: em_dma_malloc: bus_dmammem_alloc failed; "
"size %u, error %u\n", adapter->unit, size, r);
goto fail_2;
}
r = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr,
size,
em_dmamap_cb,
&dma->dma_paddr,
mapflags | BUS_DMA_NOWAIT);
if (r != 0) {
printf("em%d: em_dma_malloc: bus_dmamap_load failed; "
"error %u\n", adapter->unit, r);
goto fail_3;
}
dma->dma_size = size;
return (0);
fail_3:
bus_dmamap_unload(dma->dma_tag, dma->dma_map);
fail_2:
bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
fail_1:
bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
bus_dma_tag_destroy(dma->dma_tag);
fail_0:
dma->dma_map = NULL;
dma->dma_tag = NULL;
return (r);
}
static void
em_dma_free(struct adapter *adapter, struct em_dma_alloc *dma)
{
bus_dmamap_unload(dma->dma_tag, dma->dma_map);
bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
bus_dma_tag_destroy(dma->dma_tag);
}
/********************************************************************* /*********************************************************************
* *
* Allocate memory for tx_buffer structures. The tx_buffer stores all * Allocate memory for tx_buffer structures. The tx_buffer stores all
@ -1747,22 +1850,39 @@ em_allocate_transmit_structures(struct adapter * adapter)
static int static int
em_setup_transmit_structures(struct adapter * adapter) em_setup_transmit_structures(struct adapter * adapter)
{ {
if (em_allocate_transmit_structures(adapter)) /*
return ENOMEM; * Setup DMA descriptor areas.
*/
if (bus_dma_tag_create(NULL, /* parent */
PAGE_SIZE, 0, /* alignment, bounds */
BUS_SPACE_MAXADDR, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
MCLBYTES * 8, /* maxsize */
EM_MAX_SCATTER, /* nsegments */
MCLBYTES * 8, /* maxsegsize */
BUS_DMA_ALLOCNOW, /* flags */
&adapter->txtag)) {
printf("em%d: Unable to allocate TX DMA tag\n", adapter->unit);
return (ENOMEM);
}
if (em_allocate_transmit_structures(adapter))
return (ENOMEM);
bzero((void *) adapter->tx_desc_base, bzero((void *) adapter->tx_desc_base,
(sizeof(struct em_tx_desc)) * adapter->num_tx_desc); (sizeof(struct em_tx_desc)) * adapter->num_tx_desc);
adapter->next_avail_tx_desc = 0; adapter->next_avail_tx_desc = 0;
adapter->oldest_used_tx_desc = 0; adapter->oldest_used_tx_desc = 0;
/* Set number of descriptors available */ /* Set number of descriptors available */
adapter->num_tx_desc_avail = adapter->num_tx_desc; adapter->num_tx_desc_avail = adapter->num_tx_desc;
/* Set checksum context */ /* Set checksum context */
adapter->active_checksum_context = OFFLOAD_NONE; adapter->active_checksum_context = OFFLOAD_NONE;
return 0; return (0);
} }
/********************************************************************* /*********************************************************************
@ -1851,24 +1971,31 @@ em_initialize_transmit_unit(struct adapter * adapter)
static void static void
em_free_transmit_structures(struct adapter * adapter) em_free_transmit_structures(struct adapter * adapter)
{ {
struct em_buffer *tx_buffer; struct em_buffer *tx_buffer;
int i; int i;
INIT_DEBUGOUT("free_transmit_structures: begin"); INIT_DEBUGOUT("free_transmit_structures: begin");
if (adapter->tx_buffer_area != NULL) { if (adapter->tx_buffer_area != NULL) {
tx_buffer = adapter->tx_buffer_area; tx_buffer = adapter->tx_buffer_area;
for (i = 0; i < adapter->num_tx_desc; i++, tx_buffer++) { for (i = 0; i < adapter->num_tx_desc; i++, tx_buffer++) {
if (tx_buffer->m_head != NULL) if (tx_buffer->m_head != NULL) {
m_freem(tx_buffer->m_head); bus_dmamap_unload(adapter->txtag, tx_buffer->map);
tx_buffer->m_head = NULL; bus_dmamap_destroy(adapter->txtag, tx_buffer->map);
} m_freem(tx_buffer->m_head);
} }
if (adapter->tx_buffer_area != NULL) { tx_buffer->m_head = NULL;
free(adapter->tx_buffer_area, M_DEVBUF); }
adapter->tx_buffer_area = NULL; }
} if (adapter->tx_buffer_area != NULL) {
return; free(adapter->tx_buffer_area, M_DEVBUF);
adapter->tx_buffer_area = NULL;
}
if (adapter->txtag != NULL) {
bus_dma_tag_destroy(adapter->txtag);
adapter->txtag = NULL;
}
return;
} }
/********************************************************************* /*********************************************************************
@ -1927,11 +2054,11 @@ em_transmit_checksum_setup(struct adapter * adapter,
TXD->lower_setup.ip_fields.ipcso = TXD->lower_setup.ip_fields.ipcso =
ETHER_HDR_LEN + offsetof(struct ip, ip_sum); ETHER_HDR_LEN + offsetof(struct ip, ip_sum);
TXD->lower_setup.ip_fields.ipcse = TXD->lower_setup.ip_fields.ipcse =
ETHER_HDR_LEN + sizeof(struct ip) - 1; htole16(ETHER_HDR_LEN + sizeof(struct ip) - 1);
TXD->upper_setup.tcp_fields.tucss = TXD->upper_setup.tcp_fields.tucss =
ETHER_HDR_LEN + sizeof(struct ip); ETHER_HDR_LEN + sizeof(struct ip);
TXD->upper_setup.tcp_fields.tucse = 0; TXD->upper_setup.tcp_fields.tucse = htole16(0);
if (adapter->active_checksum_context == OFFLOAD_TCP_IP) { if (adapter->active_checksum_context == OFFLOAD_TCP_IP) {
TXD->upper_setup.tcp_fields.tucso = TXD->upper_setup.tcp_fields.tucso =
@ -1943,8 +2070,8 @@ em_transmit_checksum_setup(struct adapter * adapter,
offsetof(struct udphdr, uh_sum); offsetof(struct udphdr, uh_sum);
} }
TXD->tcp_seg_setup.data = 0; TXD->tcp_seg_setup.data = htole32(0);
TXD->cmd_and_length = (adapter->txd_cmd | E1000_TXD_CMD_DEXT); TXD->cmd_and_length = htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT);
tx_buffer->m_head = NULL; tx_buffer->m_head = NULL;
@ -1969,8 +2096,8 @@ em_clean_transmit_interrupts(struct adapter * adapter)
{ {
int s; int s;
int i, num_avail; int i, num_avail;
struct em_buffer *tx_buffer; struct em_buffer *tx_buffer;
struct em_tx_desc *tx_desc; struct em_tx_desc *tx_desc;
if (adapter->num_tx_desc_avail == adapter->num_tx_desc) if (adapter->num_tx_desc_avail == adapter->num_tx_desc)
return; return;
@ -1979,30 +2106,37 @@ em_clean_transmit_interrupts(struct adapter * adapter)
#ifdef DBG_STATS #ifdef DBG_STATS
adapter->clean_tx_interrupts++; adapter->clean_tx_interrupts++;
#endif #endif
num_avail = adapter->num_tx_desc_avail; num_avail = adapter->num_tx_desc_avail;
i = adapter->oldest_used_tx_desc; i = adapter->oldest_used_tx_desc;
tx_buffer = &adapter->tx_buffer_area[i]; tx_buffer = &adapter->tx_buffer_area[i];
tx_desc = &adapter->tx_desc_base[i]; tx_desc = &adapter->tx_desc_base[i];
while(tx_desc->upper.fields.status & E1000_TXD_STAT_DD) { while (tx_desc->upper.fields.status & E1000_TXD_STAT_DD) {
tx_desc->upper.data = 0;
num_avail++;
if (tx_buffer->m_head) {
bus_dmamap_sync(adapter->txtag, tx_buffer->map,
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(adapter->txtag, tx_buffer->map);
bus_dmamap_destroy(adapter->txtag, tx_buffer->map);
m_freem(tx_buffer->m_head);
tx_buffer->m_head = NULL;
}
tx_desc->upper.data = 0;
num_avail++;
if (tx_buffer->m_head) {
m_freem(tx_buffer->m_head);
tx_buffer->m_head = NULL;
}
if (++i == adapter->num_tx_desc) if (++i == adapter->num_tx_desc)
i = 0; i = 0;
tx_buffer = &adapter->tx_buffer_area[i]; tx_buffer = &adapter->tx_buffer_area[i];
tx_desc = &adapter->tx_desc_base[i]; tx_desc = &adapter->tx_desc_base[i];
} }
adapter->oldest_used_tx_desc = i; adapter->oldest_used_tx_desc = i;
/* /*
* If we have enough room, clear IFF_OACTIVE to tell the stack * If we have enough room, clear IFF_OACTIVE to tell the stack
@ -2031,41 +2165,51 @@ em_clean_transmit_interrupts(struct adapter * adapter)
**********************************************************************/ **********************************************************************/
static int static int
em_get_buf(int i, struct adapter *adapter, em_get_buf(int i, struct adapter *adapter,
struct mbuf *nmp) struct mbuf *nmp)
{ {
register struct mbuf *mp = nmp; register struct mbuf *mp = nmp;
struct ifnet *ifp; struct em_buffer *rx_buffer;
struct ifnet *ifp;
u_int32_t paddr;
int error;
ifp = &adapter->interface_data.ac_if; ifp = &adapter->interface_data.ac_if;
if (mp == NULL) { if (mp == NULL) {
MGETHDR(mp, M_DONTWAIT, MT_DATA); mp = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
if (mp == NULL) { if (mp == NULL) {
adapter->mbuf_alloc_failed++; adapter->mbuf_cluster_failed++;
return(ENOBUFS); return(ENOBUFS);
} }
MCLGET(mp, M_DONTWAIT); mp->m_len = mp->m_pkthdr.len = MCLBYTES;
if ((mp->m_flags & M_EXT) == 0) { } else {
m_freem(mp); mp->m_len = mp->m_pkthdr.len = MCLBYTES;
adapter->mbuf_cluster_failed++; mp->m_data = mp->m_ext.ext_buf;
return(ENOBUFS); mp->m_next = NULL;
} }
mp->m_len = mp->m_pkthdr.len = MCLBYTES;
} else {
mp->m_len = mp->m_pkthdr.len = MCLBYTES;
mp->m_data = mp->m_ext.ext_buf;
mp->m_next = NULL;
}
if (ifp->if_mtu <= ETHERMTU) { if (ifp->if_mtu <= ETHERMTU) {
m_adj(mp, ETHER_ALIGN); m_adj(mp, ETHER_ALIGN);
} }
adapter->rx_buffer_area[i].m_head = mp;
adapter->rx_desc_base[i].buffer_addr =
vtophys(mtod(mp, vm_offset_t));
return(0); rx_buffer = &adapter->rx_buffer_area[i];
/*
* Using memory from the mbuf cluster pool, invoke the
* bus_dma machinery to arrange the memory mapping.
*/
error = bus_dmamap_load(adapter->rxtag, rx_buffer->map,
mtod(mp, void *), mp->m_len,
em_dmamap_cb, &paddr, 0);
if (error) {
m_free(mp);
return(error);
}
rx_buffer->m_head = mp;
adapter->rx_desc_base[i].buffer_addr = htole64(paddr);
bus_dmamap_sync(adapter->rxtag, rx_buffer->map, BUS_DMASYNC_PREREAD);
return(0);
} }
/********************************************************************* /*********************************************************************
@ -2079,29 +2223,68 @@ em_get_buf(int i, struct adapter *adapter,
static int static int
em_allocate_receive_structures(struct adapter * adapter) em_allocate_receive_structures(struct adapter * adapter)
{ {
int i; int i, error;
struct em_buffer *rx_buffer;
if (!(adapter->rx_buffer_area = if (!(adapter->rx_buffer_area =
(struct em_buffer *) malloc(sizeof(struct em_buffer) * (struct em_buffer *) malloc(sizeof(struct em_buffer) *
adapter->num_rx_desc, M_DEVBUF, adapter->num_rx_desc, M_DEVBUF,
M_NOWAIT))) { M_NOWAIT))) {
printf("em%d: Unable to allocate rx_buffer memory\n", printf("em%d: Unable to allocate rx_buffer memory\n",
adapter->unit); adapter->unit);
return(ENOMEM); return(ENOMEM);
} }
bzero(adapter->rx_buffer_area, bzero(adapter->rx_buffer_area,
sizeof(struct em_buffer) * adapter->num_rx_desc); sizeof(struct em_buffer) * adapter->num_rx_desc);
for (i = 0; i < adapter->num_rx_desc; i++) { error = bus_dma_tag_create(NULL, /* parent */
if (em_get_buf(i, adapter, NULL) == ENOBUFS) { PAGE_SIZE, 0, /* alignment, bounds */
adapter->rx_buffer_area[i].m_head = NULL; BUS_SPACE_MAXADDR, /* lowaddr */
adapter->rx_desc_base[i].buffer_addr = 0; BUS_SPACE_MAXADDR, /* highaddr */
return(ENOBUFS); NULL, NULL, /* filter, filterarg */
} MCLBYTES, /* maxsize */
} 1, /* nsegments */
MCLBYTES, /* maxsegsize */
BUS_DMA_ALLOCNOW, /* flags */
&adapter->rxtag);
if (error != 0) {
printf("em%d: em_allocate_receive_structures: "
"bus_dma_tag_create failed; error %u\n",
adapter->unit, error);
goto fail_0;
}
return(0); rx_buffer = adapter->rx_buffer_area;
for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) {
error = bus_dmamap_create(adapter->rxtag, BUS_DMA_NOWAIT,
&rx_buffer->map);
if (error != 0) {
printf("em%d: em_allocate_receive_structures: "
"bus_dmamap_create failed; error %u\n",
adapter->unit, error);
goto fail_1;
}
}
for (i = 0; i < adapter->num_rx_desc; i++) {
error = em_get_buf(i, adapter, NULL);
if (error != 0) {
adapter->rx_buffer_area[i].m_head = NULL;
adapter->rx_desc_base[i].buffer_addr = 0;
return(error);
}
}
return(0);
fail_1:
bus_dma_tag_destroy(adapter->rxtag);
fail_0:
adapter->rxtag = NULL;
free(adapter->rx_buffer_area, M_DEVBUF);
adapter->rx_buffer_area = NULL;
return (error);
} }
/********************************************************************* /*********************************************************************
@ -2215,24 +2398,32 @@ em_initialize_receive_unit(struct adapter * adapter)
static void static void
em_free_receive_structures(struct adapter *adapter) em_free_receive_structures(struct adapter *adapter)
{ {
struct em_buffer *rx_buffer; struct em_buffer *rx_buffer;
int i; int i;
INIT_DEBUGOUT("free_receive_structures: begin"); INIT_DEBUGOUT("free_receive_structures: begin");
if (adapter->rx_buffer_area != NULL) { if (adapter->rx_buffer_area != NULL) {
rx_buffer = adapter->rx_buffer_area; rx_buffer = adapter->rx_buffer_area;
for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) { for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) {
if (rx_buffer->m_head != NULL) if (rx_buffer->map != NULL) {
m_freem(rx_buffer->m_head); bus_dmamap_unload(adapter->rxtag, rx_buffer->map);
rx_buffer->m_head = NULL; bus_dmamap_destroy(adapter->rxtag, rx_buffer->map);
} }
} if (rx_buffer->m_head != NULL)
if (adapter->rx_buffer_area != NULL) { m_freem(rx_buffer->m_head);
free(adapter->rx_buffer_area, M_DEVBUF); rx_buffer->m_head = NULL;
adapter->rx_buffer_area = NULL; }
} }
return; if (adapter->rx_buffer_area != NULL) {
free(adapter->rx_buffer_area, M_DEVBUF);
adapter->rx_buffer_area = NULL;
}
if (adapter->rxtag != NULL) {
bus_dma_tag_destroy(adapter->rxtag);
adapter->rxtag = NULL;
}
return;
} }
/********************************************************************* /*********************************************************************
@ -2255,7 +2446,7 @@ em_process_receive_interrupts(struct adapter * adapter, int count)
#endif #endif
u_int8_t accept_frame = 0; u_int8_t accept_frame = 0;
u_int8_t eop = 0; u_int8_t eop = 0;
u_int16_t len; u_int16_t len, desc_len;
int i; int i;
/* Pointer to the receive descriptor being examined. */ /* Pointer to the receive descriptor being examined. */
@ -2275,26 +2466,28 @@ em_process_receive_interrupts(struct adapter * adapter, int count)
while ((current_desc->status & E1000_RXD_STAT_DD) && (count != 0)) { while ((current_desc->status & E1000_RXD_STAT_DD) && (count != 0)) {
mp = adapter->rx_buffer_area[i].m_head; mp = adapter->rx_buffer_area[i].m_head;
bus_dmamap_sync(adapter->rxtag, adapter->rx_buffer_area[i].map,
BUS_DMASYNC_POSTREAD);
accept_frame = 1; accept_frame = 1;
desc_len = le16toh(current_desc->length);
if (current_desc->status & E1000_RXD_STAT_EOP) { if (current_desc->status & E1000_RXD_STAT_EOP) {
count--; count--;
eop = 1; eop = 1;
len = current_desc->length - ETHER_CRC_LEN; len = desc_len - ETHER_CRC_LEN;
} else { } else {
eop = 0; eop = 0;
len = current_desc->length; len = desc_len;
} }
if (current_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { if (current_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
u_int8_t last_byte; u_int8_t last_byte;
u_int32_t pkt_len = current_desc->length; u_int32_t pkt_len = desc_len;
if (adapter->fmp != NULL) if (adapter->fmp != NULL)
pkt_len += adapter->fmp->m_pkthdr.len; pkt_len += adapter->fmp->m_pkthdr.len;
last_byte = *(mtod(mp, caddr_t) + last_byte = *(mtod(mp, caddr_t) + desc_len - 1);
current_desc->length - 1);
if (TBI_ACCEPT(&adapter->hw, current_desc->status, if (TBI_ACCEPT(&adapter->hw, current_desc->status,
current_desc->errors, current_desc->errors,

View File

@ -71,6 +71,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <machine/clock.h> #include <machine/clock.h>
#include <pci/pcivar.h> #include <pci/pcivar.h>
#include <pci/pcireg.h> #include <pci/pcireg.h>
#include <sys/endian.h>
#include "opt_bdg.h" #include "opt_bdg.h"
#include <dev/em/if_em_hw.h> #include <dev/em/if_em_hw.h>
@ -242,6 +243,8 @@ POSSIBILITY OF SUCH DAMAGE.
#define EM_RXBUFFER_8192 8192 #define EM_RXBUFFER_8192 8192
#define EM_RXBUFFER_16384 16384 #define EM_RXBUFFER_16384 16384
#define EM_MAX_SCATTER 64
#ifdef __alpha__ #ifdef __alpha__
#undef vtophys #undef vtophys
#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)(va)) #define vtophys(va) alpha_XXX_dmamap((vm_offset_t)(va))
@ -264,9 +267,29 @@ typedef struct _em_vendor_info_t {
struct em_buffer { struct em_buffer {
struct mbuf *m_head; struct mbuf *m_head;
bus_dmamap_t map; /* bus_dma map for packet */
}; };
struct em_q {
bus_dmamap_t map; /* bus_dma map for packet */
int nsegs; /* # of segments/descriptors */
bus_dma_segment_t segs[EM_MAX_SCATTER];
};
/*
* Bus dma allocation structure used by
* em_dma_malloc and em_dma_free.
*/
struct em_dma_alloc {
u_int32_t dma_paddr;
caddr_t dma_vaddr;
bus_dma_tag_t dma_tag;
bus_dmamap_t dma_map;
bus_dma_segment_t dma_seg;
bus_size_t dma_size;
int dma_nseg;
};
typedef enum _XSUM_CONTEXT_T { typedef enum _XSUM_CONTEXT_T {
OFFLOAD_NONE, OFFLOAD_NONE,
@ -316,6 +339,7 @@ struct adapter {
* The index of the next available descriptor is next_avail_tx_desc. * The index of the next available descriptor is next_avail_tx_desc.
* The number of remaining tx_desc is num_tx_desc_avail. * The number of remaining tx_desc is num_tx_desc_avail.
*/ */
struct em_dma_alloc txdma; /* bus_dma glue for tx desc */
struct em_tx_desc *tx_desc_base; struct em_tx_desc *tx_desc_base;
u_int32_t next_avail_tx_desc; u_int32_t next_avail_tx_desc;
u_int32_t oldest_used_tx_desc; u_int32_t oldest_used_tx_desc;
@ -323,6 +347,7 @@ struct adapter {
u_int16_t num_tx_desc; u_int16_t num_tx_desc;
u_int32_t txd_cmd; u_int32_t txd_cmd;
struct em_buffer *tx_buffer_area; struct em_buffer *tx_buffer_area;
bus_dma_tag_t txtag; /* dma tag for tx */
/* /*
* Receive definitions * Receive definitions
@ -332,11 +357,13 @@ struct adapter {
* (at rx_buffer_area). * (at rx_buffer_area).
* The next pair to check on receive is at offset next_rx_desc_to_check * The next pair to check on receive is at offset next_rx_desc_to_check
*/ */
struct em_dma_alloc rxdma; /* bus_dma glue for rx desc */
struct em_rx_desc *rx_desc_base; struct em_rx_desc *rx_desc_base;
u_int32_t next_rx_desc_to_check; u_int32_t next_rx_desc_to_check;
u_int16_t num_rx_desc; u_int16_t num_rx_desc;
u_int32_t rx_buffer_len; u_int32_t rx_buffer_len;
struct em_buffer *rx_buffer_area; struct em_buffer *rx_buffer_area;
bus_dma_tag_t rxtag;
/* Jumbo frame */ /* Jumbo frame */
struct mbuf *fmp; struct mbuf *fmp;
@ -350,6 +377,8 @@ struct adapter {
unsigned long mbuf_cluster_failed; unsigned long mbuf_cluster_failed;
unsigned long no_tx_desc_avail1; unsigned long no_tx_desc_avail1;
unsigned long no_tx_desc_avail2; unsigned long no_tx_desc_avail2;
unsigned long no_tx_map_avail;
unsigned long no_tx_dma_setup;
u_int64_t tx_fifo_reset; u_int64_t tx_fifo_reset;
u_int64_t tx_fifo_wrk; u_int64_t tx_fifo_wrk;