Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 22 Apr 2010 20:54:32 +0000 (UTC)
From:      Juli Mallett <jmallett@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r207073 - user/jmallett/octeon/sys/mips/cavium/octe
Message-ID:  <201004222054.o3MKsWAu089135@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jmallett
Date: Thu Apr 22 20:54:32 2010
New Revision: 207073
URL: http://svn.freebsd.org/changeset/base/207073

Log:
  Comment out, port, etc., to make the main module compile.

Modified:
  user/jmallett/octeon/sys/mips/cavium/octe/cavium-ethernet.h
  user/jmallett/octeon/sys/mips/cavium/octe/ethernet.c

Modified: user/jmallett/octeon/sys/mips/cavium/octe/cavium-ethernet.h
==============================================================================
--- user/jmallett/octeon/sys/mips/cavium/octe/cavium-ethernet.h	Thu Apr 22 20:46:39 2010	(r207072)
+++ user/jmallett/octeon/sys/mips/cavium/octe/cavium-ethernet.h	Thu Apr 22 20:54:32 2010	(r207073)
@@ -103,6 +103,9 @@ typedef struct {
 	 */
 	int (*open)(struct ifnet *ifp);
 	int (*stop)(struct ifnet *ifp);
+
+	int (*init)(struct ifnet *ifp);
+	void (*uninit)(struct ifnet *ifp);
 } cvm_oct_private_t;
 
 

Modified: user/jmallett/octeon/sys/mips/cavium/octe/ethernet.c
==============================================================================
--- user/jmallett/octeon/sys/mips/cavium/octe/ethernet.c	Thu Apr 22 20:46:39 2010	(r207072)
+++ user/jmallett/octeon/sys/mips/cavium/octe/ethernet.c	Thu Apr 22 20:54:32 2010	(r207073)
@@ -25,42 +25,62 @@ This Software, including technical data,
 TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
 AND WITH ALL FAULTS AND CAVIUM  NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
 *************************************************************************/
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/mii.h>
-#include <net/dst.h>
-#include <asm/delay.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/module.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_types.h>
 
 #include "wrapper-cvmx-includes.h"
 #include "ethernet-headers.h"
 
+/*
+ * XXX/juli
+ * Convert 0444 to tunables, 0644 to sysctls.
+ */
 #if defined(CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS) && CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS
 int num_packet_buffers = CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS;
 #else
 int num_packet_buffers = 1024;
 #endif
+#if 0
 module_param(num_packet_buffers, int, 0444);
 MODULE_PARM_DESC(num_packet_buffers, "\n"
 		 "\t\tNumber of packet buffers to allocate and store in the\n"
 		 "\t\tFPA. By default, 1024 packet buffers are used unless\n"
 		 "\t\tCONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS is defined.");
+#endif
 
 int pow_receive_group = 15;
+#if 0
 module_param(pow_receive_group, int, 0444);
 MODULE_PARM_DESC(pow_receive_group, "\n"
 		 "\t\tPOW group to receive packets from. All ethernet hardware\n"
 		 "\t\twill be configured to send incomming packets to this POW\n"
 		 "\t\tgroup. Also any other software can submit packets to this\n"
 		 "\t\tgroup for the kernel to process.");
+#endif
 
 int pow_send_group = -1;
+#if 0
 module_param(pow_send_group, int, 0644);
 MODULE_PARM_DESC(pow_send_group, "\n"
 		 "\t\tPOW group to send packets to other software on. This\n"
 		 "\t\tcontrols the creation of the virtual device pow0.\n"
 		 "\t\talways_use_pow also depends on this value.");
+#endif
 
 int always_use_pow;
