Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 25 Mar 2014 11:36:05 -0700
From:      Sean Fagan <sef@ixsystems.com>
To:        freebsd-net@freebsd.org
Subject:   Non-interrupt packet sending and receiving
Message-ID:  <27D25BFC-7BB3-400F-8405-43B8D08135D2@ixsystems.com>

next in thread | raw e-mail | index | archive | help

--Apple-Mail=_CF84D4FE-C7D8-487C-93B9-541771AA3154
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
	charset=us-ascii

This isn't the same as the polled driver; this is sending and receiving =
a single packet at a time.

I've gotten (at least to a somewhat workable degree) Apple's KDP ported =
to FreeBSD.  I've only changed the dev/e1000/if_lem.c driver for now =
(that's the one VMWare shows up as :)), but since I'm not particularly =
comfortable with device drivers, let alone ethernet drivers, I needed =
some feedback.

Diffs are attached below.  Feedback would be appreciated.

(To answer some of the questions I've already gotten:  no, i can't use =
the DEVICE_POLLING routines, because that still goes through the entire =
stack. It's not here, because I am not yet happy with it, but the code =
that uses this runs in the kernel debugger, and it needs to be able to =
send and receive a single packet at a time -- and it can't let it be =
shuffled off through other layers, for reasons that I hope are fairly =
clear.  Now, one change I would like to make is the mbuf allocation that =
it uses; ideally, honestly, it should have its own mbufs -- the protocol =
never sends more than 1538 bytes in a UDP packet -- but I would probably =
try working on another ethernet driver first, modeling it after this.)

(The bulk of the diffs is moving some code out of lem_rxeof into a =
function that gets a single packet.)

Thanks,

Sean.

--Apple-Mail=_CF84D4FE-C7D8-487C-93B9-541771AA3154
Content-Disposition: attachment;
	filename=if_lem-diffs.txt
Content-Type: text/plain;
	name="if_lem-diffs.txt"
Content-Transfer-Encoding: quoted-printable

diff --git a/dev/e1000/if_lem.c b/dev/e1000/if_lem.c
index bfe2c93..90ec8b3 100644
--- a/dev/e1000/if_lem.c
+++ b/dev/e1000/if_lem.c
@@ -34,6 +34,7 @@
=20
 #include "opt_inet.h"
 #include "opt_inet6.h"
+#include "opt_ddb.h"
=20
 #ifdef HAVE_KERNEL_OPTION_HEADERS
 #include "opt_device_polling.h"
@@ -54,6 +55,7 @@
 #include <sys/sysctl.h>
 #include <sys/taskqueue.h>
 #include <sys/eventhandler.h>
+#include <sys/uio.h>
 #include <machine/bus.h>
 #include <machine/resource.h>
=20
@@ -191,7 +193,7 @@ static void	lem_free_transmit_structures(struct =
adapter *);
 static void	lem_free_receive_structures(struct adapter *);
 static void	lem_update_stats_counters(struct adapter *);
 static void	lem_add_hw_stats(struct adapter *adapter);
-static void	lem_txeof(struct adapter *);
+static void	lem_txeof(struct adapter *, int);
 static void	lem_tx_purge(struct adapter *);
 static int	lem_allocate_receive_structures(struct adapter *);
 static int	lem_allocate_transmit_structures(struct adapter *);
@@ -246,6 +248,74 @@ static void	lem_handle_rxtx(void *context, =
int pending);
 static void	lem_handle_link(void *context, int pending);
 static void	lem_add_rx_process_limit(struct adapter *, const char *,
 		    const char *, int *, int);
+#ifdef DDB
+typedef uint32_t (*kdp_link_t)(void);
+typedef int (*kdp_mode_t)(int);
+extern void *kdp_get_interface(void);
+typedef void (*kdp_send_t)(void * pkt, unsigned int pkt_len);
+typedef void (*kdp_receive_t)(void * pkt, unsigned int * pkt_len,
+			      unsigned int timeout);
+extern void kdp_register_send_receive(kdp_send_t send, kdp_receive_t =
receive);
+extern void kdp_unregister_send_receive(kdp_send_t send, kdp_receive_t =
receive);
+
+/*
+ * Function called by kdp.
+ * timeout is in milliseconds.
+ * The data is 1538 bytes.
+ * Return the length in *length; set it to 0 if no packet.
+ */
+static void lem_kdp_recv_pkt(void *data, unsigned int *length, unsigned =
int timeout);
+
+static void lem_kdp_send_pkt(void *pkt, unsigned int pkt_len);
+
+/*
+ * For kdp:
+ * lex_rxeof() may be usable.  However, we'd have to
+ * change the ifp->if_input() function pointer to be
+ * something more conducive to our needs.
+ *
+ * For transmitting, we'd want to use lem_txeof, but
+ * we have to figure out how to put data into the
+ * adapter queue.  Something like:
+ *
+ * struct mbchain *mbp;
+ * struct mbuf *m;
+ * mb_init(mbp);
+ * mb_put_uint8(mbp, 33);
+ * mb_put_uint16le(mbp, length);
+ * m =3D m_copym(mbp->mb_top, 0, M_COPYALL, M_WAIT);
+ *
+ * Then we have to get the mbuf chain (m) into the
+ * device's queue.
+ *
+ * Then:
+ *
+ * mb_done(mbp);
+ *
+ */
+/*
+ * Tell kdp about functions to query status.
+ * The link parameter is a pointer to a function
+ * which returns the status (it only cares about
+ * IFM_AVALID and IFM_ACTIVE).  Note that it has no
+ * parameters -- so it has to use the kdp_get_interface()
+ * function to find out the current interface.  This should
+ * probably change.
+ *
+ * Similarly, the mode parameter is a function which sets the
+ * status active (if its parameter is non-zero) or inactive (if
+ * its parameter is 0).
+ */
+void kdp_register_link(kdp_link_t link, kdp_mode_t mode);
+void kdp_unregister_link(kdp_link_t link, kdp_mode_t mode);
+
+// This is a bit of a lie:  it actually takes a pointer to a =
kdp_ether_addr_t structure.
+void kdp_set_interface(void *interface, const void *macaddr);
+
+static uint32_t kdp_media_status(void);
+static int kdp_set_media_state(int);
+
+#endif
=20
 #ifdef DEVICE_POLLING
 static poll_handler_t lem_poll;
@@ -835,7 +905,7 @@ lem_start_locked(struct ifnet *ifp)
          * available hits the threshold
          */
 	if (adapter->num_tx_desc_avail <=3D EM_TX_CLEANUP_THRESHOLD) {
-		lem_txeof(adapter);
+		lem_txeof(adapter, 0);
 		/* Now do we at least have a minimal? */
 		if (adapter->num_tx_desc_avail <=3D EM_TX_OP_THRESHOLD) =
{
 			adapter->no_tx_desc_avail1++;
@@ -1212,6 +1282,14 @@ lem_init_locked(struct adapter *adapter)
 	/* AMT based hardware can now take control from firmware */
 	if (adapter->has_manage && adapter->has_amt)
 		lem_get_hw_control(adapter);
+
+#ifdef DDB
+	printf("Setting interface to %p\n", ifp);
+	kdp_set_interface(ifp, adapter->hw.mac.addr);
+	kdp_register_link(kdp_media_status, NULL =
/*kdp_set_media_state*/);
+	kdp_register_send_receive(lem_kdp_send_pkt, lem_kdp_recv_pkt);
+
+#endif
 }
=20
 static void
@@ -1258,7 +1336,7 @@ lem_poll(struct ifnet *ifp, enum poll_cmd cmd, int =
count)
 	lem_rxeof(adapter, count, &rx_done);
=20
 	EM_TX_LOCK(adapter);
-	lem_txeof(adapter);
+	lem_txeof(adapter, 0);
 	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
 		lem_start_locked(ifp);
 	EM_TX_UNLOCK(adapter);
@@ -1309,7 +1387,7 @@ lem_intr(void *arg)
 	lem_rxeof(adapter, -1, NULL);
=20
 	EM_TX_LOCK(adapter);
-	lem_txeof(adapter);
+	lem_txeof(adapter, 0);
 	if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
 	    !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
 		lem_start_locked(ifp);
@@ -1348,7 +1426,7 @@ lem_handle_rxtx(void *context, int pending)
 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
 		bool more =3D lem_rxeof(adapter, =
adapter->rx_process_limit, NULL);
 		EM_TX_LOCK(adapter);
-		lem_txeof(adapter);
+		lem_txeof(adapter, 0);
 		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
 			lem_start_locked(ifp);
 		EM_TX_UNLOCK(adapter);
@@ -1405,6 +1483,34 @@ lem_irq_fast(void *arg)
 	return FILTER_HANDLED;
 }
=20
+#ifdef DDB
+static uint32_t __unused
+kdp_media_status(void)
+{
+	struct ifnet *ifp =3D kdp_get_interface();
+	struct ifmediareq ifmr =3D { .ifm_status =3D 0 };
+
+	if (ifp) {
+		lem_media_status(ifp, &ifmr);
+	}
+	return ifmr.ifm_status;
+}
+
+static int __unused
+kdp_set_media_state(int onoroff)
+{
+	struct ifnet *ifp =3D kdp_get_interface();
+	if (ifp) {
+		if (onoroff) {
+			lem_start(ifp);
+		} else {
+			lem_stop(ifp);
+		}
+	}
+	return 1;
+}
+
+#endif
=20
 /*********************************************************************
  *
@@ -2975,14 +3081,15 @@ lem_transmit_checksum_setup(struct adapter =
*adapter, struct mbuf *mp,
  *
  =
**********************************************************************/
 static void
-lem_txeof(struct adapter *adapter)
+lem_txeof(struct adapter *adapter, int nolock)
 {
         int first, last, done, num_avail;
         struct em_buffer *tx_buffer;
         struct e1000_tx_desc   *tx_desc, *eop_desc;
 	struct ifnet   *ifp =3D adapter->ifp;
=20
-	EM_TX_LOCK_ASSERT(adapter);
+	if (nolock =3D=3D 0)
+		EM_TX_LOCK_ASSERT(adapter);
=20
 #ifdef DEV_NETMAP
 	if (netmap_tx_irq(ifp, 0 | =
(NETMAP_LOCKED_ENTER|NETMAP_LOCKED_EXIT)))
@@ -3082,7 +3189,7 @@ lem_tx_purge(struct adapter *adapter)
 {
 	if ((!adapter->link_active) && (adapter->watchdog_check)) {
 		EM_TX_LOCK(adapter);
-		lem_txeof(adapter);
+		lem_txeof(adapter, 0);
 		EM_TX_UNLOCK(adapter);
 		if (adapter->watchdog_check) /* Still outstanding? */
 			lem_init_locked(adapter);
@@ -3426,6 +3533,254 @@ lem_free_receive_structures(struct adapter =
*adapter)
 	}
 }
=20
+static __unused struct mbuf *
+lem_recv_one_packet(struct adapter *adapter,
+		    int *start_desc_index)
+{
+	struct mbuf *retval =3D NULL;
+	struct mbuf *mp;	// Used to build up retval
+	int i =3D *start_desc_index;
+	struct ifnet *ifp =3D adapter->ifp;
+	u8 status =3D 0, accept_frame =3D 0, eop =3D 0;
+	u16 len, desc_len, prev_len_adj;
+	struct e1000_rx_desc *current_desc =3D NULL;
+
+//	printf("%s(%d)\n", __FUNCTION__, __LINE__);
+
+
+	while (eop =3D=3D 0) {
+		current_desc =3D &adapter->rx_desc_base[i];
+		status =3D current_desc->status;
+
+		if ((status & E1000_RXD_STAT_DD) =3D=3D 0) {
+			break;
+		}
+
+		mp =3D adapter->rx_buffer_area[i].m_head;
+		/*
+		 * Can't defer bus_dmamap_sync(9) because TBI_ACCEPT
+		 * needs to access the last received byte in the mbuf.
+		 */
+		bus_dmamap_sync(adapter->rxtag, =
adapter->rx_buffer_area[i].map,
+				BUS_DMASYNC_POSTREAD);
+		accept_frame =3D 1;
+		prev_len_adj =3D 0;
+		desc_len =3D le16toh(current_desc->length);
+
+		if (status & E1000_RXD_STAT_EOP) {
+			eop =3D 1;	// Found the end of packet
+			if (desc_len < ETHER_CRC_LEN) {
+				len =3D 0;
+				prev_len_adj =3D ETHER_CRC_LEN - =
desc_len;
+			} else {
+				len =3D desc_len - ETHER_CRC_LEN;
+			}
+		} else {
+			len =3D desc_len;
+		}
+
+		if (current_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) =
{
+			u8	last_byte;
+			u32	pkt_len =3D desc_len;
+	=09
+			if (adapter->fmp !=3D NULL)
+				pkt_len +=3D adapter->fmp->m_pkthdr.len;
+	=09
+			last_byte =3D *(mtod(mp, caddr_t) + desc_len - =
1);		=09
+			if (TBI_ACCEPT(&adapter->hw, status,
+				       current_desc->errors, pkt_len, =
last_byte,
+				       adapter->min_frame_size, =
adapter->max_frame_size)) {
+				=
e1000_tbi_adjust_stats_82543(&adapter->hw,
+							     =
&adapter->stats, pkt_len,
+							     =
adapter->hw.mac.addr,
+							     =
adapter->max_frame_size);
+				if (len > 0)
+					len--;
+			} else
+				accept_frame =3D 0;
+		}
+		if (accept_frame) {
+			if (lem_get_buf(adapter, i) !=3D 0) {
+				ifp->if_iqdrops++;
+				goto discard;
+			}
+	=09
+			/* Assign correct length to the current fragment =
*/
+			mp->m_len =3D len;
+	=09
+			if (adapter->fmp =3D=3D NULL) {
+				mp->m_pkthdr.len =3D len;
+				adapter->fmp =3D mp; /* Store the first =
mbuf */
+				adapter->lmp =3D mp;
+			} else {
+				/* Chain mbuf's together */
+				mp->m_flags &=3D ~M_PKTHDR;
+				/*
+				 * Adjust length of previous mbuf in =
chain if
+				 * we received less than 4 bytes in the =
last
+				 * descriptor.
+				 */
+				if (prev_len_adj > 0) {
+					adapter->lmp->m_len -=3D =
prev_len_adj;
+					adapter->fmp->m_pkthdr.len -=3D
+						prev_len_adj;
+				}
+				adapter->lmp->m_next =3D mp;
+				adapter->lmp =3D adapter->lmp->m_next;
+				adapter->fmp->m_pkthdr.len +=3D len;
+			}
+	=09
+			if (eop) {
+				adapter->fmp->m_pkthdr.rcvif =3D ifp;
+				ifp->if_ipackets++;
+				lem_receive_checksum(adapter, =
current_desc,
+						     adapter->fmp);
+#ifndef __NO_STRICT_ALIGNMENT
+				if (adapter->max_frame_size >
+				    (MCLBYTES - ETHER_ALIGN) &&
+				    lem_fixup_rx(adapter) !=3D 0)
+					goto skip;
+#endif
+				if (status & E1000_RXD_STAT_VP) {
+					=
adapter->fmp->m_pkthdr.ether_vtag =3D
+						=
le16toh(current_desc->special);
+					adapter->fmp->m_flags |=3D =
M_VLANTAG;
+				}
+#ifndef __NO_STRICT_ALIGNMENT
+			skip:
+#endif
+				retval =3D adapter->fmp;
+				adapter->fmp =3D NULL;
+				adapter->lmp =3D NULL;
+			}
+		} else {
+			adapter->dropped_pkts++;
+		discard:
+			/* Reuse loaded DMA map and just update mbuf =
chain */
+			mp =3D adapter->rx_buffer_area[i].m_head;
+			mp->m_len =3D mp->m_pkthdr.len =3D MCLBYTES;
+			mp->m_data =3D mp->m_ext.ext_buf;
+			mp->m_next =3D NULL;
+			if (adapter->max_frame_size <=3D
+			    (MCLBYTES - ETHER_ALIGN))
+				m_adj(mp, ETHER_ALIGN);
+			if (adapter->fmp !=3D NULL) {
+				m_freem(adapter->fmp);
+				adapter->fmp =3D NULL;
+				adapter->lmp =3D NULL;
+			}
+			retval =3D NULL;
+		}
+		/* Zero out the receive descriptors status. */
+		current_desc->status =3D 0;
+		bus_dmamap_sync(adapter->rxdma.dma_tag, =
adapter->rxdma.dma_map,
+				BUS_DMASYNC_PREREAD | =
BUS_DMASYNC_PREWRITE);
+=09
+		/* Advance our pointers to the next descriptor. */
+		if (++i =3D=3D adapter->num_rx_desc)
+			i =3D 0;
+	}
+
+	*start_desc_index =3D i;
+	/*
+	 * At this point, either retval has a packet, or is NULL
+	 */
+//	printf("%s(%d):  retval =3D %p\n", __FUNCTION__, __LINE__, =
retval);
+	return retval;
+}
+
+static void
+lem_kdp_send_pkt(__unused void *pkt, __unused unsigned int pkt_len)
+{
+	printf("%s\n", __FUNCTION__);
+	struct mbuf *m_head =3D NULL;
+	struct ifnet *ifp =3D kdp_get_interface();
+	struct adapter *adapter =3D ifp->if_softc;
+	struct iovec iov;
+	struct uio uio;
+	int error;
+
+	printf("%s(%p, %u)\n", __FUNCTION__, pkt, pkt_len);
+
+	iov.iov_base =3D (caddr_t)pkt;
+	iov.iov_len =3D pkt_len;
+	uio.uio_iov =3D &iov;
+	uio.uio_iovcnt =3D 1;
+	uio.uio_offset =3D 0;
+	uio.uio_resid =3D (ssize_t)pkt_len;
+	uio.uio_segflg =3D UIO_SYSSPACE;
+	uio.uio_rw =3D UIO_WRITE;
+	uio.uio_td =3D curthread;
+
+
+	m_head =3D m_uiotombuf(&uio, M_WAITOK, pkt_len, 0, 0);
+=09
+	if (m_head =3D=3D NULL) {
+		printf("%s(%d):  m_utiotombuf failed us!\n", =
__FUNCTION__, __LINE__);
+	} else {
+		lem_txeof(adapter, 1);
+		printf("%s(%d):  calling lem_xmit\n", __FUNCTION__, =
__LINE__);
+		error =3D lem_xmit(adapter, &m_head);
+	=09
+		if (error !=3D 0) {
+			printf("%s(%d):  lem_xmit returned %d\n", =
__FUNCTION__, __LINE__, error);
+		} else {
+			printf("%s(%d): calling lem_txeof\n", =
__FUNCTION__, __LINE__);
+			lem_txeof(adapter, 1);
+			printf("\tand done\n");
+		}
+		if (m_head)
+			m_freem(m_head);
+	}
+	return;
+}
+
+static void __unused
+lem_kdp_recv_pkt(void *data, unsigned int *length, unsigned int =
timeout)
+{
+	*length =3D 0;
+	int indx =3D 0;
+	int uSecs =3D timeout * 1000;	// DELAY takes microseconds
+	struct mbuf *packet =3D NULL;
+	struct ifnet *ifp =3D kdp_get_interface();
+	struct adapter *adapter =3D ifp->if_softc;
+	struct e1000_rx_desc *current_desc;
+
+	indx =3D adapter->next_rx_desc_to_check;
+	current_desc =3D &adapter->rx_desc_base[indx];
+
+	bus_dmamap_sync(adapter->rxdma.dma_tag,
+			adapter->rxdma.dma_map,
+			BUS_DMASYNC_POSTREAD);
+
+	if ((current_desc->status & E1000_RXD_STAT_DD) =3D=3D 0) {
+		goto done;
+	}
+
+	while (packet =3D=3D NULL &&
+	       (ifp->if_drv_flags & IFF_DRV_RUNNING) &&
+	       uSecs > 0) {
+		packet =3D lem_recv_one_packet(adapter, &indx);
+
+		if (packet =3D=3D NULL) {
+			DELAY(50);
+			uSecs -=3D 50;
+		}
+	}
+	if (packet !=3D NULL) {
+		int packet_len =3D packet->m_pkthdr.len;
+		m_copydata(packet, 0, packet_len, data);
+		*length =3D packet_len;
+		adapter->next_rx_desc_to_check =3D indx;
+		if (indx =3D=3D 0) {
+			E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), =
adapter->num_rx_desc - 1);
+		}
+
+	}
+done:
+	return;
+}
+
 /*********************************************************************
  *
  *  This routine executes in interrupt context. It replenishes
@@ -3441,9 +3796,11 @@ static bool
 lem_rxeof(struct adapter *adapter, int count, int *done)
 {
 	struct ifnet	*ifp =3D adapter->ifp;
-	struct mbuf	*mp;
-	u8		status =3D 0, accept_frame =3D 0, eop =3D 0;
-	u16 		len, desc_len, prev_len_adj;
+	u8		status =3D 0;
+	u8 __unused	accept_frame =3D 0;
+	u8 __unused	eop =3D 0;
+	u16 __unused	len;
+	u16 __unused	desc_len, prev_len_adj;
 	int		i, rx_sent =3D 0;
 	struct e1000_rx_desc   *current_desc;
=20
@@ -3467,6 +3824,14 @@ lem_rxeof(struct adapter *adapter, int count, int =
*done)
=20
 	while (count !=3D 0 && ifp->if_drv_flags & IFF_DRV_RUNNING) {
 		struct mbuf *m =3D NULL;
+#if 1
+		current_desc =3D &adapter->rx_desc_base[i];
+		status =3D current_desc->status;
+		if ((status & E1000_RXD_STAT_DD) =3D=3D 0)
+			break;
+		m =3D lem_recv_one_packet(adapter, &i);
+#else
+		struct mbuf	*mp =3D NULL;
=20
 		status =3D current_desc->status;
 		if ((status & E1000_RXD_STAT_DD) =3D=3D 0)
@@ -3598,6 +3963,8 @@ discard:
 		/* Advance our pointers to the next descriptor. */
 		if (++i =3D=3D adapter->num_rx_desc)
 			i =3D 0;
+#endif
+
 		/* Call into the stack */
 		if (m !=3D NULL) {
 			adapter->next_rx_desc_to_check =3D i;

--Apple-Mail=_CF84D4FE-C7D8-487C-93B9-541771AA3154
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=us-ascii





--Apple-Mail=_CF84D4FE-C7D8-487C-93B9-541771AA3154--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?27D25BFC-7BB3-400F-8405-43B8D08135D2>