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  }