+#if 0
 module_param(always_use_pow, int, 0444);
 MODULE_PARM_DESC(always_use_pow, "\n"
 		 "\t\tWhen set, always send to the pow group. This will cause\n"
@@ -71,8 +91,10 @@ MODULE_PARM_DESC(always_use_pow, "\n"
 		 "\t\tto allow a CVMX app to intercept all packets from the\n"
 		 "\t\tlinux kernel. You must specify pow_send_group along with\n"
 		 "\t\tthis option.");
+#endif
 
 char pow_send_list[128] = "";
+#if 0
 module_param_string(pow_send_list, pow_send_list, sizeof(pow_send_list), 0444);
 MODULE_PARM_DESC(pow_send_list, "\n"
 		 "\t\tComma separated list of ethernet devices that should use the\n"
@@ -81,14 +103,17 @@ MODULE_PARM_DESC(pow_send_list, "\n"
 		 "\t\tprecedence over this list. For example, setting this to\n"
 		 "\t\t\"eth2,spi3,spi7\" would cause these three devices to transmit\n"
 		 "\t\tusing the pow_send_group.");
+#endif
 
 
+#if 0
 static int disable_core_queueing = 1;
 module_param(disable_core_queueing, int, 0444);
 MODULE_PARM_DESC(disable_core_queueing, "\n"
 		"\t\tWhen set the networking core's tx_queue_len is set to zero.  This\n"
 		"\t\tallows packets to be sent without lock contention in the packet scheduler\n"
 		"\t\tresulting in some cases in improved throughput.\n");
+#endif
 
 extern int octeon_is_simulation(void);
 
@@ -98,10 +123,16 @@ extern int octeon_is_simulation(void);
  */
 extern cvmx_bootinfo_t *octeon_bootinfo;
 
+/*
+ * XXX
+ * This should be a per-if callout?
+ */
+#if 0
 /**
  * Periodic timer to check auto negotiation
  */
 static struct timer_list cvm_oct_poll_timer;
+#endif
 
 /**
  * Array of every ethernet device owned by this driver indexed by
@@ -109,7 +140,9 @@ static struct timer_list cvm_oct_poll_ti
  */
 struct ifnet *cvm_oct_device[TOTAL_NUMBER_OF_PORTS];
 
+#if 0
 extern struct semaphore mdio_sem;
+#endif
 
 
 /**
@@ -117,25 +150,33 @@ extern struct semaphore mdio_sem;
  *
  * @param arg    Device to check
  */
+#if 0
 static void cvm_do_timer(unsigned long arg)
 {
 	static int port;
 	if (port < CVMX_PIP_NUM_INPUT_PORTS) {
 		if (cvm_oct_device[port]) {
 			int queues_per_port;
+#if 0
 			int qos;
-			cvm_oct_private_t *priv = (cvm_oct_private_t *)netdev_priv(cvm_oct_device[port]);
+#endif
+			cvm_oct_private_t *priv = (cvm_oct_private_t *)cvm_oct_device[port]->if_softc;
 			if (priv->poll) 
 			{
+#if 0
 				/* skip polling if we don't get the lock */
 				if(!down_trylock(&mdio_sem)) {
 					priv->poll(cvm_oct_device[port]);
 					up(&mdio_sem);
 				}
+#else
+				panic("%s: wrap priv->poll with an mdio lock.", __func__);
+#endif
 			}
 
 			queues_per_port = cvmx_pko_get_num_queues(port);
 			/* Drain any pending packets in the free list */
+#if 0
 			for (qos = 0; qos < queues_per_port; qos++) {
 				if (m_queue_len(&priv->tx_free_list[qos])) {
 					spin_lock(&priv->tx_free_list[qos].lock);
@@ -144,27 +185,41 @@ static void cvm_do_timer(unsigned long a
 					spin_unlock(&priv->tx_free_list[qos].lock);
 				}
 			}
+#else
+			panic("%s: need to implement Tx queue draining.", __func__);
+#endif
+#if 0
 			cvm_oct_device[port]->get_stats(cvm_oct_device[port]);
+#else
+			panic("%s: need to implement stats getting.", __func__);
+#endif
 		}
 		port++;
+#if 0
 		/* Poll the next port in a 50th of a second.
 		   This spreads the polling of ports out a little bit */
 		mod_timer(&cvm_oct_poll_timer, jiffies + HZ/50);
+#endif
 	} else {
 		port = 0;
+#if 0
 		/* All ports have been polled. Start the next iteration through
 		   the ports in one second */
 		mod_timer(&cvm_oct_poll_timer, jiffies + HZ);
+#endif
 	}
 }
+#endif
 
 
 /**
  * Configure common hardware for all interfaces
  */
-static __init void cvm_oct_configure_common_hw(void)
+static void cvm_oct_configure_common_hw(void)
 {
+#if 0
 	int r;
+#endif
 	/* Setup the FPA */
 	cvmx_fpa_enable();
 	cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, num_packet_buffers);
@@ -179,11 +234,14 @@ static __init void cvm_oct_configure_com
 	if (!octeon_is_simulation())
 		cvmx_write_csr(CVMX_SMI_EN, 1);
 
+#if 0
 	/* Register an IRQ hander for to receive POW interrupts */
 	r = request_irq(OCTEON_IRQ_WORKQ0 + pow_receive_group, cvm_oct_do_interrupt, IRQF_SHARED, "Ethernet", cvm_oct_device);
+#endif
 
 #ifdef SMP
 	if (USE_MULTICORE_RECEIVE) {
+#if 0
 		preempt_disable();
 		{
 			int cpu;
@@ -198,6 +256,9 @@ static __init void cvm_oct_configure_com
 			}
 		}
 		preempt_enable();
+#else
+		panic("%s: need to implement CPU enumeration.", __func__);
+#endif
 	}
 #endif
 }
@@ -217,6 +278,7 @@ static __init void cvm_oct_configure_com
  * @param callback Intercept callback to set.
  * @return Device structure for the ethernet port or NULL on failure.
  */
+#if 0
 struct ifnet *cvm_oct_register_callback(const char *device_name, cvm_oct_callback_t callback)
 {
 	int port;
@@ -224,7 +286,7 @@ struct ifnet *cvm_oct_register_callback(
 	for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) {
 		if (cvm_oct_device[port] &&
 		    (strcmp(device_name, cvm_oct_device[port]->name) == 0)) {
-			cvm_oct_private_t *priv = (cvm_oct_private_t *)netdev_priv(cvm_oct_device[port]);
+			cvm_oct_private_t *priv = (cvm_oct_private_t *)cvm_oct_device[port]->if_softc;
 			priv->intercept_cb = callback;
 			wmb();
 			return cvm_oct_device[port];
@@ -233,7 +295,7 @@ struct ifnet *cvm_oct_register_callback(
 
 	return NULL;
 }
-EXPORT_SYMBOL(cvm_oct_register_callback);
+#endif
 
 
 /**
@@ -252,7 +314,7 @@ int cvm_oct_free_work(void *work_queue_e
 
 	while (segments--) {
 		cvmx_buf_ptr_t next_ptr = *(cvmx_buf_ptr_t *)cvmx_phys_to_ptr(segment_ptr.s.addr-8);
-		if (unlikely(!segment_ptr.s.i))
+		if (__predict_false(!segment_ptr.s.i))
 			cvmx_fpa_free(cvm_oct_get_buffer_ptr(segment_ptr), segment_ptr.s.pool, DONT_WRITEBACK(CVMX_FPA_PACKET_POOL_SIZE/128));
 		segment_ptr = next_ptr;
 	}
@@ -260,7 +322,6 @@ int cvm_oct_free_work(void *work_queue_e
 
 	return 0;
 }
-EXPORT_SYMBOL(cvm_oct_free_work);
 
 
 /**
@@ -269,13 +330,16 @@ EXPORT_SYMBOL(cvm_oct_free_work);
  *
  * @return Zero on success
  */
-static int __init cvm_oct_init_module(void)
+static int cvm_oct_init_module(void)
 {
+	device_t dev;
 	int num_interfaces;
 	int interface;
 	int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE;
 	int qos;
 
+	dev = NULL;
+
 	printf("cavium-ethernet: %s\n", OCTEON_SDK_VERSION_STRING);
 
 	cvm_oct_proc_initialize();
@@ -307,26 +371,31 @@ static int __init cvm_oct_init_module(vo
 
 	if ((pow_send_group != -1)) {
 		struct ifnet *ifp;
+
 		printf("\tConfiguring device for POW only access\n");
-		dev = alloc_etherdev(sizeof(cvm_oct_private_t));
+		ifp = if_alloc(IFT_ETHER);
 		if (ifp) {
 			/* Initialize the device private structure. */
-			cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
-			memset(priv, 0, sizeof(cvm_oct_private_t));
-
-			ifp->init = cvm_oct_common_init;
+			cvm_oct_private_t *priv;
+			
+			priv = malloc(sizeof(cvm_oct_private_t), M_TEMP, M_WAITOK | M_ZERO);
+			priv->init = cvm_oct_common_init;
 			priv->imode = CVMX_HELPER_INTERFACE_MODE_DISABLED;
 			priv->port = CVMX_PIP_NUM_INPUT_PORTS;
 			priv->queue = -1;
-			device_set_desc(ifp, "Cavium Octeon POW Ethernet");
+			device_set_desc(dev, "Cavium Octeon POW Ethernet");
+#if 0
 			for (qos = 0; qos < 16; qos++)
 				m_queue_head_init(&priv->tx_free_list[qos]);
+#endif
 
-			if (register_netdev(ifp) < 0) {
+			ifp->if_softc = priv;
+
+			if (priv->init(ifp) < 0) {
 				printf("\t\tFailed to register ethernet device for POW\n");
-				kfree(ifp);
+				panic("%s: need to free ifp.", __func__);
 			} else {
-				cvm_oct_device[CVMX_PIP_NUM_INPUT_PORTS] = dev;
+				cvm_oct_device[CVMX_PIP_NUM_INPUT_PORTS] = ifp;
 				printf("\t\t%s: POW send group %d, receive group %d\n",
 				if_name(ifp), pow_send_group, pow_receive_group);
 			}
@@ -343,25 +412,30 @@ static int __init cvm_oct_init_module(vo
 
 		for (port = cvmx_helper_get_ipd_port(interface, 0); port < cvmx_helper_get_ipd_port(interface, num_ports); port++) {
 			cvm_oct_private_t *priv;
-			struct ifnet *ifp = alloc_etherdev(sizeof(cvm_oct_private_t));
-			if (!dev) {
+			struct ifnet *ifp;
+			
+			ifp = if_alloc(IFT_ETHER);
+			if (!ifp) {
 				printf("\t\tFailed to allocate ethernet device for port %d\n", port);
 				continue;
 			}
+			/* XXX/juli set max send q len.  */
+#if 0
 			if (disable_core_queueing)
 				ifp->tx_queue_len = 0;
+#endif
 
 			/* Initialize the device private structure. */
-			priv = (cvm_oct_private_t *)ifp->if_softc;
-			memset(priv, 0, sizeof(cvm_oct_private_t));
-
+			priv = malloc(sizeof(cvm_oct_private_t), M_TEMP, M_WAITOK | M_ZERO);
 			priv->imode = imode;
 			priv->port = port;
 			priv->queue = cvmx_pko_get_base_queue(priv->port);
 			priv->intercept_cb = NULL;
 			priv->fau = fau - cvmx_pko_get_num_queues(port) * 4;
+#if 0
 			for (qos = 0; qos < 16; qos++)
 				m_queue_head_init(&priv->tx_free_list[qos]);
+#endif
 			for (qos = 0; qos < cvmx_pko_get_num_queues(port); qos++)
 				cvmx_fau_atomic_write32(priv->fau+qos*4, 0);
 
@@ -374,57 +448,59 @@ static int __init cvm_oct_init_module(vo
 				break;
 
 			case CVMX_HELPER_INTERFACE_MODE_NPI:
-				ifp->init = cvm_oct_common_init;
-				ifp->uninit = cvm_oct_common_uninit;
-				device_set_desc(ifp, "Cavium Octeon NPI Ethernet");
+				priv->init = cvm_oct_common_init;
+				priv->uninit = cvm_oct_common_uninit;
+				device_set_desc(dev, "Cavium Octeon NPI Ethernet");
 				break;
 
 			case CVMX_HELPER_INTERFACE_MODE_XAUI:
-				ifp->init = cvm_oct_xaui_init;
-				ifp->uninit = cvm_oct_xaui_uninit;
-				device_set_desc(ifp, "Cavium Octeon XAUI Ethernet");
+				priv->init = cvm_oct_xaui_init;
+				priv->uninit = cvm_oct_xaui_uninit;
+				device_set_desc(dev, "Cavium Octeon XAUI Ethernet");
 				break;
 
 			case CVMX_HELPER_INTERFACE_MODE_LOOP:
-				ifp->init = cvm_oct_common_init;
-				ifp->uninit = cvm_oct_common_uninit;
-				device_set_desc(ifp, "Cavium Octeon LOOP Ethernet");
+				priv->init = cvm_oct_common_init;
+				priv->uninit = cvm_oct_common_uninit;
+				device_set_desc(dev, "Cavium Octeon LOOP Ethernet");
 				break;
 
 			case CVMX_HELPER_INTERFACE_MODE_SGMII:
-				ifp->init = cvm_oct_sgmii_init;
-				ifp->uninit = cvm_oct_sgmii_uninit;
-				device_set_desc(ifp, "Cavium Octeon SGMII Ethernet");
+				priv->init = cvm_oct_sgmii_init;
+				priv->uninit = cvm_oct_sgmii_uninit;
+				device_set_desc(dev, "Cavium Octeon SGMII Ethernet");
 				break;
 
 			case CVMX_HELPER_INTERFACE_MODE_SPI:
-				ifp->init = cvm_oct_spi_init;
-				ifp->uninit = cvm_oct_spi_uninit;
-				device_set_desc(ifp, "Cavium Octeon SPI Ethernet");
+				priv->init = cvm_oct_spi_init;
+				priv->uninit = cvm_oct_spi_uninit;
+				device_set_desc(dev, "Cavium Octeon SPI Ethernet");
 				break;
 
 			case CVMX_HELPER_INTERFACE_MODE_RGMII:
-				ifp->init = cvm_oct_rgmii_init;
-				ifp->uninit = cvm_oct_rgmii_uninit;
-				device_set_desc(ifp, "Cavium Octeon RGMII Ethernet");
+				priv->init = cvm_oct_rgmii_init;
+				priv->uninit = cvm_oct_rgmii_uninit;
+				device_set_desc(dev, "Cavium Octeon RGMII Ethernet");
 				break;
 
 			case CVMX_HELPER_INTERFACE_MODE_GMII:
-				ifp->init = cvm_oct_rgmii_init;
-				ifp->uninit = cvm_oct_rgmii_uninit;
-				device_set_desc(ifp, "Cavium Octeon GMII Ethernet");
+				priv->init = cvm_oct_rgmii_init;
+				priv->uninit = cvm_oct_rgmii_uninit;
+				device_set_desc(dev, "Cavium Octeon GMII Ethernet");
 				break;
 			}
 
-			if (!ifp->init) {
-				kfree(ifp);
+			ifp->if_softc = priv;
+
+			if (!priv->init) {
+				panic("%s: unsupported device type, need to free ifp.", __func__);
 			} else
-			if (register_netdev(ifp) < 0) {
+			if (priv->init(ifp) < 0) {
 				printf("\t\tFailed to register ethernet device for interface %d, port %d\n",
 				interface, priv->port);
-				kfree(ifp);
+				panic("%s: init failed, need to free ifp.", __func__);
 			} else {
-				cvm_oct_device[priv->port] = dev;
+				cvm_oct_device[priv->port] = ifp;
 				fau -= cvmx_pko_get_num_queues(priv->port) * sizeof(uint32_t);
 			}
 		}
@@ -441,11 +517,13 @@ static int __init cvm_oct_init_module(vo
 		cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1001);
 	}
 
+#if 0
 	/* Enable the poll timer for checking RGMII status */
 	init_timer(&cvm_oct_poll_timer);
 	cvm_oct_poll_timer.data = 0;
 	cvm_oct_poll_timer.function = cvm_do_timer;
 	mod_timer(&cvm_oct_poll_timer, jiffies + HZ);
+#endif
 
 	return 0;
 }
@@ -456,7 +534,7 @@ static int __init cvm_oct_init_module(vo
  *
  * @return Zero on success
  */
-static void __exit cvm_oct_cleanup_module(void)
+static void cvm_oct_cleanup_module(void)
 {
 	int port;
 
@@ -465,10 +543,14 @@ static void __exit cvm_oct_cleanup_modul
 
 	cvmx_ipd_disable();
 
+#if 0
 	/* Free the interrupt handler */
 	free_irq(8 + pow_receive_group, cvm_oct_device);
+#endif
 
+#if 0
 	del_timer(&cvm_oct_poll_timer);
+#endif
 	cvm_oct_rx_shutdown();
 	cvmx_pko_disable();
 
@@ -476,8 +558,12 @@ static void __exit cvm_oct_cleanup_modul
 	for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) {
 		if (cvm_oct_device[port]) {
 			cvm_oct_tx_shutdown(cvm_oct_device[port]);
+#if 0
 			unregister_netdev(cvm_oct_device[port]);
 			kfree(cvm_oct_device[port]);
+#else
+			panic("%s: need to detach and free interface.", __func__);
+#endif
 			cvm_oct_device[port] = NULL;
 		}
 	}
@@ -494,14 +580,21 @@ static void __exit cvm_oct_cleanup_modul
 		cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128);
 }
 
-/* Note that this module is covered by the GPL even though the files are
-    under a BSD style license. The GPL is inherited from the CVMX files
-    used by this driver. If you would like to use the module under the
-    Cavium proprietary license, you must change the makefile to include
-    the proprietary CVMX files. */
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Cavium Networks <support@caviumnetworks.com>");
-MODULE_DESCRIPTION("Cavium Networks Octeon ethernet driver.");
-module_init(cvm_oct_init_module);
-module_exit(cvm_oct_cleanup_module);
-
+static int
+cvm_oct_modevent(module_t mod __unused, int type, void *data __unused)
+{
+	switch(type) {
+	case MOD_LOAD:
+		cvm_oct_init_module();
+		break;
+	case MOD_UNLOAD:
+	case MOD_SHUTDOWN:
+		cvm_oct_cleanup_module();
+		break;
+	default:
+		return (EOPNOTSUPP);
+        }
+	return (0);
+}
+DEV_MODULE(octe, cvm_oct_modevent, NULL);
+MODULE_VERSION(octe, 1);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201004222054.o3MKsWAu089135>