Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ixgbe/if_ixv.c
Show All 37 Lines | |||||
#include "opt_inet6.h" | #include "opt_inet6.h" | ||||
#endif | #endif | ||||
#include "ixgbe.h" | #include "ixgbe.h" | ||||
/********************************************************************* | /********************************************************************* | ||||
* Driver version | * Driver version | ||||
*********************************************************************/ | *********************************************************************/ | ||||
char ixv_driver_version[] = "1.2.5"; | char ixv_driver_version[] = "1.4.0"; | ||||
/********************************************************************* | /********************************************************************* | ||||
* PCI Device ID Table | * PCI Device ID Table | ||||
* | * | ||||
* Used by probe to select devices to load on | * Used by probe to select devices to load on | ||||
* Last field stores an index into ixv_strings | * Last field stores an index into ixv_strings | ||||
* Last entry must be all 0s | * Last entry must be all 0s | ||||
* | * | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | |||||
/* The MSI/X Interrupt handlers */ | /* The MSI/X Interrupt handlers */ | ||||
static void ixv_msix_que(void *); | static void ixv_msix_que(void *); | ||||
static void ixv_msix_mbx(void *); | static void ixv_msix_mbx(void *); | ||||
/* Deferred interrupt tasklets */ | /* Deferred interrupt tasklets */ | ||||
static void ixv_handle_que(void *, int); | static void ixv_handle_que(void *, int); | ||||
static void ixv_handle_mbx(void *, int); | static void ixv_handle_mbx(void *, int); | ||||
#ifdef DEV_NETMAP | |||||
/* | |||||
* This is defined in <dev/netmap/ixgbe_netmap.h>, which is included by | |||||
* if_ix.c. | |||||
*/ | |||||
extern void ixgbe_netmap_attach(struct adapter *adapter); | |||||
#include <net/netmap.h> | |||||
#include <sys/selinfo.h> | |||||
#include <dev/netmap/netmap_kern.h> | |||||
#endif /* DEV_NETMAP */ | |||||
/********************************************************************* | /********************************************************************* | ||||
* FreeBSD Device Interface Entry Points | * FreeBSD Device Interface Entry Points | ||||
*********************************************************************/ | *********************************************************************/ | ||||
static device_method_t ixv_methods[] = { | static device_method_t ixv_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
DEVMETHOD(device_probe, ixv_probe), | DEVMETHOD(device_probe, ixv_probe), | ||||
DEVMETHOD(device_attach, ixv_attach), | DEVMETHOD(device_attach, ixv_attach), | ||||
DEVMETHOD(device_detach, ixv_detach), | DEVMETHOD(device_detach, ixv_detach), | ||||
DEVMETHOD(device_shutdown, ixv_shutdown), | DEVMETHOD(device_shutdown, ixv_shutdown), | ||||
DEVMETHOD_END | DEVMETHOD_END | ||||
}; | }; | ||||
static driver_t ixv_driver = { | static driver_t ixv_driver = { | ||||
"ixv", ixv_methods, sizeof(struct adapter), | "ixv", ixv_methods, sizeof(struct adapter), | ||||
}; | }; | ||||
devclass_t ixv_devclass; | devclass_t ixv_devclass; | ||||
DRIVER_MODULE(ixv, pci, ixv_driver, ixv_devclass, 0, 0); | DRIVER_MODULE(ixv, pci, ixv_driver, ixv_devclass, 0, 0); | ||||
MODULE_DEPEND(ixv, pci, 1, 1, 1); | MODULE_DEPEND(ixv, pci, 1, 1, 1); | ||||
MODULE_DEPEND(ixv, ether, 1, 1, 1); | MODULE_DEPEND(ixv, ether, 1, 1, 1); | ||||
#ifdef DEV_NETMAP | |||||
MODULE_DEPEND(ix, netmap, 1, 1, 1); | |||||
#endif /* DEV_NETMAP */ | |||||
/* XXX depend on 'ix' ? */ | /* XXX depend on 'ix' ? */ | ||||
/* | /* | ||||
** TUNEABLE PARAMETERS: | ** TUNEABLE PARAMETERS: | ||||
*/ | */ | ||||
/* Number of Queues - do not exceed MSIX vectors - 1 */ | |||||
static int ixv_num_queues = 1; | |||||
TUNABLE_INT("hw.ixv.num_queues", &ixv_num_queues); | |||||
smh: As a side note this will be invisible to users, so HEAD should change this and others to a… | |||||
/* | /* | ||||
** AIM: Adaptive Interrupt Moderation | ** AIM: Adaptive Interrupt Moderation | ||||
** which means that the interrupt rate | ** which means that the interrupt rate | ||||
** is varied over time based on the | ** is varied over time based on the | ||||
** traffic for that interrupt vector | ** traffic for that interrupt vector | ||||
*/ | */ | ||||
static int ixv_enable_aim = FALSE; | static int ixv_enable_aim = FALSE; | ||||
TUNABLE_INT("hw.ixv.enable_aim", &ixv_enable_aim); | TUNABLE_INT("hw.ixv.enable_aim", &ixv_enable_aim); | ||||
▲ Show 20 Lines • Show All 143 Lines • ▼ Show 20 Lines | ixv_attach(device_t dev) | ||||
ixv_set_sysctl_value(adapter, "rx_processing_limit", | ixv_set_sysctl_value(adapter, "rx_processing_limit", | ||||
"max number of rx packets to process", | "max number of rx packets to process", | ||||
&adapter->rx_process_limit, ixv_rx_process_limit); | &adapter->rx_process_limit, ixv_rx_process_limit); | ||||
ixv_set_sysctl_value(adapter, "tx_processing_limit", | ixv_set_sysctl_value(adapter, "tx_processing_limit", | ||||
"max number of tx packets to process", | "max number of tx packets to process", | ||||
&adapter->tx_process_limit, ixv_tx_process_limit); | &adapter->tx_process_limit, ixv_tx_process_limit); | ||||
/* Sysctls for limiting the amount of work done in the taskqueues */ | |||||
ixv_set_sysctl_value(adapter, "rx_processing_limit", | |||||
"max number of rx packets to process", | |||||
&adapter->rx_process_limit, ixv_rx_process_limit); | |||||
ixv_set_sysctl_value(adapter, "tx_processing_limit", | |||||
"max number of tx packets to process", | |||||
&adapter->tx_process_limit, ixv_tx_process_limit); | |||||
/* Do descriptor calc and sanity checks */ | /* Do descriptor calc and sanity checks */ | ||||
if (((ixv_txd * sizeof(union ixgbe_adv_tx_desc)) % DBA_ALIGN) != 0 || | if (((ixv_txd * sizeof(union ixgbe_adv_tx_desc)) % DBA_ALIGN) != 0 || | ||||
ixv_txd < MIN_TXD || ixv_txd > MAX_TXD) { | ixv_txd < MIN_TXD || ixv_txd > MAX_TXD) { | ||||
device_printf(dev, "TXD config issue, using default!\n"); | device_printf(dev, "TXD config issue, using default!\n"); | ||||
adapter->num_tx_desc = DEFAULT_TXD; | adapter->num_tx_desc = DEFAULT_TXD; | ||||
} else | } else | ||||
adapter->num_tx_desc = ixv_txd; | adapter->num_tx_desc = ixv_txd; | ||||
Show All 21 Lines | if (error) { | ||||
goto err_late; | goto err_late; | ||||
} | } | ||||
/* Setup the mailbox */ | /* Setup the mailbox */ | ||||
ixgbe_init_mbx_params_vf(hw); | ixgbe_init_mbx_params_vf(hw); | ||||
ixgbe_reset_hw(hw); | ixgbe_reset_hw(hw); | ||||
/* Get the Mailbox API version */ | |||||
device_printf(dev,"MBX API %d negotiation: %d\n", | |||||
ixgbe_mbox_api_11, | |||||
ixgbevf_negotiate_api_version(hw, ixgbe_mbox_api_11)); | |||||
error = ixgbe_init_hw(hw); | error = ixgbe_init_hw(hw); | ||||
if (error) { | if (error) { | ||||
device_printf(dev,"Hardware Initialization Failure\n"); | device_printf(dev,"Hardware Initialization Failure\n"); | ||||
error = EIO; | error = EIO; | ||||
goto err_late; | goto err_late; | ||||
} | } | ||||
error = ixv_allocate_msix(adapter); | error = ixv_allocate_msix(adapter); | ||||
Show All 18 Lines | ixv_attach(device_t dev) | ||||
ixv_add_stats_sysctls(adapter); | ixv_add_stats_sysctls(adapter); | ||||
/* Register for VLAN events */ | /* Register for VLAN events */ | ||||
adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, | adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, | ||||
ixv_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); | ixv_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); | ||||
adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, | adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, | ||||
ixv_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); | ixv_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); | ||||
#ifdef DEV_NETMAP | |||||
ixgbe_netmap_attach(adapter); | |||||
#endif /* DEV_NETMAP */ | |||||
INIT_DEBUGOUT("ixv_attach: end"); | INIT_DEBUGOUT("ixv_attach: end"); | ||||
return (0); | return (0); | ||||
err_late: | err_late: | ||||
ixgbe_free_transmit_structures(adapter); | ixgbe_free_transmit_structures(adapter); | ||||
ixgbe_free_receive_structures(adapter); | ixgbe_free_receive_structures(adapter); | ||||
err_out: | err_out: | ||||
ixv_free_pci_resources(adapter); | ixv_free_pci_resources(adapter); | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | ixv_detach(device_t dev) | ||||
/* Unregister VLAN events */ | /* Unregister VLAN events */ | ||||
if (adapter->vlan_attach != NULL) | if (adapter->vlan_attach != NULL) | ||||
EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach); | EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach); | ||||
if (adapter->vlan_detach != NULL) | if (adapter->vlan_detach != NULL) | ||||
EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); | EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); | ||||
ether_ifdetach(adapter->ifp); | ether_ifdetach(adapter->ifp); | ||||
callout_drain(&adapter->timer); | callout_drain(&adapter->timer); | ||||
#ifdef DEV_NETMAP | |||||
netmap_detach(adapter->ifp); | |||||
#endif /* DEV_NETMAP */ | |||||
ixv_free_pci_resources(adapter); | ixv_free_pci_resources(adapter); | ||||
bus_generic_detach(dev); | bus_generic_detach(dev); | ||||
if_free(adapter->ifp); | if_free(adapter->ifp); | ||||
ixgbe_free_transmit_structures(adapter); | ixgbe_free_transmit_structures(adapter); | ||||
ixgbe_free_receive_structures(adapter); | ixgbe_free_receive_structures(adapter); | ||||
IXGBE_CORE_LOCK_DESTROY(adapter); | IXGBE_CORE_LOCK_DESTROY(adapter); | ||||
▲ Show 20 Lines • Show All 862 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Setup MSIX resources, note that the VF | * Setup MSIX resources, note that the VF | ||||
* device MUST use MSIX, there is no fallback. | * device MUST use MSIX, there is no fallback. | ||||
*/ | */ | ||||
static int | static int | ||||
ixv_setup_msix(struct adapter *adapter) | ixv_setup_msix(struct adapter *adapter) | ||||
{ | { | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
int rid, want; | int rid, want, msgs; | ||||
/* First try MSI/X */ | /* Must have at least 2 MSIX vectors */ | ||||
msgs = pci_msix_count(dev); | |||||
if (msgs < 2) | |||||
goto out; | |||||
rid = PCIR_BAR(3); | rid = PCIR_BAR(3); | ||||
adapter->msix_mem = bus_alloc_resource_any(dev, | adapter->msix_mem = bus_alloc_resource_any(dev, | ||||
SYS_RES_MEMORY, &rid, RF_ACTIVE); | SYS_RES_MEMORY, &rid, RF_ACTIVE); | ||||
if (adapter->msix_mem == NULL) { | if (adapter->msix_mem == NULL) { | ||||
device_printf(adapter->dev, | device_printf(adapter->dev, | ||||
"Unable to map MSIX table \n"); | "Unable to map MSIX table \n"); | ||||
goto out; | goto out; | ||||
} | } | ||||
/* | /* | ||||
** Want two vectors: one for a queue, | ** Want vectors for the queues, | ||||
** plus an additional for mailbox. | ** plus an additional for mailbox. | ||||
*/ | */ | ||||
want = 2; | want = adapter->num_queues + 1; | ||||
if ((pci_alloc_msix(dev, &want) == 0) && (want == 2)) { | if (want > msgs) { | ||||
want = msgs; | |||||
adapter->num_queues = msgs - 1; | |||||
} else | |||||
msgs = want; | |||||
if ((pci_alloc_msix(dev, &msgs) == 0) && (msgs == want)) { | |||||
device_printf(adapter->dev, | device_printf(adapter->dev, | ||||
"Using MSIX interrupts with %d vectors\n", want); | "Using MSIX interrupts with %d vectors\n", want); | ||||
return (want); | return (want); | ||||
} | } | ||||
/* Release in case alloc was insufficient */ | /* Release in case alloc was insufficient */ | ||||
pci_release_msi(dev); | pci_release_msi(dev); | ||||
out: | out: | ||||
if (adapter->msix_mem != NULL) { | if (adapter->msix_mem != NULL) { | ||||
Show All 22 Lines | ixv_allocate_pci_resources(struct adapter *adapter) | ||||
} | } | ||||
adapter->osdep.mem_bus_space_tag = | adapter->osdep.mem_bus_space_tag = | ||||
rman_get_bustag(adapter->pci_mem); | rman_get_bustag(adapter->pci_mem); | ||||
adapter->osdep.mem_bus_space_handle = | adapter->osdep.mem_bus_space_handle = | ||||
rman_get_bushandle(adapter->pci_mem); | rman_get_bushandle(adapter->pci_mem); | ||||
adapter->hw.hw_addr = (u8 *) &adapter->osdep.mem_bus_space_handle; | adapter->hw.hw_addr = (u8 *) &adapter->osdep.mem_bus_space_handle; | ||||
adapter->num_queues = 1; | /* Pick up the tuneable queues */ | ||||
adapter->num_queues = ixv_num_queues; | |||||
adapter->hw.back = &adapter->osdep; | adapter->hw.back = &adapter->osdep; | ||||
/* | /* | ||||
** Now setup MSI/X, should | ** Now setup MSI/X, should | ||||
** return us the number of | ** return us the number of | ||||
** configured vectors. | ** configured vectors. | ||||
*/ | */ | ||||
adapter->msix = ixv_setup_msix(adapter); | adapter->msix = ixv_setup_msix(adapter); | ||||
▲ Show 20 Lines • Show All 201 Lines • ▼ Show 20 Lines | |||||
**********************************************************************/ | **********************************************************************/ | ||||
#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 | #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 | ||||
static void | static void | ||||
ixv_initialize_receive_units(struct adapter *adapter) | ixv_initialize_receive_units(struct adapter *adapter) | ||||
{ | { | ||||
struct rx_ring *rxr = adapter->rx_rings; | struct rx_ring *rxr = adapter->rx_rings; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
u32 bufsz, fctrl, rxcsum, hlreg; | u32 bufsz, rxcsum, psrtype; | ||||
int max_frame; | |||||
if (ifp->if_mtu > ETHERMTU) | |||||
/* Enable broadcasts */ | |||||
fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); | |||||
fctrl |= IXGBE_FCTRL_BAM; | |||||
fctrl |= IXGBE_FCTRL_DPF; | |||||
fctrl |= IXGBE_FCTRL_PMCF; | |||||
IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); | |||||
/* Set for Jumbo Frames? */ | |||||
hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0); | |||||
if (ifp->if_mtu > ETHERMTU) { | |||||
hlreg |= IXGBE_HLREG0_JUMBOEN; | |||||
bufsz = 4096 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; | bufsz = 4096 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; | ||||
} else { | else | ||||
hlreg &= ~IXGBE_HLREG0_JUMBOEN; | |||||
bufsz = 2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; | bufsz = 2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; | ||||
} | |||||
IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); | |||||
psrtype = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR | | |||||
IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR | | |||||
IXGBE_PSRTYPE_L2HDR; | |||||
IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE, psrtype); | |||||
/* Tell PF our expected packet-size */ | |||||
max_frame = ifp->if_mtu + IXGBE_MTU_HDR; | |||||
ixgbevf_rlpml_set_vf(hw, max_frame); | |||||
for (int i = 0; i < adapter->num_queues; i++, rxr++) { | for (int i = 0; i < adapter->num_queues; i++, rxr++) { | ||||
u64 rdba = rxr->rxdma.dma_paddr; | u64 rdba = rxr->rxdma.dma_paddr; | ||||
u32 reg, rxdctl; | u32 reg, rxdctl; | ||||
/* Disable the queue */ | |||||
rxdctl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i)); | |||||
rxdctl &= ~(IXGBE_RXDCTL_ENABLE | IXGBE_RXDCTL_VME); | |||||
IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(i), rxdctl); | |||||
for (int j = 0; j < 10; j++) { | |||||
if (IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i)) & | |||||
IXGBE_RXDCTL_ENABLE) | |||||
msec_delay(1); | |||||
else | |||||
break; | |||||
} | |||||
wmb(); | |||||
/* Setup the Base and Length of the Rx Descriptor Ring */ | /* Setup the Base and Length of the Rx Descriptor Ring */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_VFRDBAL(i), | IXGBE_WRITE_REG(hw, IXGBE_VFRDBAL(i), | ||||
(rdba & 0x00000000ffffffffULL)); | (rdba & 0x00000000ffffffffULL)); | ||||
IXGBE_WRITE_REG(hw, IXGBE_VFRDBAH(i), | IXGBE_WRITE_REG(hw, IXGBE_VFRDBAH(i), | ||||
(rdba >> 32)); | (rdba >> 32)); | ||||
IXGBE_WRITE_REG(hw, IXGBE_VFRDLEN(i), | IXGBE_WRITE_REG(hw, IXGBE_VFRDLEN(i), | ||||
adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); | adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); | ||||
/* Reset the ring indices */ | |||||
IXGBE_WRITE_REG(hw, IXGBE_VFRDH(rxr->me), 0); | |||||
IXGBE_WRITE_REG(hw, IXGBE_VFRDT(rxr->me), 0); | |||||
/* Set up the SRRCTL register */ | /* Set up the SRRCTL register */ | ||||
reg = IXGBE_READ_REG(hw, IXGBE_VFSRRCTL(i)); | reg = IXGBE_READ_REG(hw, IXGBE_VFSRRCTL(i)); | ||||
reg &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; | reg &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; | ||||
reg &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; | reg &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; | ||||
reg |= bufsz; | reg |= bufsz; | ||||
reg |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; | reg |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; | ||||
IXGBE_WRITE_REG(hw, IXGBE_VFSRRCTL(i), reg); | IXGBE_WRITE_REG(hw, IXGBE_VFSRRCTL(i), reg); | ||||
Show All 12 Lines | for (int i = 0; i < adapter->num_queues; i++, rxr++) { | ||||
for (int k = 0; k < 10; k++) { | for (int k = 0; k < 10; k++) { | ||||
if (IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i)) & | if (IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i)) & | ||||
IXGBE_RXDCTL_ENABLE) | IXGBE_RXDCTL_ENABLE) | ||||
break; | break; | ||||
else | else | ||||
msec_delay(1); | msec_delay(1); | ||||
} | } | ||||
wmb(); | wmb(); | ||||
/* Set the Tail Pointer */ | |||||
#ifdef DEV_NETMAP | |||||
/* | |||||
* In netmap mode, we must preserve the buffers made | |||||
* available to userspace before the if_init() | |||||
* (this is true by default on the TX side, because | |||||
* init makes all buffers available to userspace). | |||||
* | |||||
* netmap_reset() and the device specific routines | |||||
* (e.g. ixgbe_setup_receive_rings()) map these | |||||
* buffers at the end of the NIC ring, so here we | |||||
* must set the RDT (tail) register to make sure | |||||
* they are not overwritten. | |||||
* | |||||
* In this driver the NIC ring starts at RDH = 0, | |||||
* RDT points to the last slot available for reception (?), | |||||
* so RDT = num_rx_desc - 1 means the whole ring is available. | |||||
*/ | |||||
if (ifp->if_capenable & IFCAP_NETMAP) { | |||||
struct netmap_adapter *na = NA(adapter->ifp); | |||||
struct netmap_kring *kring = &na->rx_rings[i]; | |||||
int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); | |||||
IXGBE_WRITE_REG(hw, IXGBE_VFRDT(rxr->me), t); | |||||
} else | |||||
#endif /* DEV_NETMAP */ | |||||
IXGBE_WRITE_REG(hw, IXGBE_VFRDT(rxr->me), | |||||
adapter->num_rx_desc - 1); | |||||
} | } | ||||
rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); | rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); | ||||
if (ifp->if_capenable & IFCAP_RXCSUM) | if (ifp->if_capenable & IFCAP_RXCSUM) | ||||
rxcsum |= IXGBE_RXCSUM_PCSD; | rxcsum |= IXGBE_RXCSUM_PCSD; | ||||
if (!(rxcsum & IXGBE_RXCSUM_PCSD)) | if (!(rxcsum & IXGBE_RXCSUM_PCSD)) | ||||
▲ Show 20 Lines • Show All 452 Lines • Show Last 20 Lines |
As a side note this will be invisible to users, so HEAD should change this and others to a SYSCTL.