summaryrefslogtreecommitdiff
path: root/sys/pci/if_pn.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/pci/if_pn.c')
-rw-r--r--sys/pci/if_pn.c87
1 files changed, 62 insertions, 25 deletions
diff --git a/sys/pci/if_pn.c b/sys/pci/if_pn.c
index 77c4f84a6bf9..f62f99d57cd6 100644
--- a/sys/pci/if_pn.c
+++ b/sys/pci/if_pn.c
@@ -29,7 +29,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: if_pn.c,v 1.37 1999/02/26 07:49:31 wpaul Exp $
+ * $Id: if_pn.c,v 1.41 1999/03/27 20:32:32 wpaul Exp $
*/
/*
@@ -97,7 +97,7 @@
#ifndef lint
static const char rcsid[] =
- "$Id: if_pn.c,v 1.37 1999/02/26 07:49:31 wpaul Exp $";
+ "$Id: if_pn.c,v 1.41 1999/03/27 20:32:32 wpaul Exp $";
#endif
/*
@@ -855,7 +855,12 @@ pn_attach(config_id, unit)
printf ("pn%d: couldn't map ports\n", unit);
goto fail;
}
+#ifdef __i386__
sc->pn_btag = I386_BUS_SPACE_IO;
+#endif
+#ifdef __alpha__
+ sc->pn_btag = ALPHA_BUS_SPACE_IO;
+#endif
#else
if (!(command & PCIM_CMD_MEMEN)) {
printf("pn%d: failed to enable memory mapping!\n", unit);
@@ -867,8 +872,13 @@ pn_attach(config_id, unit)
goto fail;
}
sc->pn_bhandle = vbase;
+#ifdef __i386__
sc->pn_btag = I386_BUS_SPACE_MEM;
#endif
+#ifdef __alpha__
+ sc->pn_btag = ALPHA_BUS_SPACE_MEM;
+#endif
+#endif
/* Allocate interrupt */
if (!pci_map_int(config_id, pn_intr, sc, &net_imask)) {
@@ -1246,6 +1256,9 @@ static void pn_rxeof(sc)
while(!((rxstat = sc->pn_cdata.pn_rx_head->pn_ptr->pn_status) &
PN_RXSTAT_OWN)) {
+#ifdef __alpha__
+ struct mbuf *m0 = NULL;
+#endif
cur_rx = sc->pn_cdata.pn_rx_head;
sc->pn_cdata.pn_rx_head = cur_rx->pn_nextdesc;
@@ -1305,10 +1318,51 @@ static void pn_rxeof(sc)
continue;
}
+#ifdef __alpha__
+ /*
+ * Grrrr! On the alpha platform, the start of the
+ * packet data must be longword aligned so that ip_input()
+ * doesn't perform any unaligned accesses when it tries
+ * to fiddle with the IP header. But the PNIC is stupid
+ * and wants RX buffers to start on longword boundaries.
+ * So we can't just shift the DMA address over a few
+ * bytes to alter the payload alignment. Instead, we
+ * have to chop out ethernet and IP header parts of
+ * the packet and place then in a separate mbuf with
+ * the alignment fixed up properly.
+ *
+ * As if this chip wasn't broken enough already.
+ */
+ MGETHDR(m0, M_DONTWAIT, MT_DATA);
+ if (m0 == NULL) {
+ ifp->if_ierrors++;
+ cur_rx->pn_ptr->pn_status = PN_RXSTAT;
+ cur_rx->pn_ptr->pn_ctl = PN_RXCTL_RLINK | PN_RXLEN;
+ bzero((char *)mtod(cur_rx->pn_mbuf, char *), MCLBYTES);
+ continue;
+ }
+
+ m0->m_data += 2;
+ if (total_len <= (MHLEN - 2)) {
+ bcopy(mtod(m, caddr_t), mtod(m0, caddr_t), total_len); m_freem(m);
+ m = m0;
+ m->m_pkthdr.len = m->m_len = total_len;
+ } else {
+ bcopy(mtod(m, caddr_t), mtod(m0, caddr_t), (MHLEN - 2));
+ m->m_len = total_len - (MHLEN - 2);
+ m->m_data += (MHLEN - 2);
+ m0->m_next = m;
+ m0->m_len = (MHLEN - 2);
+ m = m0;
+ m->m_pkthdr.len = total_len;
+ }
+#else
+ m->m_pkthdr.len = m->m_len = total_len;
+#endif
ifp->if_ipackets++;
eh = mtod(m, struct ether_header *);
m->m_pkthdr.rcvif = ifp;
- m->m_pkthdr.len = m->m_len = total_len;
+
#if NBPFILTER > 0
/*
* Handle BPF listeners. Let the BPF user see the packet, but
@@ -1377,7 +1431,7 @@ static void pn_txeof(sc)
cur_tx = sc->pn_cdata.pn_tx_head;
txstat = PN_TXSTATUS(cur_tx);
- if ((txstat & PN_TXSTAT_OWN) || txstat == PN_UNSENT)
+ if (txstat & PN_TXSTAT_OWN)
break;
if (txstat & PN_TXSTAT_ERRSUM) {
@@ -1424,12 +1478,6 @@ static void pn_txeoc(sc)
sc->pn_cdata.pn_tx_tail = NULL;
if (sc->pn_want_auto)
pn_autoneg_mii(sc, PN_FLAG_SCHEDDELAY, 1);
- } else {
- if (PN_TXOWN(sc->pn_cdata.pn_tx_head) == PN_UNSENT) {
- PN_TXOWN(sc->pn_cdata.pn_tx_head) = PN_TXSTAT_OWN;
- ifp->if_timer = 5;
- CSR_WRITE_4(sc, PN_TXSTART, 0xFFFFFFFF);
- }
}
return;
@@ -1588,7 +1636,7 @@ static int pn_encap(sc, c, m_head)
c->pn_mbuf = m_head;
c->pn_lastdesc = frag - 1;
- PN_TXCTL(c) |= PN_TXCTL_LASTFRAG;
+ PN_TXCTL(c) |= PN_TXCTL_LASTFRAG|PN_TXCTL_FINT;
PN_TXNEXT(c) = vtophys(&c->pn_nextdesc->pn_ptr->pn_frag[0]);
return(0);
@@ -1649,6 +1697,8 @@ static void pn_start(ifp)
if (ifp->if_bpf)
bpf_mtap(ifp, cur_tx->pn_mbuf);
#endif
+ PN_TXOWN(cur_tx) = PN_TXSTAT_OWN;
+ CSR_WRITE_4(sc, PN_TXSTART, 0xFFFFFFFF);
}
/*
@@ -1657,23 +1707,10 @@ static void pn_start(ifp)
if (cur_tx == NULL)
return;
- /*
- * Place the request for the upload interrupt
- * in the last descriptor in the chain. This way, if
- * we're chaining several packets at once, we'll only
- * get an interupt once for the whole chain rather than
- * once for each packet.
- */
- PN_TXCTL(cur_tx) |= PN_TXCTL_FINT;
sc->pn_cdata.pn_tx_tail = cur_tx;
- if (sc->pn_cdata.pn_tx_head == NULL) {
+ if (sc->pn_cdata.pn_tx_head == NULL)
sc->pn_cdata.pn_tx_head = start_tx;
- PN_TXOWN(start_tx) = PN_TXSTAT_OWN;
- CSR_WRITE_4(sc, PN_TXSTART, 0xFFFFFFFF);
- } else {
- PN_TXOWN(start_tx) = PN_UNSENT;
- }
/*
* Set a timeout in case the chip goes out to lunch.