| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: if_wm.c,v 1.359 2015/10/13 08:17:15 knakahara Exp $ */ | | 1 | /* $NetBSD: if_wm.c,v 1.360 2015/10/13 08:20:02 knakahara Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. | | 4 | * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. | | 7 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
| @@ -73,27 +73,27 @@ | | | @@ -73,27 +73,27 @@ |
73 | * TODO (in order of importance): | | 73 | * TODO (in order of importance): |
74 | * | | 74 | * |
75 | * - Check XXX'ed comments | | 75 | * - Check XXX'ed comments |
76 | * - EEE (Energy Efficiency Ethernet) | | 76 | * - EEE (Energy Efficiency Ethernet) |
77 | * - Multi queue | | 77 | * - Multi queue |
78 | * - Image Unique ID | | 78 | * - Image Unique ID |
79 | * - LPLU other than PCH* | | 79 | * - LPLU other than PCH* |
80 | * - Virtual Function | | 80 | * - Virtual Function |
81 | * - Set LED correctly (based on contents in EEPROM) | | 81 | * - Set LED correctly (based on contents in EEPROM) |
82 | * - Rework how parameters are loaded from the EEPROM. | | 82 | * - Rework how parameters are loaded from the EEPROM. |
83 | */ | | 83 | */ |
84 | | | 84 | |
85 | #include <sys/cdefs.h> | | 85 | #include <sys/cdefs.h> |
86 | __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.359 2015/10/13 08:17:15 knakahara Exp $"); | | 86 | __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.360 2015/10/13 08:20:02 knakahara Exp $"); |
87 | | | 87 | |
88 | #ifdef _KERNEL_OPT | | 88 | #ifdef _KERNEL_OPT |
89 | #include "opt_net_mpsafe.h" | | 89 | #include "opt_net_mpsafe.h" |
90 | #endif | | 90 | #endif |
91 | | | 91 | |
92 | #include <sys/param.h> | | 92 | #include <sys/param.h> |
93 | #include <sys/systm.h> | | 93 | #include <sys/systm.h> |
94 | #include <sys/callout.h> | | 94 | #include <sys/callout.h> |
95 | #include <sys/mbuf.h> | | 95 | #include <sys/mbuf.h> |
96 | #include <sys/malloc.h> | | 96 | #include <sys/malloc.h> |
97 | #include <sys/kmem.h> | | 97 | #include <sys/kmem.h> |
98 | #include <sys/kernel.h> | | 98 | #include <sys/kernel.h> |
99 | #include <sys/socket.h> | | 99 | #include <sys/socket.h> |
| @@ -603,26 +603,28 @@ static void wm_start_locked(struct ifnet | | | @@ -603,26 +603,28 @@ static void wm_start_locked(struct ifnet |
603 | static int wm_nq_tx_offload(struct wm_softc *, struct wm_txsoft *, | | 603 | static int wm_nq_tx_offload(struct wm_softc *, struct wm_txsoft *, |
604 | uint32_t *, uint32_t *, bool *); | | 604 | uint32_t *, uint32_t *, bool *); |
605 | static void wm_nq_start(struct ifnet *); | | 605 | static void wm_nq_start(struct ifnet *); |
606 | static void wm_nq_start_locked(struct ifnet *); | | 606 | static void wm_nq_start_locked(struct ifnet *); |
607 | /* Interrupt */ | | 607 | /* Interrupt */ |
608 | static int wm_txeof(struct wm_softc *); | | 608 | static int wm_txeof(struct wm_softc *); |
609 | static void wm_rxeof(struct wm_softc *); | | 609 | static void wm_rxeof(struct wm_softc *); |
610 | static void wm_linkintr_gmii(struct wm_softc *, uint32_t); | | 610 | static void wm_linkintr_gmii(struct wm_softc *, uint32_t); |
611 | static void wm_linkintr_tbi(struct wm_softc *, uint32_t); | | 611 | static void wm_linkintr_tbi(struct wm_softc *, uint32_t); |
612 | static void wm_linkintr_serdes(struct wm_softc *, uint32_t); | | 612 | static void wm_linkintr_serdes(struct wm_softc *, uint32_t); |
613 | static void wm_linkintr(struct wm_softc *, uint32_t); | | 613 | static void wm_linkintr(struct wm_softc *, uint32_t); |
614 | static int wm_intr_legacy(void *); | | 614 | static int wm_intr_legacy(void *); |
615 | #ifdef WM_MSI_MSIX | | 615 | #ifdef WM_MSI_MSIX |
| | | 616 | static int wm_setup_legacy(struct wm_softc *); |
| | | 617 | static int wm_setup_msix(struct wm_softc *); |
616 | static int wm_txintr_msix(void *); | | 618 | static int wm_txintr_msix(void *); |
617 | static int wm_rxintr_msix(void *); | | 619 | static int wm_rxintr_msix(void *); |
618 | static int wm_linkintr_msix(void *); | | 620 | static int wm_linkintr_msix(void *); |
619 | #endif | | 621 | #endif |
620 | | | 622 | |
621 | /* | | 623 | /* |
622 | * Media related. | | 624 | * Media related. |
623 | * GMII, SGMII, TBI, SERDES and SFP. | | 625 | * GMII, SGMII, TBI, SERDES and SFP. |
624 | */ | | 626 | */ |
625 | /* Common */ | | 627 | /* Common */ |
626 | static void wm_tbi_serdes_set_linkled(struct wm_softc *); | | 628 | static void wm_tbi_serdes_set_linkled(struct wm_softc *); |
627 | /* GMII related */ | | 629 | /* GMII related */ |
628 | static void wm_gmii_reset(struct wm_softc *); | | 630 | static void wm_gmii_reset(struct wm_softc *); |
| @@ -751,40 +753,26 @@ static void wm_set_eee_i350(struct wm_so | | | @@ -751,40 +753,26 @@ static void wm_set_eee_i350(struct wm_so |
751 | * Basically, PHY's workarounds are in the PHY drivers. | | 753 | * Basically, PHY's workarounds are in the PHY drivers. |
752 | */ | | 754 | */ |
753 | static void wm_kmrn_lock_loss_workaround_ich8lan(struct wm_softc *); | | 755 | static void wm_kmrn_lock_loss_workaround_ich8lan(struct wm_softc *); |
754 | static void wm_gig_downshift_workaround_ich8lan(struct wm_softc *); | | 756 | static void wm_gig_downshift_workaround_ich8lan(struct wm_softc *); |
755 | static void wm_hv_phy_workaround_ich8lan(struct wm_softc *); | | 757 | static void wm_hv_phy_workaround_ich8lan(struct wm_softc *); |
756 | static void wm_lv_phy_workaround_ich8lan(struct wm_softc *); | | 758 | static void wm_lv_phy_workaround_ich8lan(struct wm_softc *); |
757 | static void wm_k1_gig_workaround_hv(struct wm_softc *, int); | | 759 | static void wm_k1_gig_workaround_hv(struct wm_softc *, int); |
758 | static void wm_set_mdio_slow_mode_hv(struct wm_softc *); | | 760 | static void wm_set_mdio_slow_mode_hv(struct wm_softc *); |
759 | static void wm_configure_k1_ich8lan(struct wm_softc *, int); | | 761 | static void wm_configure_k1_ich8lan(struct wm_softc *, int); |
760 | static void wm_reset_init_script_82575(struct wm_softc *); | | 762 | static void wm_reset_init_script_82575(struct wm_softc *); |
761 | static void wm_reset_mdicnfg_82580(struct wm_softc *); | | 763 | static void wm_reset_mdicnfg_82580(struct wm_softc *); |
762 | static void wm_pll_workaround_i210(struct wm_softc *); | | 764 | static void wm_pll_workaround_i210(struct wm_softc *); |
763 | | | 765 | |
764 | #ifdef WM_MSI_MSIX | | | |
765 | struct _msix_matrix { | | | |
766 | const char *intrname; | | | |
767 | int(*func)(void *); | | | |
768 | int intridx; | | | |
769 | int cpuid; | | | |
770 | } msix_matrix[WM_MSIX_NINTR] = { | | | |
771 | { "TX", wm_txintr_msix, WM_MSIX_TXINTR_IDX, WM_MSIX_TXINTR_CPUID }, | | | |
772 | { "RX", wm_rxintr_msix, WM_MSIX_RXINTR_IDX, WM_MSIX_RXINTR_CPUID }, | | | |
773 | { "LINK", wm_linkintr_msix, WM_MSIX_LINKINTR_IDX, | | | |
774 | WM_MSIX_LINKINTR_CPUID }, | | | |
775 | }; | | | |
776 | #endif | | | |
777 | | | | |
778 | CFATTACH_DECL3_NEW(wm, sizeof(struct wm_softc), | | 766 | CFATTACH_DECL3_NEW(wm, sizeof(struct wm_softc), |
779 | wm_match, wm_attach, wm_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); | | 767 | wm_match, wm_attach, wm_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); |
780 | | | 768 | |
781 | /* | | 769 | /* |
782 | * Devices supported by this driver. | | 770 | * Devices supported by this driver. |
783 | */ | | 771 | */ |
784 | static const struct wm_product { | | 772 | static const struct wm_product { |
785 | pci_vendor_id_t wmp_vendor; | | 773 | pci_vendor_id_t wmp_vendor; |
786 | pci_product_id_t wmp_product; | | 774 | pci_product_id_t wmp_product; |
787 | const char *wmp_name; | | 775 | const char *wmp_name; |
788 | wm_chip_type wmp_type; | | 776 | wm_chip_type wmp_type; |
789 | uint32_t wmp_flags; | | 777 | uint32_t wmp_flags; |
790 | #define WMP_F_UNKNOWN WM_MEDIATYPE_UNKNOWN | | 778 | #define WMP_F_UNKNOWN WM_MEDIATYPE_UNKNOWN |
| @@ -1459,48 +1447,48 @@ wm_match(device_t parent, cfdata_t cf, v | | | @@ -1459,48 +1447,48 @@ wm_match(device_t parent, cfdata_t cf, v |
1459 | } | | 1447 | } |
1460 | | | 1448 | |
1461 | /* The attach function (ca_attach) */ | | 1449 | /* The attach function (ca_attach) */ |
1462 | static void | | 1450 | static void |
1463 | wm_attach(device_t parent, device_t self, void *aux) | | 1451 | wm_attach(device_t parent, device_t self, void *aux) |
1464 | { | | 1452 | { |
1465 | struct wm_softc *sc = device_private(self); | | 1453 | struct wm_softc *sc = device_private(self); |
1466 | struct pci_attach_args *pa = aux; | | 1454 | struct pci_attach_args *pa = aux; |
1467 | prop_dictionary_t dict; | | 1455 | prop_dictionary_t dict; |
1468 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | | 1456 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
1469 | pci_chipset_tag_t pc = pa->pa_pc; | | 1457 | pci_chipset_tag_t pc = pa->pa_pc; |
1470 | #ifndef WM_MSI_MSIX | | 1458 | #ifndef WM_MSI_MSIX |
1471 | pci_intr_handle_t ih; | | 1459 | pci_intr_handle_t ih; |
| | | 1460 | const char *intrstr = NULL; |
| | | 1461 | char intrbuf[PCI_INTRSTR_LEN]; |
1472 | #else | | 1462 | #else |
1473 | int counts[PCI_INTR_TYPE_SIZE]; | | 1463 | int counts[PCI_INTR_TYPE_SIZE]; |
1474 | pci_intr_type_t max_type; | | 1464 | pci_intr_type_t max_type; |
1475 | #endif | | 1465 | #endif |
1476 | const char *intrstr = NULL; | | | |
1477 | const char *eetype, *xname; | | 1466 | const char *eetype, *xname; |
1478 | bus_space_tag_t memt; | | 1467 | bus_space_tag_t memt; |
1479 | bus_space_handle_t memh; | | 1468 | bus_space_handle_t memh; |
1480 | bus_size_t memsize; | | 1469 | bus_size_t memsize; |
1481 | int memh_valid; | | 1470 | int memh_valid; |
1482 | int i, error; | | 1471 | int i, error; |
1483 | const struct wm_product *wmp; | | 1472 | const struct wm_product *wmp; |
1484 | prop_data_t ea; | | 1473 | prop_data_t ea; |
1485 | prop_number_t pn; | | 1474 | prop_number_t pn; |
1486 | uint8_t enaddr[ETHER_ADDR_LEN]; | | 1475 | uint8_t enaddr[ETHER_ADDR_LEN]; |
1487 | uint16_t cfg1, cfg2, swdpin, nvmword; | | 1476 | uint16_t cfg1, cfg2, swdpin, nvmword; |
1488 | pcireg_t preg, memtype; | | 1477 | pcireg_t preg, memtype; |
1489 | uint16_t eeprom_data, apme_mask; | | 1478 | uint16_t eeprom_data, apme_mask; |
1490 | bool force_clear_smbi; | | 1479 | bool force_clear_smbi; |
1491 | uint32_t link_mode; | | 1480 | uint32_t link_mode; |
1492 | uint32_t reg; | | 1481 | uint32_t reg; |
1493 | char intrbuf[PCI_INTRSTR_LEN]; | | | |
1494 | | | 1482 | |
1495 | sc->sc_dev = self; | | 1483 | sc->sc_dev = self; |
1496 | callout_init(&sc->sc_tick_ch, CALLOUT_FLAGS); | | 1484 | callout_init(&sc->sc_tick_ch, CALLOUT_FLAGS); |
1497 | sc->sc_stopping = false; | | 1485 | sc->sc_stopping = false; |
1498 | | | 1486 | |
1499 | wmp = wm_lookup(pa); | | 1487 | wmp = wm_lookup(pa); |
1500 | #ifdef DIAGNOSTIC | | 1488 | #ifdef DIAGNOSTIC |
1501 | if (wmp == NULL) { | | 1489 | if (wmp == NULL) { |
1502 | printf("\n"); | | 1490 | printf("\n"); |
1503 | panic("wm_attach: impossible"); | | 1491 | panic("wm_attach: impossible"); |
1504 | } | | 1492 | } |
1505 | #endif | | 1493 | #endif |
1506 | sc->sc_mediatype = WMP_MEDIATYPE(wmp->wmp_flags); | | 1494 | sc->sc_mediatype = WMP_MEDIATYPE(wmp->wmp_flags); |
| @@ -1673,114 +1661,55 @@ wm_attach(device_t parent, device_t self | | | @@ -1673,114 +1661,55 @@ wm_attach(device_t parent, device_t self |
1673 | /* Allocation settings */ | | 1661 | /* Allocation settings */ |
1674 | max_type = PCI_INTR_TYPE_MSIX; | | 1662 | max_type = PCI_INTR_TYPE_MSIX; |
1675 | counts[PCI_INTR_TYPE_MSIX] = WM_MAX_NINTR; | | 1663 | counts[PCI_INTR_TYPE_MSIX] = WM_MAX_NINTR; |
1676 | counts[PCI_INTR_TYPE_MSI] = 1; | | 1664 | counts[PCI_INTR_TYPE_MSI] = 1; |
1677 | counts[PCI_INTR_TYPE_INTX] = 1; | | 1665 | counts[PCI_INTR_TYPE_INTX] = 1; |
1678 | | | 1666 | |
1679 | alloc_retry: | | 1667 | alloc_retry: |
1680 | if (pci_intr_alloc(pa, &sc->sc_intrs, counts, max_type) != 0) { | | 1668 | if (pci_intr_alloc(pa, &sc->sc_intrs, counts, max_type) != 0) { |
1681 | aprint_error_dev(sc->sc_dev, "failed to allocate interrupt\n"); | | 1669 | aprint_error_dev(sc->sc_dev, "failed to allocate interrupt\n"); |
1682 | return; | | 1670 | return; |
1683 | } | | 1671 | } |
1684 | | | 1672 | |
1685 | if (pci_intr_type(sc->sc_intrs[0]) == PCI_INTR_TYPE_MSIX) { | | 1673 | if (pci_intr_type(sc->sc_intrs[0]) == PCI_INTR_TYPE_MSIX) { |
1686 | void *vih; | | 1674 | error = wm_setup_msix(sc); |
1687 | kcpuset_t *affinity; | | 1675 | if (error) { |
1688 | char intr_xname[INTRDEVNAMEBUF]; | | 1676 | pci_intr_release(pc, sc->sc_intrs, |
1689 | | | 1677 | counts[PCI_INTR_TYPE_MSIX]); |
1690 | kcpuset_create(&affinity, false); | | 1678 | |
1691 | | | 1679 | /* Setup for MSI: Disable MSI-X */ |
1692 | for (i = 0; i < WM_MSIX_NINTR; i++) { | | 1680 | max_type = PCI_INTR_TYPE_MSI; |
1693 | intrstr = pci_intr_string(pc, | | 1681 | counts[PCI_INTR_TYPE_MSI] = 1; |
1694 | sc->sc_intrs[msix_matrix[i].intridx], intrbuf, | | 1682 | counts[PCI_INTR_TYPE_INTX] = 1; |
1695 | sizeof(intrbuf)); | | 1683 | goto alloc_retry; |
1696 | #ifdef WM_MPSAFE | | | |
1697 | pci_intr_setattr(pc, | | | |
1698 | &sc->sc_intrs[msix_matrix[i].intridx], | | | |
1699 | PCI_INTR_MPSAFE, true); | | | |
1700 | #endif | | | |
1701 | memset(intr_xname, 0, sizeof(intr_xname)); | | | |
1702 | strlcat(intr_xname, device_xname(sc->sc_dev), | | | |
1703 | sizeof(intr_xname)); | | | |
1704 | strlcat(intr_xname, msix_matrix[i].intrname, | | | |
1705 | sizeof(intr_xname)); | | | |
1706 | vih = pci_intr_establish_xname(pc, | | | |
1707 | sc->sc_intrs[msix_matrix[i].intridx], IPL_NET, | | | |
1708 | msix_matrix[i].func, sc, intr_xname); | | | |
1709 | if (vih == NULL) { | | | |
1710 | aprint_error_dev(sc->sc_dev, | | | |
1711 | "unable to establish MSI-X(for %s)%s%s\n", | | | |
1712 | msix_matrix[i].intrname, | | | |
1713 | intrstr ? " at " : "", | | | |
1714 | intrstr ? intrstr : ""); | | | |
1715 | pci_intr_release(sc->sc_pc, sc->sc_intrs, | | | |
1716 | WM_MSIX_NINTR); | | | |
1717 | kcpuset_destroy(affinity); | | | |
1718 | | | | |
1719 | /* Setup for MSI: Disable MSI-X */ | | | |
1720 | max_type = PCI_INTR_TYPE_MSI; | | | |
1721 | counts[PCI_INTR_TYPE_MSI] = 1; | | | |
1722 | counts[PCI_INTR_TYPE_INTX] = 1; | | | |
1723 | goto alloc_retry; | | | |
1724 | } | | | |
1725 | kcpuset_zero(affinity); | | | |
1726 | /* Round-robin affinity */ | | | |
1727 | kcpuset_set(affinity, msix_matrix[i].cpuid % ncpu); | | | |
1728 | error = interrupt_distribute(vih, affinity, NULL); | | | |
1729 | if (error == 0) { | | | |
1730 | aprint_normal_dev(sc->sc_dev, | | | |
1731 | "for %s interrupting at %s affinity to %u\n", | | | |
1732 | msix_matrix[i].intrname, intrstr, | | | |
1733 | msix_matrix[i].cpuid % ncpu); | | | |
1734 | } else { | | | |
1735 | aprint_normal_dev(sc->sc_dev, | | | |
1736 | "for %s interrupting at %s\n", | | | |
1737 | msix_matrix[i].intrname, intrstr); | | | |
1738 | } | | | |
1739 | sc->sc_ihs[msix_matrix[i].intridx] = vih; | | | |
1740 | } | | 1684 | } |
| | | 1685 | } else if (pci_intr_type(sc->sc_intrs[0]) == PCI_INTR_TYPE_MSI) { |
| | | 1686 | error = wm_setup_legacy(sc); |
| | | 1687 | if (error) { |
| | | 1688 | pci_intr_release(sc->sc_pc, sc->sc_intrs, |
| | | 1689 | counts[PCI_INTR_TYPE_MSI]); |
1741 | | | 1690 | |
1742 | sc->sc_nintrs = WM_MSIX_NINTR; | | 1691 | /* The next try is for INTx: Disable MSI */ |
1743 | kcpuset_destroy(affinity); | | 1692 | max_type = PCI_INTR_TYPE_INTX; |
| | | 1693 | counts[PCI_INTR_TYPE_INTX] = 1; |
| | | 1694 | goto alloc_retry; |
| | | 1695 | } |
1744 | } else { | | 1696 | } else { |
1745 | /* MSI or INTx */ | | 1697 | error = wm_setup_legacy(sc); |
1746 | intrstr = pci_intr_string(pc, sc->sc_intrs[0], intrbuf, | | 1698 | if (error) { |
1747 | sizeof(intrbuf)); | | 1699 | pci_intr_release(sc->sc_pc, sc->sc_intrs, |
1748 | #ifdef WM_MPSAFE | | 1700 | counts[PCI_INTR_TYPE_INTX]); |
1749 | pci_intr_setattr(pc, &sc->sc_intrs[0], PCI_INTR_MPSAFE, true); | | 1701 | return; |
1750 | #endif | | | |
1751 | sc->sc_ihs[0] = pci_intr_establish_xname(pc, sc->sc_intrs[0], | | | |
1752 | IPL_NET, wm_intr_legacy, sc, device_xname(sc->sc_dev)); | | | |
1753 | if (sc->sc_ihs[0] == NULL) { | | | |
1754 | aprint_error_dev(sc->sc_dev,"unable to establish %s\n", | | | |
1755 | (pci_intr_type(sc->sc_intrs[0]) | | | |
1756 | == PCI_INTR_TYPE_MSI) ? "MSI" : "INTx"); | | | |
1757 | pci_intr_release(sc->sc_pc, sc->sc_intrs, 1); | | | |
1758 | switch (pci_intr_type(sc->sc_intrs[0])) { | | | |
1759 | case PCI_INTR_TYPE_MSI: | | | |
1760 | /* The next try is for INTx: Disable MSI */ | | | |
1761 | max_type = PCI_INTR_TYPE_INTX; | | | |
1762 | counts[PCI_INTR_TYPE_INTX] = 1; | | | |
1763 | goto alloc_retry; | | | |
1764 | case PCI_INTR_TYPE_INTX: | | | |
1765 | default: | | | |
1766 | return; | | | |
1767 | } | | | |
1768 | } | | 1702 | } |
1769 | aprint_normal_dev(sc->sc_dev, "%s at %s\n", | | | |
1770 | (pci_intr_type(sc->sc_intrs[0]) == PCI_INTR_TYPE_MSI) | | | |
1771 | ? "MSI" : "interrupting", intrstr); | | | |
1772 | | | | |
1773 | sc->sc_nintrs = 1; | | | |
1774 | } | | 1703 | } |
1775 | #endif /* WM_MSI_MSIX */ | | 1704 | #endif /* WM_MSI_MSIX */ |
1776 | | | 1705 | |
1777 | /* | | 1706 | /* |
1778 | * Check the function ID (unit number of the chip). | | 1707 | * Check the function ID (unit number of the chip). |
1779 | */ | | 1708 | */ |
1780 | if ((sc->sc_type == WM_T_82546) || (sc->sc_type == WM_T_82546_3) | | 1709 | if ((sc->sc_type == WM_T_82546) || (sc->sc_type == WM_T_82546_3) |
1781 | || (sc->sc_type == WM_T_82571) || (sc->sc_type == WM_T_80003) | | 1710 | || (sc->sc_type == WM_T_82571) || (sc->sc_type == WM_T_80003) |
1782 | || (sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576) | | 1711 | || (sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576) |
1783 | || (sc->sc_type == WM_T_82580) | | 1712 | || (sc->sc_type == WM_T_82580) |
1784 | || (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354)) | | 1713 | || (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354)) |
1785 | sc->sc_funcid = (CSR_READ(sc, WMREG_STATUS) | | 1714 | sc->sc_funcid = (CSR_READ(sc, WMREG_STATUS) |
1786 | >> STATUS_FUNCID_SHIFT) & STATUS_FUNCID_MASK; | | 1715 | >> STATUS_FUNCID_SHIFT) & STATUS_FUNCID_MASK; |
| @@ -4094,26 +4023,132 @@ wm_rxdrain(struct wm_softc *sc) | | | @@ -4094,26 +4023,132 @@ wm_rxdrain(struct wm_softc *sc) |
4094 | | | 4023 | |
4095 | KASSERT(WM_RX_LOCKED(rxq)); | | 4024 | KASSERT(WM_RX_LOCKED(rxq)); |
4096 | | | 4025 | |
4097 | for (i = 0; i < WM_NRXDESC; i++) { | | 4026 | for (i = 0; i < WM_NRXDESC; i++) { |
4098 | rxs = &rxq->rxq_soft[i]; | | 4027 | rxs = &rxq->rxq_soft[i]; |
4099 | if (rxs->rxs_mbuf != NULL) { | | 4028 | if (rxs->rxs_mbuf != NULL) { |
4100 | bus_dmamap_unload(sc->sc_dmat, rxs->rxs_dmamap); | | 4029 | bus_dmamap_unload(sc->sc_dmat, rxs->rxs_dmamap); |
4101 | m_freem(rxs->rxs_mbuf); | | 4030 | m_freem(rxs->rxs_mbuf); |
4102 | rxs->rxs_mbuf = NULL; | | 4031 | rxs->rxs_mbuf = NULL; |
4103 | } | | 4032 | } |
4104 | } | | 4033 | } |
4105 | } | | 4034 | } |
4106 | | | 4035 | |
| | | 4036 | |
| | | 4037 | #ifdef WM_MSI_MSIX |
| | | 4038 | /* |
| | | 4039 | * Both single interrupt MSI and INTx can use this function. |
| | | 4040 | */ |
| | | 4041 | static int |
| | | 4042 | wm_setup_legacy(struct wm_softc *sc) |
| | | 4043 | { |
| | | 4044 | pci_chipset_tag_t pc = sc->sc_pc; |
| | | 4045 | const char *intrstr = NULL; |
| | | 4046 | char intrbuf[PCI_INTRSTR_LEN]; |
| | | 4047 | |
| | | 4048 | intrstr = pci_intr_string(pc, sc->sc_intrs[0], intrbuf, |
| | | 4049 | sizeof(intrbuf)); |
| | | 4050 | #ifdef WM_MPSAFE |
| | | 4051 | pci_intr_setattr(pc, &sc->sc_intrs[0], PCI_INTR_MPSAFE, true); |
| | | 4052 | #endif |
| | | 4053 | sc->sc_ihs[0] = pci_intr_establish_xname(pc, sc->sc_intrs[0], |
| | | 4054 | IPL_NET, wm_intr_legacy, sc, device_xname(sc->sc_dev)); |
| | | 4055 | if (sc->sc_ihs[0] == NULL) { |
| | | 4056 | aprint_error_dev(sc->sc_dev,"unable to establish %s\n", |
| | | 4057 | (pci_intr_type(sc->sc_intrs[0]) |
| | | 4058 | == PCI_INTR_TYPE_MSI) ? "MSI" : "INTx"); |
| | | 4059 | return ENOMEM; |
| | | 4060 | } |
| | | 4061 | |
| | | 4062 | aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr); |
| | | 4063 | sc->sc_nintrs = 1; |
| | | 4064 | return 0; |
| | | 4065 | } |
| | | 4066 | |
| | | 4067 | struct _msix_matrix { |
| | | 4068 | const char *intrname; |
| | | 4069 | int(*func)(void *); |
| | | 4070 | int intridx; |
| | | 4071 | int cpuid; |
| | | 4072 | } msix_matrix[WM_MSIX_NINTR] = { |
| | | 4073 | { "TX", wm_txintr_msix, WM_MSIX_TXINTR_IDX, WM_MSIX_TXINTR_CPUID }, |
| | | 4074 | { "RX", wm_rxintr_msix, WM_MSIX_RXINTR_IDX, WM_MSIX_RXINTR_CPUID }, |
| | | 4075 | { "LINK", wm_linkintr_msix, WM_MSIX_LINKINTR_IDX, |
| | | 4076 | WM_MSIX_LINKINTR_CPUID }, |
| | | 4077 | }; |
| | | 4078 | |
| | | 4079 | static int |
| | | 4080 | wm_setup_msix(struct wm_softc *sc) |
| | | 4081 | { |
| | | 4082 | void *vih; |
| | | 4083 | kcpuset_t *affinity; |
| | | 4084 | int i, error; |
| | | 4085 | pci_chipset_tag_t pc = sc->sc_pc; |
| | | 4086 | const char *intrstr = NULL; |
| | | 4087 | char intrbuf[PCI_INTRSTR_LEN]; |
| | | 4088 | char intr_xname[INTRDEVNAMEBUF]; |
| | | 4089 | |
| | | 4090 | kcpuset_create(&affinity, false); |
| | | 4091 | |
| | | 4092 | for (i = 0; i < WM_MSIX_NINTR; i++) { |
| | | 4093 | intrstr = pci_intr_string(pc, |
| | | 4094 | sc->sc_intrs[msix_matrix[i].intridx], intrbuf, |
| | | 4095 | sizeof(intrbuf)); |
| | | 4096 | #ifdef WM_MPSAFE |
| | | 4097 | pci_intr_setattr(pc, |
| | | 4098 | &sc->sc_intrs[msix_matrix[i].intridx], |
| | | 4099 | PCI_INTR_MPSAFE, true); |
| | | 4100 | #endif |
| | | 4101 | memset(intr_xname, 0, sizeof(intr_xname)); |
| | | 4102 | strlcat(intr_xname, device_xname(sc->sc_dev), |
| | | 4103 | sizeof(intr_xname)); |
| | | 4104 | strlcat(intr_xname, msix_matrix[i].intrname, |
| | | 4105 | sizeof(intr_xname)); |
| | | 4106 | vih = pci_intr_establish_xname(pc, |
| | | 4107 | sc->sc_intrs[msix_matrix[i].intridx], IPL_NET, |
| | | 4108 | msix_matrix[i].func, sc, intr_xname); |
| | | 4109 | if (vih == NULL) { |
| | | 4110 | aprint_error_dev(sc->sc_dev, |
| | | 4111 | "unable to establish MSI-X(for %s)%s%s\n", |
| | | 4112 | msix_matrix[i].intrname, |
| | | 4113 | intrstr ? " at " : "", |
| | | 4114 | intrstr ? intrstr : ""); |
| | | 4115 | kcpuset_destroy(affinity); |
| | | 4116 | |
| | | 4117 | return ENOMEM; |
| | | 4118 | } |
| | | 4119 | kcpuset_zero(affinity); |
| | | 4120 | /* Round-robin affinity */ |
| | | 4121 | kcpuset_set(affinity, msix_matrix[i].cpuid % ncpu); |
| | | 4122 | error = interrupt_distribute(vih, affinity, NULL); |
| | | 4123 | if (error == 0) { |
| | | 4124 | aprint_normal_dev(sc->sc_dev, |
| | | 4125 | "for %s interrupting at %s affinity to %u\n", |
| | | 4126 | msix_matrix[i].intrname, intrstr, |
| | | 4127 | msix_matrix[i].cpuid % ncpu); |
| | | 4128 | } else { |
| | | 4129 | aprint_normal_dev(sc->sc_dev, |
| | | 4130 | "for %s interrupting at %s\n", |
| | | 4131 | msix_matrix[i].intrname, intrstr); |
| | | 4132 | } |
| | | 4133 | sc->sc_ihs[msix_matrix[i].intridx] = vih; |
| | | 4134 | } |
| | | 4135 | |
| | | 4136 | sc->sc_nintrs = WM_MSIX_NINTR; |
| | | 4137 | kcpuset_destroy(affinity); |
| | | 4138 | return 0; |
| | | 4139 | } |
| | | 4140 | #endif |
| | | 4141 | |
4107 | /* | | 4142 | /* |
4108 | * wm_init: [ifnet interface function] | | 4143 | * wm_init: [ifnet interface function] |
4109 | * | | 4144 | * |
4110 | * Initialize the interface. | | 4145 | * Initialize the interface. |
4111 | */ | | 4146 | */ |
4112 | static int | | 4147 | static int |
4113 | wm_init(struct ifnet *ifp) | | 4148 | wm_init(struct ifnet *ifp) |
4114 | { | | 4149 | { |
4115 | struct wm_softc *sc = ifp->if_softc; | | 4150 | struct wm_softc *sc = ifp->if_softc; |
4116 | int ret; | | 4151 | int ret; |
4117 | | | 4152 | |
4118 | WM_CORE_LOCK(sc); | | 4153 | WM_CORE_LOCK(sc); |
4119 | ret = wm_init_locked(ifp); | | 4154 | ret = wm_init_locked(ifp); |