github.com/nya3jp/tast@v0.0.0-20230601000426-85c8e4d83a9b/src/go.chromium.org/tast/core/testing/wlan/wlan.go (about) 1 // Copyright 2023 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Package wlan provides the information of the wlan device. 6 package wlan 7 8 import ( 9 "io/ioutil" 10 "os" 11 "path/filepath" 12 "regexp" 13 "strings" 14 15 "go.chromium.org/tast/core/errors" 16 ) 17 18 // DeviceID is used as a Device ID type. 19 type DeviceID int32 20 21 // DevInfo contains the information of the WLAN device. 22 type DevInfo struct { 23 // Vendor is the vendor ID seen in /sys/class/net/<interface>/vendor. 24 Vendor string 25 // Device is the product ID seen in /sys/class/net/<interface>/device. 26 Device string 27 // Compatible is the compatible property. 28 // See https://www.kernel.org/doc/Documentation/devicetree/usage-model.txt. 29 Compatible string 30 // Subsystem is the RF chip's ID. The addition of this property is necessary for 31 // device disambiguation (b/129489799). 32 Subsystem string 33 // Device (enum) ID 34 ID DeviceID 35 // The device name. 36 Name string 37 } 38 39 // WLAN Device IDs. 40 const ( 41 UnknownDevice DeviceID = iota 42 Marvell88w8897SDIO 43 Marvell88w8997PCIE 44 QualcommAtherosQCA6174 45 QualcommAtherosQCA6174SDIO 46 QualcommWCN3990 47 QualcommWCN6750 48 QualcommWCN6855 49 Intel7260 50 Intel7265 51 Intel8265 52 Intel9000 53 Intel9260 54 Intel22260 55 Intel22560 56 IntelAX201 57 IntelAX203 58 IntelAX211 59 BroadcomBCM4354SDIO 60 BroadcomBCM4356PCIE 61 BroadcomBCM4371PCIE 62 Realtek8822CPCIE 63 Realtek8852APCIE 64 Realtek8852CPCIE 65 MediaTekMT7921PCIE 66 MediaTekMT7921SDIO 67 MediaTekMT7922PCIE 68 ) 69 70 // DeviceNames map contains WLAN device names. 71 var DeviceNames = map[DeviceID]string{ 72 Marvell88w8897SDIO: "Marvell 88W8897 SDIO", 73 Marvell88w8997PCIE: "Marvell 88W8997 PCIE", 74 QualcommAtherosQCA6174: "Qualcomm Atheros QCA6174", 75 QualcommAtherosQCA6174SDIO: "Qualcomm Atheros QCA6174 SDIO", 76 QualcommWCN3990: "Qualcomm WCN3990", 77 QualcommWCN6750: "Qualcomm WCN6750", 78 QualcommWCN6855: "Qualcomm WCN6855", 79 Intel7260: "Intel 7260", 80 Intel7265: "Intel 7265", 81 Intel8265: "Intel 8265", 82 Intel9000: "Intel 9000", 83 Intel9260: "Intel 9260", 84 Intel22260: "Intel 22260", 85 Intel22560: "Intel 22560", 86 IntelAX201: "Intel AX 201", 87 IntelAX203: "Intel AX 203", 88 IntelAX211: "Intel AX 211", 89 BroadcomBCM4354SDIO: "Broadcom BCM4354 SDIO", 90 BroadcomBCM4356PCIE: "Broadcom BCM4356 PCIE", 91 BroadcomBCM4371PCIE: "Broadcom BCM4371 PCIE", 92 Realtek8822CPCIE: "Realtek 8822C PCIE", 93 Realtek8852APCIE: "Realtek 8852A PCIE", 94 Realtek8852CPCIE: "Realtek 8852C PCIE", 95 MediaTekMT7921PCIE: "MediaTek MT7921 PCIE", 96 MediaTekMT7921SDIO: "MediaTek MT7921 SDIO", 97 MediaTekMT7922PCIE: "MediaTek MT7922 PCIE", 98 } 99 100 // Mapping of device identification data to device ID. 101 var lookupWLANDev = map[DevInfo]DeviceID{ 102 {Vendor: "0x02df", Device: "0x912d"}: Marvell88w8897SDIO, 103 {Vendor: "0x1b4b", Device: "0x2b42"}: Marvell88w8997PCIE, 104 {Vendor: "0x168c", Device: "0x003e"}: QualcommAtherosQCA6174, 105 {Vendor: "0x0271", Device: "0x050a"}: QualcommAtherosQCA6174SDIO, 106 {Vendor: "0x17cb", Device: "0x1103"}: QualcommWCN6855, 107 {Vendor: "0x8086", Device: "0x08b1"}: Intel7260, 108 {Vendor: "0x8086", Device: "0x08b2"}: Intel7260, 109 {Vendor: "0x8086", Device: "0x095a"}: Intel7265, 110 {Vendor: "0x8086", Device: "0x095b"}: Intel7265, 111 // Note that Intel 9000 is also Intel 9560 aka Jefferson Peak 2. 112 {Vendor: "0x8086", Device: "0x9df0"}: Intel9000, 113 {Vendor: "0x8086", Device: "0x31dc"}: Intel9000, 114 {Vendor: "0x8086", Device: "0x2526"}: Intel9260, 115 {Vendor: "0x8086", Device: "0x2723"}: Intel22260, 116 // For integrated wifi chips, use device_id and subsystem_id together 117 // as an identifier. 118 // 0x02f0 is for Quasar on CML; 0x4070, 0x0074, 0x6074 are for HrP2. 119 {Vendor: "0x8086", Device: "0x24fd", Subsystem: "0x0010"}: Intel8265, 120 {Vendor: "0x8086", Device: "0x02f0", Subsystem: "0x0030"}: Intel9000, 121 {Vendor: "0x8086", Device: "0x02f0", Subsystem: "0x0034"}: Intel9000, 122 {Vendor: "0x8086", Device: "0x02f0", Subsystem: "0x4070"}: Intel22560, 123 {Vendor: "0x8086", Device: "0x02f0", Subsystem: "0x0074"}: Intel22560, 124 {Vendor: "0x8086", Device: "0x02f0", Subsystem: "0x6074"}: Intel22560, 125 {Vendor: "0x8086", Device: "0x4df0", Subsystem: "0x0070"}: Intel22560, 126 {Vendor: "0x8086", Device: "0x4df0", Subsystem: "0x4070"}: Intel22560, 127 {Vendor: "0x8086", Device: "0x4df0", Subsystem: "0x0074"}: Intel22560, 128 {Vendor: "0x8086", Device: "0x4df0", Subsystem: "0x6074"}: Intel22560, 129 {Vendor: "0x8086", Device: "0xa0f0", Subsystem: "0x4070"}: Intel22560, 130 {Vendor: "0x8086", Device: "0xa0f0", Subsystem: "0x0074"}: Intel22560, 131 {Vendor: "0x8086", Device: "0xa0f0", Subsystem: "0x6074"}: Intel22560, 132 {Vendor: "0x8086", Device: "0x02f0", Subsystem: "0x0070"}: IntelAX201, 133 {Vendor: "0x8086", Device: "0xa0f0", Subsystem: "0x0070"}: IntelAX201, 134 {Vendor: "0x8086", Device: "0x54f0", Subsystem: "0x0274"}: IntelAX203, 135 {Vendor: "0x8086", Device: "0x54f0", Subsystem: "0x4274"}: IntelAX203, 136 {Vendor: "0x8086", Device: "0x51f0", Subsystem: "0x0090"}: IntelAX211, 137 {Vendor: "0x8086", Device: "0x51f1", Subsystem: "0x0090"}: IntelAX211, 138 {Vendor: "0x8086", Device: "0x51f1", Subsystem: "0x0094"}: IntelAX211, 139 {Vendor: "0x8086", Device: "0x51f0", Subsystem: "0x0094"}: IntelAX211, 140 {Vendor: "0x8086", Device: "0x51f0", Subsystem: "0x4090"}: IntelAX211, 141 {Vendor: "0x8086", Device: "0x54f0", Subsystem: "0x0090"}: IntelAX211, 142 {Vendor: "0x8086", Device: "0x54f0", Subsystem: "0x0094"}: IntelAX211, 143 {Vendor: "0x8086", Device: "0x7e40", Subsystem: "0x0090"}: IntelAX211, 144 {Vendor: "0x8086", Device: "0x7e40", Subsystem: "0x0094"}: IntelAX211, 145 {Vendor: "0x14e4", Device: "0x43ec"}: BroadcomBCM4356PCIE, 146 {Vendor: "0x10ec", Device: "0xc822"}: Realtek8822CPCIE, 147 {Vendor: "0x10ec", Device: "0x8852"}: Realtek8852APCIE, 148 {Vendor: "0x10ec", Device: "0xc852"}: Realtek8852CPCIE, 149 {Vendor: "0x14c3", Device: "0x7961"}: MediaTekMT7921PCIE, 150 {Vendor: "0x037a", Device: "0x7901"}: MediaTekMT7921SDIO, 151 {Vendor: "0x14c3", Device: "0x7922"}: MediaTekMT7922PCIE, 152 {Vendor: "0x14c3", Device: "0x0616"}: MediaTekMT7922PCIE, 153 {Compatible: "qcom,wcn3990-wifi"}: QualcommWCN3990, 154 {Compatible: "qcom,wcn6750-wifi"}: QualcommWCN6750, 155 } 156 157 var compatibleRE = regexp.MustCompile("^OF_COMPATIBLE_[0-9]") 158 var wlanRE = regexp.MustCompile("DEVTYPE=wlan") 159 160 func findWlanIface() (string, error) { 161 const baseDir = "/sys/class/net/" 162 163 dirs, err := ioutil.ReadDir(baseDir) 164 if err != nil { 165 return "", errors.Wrapf(err, 166 "failed to read %s directory", baseDir) 167 } 168 for _, dir := range dirs { 169 path := filepath.Join(baseDir, dir.Name(), "uevent") 170 bs, err := ioutil.ReadFile(path) 171 if err != nil { 172 if os.IsNotExist(err) { 173 // It is perfectly OK if the file does not exist. 174 continue 175 } 176 // Other errors should be reported, though. 177 return "", errors.Wrapf(err, "failed to read %s file", path) 178 } 179 if wlanRE.MatchString(string(bs)) { 180 // ChromeOS supports only one wlan device, thus return first dir matched. 181 return dir.Name(), nil 182 } 183 } 184 return "", errors.New("Wireless device not found") 185 } 186 187 // DeviceInfo returns a public struct (DevInfo) containing the WLAN device information. 188 func DeviceInfo() (*DevInfo, error) { 189 readInfo := func(netIf, x string) (string, error) { 190 bs, err := ioutil.ReadFile(filepath.Join("/sys/class/net/", netIf, "device", x)) 191 if err != nil { 192 return "", err 193 } 194 return strings.TrimSpace(string(bs)), nil 195 } 196 197 netIf, err := findWlanIface() 198 if err != nil { 199 // Nothing important to add to the error description. 200 return nil, err 201 } 202 uevent, err := readInfo(netIf, "uevent") 203 if err != nil { 204 return nil, errors.Wrap(err, "failed to get uevent") 205 } 206 207 // Support for (qcom,wcnXXXX-wifi) chips. 208 for _, line := range strings.Split(uevent, "\n") { 209 if kv := compatibleRE.FindStringSubmatch(line); kv != nil { 210 if wifiSnoc := strings.SplitN(line, "=", 2); len(wifiSnoc) == 2 { 211 if d, ok := lookupWLANDev[DevInfo{Compatible: wifiSnoc[1]}]; ok { 212 // Found the matching device. 213 return &DevInfo{ID: d, Name: DeviceNames[d]}, nil 214 } 215 } 216 } 217 } 218 219 vendorID, err := readInfo(netIf, "vendor") 220 if err != nil { 221 return nil, errors.Wrapf(err, "failed to get vendor ID at device %q", netIf) 222 } 223 224 productID, err := readInfo(netIf, "device") 225 if err != nil { 226 return nil, errors.Wrapf(err, "failed to get product ID at device %q", netIf) 227 } 228 229 subsystemID, err := readInfo(netIf, "subsystem_device") 230 // DUTs that use SDIO as the bus technology may not have subsystem_device at all. 231 if err != nil && !os.IsNotExist(err) { 232 return nil, errors.Wrapf(err, "failed to get subsystem ID at device %q", netIf) 233 } 234 if d, ok := lookupWLANDev[DevInfo{Vendor: vendorID, Device: productID, Subsystem: subsystemID}]; ok { 235 return &DevInfo{Vendor: vendorID, Device: productID, Subsystem: subsystemID, ID: d, Name: DeviceNames[d]}, nil 236 } 237 238 if d, ok := lookupWLANDev[DevInfo{Vendor: vendorID, Device: productID}]; ok { 239 return &DevInfo{Vendor: vendorID, Device: productID, ID: d, Name: DeviceNames[d]}, nil 240 } 241 242 return nil, errors.Errorf("unknown %s device with vendorID=%s, productID=%s, subsystemID=%s", 243 netIf, vendorID, productID, subsystemID) 244 } 245 246 // List of WLAN devices that don't support MU-MIMO. 247 var denyListMUMIMO = []DeviceID{ 248 Marvell88w8897SDIO, // Tested a DUT. 249 Intel7260, // (WP2) according to datasheet. 250 Intel7265, // (StP2) tested a DUT. 251 BroadcomBCM4354SDIO, // Tested a DUT. 252 BroadcomBCM4356PCIE, // According to datasheet. 253 } 254 255 // SupportMUMIMO return true if the WLAN device support MU-MIMO. 256 func (dev *DevInfo) SupportMUMIMO() bool { 257 // Checking if the tested WLAN device does not support MU-MIMO. 258 for _, id := range denyListMUMIMO { 259 if id == dev.ID { 260 return false 261 } 262 } 263 return true 264 }