blob: b88697de9420096a9934ee7df5faf59034eeea63 [file] [log] [blame]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Package wlan provides the information of the wlan device.
package wlan
import (
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
"go.chromium.org/tast/core/errors"
)
// DeviceID is used as a Device ID type.
type DeviceID int32
// DevInfo contains the information of the WLAN device.
type DevInfo struct {
// Vendor is the vendor ID seen in /sys/class/net/<interface>/vendor.
Vendor string
// Device is the product ID seen in /sys/class/net/<interface>/device.
Device string
// Compatible is the compatible property.
// See https://www.kernel.org/doc/Documentation/devicetree/usage-model.txt.
Compatible string
// Subsystem is the RF chip's ID. The addition of this property is necessary for
// device disambiguation (b/129489799).
Subsystem string
// Device (enum) ID
ID DeviceID
// The device name.
Name string
}
// WLAN Device IDs.
const (
UnknownDevice DeviceID = iota
Marvell88w8897SDIO
Marvell88w8997PCIE
QualcommAtherosQCA6174
QualcommAtherosQCA6174SDIO
QualcommWCN3990
QualcommWCN6750
QualcommWCN6855
Intel7260
Intel7265
Intel8265
Intel9000
Intel9260
Intel22260
Intel22560
IntelAX201
IntelAX203
IntelAX211
BroadcomBCM4354SDIO
BroadcomBCM4356PCIE
BroadcomBCM4371PCIE
Realtek8822CPCIE
Realtek8852APCIE
Realtek8852CPCIE
MediaTekMT7921PCIE
MediaTekMT7921SDIO
MediaTekMT7922PCIE
)
// DeviceNames map contains WLAN device names.
var DeviceNames = map[DeviceID]string{
Marvell88w8897SDIO: "Marvell 88W8897 SDIO",
Marvell88w8997PCIE: "Marvell 88W8997 PCIE",
QualcommAtherosQCA6174: "Qualcomm Atheros QCA6174",
QualcommAtherosQCA6174SDIO: "Qualcomm Atheros QCA6174 SDIO",
QualcommWCN3990: "Qualcomm WCN3990",
QualcommWCN6750: "Qualcomm WCN6750",
QualcommWCN6855: "Qualcomm WCN6855",
Intel7260: "Intel 7260",
Intel7265: "Intel 7265",
Intel8265: "Intel 8265",
Intel9000: "Intel 9000",
Intel9260: "Intel 9260",
Intel22260: "Intel 22260",
Intel22560: "Intel 22560",
IntelAX201: "Intel AX 201",
IntelAX203: "Intel AX 203",
IntelAX211: "Intel AX 211",
BroadcomBCM4354SDIO: "Broadcom BCM4354 SDIO",
BroadcomBCM4356PCIE: "Broadcom BCM4356 PCIE",
BroadcomBCM4371PCIE: "Broadcom BCM4371 PCIE",
Realtek8822CPCIE: "Realtek 8822C PCIE",
Realtek8852APCIE: "Realtek 8852A PCIE",
Realtek8852CPCIE: "Realtek 8852C PCIE",
MediaTekMT7921PCIE: "MediaTek MT7921 PCIE",
MediaTekMT7921SDIO: "MediaTek MT7921 SDIO",
MediaTekMT7922PCIE: "MediaTek MT7922 PCIE",
}
// Mapping of device identification data to device ID.
var lookupWLANDev = map[DevInfo]DeviceID{
{Vendor: "0x02df", Device: "0x912d"}: Marvell88w8897SDIO,
{Vendor: "0x1b4b", Device: "0x2b42"}: Marvell88w8997PCIE,
{Vendor: "0x168c", Device: "0x003e"}: QualcommAtherosQCA6174,
{Vendor: "0x0271", Device: "0x050a"}: QualcommAtherosQCA6174SDIO,
{Vendor: "0x17cb", Device: "0x1103"}: QualcommWCN6855,
{Vendor: "0x8086", Device: "0x08b1"}: Intel7260,
{Vendor: "0x8086", Device: "0x08b2"}: Intel7260,
{Vendor: "0x8086", Device: "0x095a"}: Intel7265,
{Vendor: "0x8086", Device: "0x095b"}: Intel7265,
// Note that Intel 9000 is also Intel 9560 aka Jefferson Peak 2.
{Vendor: "0x8086", Device: "0x9df0"}: Intel9000,
{Vendor: "0x8086", Device: "0x31dc"}: Intel9000,
{Vendor: "0x8086", Device: "0x2526"}: Intel9260,
{Vendor: "0x8086", Device: "0x2723"}: Intel22260,
// For integrated wifi chips, use device_id and subsystem_id together
// as an identifier.
// 0x02f0 is for Quasar on CML; 0x4070, 0x0074, 0x6074 are for HrP2.
{Vendor: "0x8086", Device: "0x24fd", Subsystem: "0x0010"}: Intel8265,
{Vendor: "0x8086", Device: "0x02f0", Subsystem: "0x0030"}: Intel9000,
{Vendor: "0x8086", Device: "0x02f0", Subsystem: "0x0034"}: Intel9000,
{Vendor: "0x8086", Device: "0x02f0", Subsystem: "0x4070"}: Intel22560,
{Vendor: "0x8086", Device: "0x02f0", Subsystem: "0x0074"}: Intel22560,
{Vendor: "0x8086", Device: "0x02f0", Subsystem: "0x6074"}: Intel22560,
{Vendor: "0x8086", Device: "0x4df0", Subsystem: "0x0070"}: Intel22560,
{Vendor: "0x8086", Device: "0x4df0", Subsystem: "0x4070"}: Intel22560,
{Vendor: "0x8086", Device: "0x4df0", Subsystem: "0x0074"}: Intel22560,
{Vendor: "0x8086", Device: "0x4df0", Subsystem: "0x6074"}: Intel22560,
{Vendor: "0x8086", Device: "0xa0f0", Subsystem: "0x4070"}: Intel22560,
{Vendor: "0x8086", Device: "0xa0f0", Subsystem: "0x0074"}: Intel22560,
{Vendor: "0x8086", Device: "0xa0f0", Subsystem: "0x6074"}: Intel22560,
{Vendor: "0x8086", Device: "0x02f0", Subsystem: "0x0070"}: IntelAX201,
{Vendor: "0x8086", Device: "0xa0f0", Subsystem: "0x0070"}: IntelAX201,
{Vendor: "0x8086", Device: "0x54f0", Subsystem: "0x0274"}: IntelAX203,
{Vendor: "0x8086", Device: "0x54f0", Subsystem: "0x4274"}: IntelAX203,
{Vendor: "0x8086", Device: "0x51f0", Subsystem: "0x0090"}: IntelAX211,
{Vendor: "0x8086", Device: "0x51f1", Subsystem: "0x0090"}: IntelAX211,
{Vendor: "0x8086", Device: "0x51f1", Subsystem: "0x0094"}: IntelAX211,
{Vendor: "0x8086", Device: "0x51f0", Subsystem: "0x0094"}: IntelAX211,
{Vendor: "0x8086", Device: "0x51f0", Subsystem: "0x4090"}: IntelAX211,
{Vendor: "0x8086", Device: "0x54f0", Subsystem: "0x0090"}: IntelAX211,
{Vendor: "0x8086", Device: "0x54f0", Subsystem: "0x0094"}: IntelAX211,
{Vendor: "0x8086", Device: "0x7e40", Subsystem: "0x0090"}: IntelAX211,
{Vendor: "0x8086", Device: "0x7e40", Subsystem: "0x0094"}: IntelAX211,
{Vendor: "0x14e4", Device: "0x43ec"}: BroadcomBCM4356PCIE,
{Vendor: "0x10ec", Device: "0xc822"}: Realtek8822CPCIE,
{Vendor: "0x10ec", Device: "0x8852"}: Realtek8852APCIE,
{Vendor: "0x10ec", Device: "0xc852"}: Realtek8852CPCIE,
{Vendor: "0x14c3", Device: "0x7961"}: MediaTekMT7921PCIE,
{Vendor: "0x037a", Device: "0x7901"}: MediaTekMT7921SDIO,
{Vendor: "0x14c3", Device: "0x7922"}: MediaTekMT7922PCIE,
{Vendor: "0x14c3", Device: "0x0616"}: MediaTekMT7922PCIE,
{Compatible: "qcom,wcn3990-wifi"}: QualcommWCN3990,
{Compatible: "qcom,wcn6750-wifi"}: QualcommWCN6750,
}
var compatibleRE = regexp.MustCompile("^OF_COMPATIBLE_[0-9]")
var wlanRE = regexp.MustCompile("DEVTYPE=wlan")
func findWlanIface() (string, error) {
const baseDir = "/sys/class/net/"
dirs, err := ioutil.ReadDir(baseDir)
if err != nil {
return "", errors.Wrapf(err,
"failed to read %s directory", baseDir)
}
for _, dir := range dirs {
path := filepath.Join(baseDir, dir.Name(), "uevent")
bs, err := ioutil.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
// It is perfectly OK if the file does not exist.
continue
}
// Other errors should be reported, though.
return "", errors.Wrapf(err, "failed to read %s file", path)
}
if wlanRE.MatchString(string(bs)) {
// ChromeOS supports only one wlan device, thus return first dir matched.
return dir.Name(), nil
}
}
return "", errors.New("Wireless device not found")
}
// DeviceInfo returns a public struct (DevInfo) containing the WLAN device information.
func DeviceInfo() (*DevInfo, error) {
readInfo := func(netIf, x string) (string, error) {
bs, err := ioutil.ReadFile(filepath.Join("/sys/class/net/", netIf, "device", x))
if err != nil {
return "", err
}
return strings.TrimSpace(string(bs)), nil
}
netIf, err := findWlanIface()
if err != nil {
// Nothing important to add to the error description.
return nil, err
}
uevent, err := readInfo(netIf, "uevent")
if err != nil {
return nil, errors.Wrap(err, "failed to get uevent")
}
// Support for (qcom,wcnXXXX-wifi) chips.
for _, line := range strings.Split(uevent, "\n") {
if kv := compatibleRE.FindStringSubmatch(line); kv != nil {
if wifiSnoc := strings.SplitN(line, "=", 2); len(wifiSnoc) == 2 {
if d, ok := lookupWLANDev[DevInfo{Compatible: wifiSnoc[1]}]; ok {
// Found the matching device.
return &DevInfo{ID: d, Name: DeviceNames[d]}, nil
}
}
}
}
vendorID, err := readInfo(netIf, "vendor")
if err != nil {
return nil, errors.Wrapf(err, "failed to get vendor ID at device %q", netIf)
}
productID, err := readInfo(netIf, "device")
if err != nil {
return nil, errors.Wrapf(err, "failed to get product ID at device %q", netIf)
}
subsystemID, err := readInfo(netIf, "subsystem_device")
// DUTs that use SDIO as the bus technology may not have subsystem_device at all.
if err != nil && !os.IsNotExist(err) {
return nil, errors.Wrapf(err, "failed to get subsystem ID at device %q", netIf)
}
if d, ok := lookupWLANDev[DevInfo{Vendor: vendorID, Device: productID, Subsystem: subsystemID}]; ok {
return &DevInfo{Vendor: vendorID, Device: productID, Subsystem: subsystemID, ID: d, Name: DeviceNames[d]}, nil
}
if d, ok := lookupWLANDev[DevInfo{Vendor: vendorID, Device: productID}]; ok {
return &DevInfo{Vendor: vendorID, Device: productID, ID: d, Name: DeviceNames[d]}, nil
}
return nil, errors.Errorf("unknown %s device with vendorID=%s, productID=%s, subsystemID=%s",
netIf, vendorID, productID, subsystemID)
}
// List of WLAN devices that don't support MU-MIMO.
var denyListMUMIMO = []DeviceID{
Marvell88w8897SDIO, // Tested a DUT.
Intel7260, // (WP2) according to datasheet.
Intel7265, // (StP2) tested a DUT.
BroadcomBCM4354SDIO, // Tested a DUT.
BroadcomBCM4356PCIE, // According to datasheet.
}
// SupportMUMIMO return true if the WLAN device support MU-MIMO.
func (dev *DevInfo) SupportMUMIMO() bool {
// Checking if the tested WLAN device does not support MU-MIMO.
for _, id := range denyListMUMIMO {
if id == dev.ID {
return false
}
}
return true
}