gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/virtcontainers/types/bridges.go (about)

     1  // Copyright (c) 2017 Intel Corporation
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  //
     5  
     6  package types
     7  
     8  import "fmt"
     9  
    10  // Type represents a type of bus and bridge.
    11  type Type string
    12  
    13  const PCIBridgeMaxCapacity = 30
    14  
    15  const (
    16  	// PCI represents a PCI bus and bridge
    17  	PCI Type = "pci"
    18  
    19  	// PCIE represents a PCIe bus and bridge
    20  	PCIE Type = "pcie"
    21  )
    22  
    23  const CCWBridgeMaxCapacity = 0xffff
    24  
    25  const (
    26  	CCW Type = "ccw"
    27  )
    28  
    29  type Bridge struct {
    30  	// Devices contains information about devices plugged and its address in the bridge
    31  	Devices map[uint32]string
    32  
    33  	// ID is used to identify the bridge in the hypervisor
    34  	ID string
    35  
    36  	// Addr is the slot of the bridge
    37  	Addr int
    38  
    39  	// Type is the type of the bridge (pci, pcie, etc)
    40  	Type Type
    41  
    42  	// MaxCapacity is the max capacity of the bridge
    43  	MaxCapacity uint32
    44  }
    45  
    46  func NewBridge(bt Type, id string, devices map[uint32]string, addr int) Bridge {
    47  	var maxCapacity uint32
    48  	switch bt {
    49  	case PCI:
    50  		fallthrough
    51  	case PCIE:
    52  		maxCapacity = PCIBridgeMaxCapacity
    53  	case CCW:
    54  		maxCapacity = CCWBridgeMaxCapacity
    55  	default:
    56  		maxCapacity = 0
    57  	}
    58  	return Bridge{
    59  		Devices:     devices,
    60  		ID:          id,
    61  		Addr:        addr,
    62  		Type:        bt,
    63  		MaxCapacity: maxCapacity,
    64  	}
    65  }
    66  
    67  func (b *Bridge) AddDevice(ID string) (uint32, error) {
    68  	var addr uint32
    69  
    70  	// looking for the first available address
    71  	for i := uint32(1); i <= b.MaxCapacity; i++ {
    72  		if _, ok := b.Devices[i]; !ok {
    73  			addr = i
    74  			break
    75  		}
    76  	}
    77  
    78  	if addr == 0 {
    79  		return 0, fmt.Errorf("Unable to hot plug device on bridge: there are no empty slots")
    80  	}
    81  
    82  	// save address and device
    83  	b.Devices[addr] = ID
    84  	return addr, nil
    85  }
    86  
    87  func (b *Bridge) RemoveDevice(ID string) error {
    88  	// check if the device was hot plugged in the bridge
    89  	for addr, devID := range b.Devices {
    90  		if devID == ID {
    91  			// free address to re-use the same slot with other devices
    92  			delete(b.Devices, addr)
    93  			return nil
    94  		}
    95  	}
    96  
    97  	return fmt.Errorf("Unable to hot unplug device %s: not present on bridge", ID)
    98  }
    99  
   100  // AddressFormatCCW returns the address format for the device number. The channel subsystem-ID 0xfe is reserved to the virtual channel and the address format is in the form fe.n.dddd, where n is subchannel set ID and ddd the device number. More details at https://www.ibm.com/support/knowledgecenter/en/linuxonibm/com.ibm.linux.z.ldva/ldva_t_configuringSCSIdevices.html
   101  func (b *Bridge) AddressFormatCCW(addr string) (string, error) {
   102  	if b.Type != CCW {
   103  		return "", fmt.Errorf("Expected bridge type %T, got %T (%+v)", CCW, b.Type, b)
   104  	}
   105  
   106  	return fmt.Sprintf("fe.%x.%s", b.Addr, addr), nil
   107  }
   108  
   109  // AddressFormatCCWForVirtServer returns the address format for the virtual server. The address format is in the form of 0.n.dddd
   110  func (b *Bridge) AddressFormatCCWForVirtServer(addr string) (string, error) {
   111  	if b.Type != CCW {
   112  		return "", fmt.Errorf("Wrong bridge type")
   113  	}
   114  	return fmt.Sprintf("0.%x.%s", b.Addr, addr), nil
   115  }