diff options
author | jdp <jdp@FreeBSD.org> | 2003-08-01 17:33:59 +0000 |
---|---|---|
committer | jdp <jdp@FreeBSD.org> | 2003-08-01 17:33:59 +0000 |
commit | a8a8a6510a1ac447b83ccfaf699d87d95be84c96 (patch) | |
tree | f7af9d535127fd55adae86b8ebd86b68ce5be709 /sys/dev/em | |
parent | 25665981dd793b68604567181e50d307831c96f1 (diff) | |
download | FreeBSD-src-a8a8a6510a1ac447b83ccfaf699d87d95be84c96.zip FreeBSD-src-a8a8a6510a1ac447b83ccfaf699d87d95be84c96.tar.gz |
Add facilities for tuning the "em" driver's interrupt delays without
recompiling the driver. See the comments near the top of "if_em.h"
for descriptions of these delays. Four new loader tunables control
the system-wide default values:
hw.em.tx_int_delay
hw.em.rx_int_delay
hw.em.tx_abs_int_delay
hw.em.rx_abs_int_delay
The tunables are specified in microseconds. The valid range is
0-67108 usec., and 0 means that the timer is disabled.
There are also four new sysctls (actually, a set of four for each
"em" device in the system) to query and change the interrupt delays
after the system is up:
hw.em0.tx_int_delay
hw.em0.rx_int_delay
hw.em0.tx_abs_int_delay (not present for 82542/3/4 adapters)
hw.em0.rx_abs_int_delay (not present for 82542/3/4 adapters)
It seems to be OK to change these values even while the adapter is
passing traffic.
Approved by: Prafulla Deuskar <pdeuskar@FreeBSD.ORG>
MFC after: 4 weeks
Diffstat (limited to 'sys/dev/em')
-rw-r--r-- | sys/dev/em/if_em.c | 117 | ||||
-rw-r--r-- | sys/dev/em/if_em.h | 15 | ||||
-rw-r--r-- | sys/dev/em/if_em_osdep.h | 60 |
3 files changed, 148 insertions, 44 deletions
diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c index ceb4e1f..dd89589 100644 --- a/sys/dev/em/if_em.c +++ b/sys/dev/em/if_em.c @@ -163,6 +163,10 @@ static void em_print_debug_info(struct adapter *); static int em_is_valid_ether_addr(u_int8_t *); static int em_sysctl_stats(SYSCTL_HANDLER_ARGS); static int em_sysctl_debug_info(SYSCTL_HANDLER_ARGS); +static int em_sysctl_int_delay(SYSCTL_HANDLER_ARGS); +static void em_add_int_delay_sysctl(struct adapter *, const char *, + const char *, struct em_int_delay_info *, + int, int); /********************************************************************* * FreeBSD Device Interface Entry Points @@ -187,6 +191,23 @@ MODULE_DEPEND(em, pci, 1, 1, 1); MODULE_DEPEND(em, ether, 1, 1, 1); /********************************************************************* + * Tunable default values. + *********************************************************************/ + +#define E1000_TICKS_TO_USECS(ticks) ((1024 * (ticks) + 500) / 1000) +#define E1000_USECS_TO_TICKS(usecs) ((1000 * (usecs) + 512) / 1024) + +static int em_tx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TIDV); +static int em_rx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RDTR); +static int em_tx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TADV); +static int em_rx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RADV); + +TUNABLE_INT("hw.em.tx_int_delay", &em_tx_int_delay_dflt); +TUNABLE_INT("hw.em.rx_int_delay", &em_rx_int_delay_dflt); +TUNABLE_INT("hw.em.tx_abs_int_delay", &em_tx_abs_int_delay_dflt); +TUNABLE_INT("hw.em.rx_abs_int_delay", &em_rx_abs_int_delay_dflt); + +/********************************************************************* * Device identification routine * * em_probe determines if the driver should be loaded on @@ -305,14 +326,30 @@ em_attach(device_t dev) /* Determine hardware revision */ em_identify_hardware(adapter); + + /* Set up some sysctls for the tunable interrupt delays */ + em_add_int_delay_sysctl(adapter, "rx_int_delay", + "receive interrupt delay in usecs", &adapter->rx_int_delay, + E1000_REG_OFFSET(&adapter->hw, RDTR), em_rx_int_delay_dflt); + em_add_int_delay_sysctl(adapter, "tx_int_delay", + "transmit interrupt delay in usecs", &adapter->tx_int_delay, + E1000_REG_OFFSET(&adapter->hw, TIDV), em_tx_int_delay_dflt); + if (adapter->hw.mac_type >= em_82540) { + em_add_int_delay_sysctl(adapter, "rx_abs_int_delay", + "receive interrupt delay limit in usecs", + &adapter->rx_abs_int_delay, + E1000_REG_OFFSET(&adapter->hw, RADV), + em_rx_abs_int_delay_dflt); + em_add_int_delay_sysctl(adapter, "tx_abs_int_delay", + "transmit interrupt delay limit in usecs", + &adapter->tx_abs_int_delay, + E1000_REG_OFFSET(&adapter->hw, TADV), + em_tx_abs_int_delay_dflt); + } /* Parameters (to be read from user) */ adapter->num_tx_desc = EM_MAX_TXD; adapter->num_rx_desc = EM_MAX_RXD; - adapter->tx_int_delay = EM_TIDV; - adapter->tx_abs_int_delay = EM_TADV; - adapter->rx_int_delay = EM_RDTR; - adapter->rx_abs_int_delay = EM_RADV; adapter->hw.autoneg = DO_AUTO_NEG; adapter->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT; adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT; @@ -1982,9 +2019,10 @@ em_initialize_transmit_unit(struct adapter * adapter) } E1000_WRITE_REG(&adapter->hw, TIPG, reg_tipg); - E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay); + E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay.value); if(adapter->hw.mac_type >= em_82540) - E1000_WRITE_REG(&adapter->hw, TADV, adapter->tx_abs_int_delay); + E1000_WRITE_REG(&adapter->hw, TADV, + adapter->tx_abs_int_delay.value); /* Program the Transmit Control Register */ reg_tctl = E1000_TCTL_PSP | E1000_TCTL_EN | @@ -1999,7 +2037,7 @@ em_initialize_transmit_unit(struct adapter * adapter) /* Setup Transmit Descriptor Settings for this adapter */ adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_RS; - if (adapter->tx_int_delay > 0) + if (adapter->tx_int_delay.value > 0) adapter->txd_cmd |= E1000_TXD_CMD_IDE; return; @@ -2368,10 +2406,11 @@ em_initialize_receive_unit(struct adapter * adapter) /* Set the Receive Delay Timer Register */ E1000_WRITE_REG(&adapter->hw, RDTR, - adapter->rx_int_delay | E1000_RDT_FPDB); + adapter->rx_int_delay.value | E1000_RDT_FPDB); if(adapter->hw.mac_type >= em_82540) { - E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay); + E1000_WRITE_REG(&adapter->hw, RADV, + adapter->rx_abs_int_delay.value); /* Set the interrupt throttling rate. Value is calculated * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */ @@ -2999,3 +3038,63 @@ em_sysctl_stats(SYSCTL_HANDLER_ARGS) return error; } + +static int +em_sysctl_int_delay(SYSCTL_HANDLER_ARGS) +{ + struct em_int_delay_info *info; + struct adapter *adapter; + u_int32_t regval; + int error; + int usecs; + int ticks; + int s; + + info = (struct em_int_delay_info *)arg1; + adapter = info->adapter; + usecs = info->value; + error = sysctl_handle_int(oidp, &usecs, 0, req); + if (error != 0 || req->newptr == NULL) + return error; + if (usecs < 0 || usecs > E1000_TICKS_TO_USECS(65535)) + return EINVAL; + info->value = usecs; + ticks = E1000_USECS_TO_TICKS(usecs); + + s = splimp(); + regval = E1000_READ_OFFSET(&adapter->hw, info->offset); + regval = (regval & ~0xffff) | (ticks & 0xffff); + /* Handle a few special cases. */ + switch (info->offset) { + case E1000_RDTR: + case E1000_82542_RDTR: + regval |= E1000_RDT_FPDB; + break; + case E1000_TIDV: + case E1000_82542_TIDV: + if (ticks == 0) { + adapter->txd_cmd &= ~E1000_TXD_CMD_IDE; + /* Don't write 0 into the TIDV register. */ + regval++; + } else + adapter->txd_cmd |= E1000_TXD_CMD_IDE; + break; + } + E1000_WRITE_OFFSET(&adapter->hw, info->offset, regval); + splx(s); + return 0; +} + +static void +em_add_int_delay_sysctl(struct adapter *adapter, const char *name, + const char *description, struct em_int_delay_info *info, + int offset, int value) +{ + info->adapter = adapter; + info->offset = offset; + info->value = value; + SYSCTL_ADD_PROC(&adapter->sysctl_ctx, + SYSCTL_CHILDREN(adapter->sysctl_tree), + OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, + info, 0, em_sysctl_int_delay, "I", description); +} diff --git a/sys/dev/em/if_em.h b/sys/dev/em/if_em.h index 2532740..ca85fbb 100644 --- a/sys/dev/em/if_em.h +++ b/sys/dev/em/if_em.h @@ -294,6 +294,13 @@ typedef enum _XSUM_CONTEXT_T { OFFLOAD_UDP_IP } XSUM_CONTEXT_T; +struct adapter; +struct em_int_delay_info { + struct adapter *adapter; /* Back-pointer to the adapter struct */ + int offset; /* Register offset to read/write */ + int value; /* Current value in usecs */ +}; + /* Our adapter structure */ struct adapter { struct arpcom interface_data; @@ -320,10 +327,10 @@ struct adapter { u_int16_t link_speed; u_int16_t link_duplex; u_int32_t smartspeed; - u_int32_t tx_int_delay; - u_int32_t tx_abs_int_delay; - u_int32_t rx_int_delay; - u_int32_t rx_abs_int_delay; + struct em_int_delay_info tx_int_delay; + struct em_int_delay_info tx_abs_int_delay; + struct em_int_delay_info rx_int_delay; + struct em_int_delay_info rx_abs_int_delay; XSUM_CONTEXT_T active_checksum_context; diff --git a/sys/dev/em/if_em_osdep.h b/sys/dev/em/if_em_osdep.h index f18f446..0bd806e 100644 --- a/sys/dev/em/if_em_osdep.h +++ b/sys/dev/em/if_em_osdep.h @@ -89,38 +89,36 @@ struct em_osdep struct device *dev; }; -#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS) - -#define E1000_READ_REG(a, reg) (\ - bus_space_read_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \ - ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \ - ((a)->mac_type >= em_82543) ? E1000_##reg : E1000_82542_##reg)) - -#define E1000_WRITE_REG(a, reg, value) (\ - bus_space_write_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \ - ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \ - ((a)->mac_type >= em_82543) ? E1000_##reg : E1000_82542_##reg, \ - value)) - -#define E1000_READ_REG_ARRAY(a, reg, offset) (\ - ((a)->mac_type >= em_82543) ? \ - bus_space_read_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \ - ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \ - (E1000_##reg + ((offset) << 2))): \ - bus_space_read_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \ - ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \ - (E1000_82542_##reg + ((offset) << 2)))) - - -#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) (\ - ((a)->mac_type >= em_82543) ? \ - bus_space_write_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \ - ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \ - (E1000_##reg + ((offset) << 2)), value): \ - bus_space_write_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \ - ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \ - (E1000_82542_##reg + ((offset) << 2)), value)) +#define E1000_WRITE_FLUSH(hw) E1000_READ_REG(hw, STATUS) +/* Read from an absolute offset in the adapter's memory space */ +#define E1000_READ_OFFSET(hw, offset) \ + bus_space_read_4( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \ + ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \ + offset) + +/* Write to an absolute offset in the adapter's memory space */ +#define E1000_WRITE_OFFSET(hw, offset, value) \ + bus_space_write_4( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \ + ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \ + offset, \ + value) + +/* Convert a register name to its offset in the adapter's memory space */ +#define E1000_REG_OFFSET(hw, reg) \ + ((hw)->mac_type >= em_82543 ? E1000_##reg : E1000_82542_##reg) + +#define E1000_READ_REG(hw, reg) \ + E1000_READ_OFFSET(hw, E1000_REG_OFFSET(hw, reg)) + +#define E1000_WRITE_REG(hw, reg, value) \ + E1000_WRITE_OFFSET(hw, E1000_REG_OFFSET(hw, reg), value) + +#define E1000_READ_REG_ARRAY(hw, reg, index) \ + E1000_READ_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2)) + +#define E1000_WRITE_REG_ARRAY(hw, reg, index, value) \ + E1000_WRITE_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2), value) #endif /* _FREEBSD_OS_H_ */ |