| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: if_wm.c,v 1.362 2015/10/13 08:27:11 knakahara Exp $ */ | | 1 | /* $NetBSD: if_wm.c,v 1.363 2015/10/13 08:29:44 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.362 2015/10/13 08:27:11 knakahara Exp $"); | | 86 | __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.363 2015/10/13 08:29:44 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> |
| @@ -4054,68 +4054,72 @@ wm_setup_legacy(struct wm_softc *sc) | | | @@ -4054,68 +4054,72 @@ wm_setup_legacy(struct wm_softc *sc) |
4054 | IPL_NET, wm_intr_legacy, sc, device_xname(sc->sc_dev)); | | 4054 | IPL_NET, wm_intr_legacy, sc, device_xname(sc->sc_dev)); |
4055 | if (sc->sc_ihs[0] == NULL) { | | 4055 | if (sc->sc_ihs[0] == NULL) { |
4056 | aprint_error_dev(sc->sc_dev,"unable to establish %s\n", | | 4056 | aprint_error_dev(sc->sc_dev,"unable to establish %s\n", |
4057 | (pci_intr_type(sc->sc_intrs[0]) | | 4057 | (pci_intr_type(sc->sc_intrs[0]) |
4058 | == PCI_INTR_TYPE_MSI) ? "MSI" : "INTx"); | | 4058 | == PCI_INTR_TYPE_MSI) ? "MSI" : "INTx"); |
4059 | return ENOMEM; | | 4059 | return ENOMEM; |
4060 | } | | 4060 | } |
4061 | | | 4061 | |
4062 | aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr); | | 4062 | aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr); |
4063 | sc->sc_nintrs = 1; | | 4063 | sc->sc_nintrs = 1; |
4064 | return 0; | | 4064 | return 0; |
4065 | } | | 4065 | } |
4066 | | | 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 | | 4067 | static int |
4080 | wm_setup_msix(struct wm_softc *sc) | | 4068 | wm_setup_msix(struct wm_softc *sc) |
4081 | { | | 4069 | { |
4082 | void *vih; | | 4070 | void *vih; |
4083 | kcpuset_t *affinity; | | 4071 | kcpuset_t *affinity; |
4084 | int i, error; | | 4072 | int i, error; |
4085 | pci_chipset_tag_t pc = sc->sc_pc; | | 4073 | pci_chipset_tag_t pc = sc->sc_pc; |
4086 | const char *intrstr = NULL; | | 4074 | const char *intrstr = NULL; |
4087 | char intrbuf[PCI_INTRSTR_LEN]; | | 4075 | char intrbuf[PCI_INTRSTR_LEN]; |
4088 | char intr_xname[INTRDEVNAMEBUF]; | | 4076 | char intr_xname[INTRDEVNAMEBUF]; |
4089 | | | 4077 | |
| | | 4078 | struct _msix_matrix { |
| | | 4079 | const char *intrname; |
| | | 4080 | int(*func)(void *); |
| | | 4081 | void *arg; |
| | | 4082 | int intridx; |
| | | 4083 | int cpuid; |
| | | 4084 | } msix_matrix[WM_MSIX_NINTR] = { |
| | | 4085 | { "TX", wm_txintr_msix, sc->sc_txq, |
| | | 4086 | WM_MSIX_TXINTR_IDX, WM_MSIX_TXINTR_CPUID }, |
| | | 4087 | { "RX", wm_rxintr_msix, sc->sc_rxq, |
| | | 4088 | WM_MSIX_RXINTR_IDX, WM_MSIX_RXINTR_CPUID }, |
| | | 4089 | { "LINK", wm_linkintr_msix, sc, |
| | | 4090 | WM_MSIX_LINKINTR_IDX, WM_MSIX_LINKINTR_CPUID }, |
| | | 4091 | }; |
| | | 4092 | |
| | | 4093 | |
4090 | kcpuset_create(&affinity, false); | | 4094 | kcpuset_create(&affinity, false); |
4091 | | | 4095 | |
4092 | for (i = 0; i < WM_MSIX_NINTR; i++) { | | 4096 | for (i = 0; i < WM_MSIX_NINTR; i++) { |
4093 | intrstr = pci_intr_string(pc, | | 4097 | intrstr = pci_intr_string(pc, |
4094 | sc->sc_intrs[msix_matrix[i].intridx], intrbuf, | | 4098 | sc->sc_intrs[msix_matrix[i].intridx], intrbuf, |
4095 | sizeof(intrbuf)); | | 4099 | sizeof(intrbuf)); |
4096 | #ifdef WM_MPSAFE | | 4100 | #ifdef WM_MPSAFE |
4097 | pci_intr_setattr(pc, | | 4101 | pci_intr_setattr(pc, |
4098 | &sc->sc_intrs[msix_matrix[i].intridx], | | 4102 | &sc->sc_intrs[msix_matrix[i].intridx], |
4099 | PCI_INTR_MPSAFE, true); | | 4103 | PCI_INTR_MPSAFE, true); |
4100 | #endif | | 4104 | #endif |
4101 | memset(intr_xname, 0, sizeof(intr_xname)); | | 4105 | memset(intr_xname, 0, sizeof(intr_xname)); |
4102 | strlcat(intr_xname, device_xname(sc->sc_dev), | | 4106 | strlcat(intr_xname, device_xname(sc->sc_dev), |
4103 | sizeof(intr_xname)); | | 4107 | sizeof(intr_xname)); |
4104 | strlcat(intr_xname, msix_matrix[i].intrname, | | 4108 | strlcat(intr_xname, msix_matrix[i].intrname, |
4105 | sizeof(intr_xname)); | | 4109 | sizeof(intr_xname)); |
4106 | vih = pci_intr_establish_xname(pc, | | 4110 | vih = pci_intr_establish_xname(pc, |
4107 | sc->sc_intrs[msix_matrix[i].intridx], IPL_NET, | | 4111 | sc->sc_intrs[msix_matrix[i].intridx], IPL_NET, |
4108 | msix_matrix[i].func, sc, intr_xname); | | 4112 | msix_matrix[i].func, msix_matrix[i].arg, intr_xname); |
4109 | if (vih == NULL) { | | 4113 | if (vih == NULL) { |
4110 | aprint_error_dev(sc->sc_dev, | | 4114 | aprint_error_dev(sc->sc_dev, |
4111 | "unable to establish MSI-X(for %s)%s%s\n", | | 4115 | "unable to establish MSI-X(for %s)%s%s\n", |
4112 | msix_matrix[i].intrname, | | 4116 | msix_matrix[i].intrname, |
4113 | intrstr ? " at " : "", | | 4117 | intrstr ? " at " : "", |
4114 | intrstr ? intrstr : ""); | | 4118 | intrstr ? intrstr : ""); |
4115 | kcpuset_destroy(affinity); | | 4119 | kcpuset_destroy(affinity); |
4116 | | | 4120 | |
4117 | return ENOMEM; | | 4121 | return ENOMEM; |
4118 | } | | 4122 | } |
4119 | kcpuset_zero(affinity); | | 4123 | kcpuset_zero(affinity); |
4120 | /* Round-robin affinity */ | | 4124 | /* Round-robin affinity */ |
4121 | kcpuset_set(affinity, msix_matrix[i].cpuid % ncpu); | | 4125 | kcpuset_set(affinity, msix_matrix[i].cpuid % ncpu); |
| @@ -7051,28 +7055,28 @@ wm_intr_legacy(void *arg) | | | @@ -7051,28 +7055,28 @@ wm_intr_legacy(void *arg) |
7051 | | | 7055 | |
7052 | return handled; | | 7056 | return handled; |
7053 | } | | 7057 | } |
7054 | | | 7058 | |
7055 | #ifdef WM_MSI_MSIX | | 7059 | #ifdef WM_MSI_MSIX |
7056 | /* | | 7060 | /* |
7057 | * wm_txintr_msix: | | 7061 | * wm_txintr_msix: |
7058 | * | | 7062 | * |
7059 | * Interrupt service routine for TX complete interrupt for MSI-X. | | 7063 | * Interrupt service routine for TX complete interrupt for MSI-X. |
7060 | */ | | 7064 | */ |
7061 | static int | | 7065 | static int |
7062 | wm_txintr_msix(void *arg) | | 7066 | wm_txintr_msix(void *arg) |
7063 | { | | 7067 | { |
7064 | struct wm_softc *sc = arg; | | 7068 | struct wm_txqueue *txq = arg; |
7065 | struct wm_txqueue *txq = sc->sc_txq; | | 7069 | struct wm_softc *sc = txq->txq_sc; |
7066 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | | 7070 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
7067 | int handled = 0; | | 7071 | int handled = 0; |
7068 | | | 7072 | |
7069 | DPRINTF(WM_DEBUG_TX, | | 7073 | DPRINTF(WM_DEBUG_TX, |
7070 | ("%s: TX: got Tx intr\n", device_xname(sc->sc_dev))); | | 7074 | ("%s: TX: got Tx intr\n", device_xname(sc->sc_dev))); |
7071 | | | 7075 | |
7072 | if (sc->sc_type == WM_T_82574) | | 7076 | if (sc->sc_type == WM_T_82574) |
7073 | CSR_WRITE(sc, WMREG_IMC, ICR_TXQ(0)); /* 82574 only */ | | 7077 | CSR_WRITE(sc, WMREG_IMC, ICR_TXQ(0)); /* 82574 only */ |
7074 | else if (sc->sc_type == WM_T_82575) | | 7078 | else if (sc->sc_type == WM_T_82575) |
7075 | CSR_WRITE(sc, WMREG_EIMC, EITR_TX_QUEUE(0)); | | 7079 | CSR_WRITE(sc, WMREG_EIMC, EITR_TX_QUEUE(0)); |
7076 | else | | 7080 | else |
7077 | CSR_WRITE(sc, WMREG_EIMC, 1 << WM_MSIX_TXINTR_IDX); | | 7081 | CSR_WRITE(sc, WMREG_EIMC, 1 << WM_MSIX_TXINTR_IDX); |
7078 | | | 7082 | |
| @@ -7100,28 +7104,28 @@ out: | | | @@ -7100,28 +7104,28 @@ out: |
7100 | } | | 7104 | } |
7101 | | | 7105 | |
7102 | return handled; | | 7106 | return handled; |
7103 | } | | 7107 | } |
7104 | | | 7108 | |
7105 | /* | | 7109 | /* |
7106 | * wm_rxintr_msix: | | 7110 | * wm_rxintr_msix: |
7107 | * | | 7111 | * |
7108 | * Interrupt service routine for RX interrupt for MSI-X. | | 7112 | * Interrupt service routine for RX interrupt for MSI-X. |
7109 | */ | | 7113 | */ |
7110 | static int | | 7114 | static int |
7111 | wm_rxintr_msix(void *arg) | | 7115 | wm_rxintr_msix(void *arg) |
7112 | { | | 7116 | { |
7113 | struct wm_softc *sc = arg; | | 7117 | struct wm_rxqueue *rxq = arg; |
7114 | struct wm_rxqueue *rxq = sc->sc_rxq; | | 7118 | struct wm_softc *sc = rxq->rxq_sc; |
7115 | | | 7119 | |
7116 | DPRINTF(WM_DEBUG_TX, | | 7120 | DPRINTF(WM_DEBUG_TX, |
7117 | ("%s: RX: got Rx intr\n", device_xname(sc->sc_dev))); | | 7121 | ("%s: RX: got Rx intr\n", device_xname(sc->sc_dev))); |
7118 | | | 7122 | |
7119 | if (sc->sc_type == WM_T_82574) | | 7123 | if (sc->sc_type == WM_T_82574) |
7120 | CSR_WRITE(sc, WMREG_IMC, ICR_RXQ(0)); /* 82574 only */ | | 7124 | CSR_WRITE(sc, WMREG_IMC, ICR_RXQ(0)); /* 82574 only */ |
7121 | else if (sc->sc_type == WM_T_82575) | | 7125 | else if (sc->sc_type == WM_T_82575) |
7122 | CSR_WRITE(sc, WMREG_EIMC, EITR_RX_QUEUE(0)); | | 7126 | CSR_WRITE(sc, WMREG_EIMC, EITR_RX_QUEUE(0)); |
7123 | else | | 7127 | else |
7124 | CSR_WRITE(sc, WMREG_EIMC, 1 << WM_MSIX_RXINTR_IDX); | | 7128 | CSR_WRITE(sc, WMREG_EIMC, 1 << WM_MSIX_RXINTR_IDX); |
7125 | | | 7129 | |
7126 | WM_RX_LOCK(rxq); | | 7130 | WM_RX_LOCK(rxq); |
7127 | | | 7131 | |