diff options
author | David S. Miller <davem@davemloft.net> | 2015-05-14 19:21:42 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-05-14 19:21:42 +0300 |
commit | c16ead798ee31f154eb230a728de6c60d0786aab (patch) | |
tree | 4dbba4c8209783b1b33c64f52e02cd75b7033b88 | |
parent | 5a99e7f22b0d0f8ba65b7fb19ad3511e2497356c (diff) | |
parent | 760c295e0e8d982917d004c9095cff61c0cbd803 (diff) | |
download | linux-c16ead798ee31f154eb230a728de6c60d0786aab.tar.xz |
Merge branch 'be2net-next'
Venkat Duvvuru says:
====================
be2net: patch-set
The following patch set has one new feature addition and two fixes.
Patch 1 adds support for hwmon sysfs interface to display board temperature.
Board temperature display through ethtool statistics is removed.
Patch 2 reports "link down" in a few more error cases which are not handled
currently.
Patch 3 adds support for os2bmc. OS2BMC feature will allow the server to
communicate with the on-board BMC/idrac (Baseboard Management Controller)
over the LOM via standard Ethernet. More details are added in the commit log.
Please review.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be.h | 49 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_cmds.c | 33 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_cmds.h | 17 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_ethtool.c | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_main.c | 214 |
5 files changed, 276 insertions, 38 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 1eafc075edae..8d12b41b3b19 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -31,6 +31,8 @@ #include <linux/slab.h> #include <linux/u64_stats_sync.h> #include <linux/cpumask.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include "be_hw.h" #include "be_roce.h" @@ -314,7 +316,6 @@ struct be_rx_obj { } ____cacheline_aligned_in_smp; struct be_drv_stats { - u32 be_on_die_temperature; u32 eth_red_drops; u32 dma_map_errors; u32 rx_drops_no_pbuf; @@ -383,6 +384,7 @@ enum vf_state { #define BE_FLAGS_SETUP_DONE BIT(9) #define BE_FLAGS_EVT_INCOMPATIBLE_SFP BIT(10) #define BE_FLAGS_ERR_DETECTION_SCHEDULED BIT(11) +#define BE_FLAGS_OS2BMC BIT(12) #define BE_UC_PMAC_COUNT 30 #define BE_VF_UC_PMAC_COUNT 2 @@ -427,6 +429,8 @@ struct be_resources { u32 vf_if_cap_flags; /* VF if capability flags */ }; +#define be_is_os2bmc_enabled(adapter) (adapter->flags & BE_FLAGS_OS2BMC) + struct rss_info { u64 rss_flags; u8 rsstable[RSS_INDIR_TABLE_LEN]; @@ -434,6 +438,12 @@ struct rss_info { u8 rss_hkey[RSS_HASH_KEY_LEN]; }; +#define BE_INVALID_DIE_TEMP 0xFF +struct be_hwmon { + struct device *hwmon_dev; + u8 be_on_die_temp; /* Unit: millidegree Celsius */ +}; + /* Macros to read/write the 'features' word of be_wrb_params structure. */ #define BE_WRB_F_BIT(name) BE_WRB_F_##name##_BIT @@ -454,7 +464,8 @@ enum { BE_WRB_F_LSO_BIT, /* LSO */ BE_WRB_F_LSO6_BIT, /* LSO6 */ BE_WRB_F_VLAN_BIT, /* VLAN */ - BE_WRB_F_VLAN_SKIP_HW_BIT /* Skip VLAN tag (workaround) */ + BE_WRB_F_VLAN_SKIP_HW_BIT, /* Skip VLAN tag (workaround) */ + BE_WRB_F_OS2BMC_BIT /* Send packet to the management ring */ }; /* The structure below provides a HW-agnostic abstraction of WRB params @@ -515,6 +526,7 @@ struct be_adapter { u16 work_counter; struct delayed_work be_err_detection_work; + u8 err_flags; u32 flags; u32 cmd_privileges; /* Ethtool knobs and info */ @@ -573,8 +585,11 @@ struct be_adapter { u16 qnq_vid; u32 msg_enable; int be_get_temp_freq; + struct be_hwmon hwmon_info; u8 pf_number; struct rss_info rss_info; + /* Filters for packets that need to be sent to BMC */ + u32 bmc_filt_mask; }; #define be_physfn(adapter) (!adapter->virtfn) @@ -773,26 +788,36 @@ static inline bool is_ipv4_pkt(struct sk_buff *skb) return skb->protocol == htons(ETH_P_IP) && ip_hdr(skb)->version == 4; } -static inline bool be_multi_rxq(const struct be_adapter *adapter) +#define BE_ERROR_EEH 1 +#define BE_ERROR_UE BIT(1) +#define BE_ERROR_FW BIT(2) +#define BE_ERROR_HW (BE_ERROR_EEH | BE_ERROR_UE) +#define BE_ERROR_ANY (BE_ERROR_EEH | BE_ERROR_UE | BE_ERROR_FW) +#define BE_CLEAR_ALL 0xFF + +static inline u8 be_check_error(struct be_adapter *adapter, u32 err_type) { - return adapter->num_rx_qs > 1; + return (adapter->err_flags & err_type); } -static inline bool be_error(struct be_adapter *adapter) +static inline void be_set_error(struct be_adapter *adapter, int err_type) { - return adapter->eeh_error || adapter->hw_error || adapter->fw_timeout; + struct net_device *netdev = adapter->netdev; + + adapter->err_flags |= err_type; + netif_carrier_off(netdev); + + dev_info(&adapter->pdev->dev, "%s: Link down\n", netdev->name); } -static inline bool be_hw_error(struct be_adapter *adapter) +static inline void be_clear_error(struct be_adapter *adapter, int err_type) { - return adapter->eeh_error || adapter->hw_error; + adapter->err_flags &= ~err_type; } -static inline void be_clear_all_error(struct be_adapter *adapter) +static inline bool be_multi_rxq(const struct be_adapter *adapter) { - adapter->eeh_error = false; - adapter->hw_error = false; - adapter->fw_timeout = false; + return adapter->num_rx_qs > 1; } void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index b419bde29a6f..41150543906a 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -93,7 +93,7 @@ static void be_mcc_notify(struct be_adapter *adapter) struct be_queue_info *mccq = &adapter->mcc_obj.q; u32 val = 0; - if (be_error(adapter)) + if (be_check_error(adapter, BE_ERROR_ANY)) return; val |= mccq->id & DB_MCCQ_RING_ID_MASK; @@ -192,10 +192,12 @@ static void be_async_cmd_process(struct be_adapter *adapter, if (base_status == MCC_STATUS_SUCCESS) { struct be_cmd_resp_get_cntl_addnl_attribs *resp = (void *)resp_hdr; - adapter->drv_stats.be_on_die_temperature = + adapter->hwmon_info.be_on_die_temp = resp->on_die_temperature; } else { adapter->be_get_temp_freq = 0; + adapter->hwmon_info.be_on_die_temp = + BE_INVALID_DIE_TEMP; } return; } @@ -331,6 +333,21 @@ static void be_async_grp5_pvid_state_process(struct be_adapter *adapter, } } +#define MGMT_ENABLE_MASK 0x4 +static void be_async_grp5_fw_control_process(struct be_adapter *adapter, + struct be_mcc_compl *compl) +{ + struct be_async_fw_control *evt = (struct be_async_fw_control *)compl; + u32 evt_dw1 = le32_to_cpu(evt->event_data_word1); + + if (evt_dw1 & MGMT_ENABLE_MASK) { + adapter->flags |= BE_FLAGS_OS2BMC; + adapter->bmc_filt_mask = le32_to_cpu(evt->event_data_word2); + } else { + adapter->flags &= ~BE_FLAGS_OS2BMC; + } +} + static void be_async_grp5_evt_process(struct be_adapter *adapter, struct be_mcc_compl *compl) { @@ -347,6 +364,10 @@ static void be_async_grp5_evt_process(struct be_adapter *adapter, case ASYNC_EVENT_PVID_STATE: be_async_grp5_pvid_state_process(adapter, compl); break; + /* Async event to disable/enable os2bmc and/or mac-learning */ + case ASYNC_EVENT_FW_CONTROL: + be_async_grp5_fw_control_process(adapter, compl); + break; default: break; } @@ -487,7 +508,7 @@ static int be_mcc_wait_compl(struct be_adapter *adapter) struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; for (i = 0; i < mcc_timeout; i++) { - if (be_error(adapter)) + if (be_check_error(adapter, BE_ERROR_ANY)) return -EIO; local_bh_disable(); @@ -500,7 +521,7 @@ static int be_mcc_wait_compl(struct be_adapter *adapter) } if (i == mcc_timeout) { dev_err(&adapter->pdev->dev, "FW not responding\n"); - adapter->fw_timeout = true; + be_set_error(adapter, BE_ERROR_FW); return -EIO; } return status; @@ -539,7 +560,7 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) u32 ready; do { - if (be_error(adapter)) + if (be_check_error(adapter, BE_ERROR_ANY)) return -EIO; ready = ioread32(db); @@ -552,7 +573,7 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) if (msecs > 4000) { dev_err(&adapter->pdev->dev, "FW not responding\n"); - adapter->fw_timeout = true; + be_set_error(adapter, BE_ERROR_FW); be_detect_error(adapter); return -1; } diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index c713d514fcd1..2716e6f30d9a 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -105,6 +105,7 @@ struct be_mcc_compl { #define ASYNC_DEBUG_EVENT_TYPE_QNQ 1 #define ASYNC_EVENT_CODE_SLIPORT 0x11 #define ASYNC_EVENT_PORT_MISCONFIG 0x9 +#define ASYNC_EVENT_FW_CONTROL 0x5 enum { LINK_DOWN = 0x0, @@ -181,6 +182,22 @@ struct be_async_event_misconfig_port { u32 flags; } __packed; +#define BMC_FILT_BROADCAST_ARP BIT(0) +#define BMC_FILT_BROADCAST_DHCP_CLIENT BIT(1) +#define BMC_FILT_BROADCAST_DHCP_SERVER BIT(2) +#define BMC_FILT_BROADCAST_NET_BIOS BIT(3) +#define BMC_FILT_BROADCAST BIT(7) +#define BMC_FILT_MULTICAST_IPV6_NEIGH_ADVER BIT(8) +#define BMC_FILT_MULTICAST_IPV6_RA BIT(9) +#define BMC_FILT_MULTICAST_IPV6_RAS BIT(10) +#define BMC_FILT_MULTICAST BIT(15) +struct be_async_fw_control { + u32 event_data_word1; + u32 event_data_word2; + u32 evt_tag; + u32 event_data_word4; +} __packed; + struct be_mcc_mailbox { struct be_mcc_wrb wrb; struct be_mcc_compl compl; diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index 9124a93eb474..675cbacef772 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -123,7 +123,6 @@ static const struct be_ethtool_stat et_stats[] = { {DRVSTAT_INFO(dma_map_errors)}, /* Number of packets dropped due to random early drop function */ {DRVSTAT_INFO(eth_red_drops)}, - {DRVSTAT_INFO(be_on_die_temperature)}, {DRVSTAT_INFO(rx_roce_bytes_lsd)}, {DRVSTAT_INFO(rx_roce_bytes_msd)}, {DRVSTAT_INFO(rx_roce_frames)}, diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index f15a3cfeb217..dc7c0fd239f7 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -179,7 +179,7 @@ static void be_intr_set(struct be_adapter *adapter, bool enable) if (lancer_chip(adapter)) return; - if (adapter->eeh_error) + if (be_check_error(adapter, BE_ERROR_EEH)) return; status = be_cmd_intr_set(adapter, enable); @@ -191,6 +191,9 @@ static void be_rxq_notify(struct be_adapter *adapter, u16 qid, u16 posted) { u32 val = 0; + if (be_check_error(adapter, BE_ERROR_HW)) + return; + val |= qid & DB_RQ_RING_ID_MASK; val |= posted << DB_RQ_NUM_POSTED_SHIFT; @@ -203,6 +206,9 @@ static void be_txq_notify(struct be_adapter *adapter, struct be_tx_obj *txo, { u32 val = 0; + if (be_check_error(adapter, BE_ERROR_HW)) + return; + val |= txo->q.id & DB_TXULP_RING_ID_MASK; val |= (posted & DB_TXULP_NUM_POSTED_MASK) << DB_TXULP_NUM_POSTED_SHIFT; @@ -219,7 +225,7 @@ static void be_eq_notify(struct be_adapter *adapter, u16 qid, val |= qid & DB_EQ_RING_ID_MASK; val |= ((qid & DB_EQ_RING_ID_EXT_MASK) << DB_EQ_RING_ID_EXT_MASK_SHIFT); - if (adapter->eeh_error) + if (be_check_error(adapter, BE_ERROR_HW)) return; if (arm) @@ -240,7 +246,7 @@ void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped) val |= ((qid & DB_CQ_RING_ID_EXT_MASK) << DB_CQ_RING_ID_EXT_MASK_SHIFT); - if (adapter->eeh_error) + if (be_check_error(adapter, BE_ERROR_HW)) return; if (arm) @@ -814,6 +820,8 @@ static void wrb_fill_hdr(struct be_adapter *adapter, SET_TX_WRB_HDR_BITS(num_wrb, hdr, skb_wrb_cnt(skb)); SET_TX_WRB_HDR_BITS(len, hdr, skb->len); + SET_TX_WRB_HDR_BITS(mgmt, hdr, + BE_WRB_F_GET(wrb_params->features, OS2BMC)); } static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb, @@ -1150,6 +1158,130 @@ static void be_xmit_flush(struct be_adapter *adapter, struct be_tx_obj *txo) txo->pend_wrb_cnt = 0; } +/* OS2BMC related */ + +#define DHCP_CLIENT_PORT 68 +#define DHCP_SERVER_PORT 67 +#define NET_BIOS_PORT1 137 +#define NET_BIOS_PORT2 138 +#define DHCPV6_RAS_PORT 547 + +#define is_mc_allowed_on_bmc(adapter, eh) \ + (!is_multicast_filt_enabled(adapter) && \ + is_multicast_ether_addr(eh->h_dest) && \ + !is_broadcast_ether_addr(eh->h_dest)) + +#define is_bc_allowed_on_bmc(adapter, eh) \ + (!is_broadcast_filt_enabled(adapter) && \ + is_broadcast_ether_addr(eh->h_dest)) + +#define is_arp_allowed_on_bmc(adapter, skb) \ + (is_arp(skb) && is_arp_filt_enabled(adapter)) + +#define is_broadcast_packet(eh, adapter) \ + (is_multicast_ether_addr(eh->h_dest) && \ + !compare_ether_addr(eh->h_dest, adapter->netdev->broadcast)) + +#define is_arp(skb) (skb->protocol == htons(ETH_P_ARP)) + +#define is_arp_filt_enabled(adapter) \ + (adapter->bmc_filt_mask & (BMC_FILT_BROADCAST_ARP)) + +#define is_dhcp_client_filt_enabled(adapter) \ + (adapter->bmc_filt_mask & BMC_FILT_BROADCAST_DHCP_CLIENT) + +#define is_dhcp_srvr_filt_enabled(adapter) \ + (adapter->bmc_filt_mask & BMC_FILT_BROADCAST_DHCP_SERVER) + +#define is_nbios_filt_enabled(adapter) \ + (adapter->bmc_filt_mask & BMC_FILT_BROADCAST_NET_BIOS) + +#define is_ipv6_na_filt_enabled(adapter) \ + (adapter->bmc_filt_mask & \ + BMC_FILT_MULTICAST_IPV6_NEIGH_ADVER) + +#define is_ipv6_ra_filt_enabled(adapter) \ + (adapter->bmc_filt_mask & BMC_FILT_MULTICAST_IPV6_RA) + +#define is_ipv6_ras_filt_enabled(adapter) \ + (adapter->bmc_filt_mask & BMC_FILT_MULTICAST_IPV6_RAS) + +#define is_broadcast_filt_enabled(adapter) \ + (adapter->bmc_filt_mask & BMC_FILT_BROADCAST) + +#define is_multicast_filt_enabled(adapter) \ + (adapter->bmc_filt_mask & BMC_FILT_MULTICAST) + +static bool be_send_pkt_to_bmc(struct be_adapter *adapter, + struct sk_buff **skb) +{ + struct ethhdr *eh = (struct ethhdr *)(*skb)->data; + bool os2bmc = false; + + if (!be_is_os2bmc_enabled(adapter)) + goto done; + + if (!is_multicast_ether_addr(eh->h_dest)) + goto done; + + if (is_mc_allowed_on_bmc(adapter, eh) || + is_bc_allowed_on_bmc(adapter, eh) || + is_arp_allowed_on_bmc(adapter, (*skb))) { + os2bmc = true; + goto done; + } + + if ((*skb)->protocol == htons(ETH_P_IPV6)) { + struct ipv6hdr *hdr = ipv6_hdr((*skb)); + u8 nexthdr = hdr->nexthdr; + + if (nexthdr == IPPROTO_ICMPV6) { + struct icmp6hdr *icmp6 = icmp6_hdr((*skb)); + + switch (icmp6->icmp6_type) { + case NDISC_ROUTER_ADVERTISEMENT: + os2bmc = is_ipv6_ra_filt_enabled(adapter); + goto done; + case NDISC_NEIGHBOUR_ADVERTISEMENT: + os2bmc = is_ipv6_na_filt_enabled(adapter); + goto done; + default: + break; + } + } + } + + if (is_udp_pkt((*skb))) { + struct udphdr *udp = udp_hdr((*skb)); + + switch (udp->dest) { + case DHCP_CLIENT_PORT: + os2bmc = is_dhcp_client_filt_enabled(adapter); + goto done; + case DHCP_SERVER_PORT: + os2bmc = is_dhcp_srvr_filt_enabled(adapter); + goto done; + case NET_BIOS_PORT1: + case NET_BIOS_PORT2: + os2bmc = is_nbios_filt_enabled(adapter); + goto done; + case DHCPV6_RAS_PORT: + os2bmc = is_ipv6_ras_filt_enabled(adapter); + goto done; + default: + break; + } + } +done: + /* For packets over a vlan, which are destined + * to BMC, asic expects the vlan to be inline in the packet. + */ + if (os2bmc) + *skb = be_insert_vlan_in_pkt(adapter, *skb, NULL); + + return os2bmc; +} + static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); @@ -1171,6 +1303,18 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) goto drop; } + /* if os2bmc is enabled and if the pkt is destined to bmc, + * enqueue the pkt a 2nd time with mgmt bit set. + */ + if (be_send_pkt_to_bmc(adapter, &skb)) { + BE_WRB_F_SET(wrb_params.features, OS2BMC, 1); + wrb_cnt = be_xmit_enqueue(adapter, txo, skb, &wrb_params); + if (unlikely(!wrb_cnt)) + goto drop; + else + skb_get(skb); + } + if (be_is_txq_full(txo)) { netif_stop_subqueue(netdev, q_idx); tx_stats(txo)->tx_stops++; @@ -2324,7 +2468,9 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo) if (lancer_chip(adapter)) break; - if (flush_wait++ > 10 || be_hw_error(adapter)) { + if (flush_wait++ > 50 || + be_check_error(adapter, + BE_ERROR_HW)) { dev_warn(&adapter->pdev->dev, "did not receive flush compl\n"); break; @@ -2385,7 +2531,8 @@ static void be_tx_compl_clean(struct be_adapter *adapter) pending_txqs--; } - if (pending_txqs == 0 || ++timeo > 10 || be_hw_error(adapter)) + if (pending_txqs == 0 || ++timeo > 10 || + be_check_error(adapter, BE_ERROR_HW)) break; mdelay(1); @@ -2995,22 +3142,19 @@ void be_detect_error(struct be_adapter *adapter) u32 ue_lo = 0, ue_hi = 0, ue_lo_mask = 0, ue_hi_mask = 0; u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; u32 i; - bool error_detected = false; struct device *dev = &adapter->pdev->dev; - struct net_device *netdev = adapter->netdev; - if (be_hw_error(adapter)) + if (be_check_error(adapter, BE_ERROR_HW)) return; if (lancer_chip(adapter)) { sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); if (sliport_status & SLIPORT_STATUS_ERR_MASK) { + be_set_error(adapter, BE_ERROR_UE); sliport_err1 = ioread32(adapter->db + SLIPORT_ERROR1_OFFSET); sliport_err2 = ioread32(adapter->db + SLIPORT_ERROR2_OFFSET); - adapter->hw_error = true; - error_detected = true; /* Do not log error messages if its a FW reset */ if (sliport_err1 == SLIPORT_ERROR_FW_RESET1 && sliport_err2 == SLIPORT_ERROR_FW_RESET2) { @@ -3042,12 +3186,12 @@ void be_detect_error(struct be_adapter *adapter) */ if (ue_lo || ue_hi) { - error_detected = true; dev_err(dev, "Unrecoverable Error detected in the adapter"); dev_err(dev, "Please reboot server to recover"); if (skyhawk_chip(adapter)) - adapter->hw_error = true; + be_set_error(adapter, BE_ERROR_UE); + for (i = 0; ue_lo; ue_lo >>= 1, i++) { if (ue_lo & 1) dev_err(dev, "UE: %s bit set\n", @@ -3060,8 +3204,6 @@ void be_detect_error(struct be_adapter *adapter) } } } - if (error_detected) - netif_carrier_off(netdev); } static void be_msix_disable(struct be_adapter *adapter) @@ -4183,7 +4325,7 @@ static int be_func_init(struct be_adapter *adapter) msleep(100); /* We can clear all errors when function reset succeeds */ - be_clear_all_error(adapter); + be_clear_error(adapter, BE_CLEAR_ALL); } /* Tell FW we're ready to fire cmds */ @@ -5204,7 +5346,7 @@ static void be_err_detection_task(struct work_struct *work) be_detect_error(adapter); - if (adapter->hw_error) { + if (be_check_error(adapter, BE_ERROR_HW)) { be_cleanup(adapter); /* As of now error recovery support is in Lancer only */ @@ -5470,6 +5612,30 @@ static void be_remove(struct pci_dev *pdev) free_netdev(adapter->netdev); } +ssize_t be_hwmon_show_temp(struct device *dev, + struct device_attribute *dev_attr, + char *buf) +{ + struct be_adapter *adapter = dev_get_drvdata(dev); + + /* Unit: millidegree Celsius */ + if (adapter->hwmon_info.be_on_die_temp == BE_INVALID_DIE_TEMP) + return -EIO; + else + return sprintf(buf, "%u\n", + adapter->hwmon_info.be_on_die_temp * 1000); +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, + be_hwmon_show_temp, NULL, 1); + +static struct attribute *be_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL +}; + +ATTRIBUTE_GROUPS(be_hwmon); + static char *mc_name(struct be_adapter *adapter) { char *str = ""; /* default */ @@ -5589,6 +5755,16 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) be_schedule_err_detection(adapter); + /* On Die temperature not supported for VF. */ + if (be_physfn(adapter)) { + adapter->hwmon_info.hwmon_dev = + devm_hwmon_device_register_with_groups(&pdev->dev, + DRV_NAME, + adapter, + be_hwmon_groups); + adapter->hwmon_info.be_on_die_temp = BE_INVALID_DIE_TEMP; + } + dev_info(&pdev->dev, "%s: %s %s port %c\n", nic_name(pdev), func_name(adapter), mc_name(adapter), adapter->port_name); @@ -5681,8 +5857,8 @@ static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev, dev_err(&adapter->pdev->dev, "EEH error detected\n"); - if (!adapter->eeh_error) { - adapter->eeh_error = true; + if (!be_check_error(adapter, BE_ERROR_EEH)) { + be_set_error(adapter, BE_ERROR_EEH); be_cancel_err_detection(adapter); @@ -5729,7 +5905,7 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev) return PCI_ERS_RESULT_DISCONNECT; pci_cleanup_aer_uncorrect_error_status(pdev); - be_clear_all_error(adapter); + be_clear_error(adapter, BE_CLEAR_ALL); return PCI_ERS_RESULT_RECOVERED; } |