Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/e1000/if_em.c
Show First 20 Lines • Show All 299 Lines • ▼ Show 20 Lines | |||||
static bool em_if_vlan_filter_capable(struct e1000_softc *); | static bool em_if_vlan_filter_capable(struct e1000_softc *); | ||||
static bool em_if_vlan_filter_used(struct e1000_softc *); | static bool em_if_vlan_filter_used(struct e1000_softc *); | ||||
static void em_if_vlan_filter_enable(struct e1000_softc *); | static void em_if_vlan_filter_enable(struct e1000_softc *); | ||||
static void em_if_vlan_filter_disable(struct e1000_softc *); | static void em_if_vlan_filter_disable(struct e1000_softc *); | ||||
static void em_if_vlan_filter_write(struct e1000_softc *); | static void em_if_vlan_filter_write(struct e1000_softc *); | ||||
static void em_setup_vlan_hw_support(struct e1000_softc *); | static void em_setup_vlan_hw_support(struct e1000_softc *); | ||||
static int em_sysctl_nvm_info(SYSCTL_HANDLER_ARGS); | static int em_sysctl_nvm_info(SYSCTL_HANDLER_ARGS); | ||||
static void em_print_nvm_info(struct e1000_softc *); | static void em_print_nvm_info(struct e1000_softc *); | ||||
static void em_fw_version_locked(if_ctx_t); | |||||
static void em_sbuf_fw_version(struct e1000_fw_version *, struct sbuf *); | |||||
static void em_print_fw_version(struct e1000_softc *); | |||||
static int em_sysctl_print_fw_version(SYSCTL_HANDLER_ARGS); | |||||
static int em_sysctl_debug_info(SYSCTL_HANDLER_ARGS); | static int em_sysctl_debug_info(SYSCTL_HANDLER_ARGS); | ||||
static int em_get_rs(SYSCTL_HANDLER_ARGS); | static int em_get_rs(SYSCTL_HANDLER_ARGS); | ||||
static void em_print_debug_info(struct e1000_softc *); | static void em_print_debug_info(struct e1000_softc *); | ||||
static int em_is_valid_ether_addr(u8 *); | static int em_is_valid_ether_addr(u8 *); | ||||
static int em_sysctl_int_delay(SYSCTL_HANDLER_ARGS); | static int em_sysctl_int_delay(SYSCTL_HANDLER_ARGS); | ||||
static void em_add_int_delay_sysctl(struct e1000_softc *, const char *, | static void em_add_int_delay_sysctl(struct e1000_softc *, const char *, | ||||
const char *, struct em_int_delay_info *, int, int); | const char *, struct em_int_delay_info *, int, int); | ||||
/* Management and WOL Support */ | /* Management and WOL Support */ | ||||
▲ Show 20 Lines • Show All 471 Lines • ▼ Show 20 Lines | |||||
*********************************************************************/ | *********************************************************************/ | ||||
static int | static int | ||||
em_if_attach_pre(if_ctx_t ctx) | em_if_attach_pre(if_ctx_t ctx) | ||||
{ | { | ||||
struct e1000_softc *sc; | struct e1000_softc *sc; | ||||
if_softc_ctx_t scctx; | if_softc_ctx_t scctx; | ||||
device_t dev; | device_t dev; | ||||
struct e1000_hw *hw; | struct e1000_hw *hw; | ||||
struct sysctl_oid_list *child; | |||||
struct sysctl_ctx_list *ctx_list; | |||||
int error = 0; | int error = 0; | ||||
INIT_DEBUGOUT("em_if_attach_pre: begin"); | INIT_DEBUGOUT("em_if_attach_pre: begin"); | ||||
dev = iflib_get_dev(ctx); | dev = iflib_get_dev(ctx); | ||||
sc = iflib_get_softc(ctx); | sc = iflib_get_softc(ctx); | ||||
sc->ctx = sc->osdep.ctx = ctx; | sc->ctx = sc->osdep.ctx = ctx; | ||||
sc->dev = sc->osdep.dev = dev; | sc->dev = sc->osdep.dev = dev; | ||||
scctx = sc->shared = iflib_get_softc_ctx(ctx); | scctx = sc->shared = iflib_get_softc_ctx(ctx); | ||||
sc->media = iflib_get_media(ctx); | sc->media = iflib_get_media(ctx); | ||||
hw = &sc->hw; | hw = &sc->hw; | ||||
sc->tx_process_limit = scctx->isc_ntxd[0]; | sc->tx_process_limit = scctx->isc_ntxd[0]; | ||||
/* Determine hardware and mac info */ | |||||
em_identify_hardware(ctx); | |||||
/* SYSCTL stuff */ | /* SYSCTL stuff */ | ||||
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), | ctx_list = device_get_sysctl_ctx(dev); | ||||
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), | child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); | ||||
OID_AUTO, "nvm", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, | |||||
sc, 0, em_sysctl_nvm_info, "I", "NVM Information"); | |||||
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), | SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "nvm", | ||||
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, | ||||
OID_AUTO, "debug", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, | em_sysctl_nvm_info, "I", "NVM Information"); | ||||
sc, 0, em_sysctl_debug_info, "I", "Debug Information"); | |||||
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), | SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "fw_version", | ||||
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), | CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0, | ||||
OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, | em_sysctl_print_fw_version, "A", | ||||
sc, 0, em_set_flowcntl, "I", "Flow Control"); | "Prints FW/NVM Versions"); | ||||
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), | SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "debug", | ||||
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, | ||||
OID_AUTO, "reg_dump", | em_sysctl_debug_info, "I", "Debug Information"); | ||||
SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "fc", | |||||
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, | |||||
em_set_flowcntl, "I", "Flow Control"); | |||||
SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "reg_dump", | |||||
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0, | CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0, | ||||
em_get_regs, "A", "Dump Registers"); | em_get_regs, "A", "Dump Registers"); | ||||
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), | SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "rs_dump", | ||||
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), | |||||
OID_AUTO, "rs_dump", | |||||
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, | ||||
em_get_rs, "I", "Dump RS indexes"); | em_get_rs, "I", "Dump RS indexes"); | ||||
/* Determine hardware and mac info */ | |||||
em_identify_hardware(ctx); | |||||
scctx->isc_tx_nsegments = EM_MAX_SCATTER; | scctx->isc_tx_nsegments = EM_MAX_SCATTER; | ||||
scctx->isc_nrxqsets_max = scctx->isc_ntxqsets_max = em_set_num_queues(ctx); | scctx->isc_nrxqsets_max = scctx->isc_ntxqsets_max = em_set_num_queues(ctx); | ||||
if (bootverbose) | if (bootverbose) | ||||
device_printf(dev, "attach_pre capping queues at %d\n", | device_printf(dev, "attach_pre capping queues at %d\n", | ||||
scctx->isc_ntxqsets_max); | scctx->isc_ntxqsets_max); | ||||
if (hw->mac.type >= igb_mac_min) { | if (hw->mac.type >= igb_mac_min) { | ||||
scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0] * sizeof(union e1000_adv_tx_desc), EM_DBA_ALIGN); | scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0] * sizeof(union e1000_adv_tx_desc), EM_DBA_ALIGN); | ||||
▲ Show 20 Lines • Show All 192 Lines • ▼ Show 20 Lines | em_if_attach_pre(if_ctx_t ctx) | ||||
/* Check SOL/IDER usage */ | /* Check SOL/IDER usage */ | ||||
if (e1000_check_reset_block(hw)) | if (e1000_check_reset_block(hw)) | ||||
device_printf(dev, "PHY reset is blocked" | device_printf(dev, "PHY reset is blocked" | ||||
" due to SOL/IDER session.\n"); | " due to SOL/IDER session.\n"); | ||||
/* Sysctl for setting Energy Efficient Ethernet */ | /* Sysctl for setting Energy Efficient Ethernet */ | ||||
hw->dev_spec.ich8lan.eee_disable = eee_setting; | hw->dev_spec.ich8lan.eee_disable = eee_setting; | ||||
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), | SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "eee_control", | ||||
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, | ||||
OID_AUTO, "eee_control", | em_sysctl_eee, "I", "Disable Energy Efficient Ethernet"); | ||||
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, | |||||
sc, 0, em_sysctl_eee, "I", | |||||
"Disable Energy Efficient Ethernet"); | |||||
/* | /* | ||||
** Start from a known state, this is | ** Start from a known state, this is | ||||
** important in reading the nvm and | ** important in reading the nvm and | ||||
** mac from that. | ** mac from that. | ||||
*/ | */ | ||||
e1000_reset_hw(hw); | e1000_reset_hw(hw); | ||||
Show All 26 Lines | if (sc->vf_ifp) { | ||||
(struct ether_addr *)hw->mac.addr); | (struct ether_addr *)hw->mac.addr); | ||||
} else { | } else { | ||||
device_printf(dev, "Invalid MAC address\n"); | device_printf(dev, "Invalid MAC address\n"); | ||||
error = EIO; | error = EIO; | ||||
goto err_late; | goto err_late; | ||||
} | } | ||||
} | } | ||||
/* Save the EEPROM/NVM versions, must be done under IFLIB_CTX_LOCK */ | |||||
em_fw_version_locked(ctx); | |||||
em_print_fw_version(sc); | |||||
/* Disable ULP support */ | /* Disable ULP support */ | ||||
e1000_disable_ulp_lpt_lp(hw, true); | e1000_disable_ulp_lpt_lp(hw, true); | ||||
/* | /* | ||||
* Get Wake-on-Lan and Management info for later use | * Get Wake-on-Lan and Management info for later use | ||||
*/ | */ | ||||
em_get_wakeup(ctx); | em_get_wakeup(ctx); | ||||
▲ Show 20 Lines • Show All 3,367 Lines • ▼ Show 20 Lines | SYSCTL_ADD_UQUAD(ctx, int_list, OID_AUTO, "rx_desc_min_thresh", | ||||
CTLFLAG_RD, &sc->stats.icrxdmtc, | CTLFLAG_RD, &sc->stats.icrxdmtc, | ||||
"Interrupt Cause Rx Desc Min Thresh Count"); | "Interrupt Cause Rx Desc Min Thresh Count"); | ||||
SYSCTL_ADD_UQUAD(ctx, int_list, OID_AUTO, "rx_overrun", | SYSCTL_ADD_UQUAD(ctx, int_list, OID_AUTO, "rx_overrun", | ||||
CTLFLAG_RD, &sc->stats.icrxoc, | CTLFLAG_RD, &sc->stats.icrxoc, | ||||
"Interrupt Cause Receiver Overrun Count"); | "Interrupt Cause Receiver Overrun Count"); | ||||
} | } | ||||
static void | |||||
em_fw_version_locked(if_ctx_t ctx) | |||||
{ | |||||
struct e1000_softc *sc = iflib_get_softc(ctx); | |||||
struct e1000_hw *hw = &sc->hw; | |||||
struct e1000_fw_version *fw_ver = &sc->fw_ver; | |||||
uint16_t eep = 0; | |||||
/* | |||||
* em_fw_version_locked() must run under the IFLIB_CTX_LOCK to meet the | |||||
* NVM locking model, so we do it in em_if_attach_pre() | |||||
*/ | |||||
ASSERT_CTX_LOCK_HELD(hw); | |||||
*fw_ver = (struct e1000_fw_version){0}; | |||||
if (hw->mac.type >= igb_mac_min) { | |||||
/* | |||||
* Use the Shared Code for igb(4) | |||||
*/ | |||||
e1000_get_fw_version(hw, fw_ver); | |||||
} else { | |||||
/* | |||||
gallatin: If it was me, I'd probably print something like "NVM version unknown" | |||||
* Otherwise, EEPROM version should be present on (almost?) all | |||||
* devices here | |||||
*/ | |||||
if(e1000_read_nvm(hw, NVM_VERSION, 1, &eep)) { | |||||
INIT_DEBUGOUT("can't get EEPROM version"); | |||||
return; | |||||
} | |||||
fw_ver->eep_major = (eep & NVM_MAJOR_MASK) >> NVM_MAJOR_SHIFT; | |||||
fw_ver->eep_minor = (eep & NVM_MINOR_MASK) >> NVM_MINOR_SHIFT; | |||||
fw_ver->eep_build = (eep & NVM_IMAGE_ID_MASK); | |||||
} | |||||
} | |||||
static void | |||||
em_sbuf_fw_version(struct e1000_fw_version *fw_ver, struct sbuf *buf) | |||||
{ | |||||
const char *space = ""; | |||||
if (fw_ver->eep_major || fw_ver->eep_minor || fw_ver->eep_build) { | |||||
sbuf_printf(buf, "EEPROM V%d.%d-%d", fw_ver->eep_major, | |||||
fw_ver->eep_minor, fw_ver->eep_build); | |||||
space = " "; | |||||
} | |||||
if (fw_ver->invm_major || fw_ver->invm_minor || fw_ver->invm_img_type) { | |||||
sbuf_printf(buf, "%sNVM V%d.%d imgtype%d", | |||||
space, fw_ver->invm_major, fw_ver->invm_minor, | |||||
fw_ver->invm_img_type); | |||||
space = " "; | |||||
} | |||||
if (fw_ver->or_valid) { | |||||
sbuf_printf(buf, "%sOption ROM V%d-b%d-p%d", | |||||
space, fw_ver->or_major, fw_ver->or_build, | |||||
fw_ver->or_patch); | |||||
space = " "; | |||||
} | |||||
if (fw_ver->etrack_id) | |||||
sbuf_printf(buf, "%seTrack 0x%08x", space, fw_ver->etrack_id); | |||||
} | |||||
static void | |||||
em_print_fw_version(struct e1000_softc *sc ) | |||||
{ | |||||
device_t dev = sc->dev; | |||||
struct sbuf *buf; | |||||
int error = 0; | |||||
buf = sbuf_new_auto(); | |||||
if (!buf) { | |||||
device_printf(dev, "Could not allocate sbuf for output.\n"); | |||||
return; | |||||
} | |||||
em_sbuf_fw_version(&sc->fw_ver, buf); | |||||
error = sbuf_finish(buf); | |||||
if (error) | |||||
device_printf(dev, "Error finishing sbuf: %d\n", error); | |||||
else if (sbuf_len(buf)) | |||||
device_printf(dev, "%s\n", sbuf_data(buf)); | |||||
sbuf_delete(buf); | |||||
} | |||||
static int | |||||
em_sysctl_print_fw_version(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct e1000_softc *sc = (struct e1000_softc *)arg1; | |||||
device_t dev = sc->dev; | |||||
struct sbuf *buf; | |||||
int error = 0; | |||||
buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); | |||||
if (!buf) { | |||||
device_printf(dev, "Could not allocate sbuf for output.\n"); | |||||
return (ENOMEM); | |||||
} | |||||
em_sbuf_fw_version(&sc->fw_ver, buf); | |||||
error = sbuf_finish(buf); | |||||
if (error) | |||||
device_printf(dev, "Error finishing sbuf: %d\n", error); | |||||
sbuf_delete(buf); | |||||
return (0); | |||||
} | |||||
/********************************************************************** | /********************************************************************** | ||||
* | * | ||||
* This routine provides a way to dump out the adapter eeprom, | * This routine provides a way to dump out the adapter eeprom, | ||||
* often a useful debug/service tool. This only dumps the first | * often a useful debug/service tool. This only dumps the first | ||||
* 32 words, stuff that matters is in that extent. | * 32 words, stuff that matters is in that extent. | ||||
* | * | ||||
**********************************************************************/ | **********************************************************************/ | ||||
static int | static int | ||||
Show All 18 Lines | if (result == 1) | ||||
em_print_nvm_info(sc); | em_print_nvm_info(sc); | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
em_print_nvm_info(struct e1000_softc *sc) | em_print_nvm_info(struct e1000_softc *sc) | ||||
{ | { | ||||
struct e1000_hw *hw = &sc->hw; | |||||
struct sx *iflib_ctx_lock = iflib_ctx_lock_get(sc->ctx); | |||||
u16 eeprom_data; | u16 eeprom_data; | ||||
int i, j, row = 0; | int i, j, row = 0; | ||||
/* Its a bit crude, but it gets the job done */ | /* Its a bit crude, but it gets the job done */ | ||||
printf("\nInterface EEPROM Dump:\n"); | printf("\nInterface EEPROM Dump:\n"); | ||||
printf("Offset\n0x0000 "); | printf("Offset\n0x0000 "); | ||||
/* We rely on the IFLIB_CTX_LOCK as part of NVM locking model */ | |||||
kbowlingAuthorUnsubmitted Not Done Inline ActionsThis will be committed as a separate bug fix, it prevents a KASSERT deep in the shared code kbowling: This will be committed as a separate bug fix, it prevents a KASSERT deep in the shared code | |||||
sx_xlock(iflib_ctx_lock); | |||||
ASSERT_CTX_LOCK_HELD(hw); | |||||
for (i = 0, j = 0; i < 32; i++, j++) { | for (i = 0, j = 0; i < 32; i++, j++) { | ||||
if (j == 8) { /* Make the offset block */ | if (j == 8) { /* Make the offset block */ | ||||
j = 0; ++row; | j = 0; ++row; | ||||
printf("\n0x00%x0 ",row); | printf("\n0x00%x0 ",row); | ||||
} | } | ||||
e1000_read_nvm(&sc->hw, i, 1, &eeprom_data); | e1000_read_nvm(hw, i, 1, &eeprom_data); | ||||
printf("%04x ", eeprom_data); | printf("%04x ", eeprom_data); | ||||
} | } | ||||
sx_xunlock(iflib_ctx_lock); | |||||
printf("\n"); | printf("\n"); | ||||
} | } | ||||
static int | static int | ||||
em_sysctl_int_delay(SYSCTL_HANDLER_ARGS) | em_sysctl_int_delay(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct em_int_delay_info *info; | struct em_int_delay_info *info; | ||||
struct e1000_softc *sc; | struct e1000_softc *sc; | ||||
▲ Show 20 Lines • Show All 219 Lines • Show Last 20 Lines |
If it was me, I'd probably print something like "NVM version unknown"