|
@@ -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;
|
|
|
}
|
|
|
|