From ef2c844d01e78723af54b6ca67019fd9fe7f08e4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 17 Aug 2020 13:08:05 +0100 Subject: [efi] Attempt NII initialisation both with and without cable detection We currently use a heuristic to determine whether or not to request cable detection in PXE_OPCODE_INITIALIZE, based on the need to work around a known Emulex driver bug (see commit c0b61ba "[efi] Work around bugs in Emulex NII driver") and the need to accommodate links that are legitimately slow to come up (see commit 6324227 "[efi] Skip cable detection at initialisation where possible"). This heuristic appears to fail with newer Emulex drivers. Attempt to support all known drivers (past and present) by first attempting initialisation with cable detection, then falling back to attempting initialisation without cable detection. Reported-by: Kwang Woo Lee Tested-by: Kwang Woo Lee Signed-off-by: Michael Brown --- src/drivers/net/efi/nii.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c index 2d87e0c63..e76e211c1 100644 --- a/src/drivers/net/efi/nii.c +++ b/src/drivers/net/efi/nii.c @@ -788,6 +788,20 @@ static int nii_initialise_flags ( struct nii_nic *nii, unsigned int flags ) { return rc; } +/** + * Initialise UNDI with cable detection + * + * @v nii NII NIC + * @ret rc Return status code + */ +static int nii_initialise_cable ( struct nii_nic *nii ) { + unsigned int flags; + + /* Initialise UNDI */ + flags = PXE_OPFLAGS_INITIALIZE_DETECT_CABLE; + return nii_initialise_flags ( nii, flags ); +} + /** * Initialise UNDI * @@ -1122,7 +1136,6 @@ static void nii_poll ( struct net_device *netdev ) { */ static int nii_open ( struct net_device *netdev ) { struct nii_nic *nii = netdev->priv; - unsigned int flags; int rc; /* Initialise NIC @@ -1140,15 +1153,21 @@ static int nii_open ( struct net_device *netdev ) { * presence during initialisation on links that are physically * slow to reach link-up. * - * Attempt to work around both of these problems by requesting - * cable detection at this point if any only if the driver is - * not capable of reporting link status changes at runtime via - * PXE_OPCODE_GET_STATUS. + * Attempt to work around both of these problems by first + * attempting to initialise with cable presence detection, + * then falling back to initialising without cable presence + * detection. */ - flags = ( nii->media ? PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE - : PXE_OPFLAGS_INITIALIZE_DETECT_CABLE ); - if ( ( rc = nii_initialise_flags ( nii, flags ) ) != 0 ) - goto err_initialise; + if ( ( rc = nii_initialise_cable ( nii ) ) != 0 ) { + DBGC ( nii, "NII %s could not initialise with cable " + "detection: %s\n", nii->dev.name, strerror ( rc ) ); + if ( ( rc = nii_initialise ( nii ) ) != 0 ) { + DBGC ( nii, "NII %s could not initialise without " + "cable detection: %s\n", + nii->dev.name, strerror ( rc ) ); + goto err_initialise; + } + } /* Attempt to set station address */ if ( ( rc = nii_set_station_address ( nii, netdev ) ) != 0 ) { -- cgit v1.2.3-55-g7522 From eecb75ba4809bd5d3e6d63413a45c5fccbda2bc2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 24 Sep 2020 21:45:03 +0100 Subject: [pci] Update drivers to use pci_ioremap() Signed-off-by: Michael Brown --- src/arch/x86/drivers/xen/hvm.c | 6 ++++-- src/arch/x86/drivers/xen/hvm.h | 2 ++ src/drivers/bus/pcimsix.c | 2 +- src/drivers/bus/virtio-pci.c | 2 +- src/drivers/infiniband/arbel.c | 15 +++++++++------ src/drivers/infiniband/flexboot_nodnic.c | 2 +- src/drivers/infiniband/golan.c | 6 +++--- src/drivers/infiniband/hermon.c | 18 ++++++++++++------ src/drivers/infiniband/linda.c | 2 +- .../infiniband/mlx_utils_flexboot/src/mlx_pci_priv.c | 2 +- src/drivers/infiniband/qib7322.c | 2 +- src/drivers/net/amd8111e.c | 2 +- src/drivers/net/ath/ath5k/ath5k.c | 2 +- src/drivers/net/ath/ath9k/ath9k.c | 2 +- src/drivers/net/b44.c | 2 +- src/drivers/net/bnx2.c | 2 +- src/drivers/net/bnxt/bnxt.c | 2 +- src/drivers/net/ena.c | 2 +- src/drivers/net/etherfabric.c | 2 +- src/drivers/net/exanic.c | 4 ++-- src/drivers/net/forcedeth.c | 2 +- src/drivers/net/icplus.c | 2 +- src/drivers/net/igbvf/igbvf_main.c | 2 +- src/drivers/net/intel.c | 2 +- src/drivers/net/intelx.c | 2 +- src/drivers/net/intelxl.c | 2 +- src/drivers/net/intelxlvf.c | 2 +- src/drivers/net/intelxvf.c | 2 +- src/drivers/net/jme.c | 2 +- src/drivers/net/myson.c | 2 +- src/drivers/net/natsemi.c | 2 +- src/drivers/net/phantom/phantom.c | 2 +- src/drivers/net/prism2_pci.c | 2 +- src/drivers/net/realtek.c | 2 +- src/drivers/net/rhine.c | 2 +- src/drivers/net/sfc/efx_common.c | 2 +- src/drivers/net/sis190.c | 2 +- src/drivers/net/skeleton.c | 2 +- src/drivers/net/skge.c | 5 +++-- src/drivers/net/sky2.c | 2 +- src/drivers/net/tg3/tg3.c | 2 +- src/drivers/net/thunderx.c | 16 ++++++++-------- src/drivers/net/velocity.c | 2 +- src/drivers/net/vmxnet3.c | 8 ++++---- src/drivers/net/vxge/vxge_main.c | 2 +- src/drivers/usb/ehci.c | 2 +- src/drivers/usb/xhci.c | 2 +- 47 files changed, 85 insertions(+), 71 deletions(-) (limited to 'src/drivers') diff --git a/src/arch/x86/drivers/xen/hvm.c b/src/arch/x86/drivers/xen/hvm.c index 57196f555..311f343ca 100644 --- a/src/arch/x86/drivers/xen/hvm.c +++ b/src/arch/x86/drivers/xen/hvm.c @@ -175,7 +175,7 @@ static void * hvm_ioremap ( struct hvm_device *hvm, unsigned int space, } /* Map this space */ - mmio = ioremap ( ( hvm->mmio + hvm->mmio_offset ), len ); + mmio = pci_ioremap ( hvm->pci, ( hvm->mmio + hvm->mmio_offset ), len ); if ( ! mmio ) { DBGC ( hvm, "HVM could not map MMIO space [%08lx,%08lx)\n", ( hvm->mmio + hvm->mmio_offset ), @@ -371,7 +371,8 @@ static int hvm_map_xenstore ( struct hvm_device *hvm ) { xenstore_phys = ( xenstore_pfn * PAGE_SIZE ); /* Map XenStore */ - hvm->xen.store.intf = ioremap ( xenstore_phys, PAGE_SIZE ); + hvm->xen.store.intf = pci_ioremap ( hvm->pci, xenstore_phys, + PAGE_SIZE ); if ( ! hvm->xen.store.intf ) { DBGC ( hvm, "HVM could not map XenStore at [%08lx,%08lx)\n", xenstore_phys, ( xenstore_phys + PAGE_SIZE ) ); @@ -420,6 +421,7 @@ static int hvm_probe ( struct pci_device *pci ) { rc = -ENOMEM; goto err_alloc; } + hvm->pci = pci; hvm->mmio = pci_bar_start ( pci, HVM_MMIO_BAR ); hvm->mmio_len = pci_bar_size ( pci, HVM_MMIO_BAR ); DBGC2 ( hvm, "HVM has MMIO space [%08lx,%08lx)\n", diff --git a/src/arch/x86/drivers/xen/hvm.h b/src/arch/x86/drivers/xen/hvm.h index 72ed94f6d..88e490815 100644 --- a/src/arch/x86/drivers/xen/hvm.h +++ b/src/arch/x86/drivers/xen/hvm.h @@ -39,6 +39,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); struct hvm_device { /** Xen hypervisor */ struct xen_hypervisor xen; + /** PCI device */ + struct pci_device *pci; /** CPUID base */ uint32_t cpuid_base; /** Length of hypercall table */ diff --git a/src/drivers/bus/pcimsix.c b/src/drivers/bus/pcimsix.c index 80893c418..eb0450d91 100644 --- a/src/drivers/bus/pcimsix.c +++ b/src/drivers/bus/pcimsix.c @@ -84,7 +84,7 @@ static void * pci_msix_ioremap ( struct pci_device *pci, struct pci_msix *msix, msix, pci_msix_name ( cfg ), base, bar, offset ); /* Map BAR portion */ - io = ioremap ( ( start + offset ), PCI_MSIX_LEN ); + io = pci_ioremap ( pci, ( start + offset ), PCI_MSIX_LEN ); if ( ! io ) { DBGC ( msix, "MSI-X %p %s could not map %#08lx\n", msix, pci_msix_name ( cfg ), base ); diff --git a/src/drivers/bus/virtio-pci.c b/src/drivers/bus/virtio-pci.c index 402bf4f12..5d2d62750 100644 --- a/src/drivers/bus/virtio-pci.c +++ b/src/drivers/bus/virtio-pci.c @@ -321,7 +321,7 @@ int virtio_pci_map_capability(struct pci_device *pci, int cap, size_t minlen, region->flags = VIRTIO_PCI_REGION_PORT; } else { /* Region mapped into memory space */ - region->base = ioremap(base + offset, length); + region->base = pci_ioremap(pci, base + offset, length); region->flags = VIRTIO_PCI_REGION_MEMORY; } } diff --git a/src/drivers/infiniband/arbel.c b/src/drivers/infiniband/arbel.c index 98a2b6010..eb7911aa4 100644 --- a/src/drivers/infiniband/arbel.c +++ b/src/drivers/infiniband/arbel.c @@ -2059,7 +2059,8 @@ static int arbel_start_firmware ( struct arbel *arbel ) { eq_set_ci_base_addr = ( ( (uint64_t) MLX_GET ( &fw, eq_set_ci_base_addr_h ) << 32 ) | ( (uint64_t) MLX_GET ( &fw, eq_set_ci_base_addr_l ) ) ); - arbel->eq_ci_doorbells = ioremap ( eq_set_ci_base_addr, 0x200 ); + arbel->eq_ci_doorbells = pci_ioremap ( arbel->pci, eq_set_ci_base_addr, + 0x200 ); /* Enable locally-attached memory. Ignore failure; there may * be no attached memory. @@ -3025,6 +3026,8 @@ static void arbel_free ( struct arbel *arbel ) { static int arbel_probe ( struct pci_device *pci ) { struct arbel *arbel; struct ib_device *ibdev; + unsigned long config; + unsigned long uar; int i; int rc; @@ -3041,11 +3044,11 @@ static int arbel_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map PCI BARs */ - arbel->config = ioremap ( pci_bar_start ( pci, ARBEL_PCI_CONFIG_BAR ), - ARBEL_PCI_CONFIG_BAR_SIZE ); - arbel->uar = ioremap ( ( pci_bar_start ( pci, ARBEL_PCI_UAR_BAR ) + - ARBEL_PCI_UAR_IDX * ARBEL_PCI_UAR_SIZE ), - ARBEL_PCI_UAR_SIZE ); + config = pci_bar_start ( pci, ARBEL_PCI_CONFIG_BAR ); + arbel->config = pci_ioremap ( pci, config, ARBEL_PCI_CONFIG_BAR_SIZE ); + uar = ( pci_bar_start ( pci, ARBEL_PCI_UAR_BAR ) + + ARBEL_PCI_UAR_IDX * ARBEL_PCI_UAR_SIZE ); + arbel->uar = pci_ioremap ( pci, uar, ARBEL_PCI_UAR_SIZE ); /* Allocate Infiniband devices */ for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ ) { diff --git a/src/drivers/infiniband/flexboot_nodnic.c b/src/drivers/infiniband/flexboot_nodnic.c index 7d039fffc..54b858406 100644 --- a/src/drivers/infiniband/flexboot_nodnic.c +++ b/src/drivers/infiniband/flexboot_nodnic.c @@ -1461,7 +1461,7 @@ static int flexboot_nodnic_alloc_uar ( struct flexboot_nodnic *flexboot_nodnic ) return -EINVAL; } uar->phys = ( pci_bar_start ( pci, FLEXBOOT_NODNIC_HCA_BAR ) + (mlx_uint32)uar->offset ); - uar->virt = ( void * )( ioremap ( uar->phys, FLEXBOOT_NODNIC_PAGE_SIZE ) ); + uar->virt = ( void * )( pci_ioremap ( pci, uar->phys, FLEXBOOT_NODNIC_PAGE_SIZE ) ); return status; } diff --git a/src/drivers/infiniband/golan.c b/src/drivers/infiniband/golan.c index e96ba2698..7ab4a4ee6 100755 --- a/src/drivers/infiniband/golan.c +++ b/src/drivers/infiniband/golan.c @@ -693,7 +693,7 @@ static inline int golan_alloc_uar(struct golan *golan) uar->index = be32_to_cpu(out->uarn) & 0xffffff; uar->phys = (pci_bar_start(golan->pci, GOLAN_HCA_BAR) + (uar->index << GOLAN_PAGE_SHIFT)); - uar->virt = (void *)(ioremap(uar->phys, GOLAN_PAGE_SIZE)); + uar->virt = (void *)(pci_ioremap(golan->pci, uar->phys, GOLAN_PAGE_SIZE)); DBGC( golan , "%s: UAR allocated with index 0x%x\n", __FUNCTION__, uar->index); return 0; @@ -922,8 +922,8 @@ static inline void golan_pci_init(struct golan *golan) adjust_pci_device ( pci ); /* Get HCA BAR */ - golan->iseg = ioremap ( pci_bar_start ( pci, GOLAN_HCA_BAR), - GOLAN_PCI_CONFIG_BAR_SIZE ); + golan->iseg = pci_ioremap ( pci, pci_bar_start ( pci, GOLAN_HCA_BAR), + GOLAN_PCI_CONFIG_BAR_SIZE ); } static inline struct golan *golan_alloc() diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index 9675c156b..b6599588f 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -3782,6 +3782,8 @@ static int hermon_probe ( struct pci_device *pci ) { struct ib_device *ibdev; struct net_device *netdev; struct hermon_port *port; + unsigned long config; + unsigned long uar; unsigned int i; int rc; @@ -3798,10 +3800,12 @@ static int hermon_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map PCI BARs */ - hermon->config = ioremap ( pci_bar_start ( pci, HERMON_PCI_CONFIG_BAR ), - HERMON_PCI_CONFIG_BAR_SIZE ); - hermon->uar = ioremap ( pci_bar_start ( pci, HERMON_PCI_UAR_BAR ), - HERMON_UAR_NON_EQ_PAGE * HERMON_PAGE_SIZE ); + config = pci_bar_start ( pci, HERMON_PCI_CONFIG_BAR ); + hermon->config = pci_ioremap ( pci, config, + HERMON_PCI_CONFIG_BAR_SIZE ); + uar = pci_bar_start ( pci, HERMON_PCI_UAR_BAR ); + hermon->uar = pci_ioremap ( pci, uar, + HERMON_UAR_NON_EQ_PAGE * HERMON_PAGE_SIZE ); /* Reset device */ hermon_reset ( hermon ); @@ -3937,6 +3941,7 @@ static void hermon_remove ( struct pci_device *pci ) { */ static int hermon_bofm_probe ( struct pci_device *pci ) { struct hermon *hermon; + unsigned long config; int rc; /* Allocate Hermon device */ @@ -3952,8 +3957,9 @@ static int hermon_bofm_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map PCI BAR */ - hermon->config = ioremap ( pci_bar_start ( pci, HERMON_PCI_CONFIG_BAR ), - HERMON_PCI_CONFIG_BAR_SIZE ); + config = pci_bar_start ( pci, HERMON_PCI_CONFIG_BAR ); + hermon->config = pci_ioremap ( pci, config, + HERMON_PCI_CONFIG_BAR_SIZE ); /* Initialise BOFM device */ bofm_init ( &hermon->bofm, pci, &hermon_bofm_operations ); diff --git a/src/drivers/infiniband/linda.c b/src/drivers/infiniband/linda.c index e8d61c865..8c2c090bc 100644 --- a/src/drivers/infiniband/linda.c +++ b/src/drivers/infiniband/linda.c @@ -2335,7 +2335,7 @@ static int linda_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map PCI BARs */ - linda->regs = ioremap ( pci->membase, LINDA_BAR0_SIZE ); + linda->regs = pci_ioremap ( pci, pci->membase, LINDA_BAR0_SIZE ); DBGC2 ( linda, "Linda %p has BAR at %08lx\n", linda, pci->membase ); /* Print some general data */ diff --git a/src/drivers/infiniband/mlx_utils_flexboot/src/mlx_pci_priv.c b/src/drivers/infiniband/mlx_utils_flexboot/src/mlx_pci_priv.c index b474a4a63..6b42bcafc 100644 --- a/src/drivers/infiniband/mlx_utils_flexboot/src/mlx_pci_priv.c +++ b/src/drivers/infiniband/mlx_utils_flexboot/src/mlx_pci_priv.c @@ -115,7 +115,7 @@ mlx_pci_init_priv( mlx_status status = MLX_SUCCESS; adjust_pci_device ( utils->pci ); #ifdef DEVICE_CX3 - utils->config = ioremap ( pci_bar_start ( utils->pci, PCI_BASE_ADDRESS_0), + utils->config = pci_ioremap ( utils->pci, pci_bar_start ( utils->pci, PCI_BASE_ADDRESS_0), 0x100000 ); #endif return status; diff --git a/src/drivers/infiniband/qib7322.c b/src/drivers/infiniband/qib7322.c index 18011c19a..a5606dd03 100644 --- a/src/drivers/infiniband/qib7322.c +++ b/src/drivers/infiniband/qib7322.c @@ -2297,7 +2297,7 @@ static int qib7322_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map PCI BARs */ - qib7322->regs = ioremap ( pci->membase, QIB7322_BAR0_SIZE ); + qib7322->regs = pci_ioremap ( pci, pci->membase, QIB7322_BAR0_SIZE ); DBGC2 ( qib7322, "QIB7322 %p has BAR at %08lx\n", qib7322, pci->membase ); diff --git a/src/drivers/net/amd8111e.c b/src/drivers/net/amd8111e.c index 693d77d1d..babd12d3c 100644 --- a/src/drivers/net/amd8111e.c +++ b/src/drivers/net/amd8111e.c @@ -664,7 +664,7 @@ static int amd8111e_probe(struct nic *nic, struct pci_device *pdev) memset(lp, 0, sizeof(*lp)); lp->pdev = pdev; lp->nic = nic; - lp->mmio = ioremap(mmio_start, mmio_len); + lp->mmio = pci_ioremap(pdev, mmio_start, mmio_len); lp->opened = 1; adjust_pci_device(pdev); diff --git a/src/drivers/net/ath/ath5k/ath5k.c b/src/drivers/net/ath/ath5k/ath5k.c index a500175a7..d8c47909d 100644 --- a/src/drivers/net/ath/ath5k/ath5k.c +++ b/src/drivers/net/ath/ath5k/ath5k.c @@ -280,7 +280,7 @@ static int ath5k_probe(struct pci_device *pdev) */ pci_write_config_byte(pdev, 0x41, 0); - mem = ioremap(pdev->membase, 0x10000); + mem = pci_ioremap(pdev, pdev->membase, 0x10000); if (!mem) { DBG("ath5k: cannot remap PCI memory region\n"); ret = -EIO; diff --git a/src/drivers/net/ath/ath9k/ath9k.c b/src/drivers/net/ath/ath9k/ath9k.c index 183aa65f6..98b7ecd5a 100644 --- a/src/drivers/net/ath/ath9k/ath9k.c +++ b/src/drivers/net/ath/ath9k/ath9k.c @@ -138,7 +138,7 @@ static int ath_pci_probe(struct pci_device *pdev) if ((val & 0x0000ff00) != 0) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); - mem = ioremap(pdev->membase, 0x10000); + mem = pci_ioremap(pdev, pdev->membase, 0x10000); if (!mem) { DBG("ath9K: PCI memory map error\n") ; ret = -EIO; diff --git a/src/drivers/net/b44.c b/src/drivers/net/b44.c index d9aeb1b4b..e0e6f4642 100644 --- a/src/drivers/net/b44.c +++ b/src/drivers/net/b44.c @@ -673,7 +673,7 @@ static int b44_probe(struct pci_device *pci) bp->pci = pci; /* Map device registers */ - bp->regs = ioremap(pci->membase, B44_REGS_SIZE); + bp->regs = pci_ioremap(pci, pci->membase, B44_REGS_SIZE); if (!bp->regs) { netdev_put(netdev); return -ENOMEM; diff --git a/src/drivers/net/bnx2.c b/src/drivers/net/bnx2.c index 4ebcc52a9..d5783ff99 100644 --- a/src/drivers/net/bnx2.c +++ b/src/drivers/net/bnx2.c @@ -2152,7 +2152,7 @@ bnx2_init_board(struct pci_device *pdev, struct nic *nic) bnx2reg_base = pci_bar_start(pdev, PCI_BASE_ADDRESS_0); bnx2reg_len = MB_GET_CID_ADDR(17); - bp->regview = ioremap(bnx2reg_base, bnx2reg_len); + bp->regview = pci_ioremap(pdev, bnx2reg_base, bnx2reg_len); if (!bp->regview) { printf("Cannot map register space, aborting.\n"); diff --git a/src/drivers/net/bnxt/bnxt.c b/src/drivers/net/bnxt/bnxt.c index e6bceb970..fe84ea0e4 100644 --- a/src/drivers/net/bnxt/bnxt.c +++ b/src/drivers/net/bnxt/bnxt.c @@ -60,7 +60,7 @@ static void *bnxt_pci_base ( struct pci_device *pdev, unsigned int reg ) reg_base = pci_bar_start ( pdev, reg ); reg_size = pci_bar_size ( pdev, reg ); - return ioremap ( reg_base, reg_size ); + return pci_ioremap ( pdev, reg_base, reg_size ); } static int bnxt_get_pci_info ( struct bnxt *bp ) diff --git a/src/drivers/net/ena.c b/src/drivers/net/ena.c index 0f25c0beb..5c76eb6fd 100644 --- a/src/drivers/net/ena.c +++ b/src/drivers/net/ena.c @@ -933,7 +933,7 @@ static int ena_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map registers */ - ena->regs = ioremap ( pci->membase, ENA_BAR_SIZE ); + ena->regs = pci_ioremap ( pci, pci->membase, ENA_BAR_SIZE ); if ( ! ena->regs ) { rc = -ENODEV; goto err_ioremap; diff --git a/src/drivers/net/etherfabric.c b/src/drivers/net/etherfabric.c index 2cd41d4ca..cd567f1d9 100644 --- a/src/drivers/net/etherfabric.c +++ b/src/drivers/net/etherfabric.c @@ -4150,7 +4150,7 @@ efab_probe ( struct pci_device *pci ) /* Get iobase/membase */ mmio_start = pci_bar_start ( pci, PCI_BASE_ADDRESS_2 ); mmio_len = pci_bar_size ( pci, PCI_BASE_ADDRESS_2 ); - efab->membase = ioremap ( mmio_start, mmio_len ); + efab->membase = pci_ioremap ( pci, mmio_start, mmio_len ); EFAB_TRACE ( "BAR of %lx bytes at phys %lx mapped at %p\n", mmio_len, mmio_start, efab->membase ); diff --git a/src/drivers/net/exanic.c b/src/drivers/net/exanic.c index 287e14e8d..8849da285 100644 --- a/src/drivers/net/exanic.c +++ b/src/drivers/net/exanic.c @@ -800,7 +800,7 @@ static int exanic_probe ( struct pci_device *pci ) { /* Map registers */ regs_bar_start = pci_bar_start ( pci, EXANIC_REGS_BAR ); - exanic->regs = ioremap ( regs_bar_start, EXANIC_REGS_LEN ); + exanic->regs = pci_ioremap ( pci, regs_bar_start, EXANIC_REGS_LEN ); if ( ! exanic->regs ) { rc = -ENODEV; goto err_ioremap_regs; @@ -824,7 +824,7 @@ static int exanic_probe ( struct pci_device *pci ) { /* Map transmit region */ tx_bar_start = pci_bar_start ( pci, EXANIC_TX_BAR ); tx_bar_len = pci_bar_size ( pci, EXANIC_TX_BAR ); - exanic->tx = ioremap ( tx_bar_start, tx_bar_len ); + exanic->tx = pci_ioremap ( pci, tx_bar_start, tx_bar_len ); if ( ! exanic->tx ) { rc = -ENODEV; goto err_ioremap_tx; diff --git a/src/drivers/net/forcedeth.c b/src/drivers/net/forcedeth.c index 7f044b192..94cc6063b 100644 --- a/src/drivers/net/forcedeth.c +++ b/src/drivers/net/forcedeth.c @@ -1762,7 +1762,7 @@ forcedeth_map_regs ( struct forcedeth_private *priv ) } rc = -ENOMEM; - ioaddr = ioremap ( addr, register_size ); + ioaddr = pci_ioremap ( priv->pci_dev, addr, register_size ); if ( ! ioaddr ) { DBG ( "Cannot remap MMIO\n" ); goto err_ioremap; diff --git a/src/drivers/net/icplus.c b/src/drivers/net/icplus.c index 4bed92427..58092fade 100644 --- a/src/drivers/net/icplus.c +++ b/src/drivers/net/icplus.c @@ -726,7 +726,7 @@ static int icplus_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map registers */ - icp->regs = ioremap ( pci->membase, ICP_BAR_SIZE ); + icp->regs = pci_ioremap ( pci, pci->membase, ICP_BAR_SIZE ); if ( ! icp->regs ) { rc = -ENODEV; goto err_ioremap; diff --git a/src/drivers/net/igbvf/igbvf_main.c b/src/drivers/net/igbvf/igbvf_main.c index fc7021c38..39d4e7f8a 100644 --- a/src/drivers/net/igbvf/igbvf_main.c +++ b/src/drivers/net/igbvf/igbvf_main.c @@ -843,7 +843,7 @@ int igbvf_probe ( struct pci_device *pdev ) DBG ( "mmio_start: %#08lx\n", mmio_start ); DBG ( "mmio_len: %#08lx\n", mmio_len ); - adapter->hw.hw_addr = ioremap ( mmio_start, mmio_len ); + adapter->hw.hw_addr = pci_ioremap ( pdev, mmio_start, mmio_len ); DBG ( "adapter->hw.hw_addr: %p\n", adapter->hw.hw_addr ); if ( ! adapter->hw.hw_addr ) { diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c index d9b8b46b7..97f50a943 100644 --- a/src/drivers/net/intel.c +++ b/src/drivers/net/intel.c @@ -959,7 +959,7 @@ static int intel_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map registers */ - intel->regs = ioremap ( pci->membase, INTEL_BAR_SIZE ); + intel->regs = pci_ioremap ( pci, pci->membase, INTEL_BAR_SIZE ); if ( ! intel->regs ) { rc = -ENODEV; goto err_ioremap; diff --git a/src/drivers/net/intelx.c b/src/drivers/net/intelx.c index 91fb7955f..38e8467a9 100644 --- a/src/drivers/net/intelx.c +++ b/src/drivers/net/intelx.c @@ -405,7 +405,7 @@ static int intelx_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map registers */ - intel->regs = ioremap ( pci->membase, INTEL_BAR_SIZE ); + intel->regs = pci_ioremap ( pci, pci->membase, INTEL_BAR_SIZE ); if ( ! intel->regs ) { rc = -ENODEV; goto err_ioremap; diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c index c98ba265c..08c90bc48 100644 --- a/src/drivers/net/intelxl.c +++ b/src/drivers/net/intelxl.c @@ -1673,7 +1673,7 @@ static int intelxl_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map registers */ - intelxl->regs = ioremap ( pci->membase, INTELXL_BAR_SIZE ); + intelxl->regs = pci_ioremap ( pci, pci->membase, INTELXL_BAR_SIZE ); if ( ! intelxl->regs ) { rc = -ENODEV; goto err_ioremap; diff --git a/src/drivers/net/intelxlvf.c b/src/drivers/net/intelxlvf.c index 8f76daf3d..83e484c8d 100644 --- a/src/drivers/net/intelxlvf.c +++ b/src/drivers/net/intelxlvf.c @@ -612,7 +612,7 @@ static int intelxlvf_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map registers */ - intelxl->regs = ioremap ( pci->membase, INTELXLVF_BAR_SIZE ); + intelxl->regs = pci_ioremap ( pci, pci->membase, INTELXLVF_BAR_SIZE ); if ( ! intelxl->regs ) { rc = -ENODEV; goto err_ioremap; diff --git a/src/drivers/net/intelxvf.c b/src/drivers/net/intelxvf.c index 2caeec27e..fef3024e9 100644 --- a/src/drivers/net/intelxvf.c +++ b/src/drivers/net/intelxvf.c @@ -456,7 +456,7 @@ static int intelxvf_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map registers */ - intel->regs = ioremap ( pci->membase, INTELVF_BAR_SIZE ); + intel->regs = pci_ioremap ( pci, pci->membase, INTELVF_BAR_SIZE ); if ( ! intel->regs ) { rc = -ENODEV; goto err_ioremap; diff --git a/src/drivers/net/jme.c b/src/drivers/net/jme.c index 29694b699..b68b96c88 100644 --- a/src/drivers/net/jme.c +++ b/src/drivers/net/jme.c @@ -1191,7 +1191,7 @@ jme_probe(struct pci_device *pci) jme = netdev->priv; pci_set_drvdata(pci, netdev); netdev->dev = &pci->dev; - jme->regs = ioremap(pci->membase, JME_REGS_SIZE); + jme->regs = pci_ioremap(pci, pci->membase, JME_REGS_SIZE); if (!(jme->regs)) { DBG("Mapping PCI resource region error.\n"); rc = -ENOMEM; diff --git a/src/drivers/net/myson.c b/src/drivers/net/myson.c index 84a550596..4dd0aab4a 100644 --- a/src/drivers/net/myson.c +++ b/src/drivers/net/myson.c @@ -606,7 +606,7 @@ static int myson_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map registers */ - myson->regs = ioremap ( pci->membase, MYSON_BAR_SIZE ); + myson->regs = pci_ioremap ( pci, pci->membase, MYSON_BAR_SIZE ); if ( ! myson->regs ) { rc = -ENODEV; goto err_ioremap; diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 9f2c3029c..33cf68b3c 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -853,7 +853,7 @@ static int natsemi_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map registers */ - natsemi->regs = ioremap ( pci->membase, NATSEMI_BAR_SIZE ); + natsemi->regs = pci_ioremap ( pci, pci->membase, NATSEMI_BAR_SIZE ); if ( ! natsemi->regs ) { rc = -ENODEV; goto err_ioremap; diff --git a/src/drivers/net/phantom/phantom.c b/src/drivers/net/phantom/phantom.c index 781049ff4..8f247ff8e 100644 --- a/src/drivers/net/phantom/phantom.c +++ b/src/drivers/net/phantom/phantom.c @@ -1837,7 +1837,7 @@ static int phantom_map_crb ( struct phantom_nic *phantom, return -EINVAL; } - phantom->bar0 = ioremap ( bar0_start, bar0_size ); + phantom->bar0 = pci_ioremap ( pci, bar0_start, bar0_size ); if ( ! phantom->bar0 ) { DBGC ( phantom, "Phantom %p could not map BAR0\n", phantom ); return -EIO; diff --git a/src/drivers/net/prism2_pci.c b/src/drivers/net/prism2_pci.c index 69ddf0fb0..2feb69522 100644 --- a/src/drivers/net/prism2_pci.c +++ b/src/drivers/net/prism2_pci.c @@ -36,7 +36,7 @@ static int prism2_pci_probe ( struct nic *nic, struct pci_device *pci ) { hfa384x_t *hw = &hw_global; printf ( "Prism2.5 has registers at %#lx\n", pci->membase ); - hw->membase = ioremap ( pci->membase, 0x100 ); + hw->membase = pci_ioremap ( pci, pci->membase, 0x100 ); nic->ioaddr = pci->membase; nic->irqno = 0; diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index 310b9f96a..0421b4db7 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -1128,7 +1128,7 @@ static int realtek_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map registers */ - rtl->regs = ioremap ( pci->membase, RTL_BAR_SIZE ); + rtl->regs = pci_ioremap ( pci, pci->membase, RTL_BAR_SIZE ); if ( ! rtl->regs ) { rc = -ENODEV; goto err_ioremap; diff --git a/src/drivers/net/rhine.c b/src/drivers/net/rhine.c index a1dc58725..cbe21c316 100644 --- a/src/drivers/net/rhine.c +++ b/src/drivers/net/rhine.c @@ -700,7 +700,7 @@ static int rhine_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map registers */ - rhn->regs = ioremap ( pci->membase, RHINE_BAR_SIZE ); + rhn->regs = pci_ioremap ( pci, pci->membase, RHINE_BAR_SIZE ); rhn->ioaddr = pci->ioaddr; DBGC ( rhn, "RHINE %p regs at %08lx, I/O at %04lx\n", rhn, pci->membase, pci->ioaddr ); diff --git a/src/drivers/net/sfc/efx_common.c b/src/drivers/net/sfc/efx_common.c index 403887707..fd465612e 100644 --- a/src/drivers/net/sfc/efx_common.c +++ b/src/drivers/net/sfc/efx_common.c @@ -85,7 +85,7 @@ void efx_probe(struct net_device *netdev, enum efx_revision revision) efx->mmio_start = pci_bar_start(pci, reg); efx->mmio_len = pci_bar_size(pci, reg); - efx->membase = ioremap(efx->mmio_start, efx->mmio_len); + efx->membase = pci_ioremap(pci, efx->mmio_start, efx->mmio_len); DBGCP(efx, "BAR of %lx bytes at phys %lx mapped at %p\n", efx->mmio_len, efx->mmio_start, efx->membase); diff --git a/src/drivers/net/sis190.c b/src/drivers/net/sis190.c index b92e95f2a..11dda1c97 100644 --- a/src/drivers/net/sis190.c +++ b/src/drivers/net/sis190.c @@ -886,7 +886,7 @@ static int sis190_init_board(struct pci_device *pdev, struct net_device **netdev adjust_pci_device(pdev); - ioaddr = ioremap(pdev->membase, SIS190_REGS_SIZE); + ioaddr = pci_ioremap(pdev, pdev->membase, SIS190_REGS_SIZE); if (!ioaddr) { DBG("sis190: cannot remap MMIO, aborting\n"); rc = -EIO; diff --git a/src/drivers/net/skeleton.c b/src/drivers/net/skeleton.c index 0bae3089c..a76c6e3d9 100644 --- a/src/drivers/net/skeleton.c +++ b/src/drivers/net/skeleton.c @@ -195,7 +195,7 @@ static int skeleton_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map registers */ - skel->regs = ioremap ( pci->membase, SKELETON_BAR_SIZE ); + skel->regs = pci_ioremap ( pci, pci->membase, SKELETON_BAR_SIZE ); if ( ! skel->regs ) { rc = -ENODEV; goto err_ioremap; diff --git a/src/drivers/net/skge.c b/src/drivers/net/skge.c index c3264225b..c9a7891ba 100755 --- a/src/drivers/net/skge.c +++ b/src/drivers/net/skge.c @@ -2346,8 +2346,9 @@ static int skge_probe(struct pci_device *pdev) hw->pdev = pdev; - hw->regs = (unsigned long)ioremap(pci_bar_start(pdev, PCI_BASE_ADDRESS_0), - SKGE_REG_SIZE); + hw->regs = (unsigned long)pci_ioremap(pdev, + pci_bar_start(pdev, PCI_BASE_ADDRESS_0), + SKGE_REG_SIZE); if (!hw->regs) { DBG(PFX "cannot map device registers\n"); goto err_out_free_hw; diff --git a/src/drivers/net/sky2.c b/src/drivers/net/sky2.c index 211f22466..0d11e17df 100644 --- a/src/drivers/net/sky2.c +++ b/src/drivers/net/sky2.c @@ -2278,7 +2278,7 @@ static int sky2_probe(struct pci_device *pdev) hw->pdev = pdev; - hw->regs = (unsigned long)ioremap(pci_bar_start(pdev, PCI_BASE_ADDRESS_0), 0x4000); + hw->regs = (unsigned long)pci_ioremap(pdev, pci_bar_start(pdev, PCI_BASE_ADDRESS_0), 0x4000); if (!hw->regs) { DBG(PFX "cannot map device registers\n"); goto err_out_free_hw; diff --git a/src/drivers/net/tg3/tg3.c b/src/drivers/net/tg3/tg3.c index 1bed06649..f6c038112 100644 --- a/src/drivers/net/tg3/tg3.c +++ b/src/drivers/net/tg3/tg3.c @@ -771,7 +771,7 @@ static int tg3_init_one(struct pci_device *pdev) reg_base = pci_bar_start(pdev, PCI_BASE_ADDRESS_0); reg_size = pci_bar_size(pdev, PCI_BASE_ADDRESS_0); - tp->regs = ioremap(reg_base, reg_size); + tp->regs = pci_ioremap(pdev, reg_base, reg_size); if (!tp->regs) { DBGC(&pdev->dev, "Failed to remap device registers\n"); errno = -ENOENT; diff --git a/src/drivers/net/thunderx.c b/src/drivers/net/thunderx.c index 9ddb98ab8..1865a9b91 100644 --- a/src/drivers/net/thunderx.c +++ b/src/drivers/net/thunderx.c @@ -645,11 +645,11 @@ static void txnic_poll ( struct txnic *vnic ) { /** * Allocate virtual NIC * - * @v dev Underlying device + * @v pci Underlying PCI device * @v membase Register base address * @ret vnic Virtual NIC, or NULL on failure */ -static struct txnic * txnic_alloc ( struct device *dev, +static struct txnic * txnic_alloc ( struct pci_device *pci, unsigned long membase ) { struct net_device *netdev; struct txnic *vnic; @@ -658,10 +658,10 @@ static struct txnic * txnic_alloc ( struct device *dev, netdev = alloc_etherdev ( sizeof ( *vnic ) ); if ( ! netdev ) goto err_alloc_netdev; - netdev->dev = dev; + netdev->dev = &pci->dev; vnic = netdev->priv; vnic->netdev = netdev; - vnic->name = dev->name; + vnic->name = pci->dev.name; /* Allow caller to reuse netdev->priv. (The generic virtual * NIC code never assumes that netdev->priv==vnic.) @@ -684,7 +684,7 @@ static struct txnic * txnic_alloc ( struct device *dev, goto err_alloc_rq; /* Map registers */ - vnic->regs = ioremap ( membase, TXNIC_VF_BAR_SIZE ); + vnic->regs = pci_ioremap ( pci, membase, TXNIC_VF_BAR_SIZE ); if ( ! vnic->regs ) goto err_ioremap; @@ -1103,7 +1103,7 @@ static int txnic_lmac_probe ( struct txnic_lmac *lmac ) { membase = ( pf->vf_membase + ( lmac->idx * pf->vf_stride ) ); /* Allocate and initialise network device */ - vnic = txnic_alloc ( &bgx->pci->dev, membase ); + vnic = txnic_alloc ( bgx->pci, membase ); if ( ! vnic ) { rc = -ENOMEM; goto err_alloc; @@ -1275,7 +1275,7 @@ static int txnic_pf_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map registers */ - pf->regs = ioremap ( membase, TXNIC_PF_BAR_SIZE ); + pf->regs = pci_ioremap ( pci, membase, TXNIC_PF_BAR_SIZE ); if ( ! pf->regs ) { rc = -ENODEV; goto err_ioremap; @@ -1633,7 +1633,7 @@ static int txnic_bgx_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map registers */ - bgx->regs = ioremap ( membase, TXNIC_BGX_BAR_SIZE ); + bgx->regs = pci_ioremap ( pci, membase, TXNIC_BGX_BAR_SIZE ); if ( ! bgx->regs ) { rc = -ENODEV; goto err_ioremap; diff --git a/src/drivers/net/velocity.c b/src/drivers/net/velocity.c index 0a2a3ac10..994e07a64 100644 --- a/src/drivers/net/velocity.c +++ b/src/drivers/net/velocity.c @@ -731,7 +731,7 @@ static int velocity_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map registers */ - vlc->regs = ioremap ( pci->membase, VELOCITY_BAR_SIZE ); + vlc->regs = pci_ioremap ( pci, pci->membase, VELOCITY_BAR_SIZE ); vlc->netdev = netdev; /* Reset the NIC */ diff --git a/src/drivers/net/vmxnet3.c b/src/drivers/net/vmxnet3.c index 6a54dbf89..3e0ab03cd 100644 --- a/src/drivers/net/vmxnet3.c +++ b/src/drivers/net/vmxnet3.c @@ -641,14 +641,14 @@ static int vmxnet3_probe ( struct pci_device *pci ) { adjust_pci_device ( pci ); /* Map PCI BARs */ - vmxnet->pt = ioremap ( pci_bar_start ( pci, VMXNET3_PT_BAR ), - VMXNET3_PT_LEN ); + vmxnet->pt = pci_ioremap ( pci, pci_bar_start ( pci, VMXNET3_PT_BAR ), + VMXNET3_PT_LEN ); if ( ! vmxnet->pt ) { rc = -ENODEV; goto err_ioremap_pt; } - vmxnet->vd = ioremap ( pci_bar_start ( pci, VMXNET3_VD_BAR ), - VMXNET3_VD_LEN ); + vmxnet->vd = pci_ioremap ( pci, pci_bar_start ( pci, VMXNET3_VD_BAR ), + VMXNET3_VD_LEN ); if ( ! vmxnet->vd ) { rc = -ENODEV; goto err_ioremap_vd; diff --git a/src/drivers/net/vxge/vxge_main.c b/src/drivers/net/vxge/vxge_main.c index 8b099c0e2..631928318 100644 --- a/src/drivers/net/vxge/vxge_main.c +++ b/src/drivers/net/vxge/vxge_main.c @@ -520,7 +520,7 @@ vxge_probe(struct pci_device *pdev) /* sets the bus master */ adjust_pci_device(pdev); - bar0 = ioremap(mmio_start, mmio_len); + bar0 = pci_ioremap(pdev, mmio_start, mmio_len); if (!bar0) { vxge_debug(VXGE_ERR, "%s : cannot remap io memory bar0\n", __func__); diff --git a/src/drivers/usb/ehci.c b/src/drivers/usb/ehci.c index 29c32b356..15193efe1 100644 --- a/src/drivers/usb/ehci.c +++ b/src/drivers/usb/ehci.c @@ -1989,7 +1989,7 @@ static int ehci_probe ( struct pci_device *pci ) { /* Map registers */ bar_start = pci_bar_start ( pci, EHCI_BAR ); bar_size = pci_bar_size ( pci, EHCI_BAR ); - ehci->regs = ioremap ( bar_start, bar_size ); + ehci->regs = pci_ioremap ( pci, bar_start, bar_size ); if ( ! ehci->regs ) { rc = -ENODEV; goto err_ioremap; diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index aa6ca73c4..c4a1dc337 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -3261,7 +3261,7 @@ static int xhci_probe ( struct pci_device *pci ) { /* Map registers */ bar_start = pci_bar_start ( pci, XHCI_BAR ); bar_size = pci_bar_size ( pci, XHCI_BAR ); - xhci->regs = ioremap ( bar_start, bar_size ); + xhci->regs = pci_ioremap ( pci, bar_start, bar_size ); if ( ! xhci->regs ) { rc = -ENODEV; goto err_ioremap; -- cgit v1.2.3-55-g7522 From f42ba772c8050da266b69504efff8e16f2fda8c2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 29 Sep 2020 10:16:14 +0100 Subject: [usb] Reset control endpoints immediately after failure The current error handling mechanism defers the endpoint reset until the next use of the endpoint, on the basis that errors are detected during completions and completion handling should not recursively call usb_poll(). In the case of usb_control(), we are already at the level that calls usb_poll() and can therefore safely perform the endpoint reset immediately. This has no impact on functionality, but does make debugging traces easier to read since the reset will appear immediately after the causative error. Signed-off-by: Michael Brown --- src/drivers/bus/usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/drivers') diff --git a/src/drivers/bus/usb.c b/src/drivers/bus/usb.c index a7b687528..74f11ecb8 100644 --- a/src/drivers/bus/usb.c +++ b/src/drivers/bus/usb.c @@ -818,6 +818,7 @@ int usb_control ( struct usb_device *usb, unsigned int request, "failed: %s\n", usb->name, request, value, index, strerror ( rc ) ); free_iob ( cmplt ); + usb_endpoint_reset ( ep ); return rc; } -- cgit v1.2.3-55-g7522 From 8eb19a178a5d6ca89ca2b8200dae0f7cec15ae2c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 29 Sep 2020 14:39:54 +0100 Subject: [usb] Show debug message on device removal Signed-off-by: Michael Brown --- src/drivers/bus/usb.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/drivers') diff --git a/src/drivers/bus/usb.c b/src/drivers/bus/usb.c index 74f11ecb8..fca47fd36 100644 --- a/src/drivers/bus/usb.c +++ b/src/drivers/bus/usb.c @@ -1637,6 +1637,11 @@ static void unregister_usb ( struct usb_device *usb ) { struct io_buffer *iobuf; struct io_buffer *tmp; + DBGC ( usb, "USB %s addr %d %04x:%04x class %d:%d:%d removed\n", + usb->name, usb->address, le16_to_cpu ( usb->device.vendor ), + le16_to_cpu ( usb->device.product ), usb->device.class.class, + usb->device.class.subclass, usb->device.class.protocol ); + /* Sanity checks */ assert ( port->usb == usb ); -- cgit v1.2.3-55-g7522 From 7c6fdf57eadb382fc86719daf79c7afa78ace530 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 1 Oct 2020 18:26:37 +0100 Subject: [usb] Avoid integer underflow on malformed string descriptors Signed-off-by: Michael Brown --- src/drivers/bus/usb.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/drivers') diff --git a/src/drivers/bus/usb.c b/src/drivers/bus/usb.c index fca47fd36..14eabb6b4 100644 --- a/src/drivers/bus/usb.c +++ b/src/drivers/bus/usb.c @@ -913,9 +913,15 @@ int usb_get_string_descriptor ( struct usb_device *usb, unsigned int index, sizeof ( *desc ) ) ) != 0 ) goto err_get_descriptor; - /* Copy to buffer */ + /* Calculate string length */ + if ( desc->header.len < sizeof ( desc->header ) ) { + rc = -EINVAL; + goto err_len; + } actual = ( ( desc->header.len - sizeof ( desc->header ) ) / sizeof ( desc->character[0] ) ); + + /* Copy to buffer */ for ( i = 0 ; ( ( i < actual ) && ( i < max ) ) ; i++ ) buf[i] = le16_to_cpu ( desc->character[i] ); if ( len ) @@ -926,6 +932,7 @@ int usb_get_string_descriptor ( struct usb_device *usb, unsigned int index, return actual; + err_len: err_get_descriptor: free ( desc ); err_alloc: -- cgit v1.2.3-55-g7522 From eede697ece879c5f9bba341a155f03235c42f2df Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 2 Oct 2020 00:04:26 +0100 Subject: [ncm] Treat a zero divisor as indicating no alignment requirements A zero divisor will currently lead to a 16-bit integer overflow when calculating the transmit padding, and a potential division by zero if assertions are enabled. Avoid these problems by treating a divisor value of zero as equivalent to a divisor value of one (i.e. no alignment requirements). Signed-off-by: Michael Brown --- src/drivers/net/ncm.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/net/ncm.c b/src/drivers/net/ncm.c index 1837291f7..cc07a4388 100644 --- a/src/drivers/net/ncm.c +++ b/src/drivers/net/ncm.c @@ -558,6 +558,8 @@ static int ncm_probe ( struct usb_function *func, struct usb_interface_descriptor *comms; struct ecm_ethernet_descriptor *ethernet; struct ncm_ntb_parameters params; + unsigned int remainder; + unsigned int divisor; int rc; /* Allocate and initialise structure */ @@ -616,14 +618,15 @@ static int ncm_probe ( struct usb_function *func, DBGC2 ( ncm, "NCM %p maximum IN size is %zd bytes\n", ncm, ncm->mtu ); /* Calculate transmit padding */ - ncm->padding = ( ( le16_to_cpu ( params.out.remainder ) - - sizeof ( struct ncm_ntb_header ) - ETH_HLEN ) & - ( le16_to_cpu ( params.out.divisor ) - 1 ) ); + divisor = ( params.out.divisor ? + le16_to_cpu ( params.out.divisor ) : 1 ); + remainder = le16_to_cpu ( params.out.remainder ); + ncm->padding = ( ( remainder - sizeof ( struct ncm_ntb_header ) - + ETH_HLEN ) & ( divisor - 1 ) ); DBGC2 ( ncm, "NCM %p using %zd-byte transmit padding\n", ncm, ncm->padding ); assert ( ( ( sizeof ( struct ncm_ntb_header ) + ncm->padding + - ETH_HLEN ) % le16_to_cpu ( params.out.divisor ) ) == - le16_to_cpu ( params.out.remainder ) ); + ETH_HLEN ) % divisor ) == remainder ); /* Register network device */ if ( ( rc = register_netdev ( netdev ) ) != 0 ) -- cgit v1.2.3-55-g7522 From ebf01660810c4ff923754323049d49d37321fd49 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 12 Oct 2020 15:21:25 +0100 Subject: [usb] Allow device halt to be cleared independently of host controller Closing and reopening a USB endpoint will clear any halt status recorded by the host controller, but may leave the endpoint halted at the device. This will cause the first packet submitted to the reopened endpoint to be lost, before the automatic stall recovery mechanism detects the halt and resets the endpoint. This is relatively harmless for USB network or HID devices, since the wire protocols will recover gracefully from dropped packets. Some protocols (e.g. for USB mass storage devices) assume zero packet loss and so would be adversely affected. Fix by allowing any device endpoint halt status to be cleared on a freshly opened endpoint. Signed-off-by: Michael Brown --- src/drivers/bus/usb.c | 45 +++++++++++++++++++++++++++++++-------------- src/include/ipxe/usb.h | 1 + 2 files changed, 32 insertions(+), 14 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/bus/usb.c b/src/drivers/bus/usb.c index 14eabb6b4..88df9c64a 100644 --- a/src/drivers/bus/usb.c +++ b/src/drivers/bus/usb.c @@ -362,6 +362,35 @@ static int usb_endpoint_clear_tt ( struct usb_endpoint *ep ) { return 0; } +/** + * Clear endpoint halt (if applicable) + * + * @v ep USB endpoint + * @ret rc Return status code + */ +int usb_endpoint_clear_halt ( struct usb_endpoint *ep ) { + struct usb_device *usb = ep->usb; + unsigned int type; + int rc; + + /* Clear transaction translator, if applicable */ + if ( ( rc = usb_endpoint_clear_tt ( ep ) ) != 0 ) + return rc; + + /* Clear endpoint halt (if applicable) */ + type = ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK ); + if ( ( type != USB_ENDPOINT_ATTR_CONTROL ) && + ( ( rc = usb_clear_feature ( usb, USB_RECIP_ENDPOINT, + USB_ENDPOINT_HALT, + ep->address ) ) != 0 ) ) { + DBGC ( usb, "USB %s %s could not clear endpoint halt: %s\n", + usb->name, usb_endpoint_name ( ep ), strerror ( rc ) ); + return rc; + } + + return 0; +} + /** * Close USB endpoint * @@ -399,27 +428,15 @@ void usb_endpoint_close ( struct usb_endpoint *ep ) { */ static int usb_endpoint_reset ( struct usb_endpoint *ep ) { struct usb_device *usb = ep->usb; - unsigned int type; int rc; /* Sanity check */ assert ( ! list_empty ( &ep->halted ) ); - /* Clear transaction translator, if applicable */ - if ( ( rc = usb_endpoint_clear_tt ( ep ) ) != 0 ) + /* Clear device halt, if applicable */ + if ( ( rc = usb_endpoint_clear_halt ( ep ) ) != 0 ) return rc; - /* Clear endpoint halt, if applicable */ - type = ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK ); - if ( ( type != USB_ENDPOINT_ATTR_CONTROL ) && - ( ( rc = usb_clear_feature ( usb, USB_RECIP_ENDPOINT, - USB_ENDPOINT_HALT, - ep->address ) ) != 0 ) ) { - DBGC ( usb, "USB %s %s could not clear endpoint halt: %s\n", - usb->name, usb_endpoint_name ( ep ), strerror ( rc ) ); - return rc; - } - /* Reset endpoint */ if ( ( rc = ep->host->reset ( ep ) ) != 0 ) { DBGC ( usb, "USB %s %s could not reset: %s\n", diff --git a/src/include/ipxe/usb.h b/src/include/ipxe/usb.h index 68289d26d..a05ac613c 100644 --- a/src/include/ipxe/usb.h +++ b/src/include/ipxe/usb.h @@ -580,6 +580,7 @@ usb_endpoint_described ( struct usb_endpoint *ep, struct usb_interface_descriptor *interface, unsigned int type, unsigned int index ); extern int usb_endpoint_open ( struct usb_endpoint *ep ); +extern int usb_endpoint_clear_halt ( struct usb_endpoint *ep ); extern void usb_endpoint_close ( struct usb_endpoint *ep ); extern int usb_message ( struct usb_endpoint *ep, unsigned int request, unsigned int value, unsigned int index, -- cgit v1.2.3-55-g7522 From e30c26d01c7493a7e02e77fc80c490fc85612d5a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 12 Oct 2020 15:28:26 +0100 Subject: [usb] Allow endpoints to be refilled to a specified upper limit For USB mass storage devices, we do not want to submit more bulk IN packets than are required for the inbound data, since this will waste memory. Allow an upper limit to be specified on each refill attempt. The endpoint will be refilled to the lower of this limit or the limit specified by usb_refill_init(). Signed-off-by: Michael Brown --- src/drivers/bus/usb.c | 19 ++++++++++++++++--- src/include/ipxe/usb.h | 1 + 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/bus/usb.c b/src/drivers/bus/usb.c index 88df9c64a..70a86c913 100644 --- a/src/drivers/bus/usb.c +++ b/src/drivers/bus/usb.c @@ -651,12 +651,13 @@ int usb_prefill ( struct usb_endpoint *ep ) { } /** - * Refill endpoint + * Refill endpoint up to specified limit * * @v ep USB endpoint + * @v max Fill limit * @ret rc Return status code */ -int usb_refill ( struct usb_endpoint *ep ) { +int usb_refill_limit ( struct usb_endpoint *ep, unsigned int max ) { struct io_buffer *iobuf; size_t reserve = ep->reserve; size_t len = ( ep->len ? ep->len : ep->mtu ); @@ -667,7 +668,9 @@ int usb_refill ( struct usb_endpoint *ep ) { assert ( ep->max > 0 ); /* Refill endpoint */ - while ( ep->fill < ep->max ) { + if ( max > ep->max ) + max = ep->max; + while ( ep->fill < max ) { /* Get or allocate buffer */ if ( list_empty ( &ep->recycled ) ) { @@ -698,6 +701,16 @@ int usb_refill ( struct usb_endpoint *ep ) { return 0; } +/** + * Refill endpoint + * + * @v ep USB endpoint + * @ret rc Return status code + */ +int usb_refill ( struct usb_endpoint *ep ) { + return usb_refill_limit ( ep, ep->max ); +} + /** * Discard endpoint recycled buffer list * diff --git a/src/include/ipxe/usb.h b/src/include/ipxe/usb.h index a05ac613c..70d6daf33 100644 --- a/src/include/ipxe/usb.h +++ b/src/include/ipxe/usb.h @@ -621,6 +621,7 @@ usb_recycle ( struct usb_endpoint *ep, struct io_buffer *iobuf ) { } extern int usb_prefill ( struct usb_endpoint *ep ); +extern int usb_refill_limit ( struct usb_endpoint *ep, unsigned int max ); extern int usb_refill ( struct usb_endpoint *ep ); extern void usb_flush ( struct usb_endpoint *ep ); -- cgit v1.2.3-55-g7522 From 6d680bdec59b103f84ee922ec66ae5219c939938 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 12 Oct 2020 15:31:49 +0100 Subject: [usbblk] Add support for USB mass storage devices Some UEFI BIOSes (observed with at least the Insyde UEFI BIOS on a Microsoft Surface Go) provide a very broken version of the UsbMassStorageDxe driver that is incapable of binding to the standard EFI_USB_IO_PROTOCOL instances and instead relies on an undocumented proprietary protocol (with GUID c965c76a-d71e-4e66-ab06-c6230d528425) installed by the platform's custom version of UsbCoreDxe. The upshot is that USB mass storage devices become inaccessible once iPXE's native USB host controller drivers are loaded. One possible workaround is to load a known working version of UsbMassStorageDxe (e.g. from the EDK2 tree): this driver will correctly bind to the standard EFI_USB_IO_PROTOCOL instances exposed by iPXE. This workaround is ugly in practice, since it involves embedding UsbMassStorageDxe.efi into the iPXE binary and including an embedded script to perform the required "chain UsbMassStorageDxe.efi". Provide a native USB mass storage driver for iPXE, allowing USB mass storage devices to be exposed as iPXE SAN devices. Signed-off-by: Michael Brown --- src/config/config_usb.c | 3 + src/config/defaults/efi.h | 1 + src/config/defaults/pcbios.h | 1 + src/config/usb.h | 1 + src/drivers/usb/usbblk.c | 897 +++++++++++++++++++++++++++++++++++++++++++ src/drivers/usb/usbblk.h | 121 ++++++ src/include/ipxe/errfile.h | 1 + 7 files changed, 1025 insertions(+) create mode 100644 src/drivers/usb/usbblk.c create mode 100644 src/drivers/usb/usbblk.h (limited to 'src/drivers') diff --git a/src/config/config_usb.c b/src/config/config_usb.c index 17296d277..b679aeb27 100644 --- a/src/config/config_usb.c +++ b/src/config/config_usb.c @@ -53,6 +53,9 @@ REQUIRE_OBJECT ( usbio ); #ifdef USB_KEYBOARD REQUIRE_OBJECT ( usbkbd ); #endif +#ifdef USB_BLOCK +REQUIRE_OBJECT ( usbblk ); +#endif /* * Drag in USB external interfaces diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index e707dfa6a..4ae6a316e 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -39,6 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define USB_HCD_EHCI /* EHCI USB host controller */ #define USB_HCD_UHCI /* UHCI USB host controller */ #define USB_EFI /* Provide EFI_USB_IO_PROTOCOL interface */ +#define USB_BLOCK /* USB block devices */ #define REBOOT_CMD /* Reboot command */ diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index 21821c95c..41afb9033 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -48,6 +48,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define USB_HCD_EHCI /* EHCI USB host controller */ #define USB_HCD_UHCI /* UHCI USB host controller */ #define USB_KEYBOARD /* USB keyboards */ +#define USB_BLOCK /* USB block devices */ #define REBOOT_CMD /* Reboot command */ #define CPUID_CMD /* x86 CPU feature detection command */ diff --git a/src/config/usb.h b/src/config/usb.h index d2519d877..4252ec229 100644 --- a/src/config/usb.h +++ b/src/config/usb.h @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ //#undef USB_KEYBOARD /* USB keyboards */ +//#undef USB_BLOCK /* USB block devices */ /* * USB external interfaces diff --git a/src/drivers/usb/usbblk.c b/src/drivers/usb/usbblk.c new file mode 100644 index 000000000..a68e3ced5 --- /dev/null +++ b/src/drivers/usb/usbblk.c @@ -0,0 +1,897 @@ +/* + * Copyright (C) 2020 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include "usbblk.h" + +/** @file + * + * USB mass storage driver + * + */ + +static void usbblk_stop ( struct usbblk_device *usbblk, int rc ); + +/** List of USB block devices */ +static LIST_HEAD ( usbblk_devices ); + +/****************************************************************************** + * + * Endpoint management + * + ****************************************************************************** + */ + +/** + * Open endpoints + * + * @v usbblk USB block device + * @ret rc Return status code + */ +static int usbblk_open ( struct usbblk_device *usbblk ) { + struct usb_device *usb = usbblk->func->usb; + unsigned int interface = usbblk->func->interface[0]; + int rc; + + /* Sanity checks */ + assert ( ! usbblk->in.open ); + assert ( ! usbblk->out.open ); + + /* Issue reset */ + if ( ( rc = usb_control ( usb, USBBLK_RESET, 0, interface, + NULL, 0 ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s could not issue reset: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err_reset; + } + + /* Open bulk OUT endpoint */ + if ( ( rc = usb_endpoint_open ( &usbblk->out ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s could not open bulk OUT: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err_open_out; + } + + /* Clear any bulk OUT halt condition */ + if ( ( rc = usb_endpoint_clear_halt ( &usbblk->out ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s could not reset bulk OUT: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err_clear_out; + } + + /* Open bulk IN endpoint */ + if ( ( rc = usb_endpoint_open ( &usbblk->in ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s could not open bulk IN: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err_open_in; + } + + /* Clear any bulk IN halt condition */ + if ( ( rc = usb_endpoint_clear_halt ( &usbblk->in ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s could not reset bulk IN: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err_clear_in; + } + + return 0; + + err_clear_in: + usb_endpoint_close ( &usbblk->in ); + err_open_in: + err_clear_out: + usb_endpoint_close ( &usbblk->out ); + err_open_out: + err_reset: + return rc; +} + +/** + * Close endpoints + * + * @v usbblk USB block device + */ +static void usbblk_close ( struct usbblk_device *usbblk ) { + + /* Close bulk OUT endpoint */ + if ( usbblk->out.open ) + usb_endpoint_close ( &usbblk->out ); + + /* Close bulk IN endpoint */ + if ( usbblk->in.open ) + usb_endpoint_close ( &usbblk->in ); +} + +/****************************************************************************** + * + * Bulk OUT endpoint + * + ****************************************************************************** + */ + +/** + * Issue bulk OUT command + * + * @v usbblk USB block device + * @ret rc Return status code + */ +static int usbblk_out_command ( struct usbblk_device *usbblk ) { + struct usbblk_command *cmd = &usbblk->cmd; + struct usbblk_command_wrapper *wrapper; + struct io_buffer *iobuf; + int rc; + + /* Sanity checks */ + assert ( cmd->tag ); + assert ( ! ( cmd->scsi.data_in_len && cmd->scsi.data_out_len ) ); + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( sizeof ( *wrapper ) ); + if ( ! iobuf ) { + rc = -ENOMEM; + goto err_alloc; + } + + /* Populate command */ + wrapper = iob_put ( iobuf, sizeof ( *wrapper ) ); + memset ( wrapper, 0, sizeof ( *wrapper ) ); + wrapper->signature = cpu_to_le32 ( USBBLK_COMMAND_SIGNATURE ); + wrapper->tag = cmd->tag; /* non-endian */ + if ( cmd->scsi.data_out_len ) { + wrapper->len = cpu_to_le32 ( cmd->scsi.data_out_len ); + } else { + wrapper->len = cpu_to_le32 ( cmd->scsi.data_in_len ); + wrapper->flags = USB_DIR_IN; + } + wrapper->lun = ntohs ( cmd->scsi.lun.u16[0] ); + wrapper->cblen = sizeof ( wrapper->cb ); + memcpy ( wrapper->cb, &cmd->scsi.cdb, sizeof ( wrapper->cb ) ); + + /* Issue command */ + if ( ( rc = usb_stream ( &usbblk->out, iobuf, 0 ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s bulk OUT could not issue command: " + "%s\n", usbblk->func->name, strerror ( rc ) ); + goto err_stream; + } + + return 0; + + err_stream: + free_iob ( iobuf ); + err_alloc: + return rc; +} + +/** + * Send bulk OUT data block + * + * @v usbblk USB block device + * @ret rc Return status code + */ +static int usbblk_out_data ( struct usbblk_device *usbblk ) { + struct usbblk_command *cmd = &usbblk->cmd; + struct io_buffer *iobuf; + size_t len; + int rc; + + /* Calculate length */ + assert ( cmd->tag ); + assert ( cmd->scsi.data_out != UNULL ); + assert ( cmd->offset < cmd->scsi.data_out_len ); + len = ( cmd->scsi.data_out_len - cmd->offset ); + if ( len > USBBLK_MAX_LEN ) + len = USBBLK_MAX_LEN; + assert ( ( len % usbblk->out.mtu ) == 0 ); + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( len ); + if ( ! iobuf ) { + rc = -ENOMEM; + goto err_alloc; + } + + /* Populate I/O buffer */ + copy_from_user ( iob_put ( iobuf, len ), cmd->scsi.data_out, + cmd->offset, len ); + + /* Send data */ + if ( ( rc = usb_stream ( &usbblk->out, iobuf, 0 ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s bulk OUT could not send data: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err_stream; + } + + /* Consume data */ + cmd->offset += len; + + return 0; + + err_stream: + free_iob ( iobuf ); + err_alloc: + return rc; +} + +/** + * Refill bulk OUT endpoint + * + * @v usbblk USB block device + * @ret rc Return status code + */ +static int usbblk_out_refill ( struct usbblk_device *usbblk ) { + struct usbblk_command *cmd = &usbblk->cmd; + int rc; + + /* Sanity checks */ + assert ( cmd->tag ); + + /* Refill endpoint */ + while ( ( cmd->offset < cmd->scsi.data_out_len ) && + ( usbblk->out.fill < USBBLK_MAX_FILL ) ) { + if ( ( rc = usbblk_out_data ( usbblk ) ) != 0 ) + return rc; + } + + return 0; +} + +/** + * Complete bulk OUT transfer + * + * @v ep USB endpoint + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void usbblk_out_complete ( struct usb_endpoint *ep, + struct io_buffer *iobuf, int rc ) { + struct usbblk_device *usbblk = + container_of ( ep, struct usbblk_device, out ); + struct usbblk_command *cmd = &usbblk->cmd; + + /* Ignore cancellations after closing endpoint */ + if ( ! ep->open ) + goto drop; + + /* Sanity check */ + assert ( cmd->tag ); + + /* Check for failures */ + if ( rc != 0 ) { + DBGC ( usbblk, "USBBLK %s bulk OUT failed: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err; + } + + /* Trigger refill process, if applicable */ + if ( cmd->offset < cmd->scsi.data_out_len ) + process_add ( &usbblk->process ); + + drop: + /* Free I/O buffer */ + free_iob ( iobuf ); + + return; + + err: + free_iob ( iobuf ); + usbblk_stop ( usbblk, rc ); +} + +/** Bulk OUT endpoint operations */ +static struct usb_endpoint_driver_operations usbblk_out_operations = { + .complete = usbblk_out_complete, +}; + +/****************************************************************************** + * + * Bulk IN endpoint + * + ****************************************************************************** + */ + +/** + * Handle bulk IN data block + * + * @v usbblk USB block device + * @v data Data block + * @v len Length of data + * @ret rc Return status code + */ +static int usbblk_in_data ( struct usbblk_device *usbblk, const void *data, + size_t len ) { + struct usbblk_command *cmd = &usbblk->cmd; + + /* Sanity checks */ + assert ( cmd->tag ); + assert ( cmd->scsi.data_in != UNULL ); + assert ( cmd->offset <= cmd->scsi.data_in_len ); + assert ( len <= ( cmd->scsi.data_in_len - cmd->offset ) ); + + /* Store data */ + copy_to_user ( cmd->scsi.data_in, cmd->offset, data, len ); + cmd->offset += len; + + return 0; +} + +/** + * Handle bulk IN status + * + * @v usbblk USB block device + * @v data Status data + * @v len Length of status data + * @ret rc Return status code + */ +static int usbblk_in_status ( struct usbblk_device *usbblk, const void *data, + size_t len ) { + struct usbblk_command *cmd = &usbblk->cmd; + const struct usbblk_status_wrapper *stat; + + /* Sanity checks */ + assert ( cmd->tag ); + + /* Validate length */ + if ( len < sizeof ( *stat ) ) { + DBGC ( usbblk, "USBBLK %s bulk IN malformed status:\n", + usbblk->func->name ); + DBGC_HDA ( usbblk, 0, data, len ); + return -EIO; + } + stat = data; + + /* Validate signature */ + if ( stat->signature != cpu_to_le32 ( USBBLK_STATUS_SIGNATURE ) ) { + DBGC ( usbblk, "USBBLK %s bulk IN invalid signature %08x:\n", + usbblk->func->name, le32_to_cpu ( stat->signature ) ); + DBGC_HDA ( usbblk, 0, stat, sizeof ( *stat ) ); + return -EIO; + } + + /* Validate tag */ + if ( stat->tag != cmd->tag ) { + DBGC ( usbblk, "USBBLK %s bulk IN tag mismatch (got %08x, " + "expected %08x):\n", + usbblk->func->name, stat->tag, cmd->tag ); + DBGC_HDA ( usbblk, 0, stat, sizeof ( *stat ) ); + return -EIO; + } + + /* Check status */ + if ( stat->status ) { + DBGC ( usbblk, "USBBLK %s bulk IN status %02x:\n", + usbblk->func->name, stat->status ); + DBGC_HDA ( usbblk, 0, stat, sizeof ( *stat ) ); + return -EIO; + } + + /* Check for residual data */ + if ( stat->residue ) { + DBGC ( usbblk, "USBBLK %s bulk IN residue %#x:\n", + usbblk->func->name, le32_to_cpu ( stat->residue ) ); + return -EIO; + } + + /* Mark command as complete */ + usbblk_stop ( usbblk, 0 ); + + return 0; +} + +/** + * Refill bulk IN endpoint + * + * @v usbblk USB block device + * @ret rc Return status code + */ +static int usbblk_in_refill ( struct usbblk_device *usbblk ) { + struct usbblk_command *cmd = &usbblk->cmd; + struct usbblk_status_wrapper *stat; + size_t remaining; + unsigned int max; + int rc; + + /* Sanity checks */ + assert ( cmd->tag ); + + /* Calculate maximum required refill */ + remaining = sizeof ( *stat ); + if ( cmd->scsi.data_in_len ) { + assert ( cmd->offset <= cmd->scsi.data_in_len ); + remaining += ( cmd->scsi.data_in_len - cmd->offset ); + } + max = ( ( remaining + USBBLK_MAX_LEN - 1 ) / USBBLK_MAX_LEN ); + + /* Refill bulk IN endpoint */ + if ( ( rc = usb_refill_limit ( &usbblk->in, max ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Complete bulk IN transfer + * + * @v ep USB endpoint + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void usbblk_in_complete ( struct usb_endpoint *ep, + struct io_buffer *iobuf, int rc ) { + struct usbblk_device *usbblk = + container_of ( ep, struct usbblk_device, in ); + struct usbblk_command *cmd = &usbblk->cmd; + size_t remaining; + size_t len; + + /* Ignore cancellations after closing endpoint */ + if ( ! ep->open ) + goto drop; + + /* Sanity check */ + assert ( cmd->tag ); + + /* Handle errors */ + if ( rc != 0 ) { + DBGC ( usbblk, "USBBLK %s bulk IN failed: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err; + } + + /* Trigger refill process */ + process_add ( &usbblk->process ); + + /* Handle data portion, if any */ + if ( cmd->scsi.data_in_len ) { + assert ( cmd->offset <= cmd->scsi.data_in_len ); + remaining = ( cmd->scsi.data_in_len - cmd->offset ); + len = iob_len ( iobuf ); + if ( len > remaining ) + len = remaining; + if ( len ) { + if ( ( rc = usbblk_in_data ( usbblk, iobuf->data, + len ) ) != 0 ) + goto err; + iob_pull ( iobuf, len ); + } + } + + /* Handle status portion, if any */ + len = iob_len ( iobuf ); + if ( len ) { + if ( ( rc = usbblk_in_status ( usbblk, iobuf->data, + len ) ) != 0 ) + goto err; + } + + drop: + /* Free I/O buffer */ + free_iob ( iobuf ); + + return; + + err: + free_iob ( iobuf ); + usbblk_stop ( usbblk, rc ); +} + +/** Bulk IN endpoint operations */ +static struct usb_endpoint_driver_operations usbblk_in_operations = { + .complete = usbblk_in_complete, +}; + +/****************************************************************************** + * + * Refill process + * + ****************************************************************************** + */ + +/** + * Refill endpoints + * + * @v usbblk USB block device + */ +static void usbblk_step ( struct usbblk_device *usbblk ) { + + /* Refill bulk OUT endpoint */ + usbblk_out_refill ( usbblk ); + + /* Refill bulk IN endpoint */ + usbblk_in_refill ( usbblk ); +} + +/** Refill process descriptor */ +static struct process_descriptor usbblk_process_desc = + PROC_DESC ( struct usbblk_device, process, usbblk_step ); + +/****************************************************************************** + * + * SCSI command management + * + ****************************************************************************** + */ + +/** Next command tag */ +static uint16_t usbblk_tag; + +/** + * Stop SCSI command + * + * @v usbblk USB block device + * @v rc Reason for stop + */ +static void usbblk_stop ( struct usbblk_device *usbblk, int rc ) { + + /* Stop process */ + process_del ( &usbblk->process ); + + /* Reset command */ + memset ( &usbblk->cmd, 0, sizeof ( usbblk->cmd ) ); + + /* Close endpoints if an error occurred */ + if ( rc != 0 ) { + DBGC ( usbblk, "USBBLK %s closing for error recovery\n", + usbblk->func->name ); + usbblk_close ( usbblk ); + } + + /* Terminate command */ + intf_restart ( &usbblk->data, rc ); +} + +/** + * Start new SCSI command + * + * @v usbblk USB block device + * @v scsicmd SCSI command + * @ret rc Return status code + */ +static int usbblk_start ( struct usbblk_device *usbblk, + struct scsi_cmd *scsicmd ) { + struct usbblk_command *cmd = &usbblk->cmd; + int rc; + + /* Fail if command is in progress */ + if ( cmd->tag ) { + rc = -EBUSY; + DBGC ( usbblk, "USBBLK %s cannot support multiple commands\n", + usbblk->func->name ); + goto err_busy; + } + + /* Refuse bidirectional commands */ + if ( scsicmd->data_in_len && scsicmd->data_out_len ) { + rc = -EOPNOTSUPP; + DBGC ( usbblk, "USBBLK %s cannot support bidirectional " + "commands\n", usbblk->func->name ); + goto err_bidirectional; + } + + /* Sanity checks */ + assert ( ! process_running ( &usbblk->process ) ); + assert ( cmd->offset == 0 ); + + /* Initialise command */ + memcpy ( &cmd->scsi, scsicmd, sizeof ( cmd->scsi ) ); + cmd->tag = ( USBBLK_TAG_MAGIC | ++usbblk_tag ); + + /* Issue bulk OUT command */ + if ( ( rc = usbblk_out_command ( usbblk ) ) != 0 ) + goto err_command; + + /* Start refill process */ + process_add ( &usbblk->process ); + + return 0; + + err_command: + memset ( &usbblk->cmd, 0, sizeof ( usbblk->cmd ) ); + err_bidirectional: + err_busy: + return rc; +} + +/****************************************************************************** + * + * SCSI interfaces + * + ****************************************************************************** + */ + +/** SCSI data interface operations */ +static struct interface_operation usbblk_data_operations[] = { + INTF_OP ( intf_close, struct usbblk_device *, usbblk_stop ), +}; + +/** SCSI data interface descriptor */ +static struct interface_descriptor usbblk_data_desc = + INTF_DESC ( struct usbblk_device, data, usbblk_data_operations ); + +/** + * Check SCSI command flow-control window + * + * @v usbblk USB block device + * @ret len Length of window + */ +static size_t usbblk_scsi_window ( struct usbblk_device *usbblk ) { + struct usbblk_command *cmd = &usbblk->cmd; + + /* Allow a single command if no command is currently in progress */ + return ( cmd->tag ? 0 : 1 ); +} + +/** + * Issue SCSI command + * + * @v usbblk USB block device + * @v data SCSI data interface + * @v scsicmd SCSI command + * @ret tag Command tag, or negative error + */ +static int usbblk_scsi_command ( struct usbblk_device *usbblk, + struct interface *data, + struct scsi_cmd *scsicmd ) { + struct usbblk_command *cmd = &usbblk->cmd; + int rc; + + /* (Re)open endpoints if needed */ + if ( ( ! usbblk->in.open ) && ( ( rc = usbblk_open ( usbblk ) ) != 0 ) ) + goto err_open; + + /* Start new command */ + if ( ( rc = usbblk_start ( usbblk, scsicmd ) ) != 0 ) + goto err_start; + + /* Attach to parent interface and return */ + intf_plug_plug ( &usbblk->data, data ); + return cmd->tag; + + usbblk_stop ( usbblk, rc ); + err_start: + usbblk_close ( usbblk ); + err_open: + return rc; +} + +/** + * Close SCSI interface + * + * @v usbblk USB block device + * @v rc Reason for close + */ +static void usbblk_scsi_close ( struct usbblk_device *usbblk, int rc ) { + + /* Restart interfaces */ + intfs_restart ( rc, &usbblk->scsi, &usbblk->data, NULL ); + + /* Stop any in-progress command */ + usbblk_stop ( usbblk, rc ); + + /* Close endpoints */ + usbblk_close ( usbblk ); + + /* Flag as closed */ + usbblk->opened = 0; +} + +/** SCSI command interface operations */ +static struct interface_operation usbblk_scsi_operations[] = { + INTF_OP ( scsi_command, struct usbblk_device *, usbblk_scsi_command ), + INTF_OP ( xfer_window, struct usbblk_device *, usbblk_scsi_window ), + INTF_OP ( intf_close, struct usbblk_device *, usbblk_scsi_close ), +}; + +/** SCSI command interface descriptor */ +static struct interface_descriptor usbblk_scsi_desc = + INTF_DESC ( struct usbblk_device, scsi, usbblk_scsi_operations ); + +/****************************************************************************** + * + * SAN device interface + * + ****************************************************************************** + */ + +/** + * Find USB block device + * + * @v name USB block device name + * @ret usbblk USB block device, or NULL + */ +static struct usbblk_device * usbblk_find ( const char *name ) { + struct usbblk_device *usbblk; + + /* Look for matching device */ + list_for_each_entry ( usbblk, &usbblk_devices, list ) { + if ( strcmp ( usbblk->func->name, name ) == 0 ) + return usbblk; + } + + return NULL; +} + +/** + * Open USB block device URI + * + * @v parent Parent interface + * @v uri URI + * @ret rc Return status code + */ +static int usbblk_open_uri ( struct interface *parent, struct uri *uri ) { + static struct scsi_lun lun; + struct usbblk_device *usbblk; + int rc; + + /* Sanity check */ + if ( ! uri->opaque ) + return -EINVAL; + + /* Find matching device */ + usbblk = usbblk_find ( uri->opaque ); + if ( ! usbblk ) + return -ENOENT; + + /* Fail if device is already open */ + if ( usbblk->opened ) + return -EBUSY; + + /* Open SCSI device */ + if ( ( rc = scsi_open ( parent, &usbblk->scsi, &lun ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s could not open SCSI device: %s\n", + usbblk->func->name, strerror ( rc ) ); + return rc; + } + + /* Mark as opened */ + usbblk->opened = 1; + + return 0; +} + +/** USB block device URI opener */ +struct uri_opener usbblk_uri_opener __uri_opener = { + .scheme = "usb", + .open = usbblk_open_uri, +}; + +/****************************************************************************** + * + * USB interface + * + ****************************************************************************** + */ + +/** + * Probe device + * + * @v func USB function + * @v config Configuration descriptor + * @ret rc Return status code + */ +static int usbblk_probe ( struct usb_function *func, + struct usb_configuration_descriptor *config ) { + struct usb_device *usb = func->usb; + struct usbblk_device *usbblk; + struct usb_interface_descriptor *desc; + int rc; + + /* Allocate and initialise structure */ + usbblk = zalloc ( sizeof ( *usbblk ) ); + if ( ! usbblk ) { + rc = -ENOMEM; + goto err_alloc; + } + usbblk->func = func; + usb_endpoint_init ( &usbblk->out, usb, &usbblk_out_operations ); + usb_endpoint_init ( &usbblk->in, usb, &usbblk_in_operations ); + usb_refill_init ( &usbblk->in, 0, USBBLK_MAX_LEN, USBBLK_MAX_FILL ); + intf_init ( &usbblk->scsi, &usbblk_scsi_desc, &usbblk->refcnt ); + intf_init ( &usbblk->data, &usbblk_data_desc, &usbblk->refcnt ); + process_init_stopped ( &usbblk->process, &usbblk_process_desc, + &usbblk->refcnt ); + + /* Locate interface descriptor */ + desc = usb_interface_descriptor ( config, func->interface[0], 0 ); + if ( ! desc ) { + DBGC ( usbblk, "USBBLK %s missing interface descriptor\n", + usbblk->func->name ); + rc = -ENOENT; + goto err_desc; + } + + /* Describe endpoints */ + if ( ( rc = usb_endpoint_described ( &usbblk->out, config, desc, + USB_BULK_OUT, 0 ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s could not describe bulk OUT: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err_out; + } + if ( ( rc = usb_endpoint_described ( &usbblk->in, config, desc, + USB_BULK_IN, 0 ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s could not describe bulk IN: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err_in; + } + + /* Add to list of devices */ + list_add_tail ( &usbblk->list, &usbblk_devices ); + + usb_func_set_drvdata ( func, usbblk ); + return 0; + + err_in: + err_out: + err_desc: + ref_put ( &usbblk->refcnt ); + err_alloc: + return rc; +} + +/** + * Remove device + * + * @v func USB function + */ +static void usbblk_remove ( struct usb_function *func ) { + struct usbblk_device *usbblk = usb_func_get_drvdata ( func ); + + /* Remove from list of devices */ + list_del ( &usbblk->list ); + + /* Close all interfaces */ + usbblk_scsi_close ( usbblk, -ENODEV ); + + /* Shut down interfaces */ + intfs_shutdown ( -ENODEV, &usbblk->scsi, &usbblk->data, NULL ); + + /* Drop reference */ + ref_put ( &usbblk->refcnt ); +} + +/** Mass storage class device IDs */ +static struct usb_device_id usbblk_ids[] = { + { + .name = "usbblk", + .vendor = USB_ANY_ID, + .product = USB_ANY_ID, + }, +}; + +/** Mass storage driver */ +struct usb_driver usbblk_driver __usb_driver = { + .ids = usbblk_ids, + .id_count = ( sizeof ( usbblk_ids ) / sizeof ( usbblk_ids[0] ) ), + .class = USB_CLASS_ID ( USB_CLASS_MSC, USB_SUBCLASS_MSC_SCSI, + USB_PROTOCOL_MSC_BULK ), + .score = USB_SCORE_NORMAL, + .probe = usbblk_probe, + .remove = usbblk_remove, +}; diff --git a/src/drivers/usb/usbblk.h b/src/drivers/usb/usbblk.h new file mode 100644 index 000000000..65d0705e3 --- /dev/null +++ b/src/drivers/usb/usbblk.h @@ -0,0 +1,121 @@ +#ifndef _USBBLK_H +#define _USBBLK_H + +/** @file + * + * USB mass storage driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include + +/** Mass storage class code */ +#define USB_CLASS_MSC 0x08 + +/** SCSI command set subclass code */ +#define USB_SUBCLASS_MSC_SCSI 0x06 + +/** Bulk-only transport protocol */ +#define USB_PROTOCOL_MSC_BULK 0x50 + +/** Mass storage reset command */ +#define USBBLK_RESET ( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE | \ + USB_REQUEST_TYPE ( 255 ) ) + +/** Command block wrapper */ +struct usbblk_command_wrapper { + /** Signature */ + uint32_t signature; + /** Tag */ + uint32_t tag; + /** Data transfer length */ + uint32_t len; + /** Flags */ + uint8_t flags; + /** LUN */ + uint8_t lun; + /** Command block length */ + uint8_t cblen; + /** Command block */ + uint8_t cb[16]; +} __attribute__ (( packed )); + +/** Command block wrapper signature */ +#define USBBLK_COMMAND_SIGNATURE 0x43425355UL + +/** Command status wrapper */ +struct usbblk_status_wrapper { + /** Signature */ + uint32_t signature; + /** Tag */ + uint32_t tag; + /** Data residue */ + uint32_t residue; + /** Status */ + uint8_t status; +} __attribute__ (( packed )); + +/** Command status wrapper signature */ +#define USBBLK_STATUS_SIGNATURE 0x53425355UL + +/** A USB mass storage command */ +struct usbblk_command { + /** SCSI command */ + struct scsi_cmd scsi; + /** Command tag (0 for no command in progress) */ + uint32_t tag; + /** Offset within data buffer */ + size_t offset; +}; + +/** A USB mass storage device */ +struct usbblk_device { + /** Reference count */ + struct refcnt refcnt; + /** List of devices */ + struct list_head list; + + /** USB function */ + struct usb_function *func; + /** Bulk OUT endpoint */ + struct usb_endpoint out; + /** Bulk IN endpoint */ + struct usb_endpoint in; + + /** SCSI command-issuing interface */ + struct interface scsi; + /** SCSI data interface */ + struct interface data; + /** Command process */ + struct process process; + /** Device opened flag */ + int opened; + + /** Current command (if any) */ + struct usbblk_command cmd; +}; + +/** Command tag magic + * + * This is a policy decision. + */ +#define USBBLK_TAG_MAGIC 0x18ae0000 + +/** Maximum length of USB data block + * + * This is a policy decision. + */ +#define USBBLK_MAX_LEN 2048 + +/** Maximum endpoint fill level + * + * This is a policy decision. + */ +#define USBBLK_MAX_FILL 4 + +#endif /* _USBBLK_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 242f91f82..8238d4925 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -208,6 +208,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_intelxl ( ERRFILE_DRIVER | 0x00cb0000 ) #define ERRFILE_pcimsix ( ERRFILE_DRIVER | 0x00cc0000 ) #define ERRFILE_intelxlvf ( ERRFILE_DRIVER | 0x00cd0000 ) +#define ERRFILE_usbblk ( ERRFILE_DRIVER | 0x00ce0000 ) #define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 ) #define ERRFILE_arp ( ERRFILE_NET | 0x00010000 ) -- cgit v1.2.3-55-g7522 From 2bf0fd39cafcfaf9a2a66f1f22bbe36640a72b6c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 16 Oct 2020 14:12:56 +0100 Subject: [efi] Split device path functions out to efi_path.c Signed-off-by: Michael Brown --- src/drivers/usb/usbio.c | 5 ++-- src/image/efi_image.c | 4 +-- src/include/ipxe/efi/efi_path.h | 19 ++++++++++++++ src/include/ipxe/efi/efi_utils.h | 4 --- src/interface/efi/efi_block.c | 8 +++--- src/interface/efi/efi_debug.c | 4 +-- src/interface/efi/efi_driver.c | 4 +-- src/interface/efi/efi_init.c | 4 +-- src/interface/efi/efi_local.c | 4 +-- src/interface/efi/efi_path.c | 57 ++++++++++++++++++++++++++++++++++++++++ src/interface/efi/efi_snp.c | 3 ++- src/interface/efi/efi_snp_hii.c | 3 ++- src/interface/efi/efi_usb.c | 4 +-- src/interface/efi/efi_utils.c | 30 --------------------- 14 files changed, 99 insertions(+), 54 deletions(-) create mode 100644 src/include/ipxe/efi/efi_path.h create mode 100644 src/interface/efi/efi_path.c (limited to 'src/drivers') diff --git a/src/drivers/usb/usbio.c b/src/drivers/usb/usbio.c index dfb93dab1..278b43cd3 100644 --- a/src/drivers/usb/usbio.c +++ b/src/drivers/usb/usbio.c @@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -206,7 +207,7 @@ static int usbio_open ( struct usbio_device *usbio, unsigned int interface ) { path = usbio->path; usbpath = usbio->usbpath; usbpath->InterfaceNumber = interface; - end = efi_devpath_end ( path ); + end = efi_path_end ( path ); /* Locate handle for this endpoint's interface */ if ( ( efirc = bs->LocateDevicePath ( &efi_usb_io_protocol_guid, &path, @@ -1503,7 +1504,7 @@ static int usbio_path ( struct usbio_device *usbio ) { path = u.interface; /* Locate end of device path and sanity check */ - len = efi_devpath_len ( path ); + len = efi_path_len ( path ); if ( len < sizeof ( *usbpath ) ) { DBGC ( usbio, "USBIO %s underlength device path\n", efi_handle_name ( handle ) ); diff --git a/src/image/efi_image.c b/src/image/efi_image.c index 942b7aeeb..3c98decbf 100644 --- a/src/image/efi_image.c +++ b/src/image/efi_image.c @@ -26,7 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include +#include #include #include #include @@ -75,7 +75,7 @@ efi_image_path ( struct image *image, EFI_DEVICE_PATH_PROTOCOL *parent ) { size_t len; /* Calculate device path lengths */ - prefix_len = efi_devpath_len ( parent ); + prefix_len = efi_path_len ( parent ); name_len = strlen ( image->name ); filepath_len = ( SIZE_OF_FILEPATH_DEVICE_PATH + ( name_len + 1 /* NUL */ ) * sizeof ( wchar_t ) ); diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h new file mode 100644 index 000000000..f8b95fd21 --- /dev/null +++ b/src/include/ipxe/efi/efi_path.h @@ -0,0 +1,19 @@ +#ifndef _IPXE_EFI_PATH_H +#define _IPXE_EFI_PATH_H + +/** @file + * + * EFI device paths + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include + +extern EFI_DEVICE_PATH_PROTOCOL * +efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path ); +extern size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ); + +#endif /* _IPXE_EFI_PATH_H */ diff --git a/src/include/ipxe/efi/efi_utils.h b/src/include/ipxe/efi/efi_utils.h index 67acba17e..270d38dc8 100644 --- a/src/include/ipxe/efi/efi_utils.h +++ b/src/include/ipxe/efi/efi_utils.h @@ -9,13 +9,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include -#include struct device; -extern EFI_DEVICE_PATH_PROTOCOL * -efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ); -extern size_t efi_devpath_len ( EFI_DEVICE_PATH_PROTOCOL *path ); extern int efi_locate_device ( EFI_HANDLE device, EFI_GUID *protocol, EFI_HANDLE *parent ); extern int efi_child_add ( EFI_HANDLE parent, EFI_HANDLE child ); diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index 0024fbbea..a63bc9ccf 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -54,7 +54,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include +#include #include /** ACPI table protocol protocol */ @@ -288,7 +288,7 @@ static int efi_block_hook ( unsigned int drive, struct uri **uris, } /* Calculate length of private data */ - prefix_len = efi_devpath_len ( snpdev->path ); + prefix_len = efi_path_len ( snpdev->path ); uri_len = format_uri ( uris[0], NULL, 0 ); vendor_len = ( sizeof ( *vendor ) + ( ( uri_len + 1 /* NUL */ ) * sizeof ( wchar_t ) ) ); @@ -551,7 +551,7 @@ static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle, } /* Check if this device is a child of our block device */ - prefix_len = efi_devpath_len ( block->path ); + prefix_len = efi_path_len ( block->path ); if ( memcmp ( path.path, block->path, prefix_len ) != 0 ) { /* Not a child device */ rc = -ENOTTY; @@ -561,7 +561,7 @@ static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle, sandev->drive, efi_devpath_text ( path.path ) ); /* Construct device path for boot image */ - end = efi_devpath_end ( path.path ); + end = efi_path_end ( path.path ); prefix_len = ( ( ( void * ) end ) - ( ( void * ) path.path ) ); filepath_len = ( SIZE_OF_FILEPATH_DEVICE_PATH + ( filename ? diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c index f7be9476e..7cff14614 100644 --- a/src/interface/efi/efi_debug.c +++ b/src/interface/efi/efi_debug.c @@ -37,7 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include +#include #include #include #include @@ -378,7 +378,7 @@ efi_devpath_text ( EFI_DEVICE_PATH_PROTOCOL *path ) { /* If we have no DevicePathToText protocol then use a raw hex string */ if ( ! efidpt ) { DBG ( "[No DevicePathToText]" ); - len = efi_devpath_len ( path ); + len = efi_path_len ( path ); base16_encode ( path, len, text, sizeof ( text ) ); return text; } diff --git a/src/interface/efi/efi_driver.c b/src/interface/efi/efi_driver.c index a6c0f3032..8388dd535 100644 --- a/src/interface/efi/efi_driver.c +++ b/src/interface/efi/efi_driver.c @@ -30,7 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include +#include #include /** @file @@ -202,7 +202,7 @@ efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, efi_handle_name ( device ), strerror ( rc ) ); goto err_open_path; } - path_len = ( efi_devpath_len ( path.path ) + sizeof ( *path_end ) ); + path_len = ( efi_path_len ( path.path ) + sizeof ( *path_end ) ); /* Allocate and initialise structure */ efidev = zalloc ( sizeof ( *efidev ) + path_len ); diff --git a/src/interface/efi/efi_init.c b/src/interface/efi/efi_init.c index 70212b184..6d46c5669 100644 --- a/src/interface/efi/efi_init.c +++ b/src/interface/efi/efi_init.c @@ -26,7 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include +#include #include /** Image handle passed to entry point */ @@ -252,7 +252,7 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle, * path, since the device handle itself may become invalidated * when we load our own drivers. */ - device_path_len = ( efi_devpath_len ( device_path ) + + device_path_len = ( efi_path_len ( device_path ) + sizeof ( EFI_DEVICE_PATH_PROTOCOL ) ); if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, device_path_len, &device_path_copy ) ) != 0 ) { diff --git a/src/interface/efi/efi_local.c b/src/interface/efi/efi_local.c index 617895650..4ebca5726 100644 --- a/src/interface/efi/efi_local.c +++ b/src/interface/efi/efi_local.c @@ -37,7 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include +#include #include #include #include @@ -425,7 +425,7 @@ static int efi_local_open_resolved ( struct efi_local *local, static int efi_local_open_path ( struct efi_local *local, const char *path ) { FILEPATH_DEVICE_PATH *fp = container_of ( efi_loaded_image->FilePath, FILEPATH_DEVICE_PATH, Header); - size_t fp_len = ( fp ? efi_devpath_len ( &fp->Header ) : 0 ); + size_t fp_len = ( fp ? efi_path_len ( &fp->Header ) : 0 ); char base[ fp_len / 2 /* Cannot exceed this length */ ]; size_t remaining = sizeof ( base ); size_t len; diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c new file mode 100644 index 000000000..1b297567c --- /dev/null +++ b/src/interface/efi/efi_path.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2020 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include + +/** @file + * + * EFI device paths + * + */ + +/** + * Find end of device path + * + * @v path Path to device + * @ret path_end End of device path + */ +EFI_DEVICE_PATH_PROTOCOL * efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path ) { + + while ( path->Type != END_DEVICE_PATH_TYPE ) { + path = ( ( ( void * ) path ) + + /* There's this amazing new-fangled thing known as + * a UINT16, but who wants to use one of those? */ + ( ( path->Length[1] << 8 ) | path->Length[0] ) ); + } + + return path; +} + +/** + * Find length of device path (excluding terminator) + * + * @v path Path to device + * @ret path_len Length of device path + */ +size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ) { + EFI_DEVICE_PATH_PROTOCOL *end = efi_path_end ( path ); + + return ( ( ( void * ) end ) - ( ( void * ) path ) ); +} diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c index d648700f6..f5c736a11 100644 --- a/src/interface/efi/efi_snp.c +++ b/src/interface/efi/efi_snp.c @@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include #include @@ -1714,7 +1715,7 @@ static int efi_snp_probe ( struct net_device *netdev ) { "%s", netdev->name ); /* Allocate the new device path */ - path_prefix_len = efi_devpath_len ( efidev->path ); + path_prefix_len = efi_path_len ( efidev->path ); snpdev->path = zalloc ( path_prefix_len + sizeof ( *macpath ) + sizeof ( *vlanpath ) + sizeof ( *path_end ) ); if ( ! snpdev->path ) { diff --git a/src/interface/efi/efi_snp_hii.c b/src/interface/efi/efi_snp_hii.c index 1e681a429..05c068a8c 100644 --- a/src/interface/efi/efi_snp_hii.c +++ b/src/interface/efi/efi_snp_hii.c @@ -63,6 +63,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include @@ -680,7 +681,7 @@ int efi_snp_hii_install ( struct efi_snp_device *snpdev ) { } /* Allocate the new device path */ - path_prefix_len = efi_devpath_len ( snpdev->path ); + path_prefix_len = efi_path_len ( snpdev->path ); snpdev->hii_child_path = zalloc ( path_prefix_len + sizeof ( *vendor_path ) + sizeof ( *path_end ) ); diff --git a/src/interface/efi/efi_usb.c b/src/interface/efi/efi_usb.c index 4ddc14910..7ffeb7ffa 100644 --- a/src/interface/efi/efi_usb.c +++ b/src/interface/efi/efi_usb.c @@ -30,7 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include +#include #include #include #include @@ -1120,7 +1120,7 @@ static int efi_usb_install ( struct efi_usb_device *usbdev, /* Calculate device path length */ path_count = ( usb_depth ( usbdev->usb ) + 1 ); - path_prefix_len = efi_devpath_len ( efidev->path ); + path_prefix_len = efi_path_len ( efidev->path ); path_len = ( path_prefix_len + ( path_count * sizeof ( *usbpath ) ) + sizeof ( *path_end ) ); diff --git a/src/interface/efi/efi_utils.c b/src/interface/efi/efi_utils.c index 4dc75414c..f8ffce915 100644 --- a/src/interface/efi/efi_utils.c +++ b/src/interface/efi/efi_utils.c @@ -32,36 +32,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/** - * Find end of device path - * - * @v path Path to device - * @ret path_end End of device path - */ -EFI_DEVICE_PATH_PROTOCOL * efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ) { - - while ( path->Type != END_DEVICE_PATH_TYPE ) { - path = ( ( ( void * ) path ) + - /* There's this amazing new-fangled thing known as - * a UINT16, but who wants to use one of those? */ - ( ( path->Length[1] << 8 ) | path->Length[0] ) ); - } - - return path; -} - -/** - * Find length of device path (excluding terminator) - * - * @v path Path to device - * @ret path_len Length of device path - */ -size_t efi_devpath_len ( EFI_DEVICE_PATH_PROTOCOL *path ) { - EFI_DEVICE_PATH_PROTOCOL *end = efi_devpath_end ( path ); - - return ( ( ( void * ) end ) - ( ( void * ) path ) ); -} - /** * Locate parent device supporting a given protocol * -- cgit v1.2.3-55-g7522 From 1e8648f6113691366729bbffc3412bcf3a27ece2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 16 Oct 2020 15:11:16 +0100 Subject: [usbblk] Allow USB block device to be described using an EFI device path Signed-off-by: Michael Brown --- src/drivers/usb/usbblk.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/drivers') diff --git a/src/drivers/usb/usbblk.c b/src/drivers/usb/usbblk.c index a68e3ced5..5a086d3f8 100644 --- a/src/drivers/usb/usbblk.c +++ b/src/drivers/usb/usbblk.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include "usbblk.h" /** @file @@ -702,11 +703,25 @@ static void usbblk_scsi_close ( struct usbblk_device *usbblk, int rc ) { usbblk->opened = 0; } +/** + * Describe as an EFI device path + * + * @v usbblk USB block device + * @ret path EFI device path, or NULL on error + */ +static EFI_DEVICE_PATH_PROTOCOL * +usbblk_efi_describe ( struct usbblk_device *usbblk ) { + + return efi_usb_path ( usbblk->func ); +} + /** SCSI command interface operations */ static struct interface_operation usbblk_scsi_operations[] = { INTF_OP ( scsi_command, struct usbblk_device *, usbblk_scsi_command ), INTF_OP ( xfer_window, struct usbblk_device *, usbblk_scsi_window ), INTF_OP ( intf_close, struct usbblk_device *, usbblk_scsi_close ), + EFI_INTF_OP ( efi_describe, struct usbblk_device *, + usbblk_efi_describe ), }; /** SCSI command interface descriptor */ -- cgit v1.2.3-55-g7522 From 16873703ddea2d64fac1809967ef5198b8764baa Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 30 Oct 2020 13:51:30 +0000 Subject: [efi] Avoid dragging in USB subsystem via efi_usb_path() Commit 87e39a9c9 ("[efi] Split efi_usb_path() out to a separate function") unintentionally introduced an undefined symbol reference from efi_path.o to usb_depth(), causing the USB subsystem to become a dependency of all EFI builds. Fix by converting usb_depth() to a static inline function. Reported-by: Pico Mitchell Signed-off-by: Michael Brown --- src/drivers/bus/usb.c | 17 ----------------- src/include/ipxe/usb.h | 18 +++++++++++++++++- 2 files changed, 17 insertions(+), 18 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/bus/usb.c b/src/drivers/bus/usb.c index 70a86c913..428ae26c1 100644 --- a/src/drivers/bus/usb.c +++ b/src/drivers/bus/usb.c @@ -2277,23 +2277,6 @@ unsigned int usb_route_string ( struct usb_device *usb ) { return route; } -/** - * Get USB depth - * - * @v usb USB device - * @ret depth Hub depth - */ -unsigned int usb_depth ( struct usb_device *usb ) { - struct usb_device *parent; - unsigned int depth; - - /* Navigate up to root hub, constructing depth as we go */ - for ( depth = 0 ; ( parent = usb->port->hub->usb ) ; usb = parent ) - depth++; - - return depth; -} - /** * Get USB root hub port * diff --git a/src/include/ipxe/usb.h b/src/include/ipxe/usb.h index f41f4c355..911247ede 100644 --- a/src/include/ipxe/usb.h +++ b/src/include/ipxe/usb.h @@ -1239,6 +1239,23 @@ usb_set_interface ( struct usb_device *usb, unsigned int interface, NULL, 0 ); } +/** + * Get USB depth + * + * @v usb USB device + * @ret depth Hub depth + */ +static inline unsigned int usb_depth ( struct usb_device *usb ) { + struct usb_device *parent; + unsigned int depth; + + /* Navigate up to root hub, constructing depth as we go */ + for ( depth = 0 ; ( parent = usb->port->hub->usb ) ; usb = parent ) + depth++; + + return depth; +} + extern struct list_head usb_buses; extern struct usb_interface_descriptor * @@ -1274,7 +1291,6 @@ extern struct usb_bus * find_usb_bus_by_location ( unsigned int bus_type, extern int usb_alloc_address ( struct usb_bus *bus ); extern void usb_free_address ( struct usb_bus *bus, unsigned int address ); extern unsigned int usb_route_string ( struct usb_device *usb ); -extern unsigned int usb_depth ( struct usb_device *usb ); extern struct usb_port * usb_root_hub_port ( struct usb_device *usb ); extern struct usb_port * usb_transaction_translator ( struct usb_device *usb ); -- cgit v1.2.3-55-g7522 From f560e7b70b5b1a3ecd2d03d8f319e79327dbd6c3 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 4 Nov 2020 14:24:52 +0000 Subject: [realtek] Reset NIC when closing interface if using legacy mode The legacy transmit descriptor index is not reset by anything short of a full device reset. This can cause the legacy transmit ring to stall after closing and reopening the device, since the hardware and software indices will be out of sync. Fix by performing a reset after closing the interface. Do this only if operating in legacy mode, since in C+ mode the reset is not required and would undesirably clear additional state (such as the C+ command register itself). Signed-off-by: Michael Brown --- src/drivers/net/realtek.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/drivers') diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index 0421b4db7..e74128c4c 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -768,6 +768,10 @@ static void realtek_close ( struct net_device *netdev ) { /* Destroy transmit descriptor ring */ realtek_destroy_ring ( rtl, &rtl->tx ); + + /* Reset legacy transmit descriptor index, if applicable */ + if ( rtl->legacy ) + realtek_reset ( rtl ); } /** -- cgit v1.2.3-55-g7522 From be1c87b72237f633c4f4b05bcb133acf2967d788 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 5 Nov 2020 19:08:48 +0000 Subject: [malloc] Rename malloc_dma() to malloc_phys() The malloc_dma() function allocates memory with specified physical alignment, and is typically (though not exclusively) used to allocate memory for DMA. Rename to malloc_phys() to more closely match the functionality, and to create name space for functions that specifically allocate and map DMA-capable buffers. Signed-off-by: Michael Brown --- src/arch/x86/drivers/hyperv/hyperv.c | 12 ++--- src/arch/x86/drivers/xen/hvm.c | 4 +- src/core/iobuf.c | 12 ++--- src/core/malloc.c | 4 +- src/drivers/infiniband/arbel.c | 62 +++++++++++----------- src/drivers/infiniband/golan.c | 58 ++++++++++---------- src/drivers/infiniband/hermon.c | 60 ++++++++++----------- src/drivers/infiniband/linda.c | 16 +++--- .../mlx_utils_flexboot/src/mlx_memory_priv.c | 4 +- src/drivers/infiniband/qib7322.c | 16 +++--- src/drivers/net/3c90x.c | 8 +-- src/drivers/net/ath/ath5k/ath5k.c | 6 +-- src/drivers/net/ath/ath9k/ath9k_init.c | 6 +-- src/drivers/net/atl1e.c | 4 +- src/drivers/net/b44.c | 12 ++--- src/drivers/net/bnxt/bnxt.c | 30 +++++------ src/drivers/net/eepro100.c | 18 +++---- src/drivers/net/ena.c | 24 ++++----- src/drivers/net/etherfabric.c | 4 +- src/drivers/net/exanic.c | 6 +-- src/drivers/net/forcedeth.c | 4 +- src/drivers/net/icplus.c | 6 +-- src/drivers/net/igbvf/igbvf_main.c | 10 ++-- src/drivers/net/intel.c | 4 +- src/drivers/net/intelxl.c | 10 ++-- src/drivers/net/jme.c | 8 +-- src/drivers/net/myri10ge.c | 8 +-- src/drivers/net/myson.c | 6 +-- src/drivers/net/natsemi.c | 6 +-- src/drivers/net/netfront.c | 6 +-- src/drivers/net/pcnet32.c | 8 +-- src/drivers/net/phantom/phantom.c | 16 +++--- src/drivers/net/realtek.c | 10 ++-- src/drivers/net/rhine.c | 4 +- src/drivers/net/rtl818x/rtl818x.c | 12 ++--- src/drivers/net/sfc/efx_hunt.c | 4 +- src/drivers/net/sis190.c | 8 +-- src/drivers/net/skge.c | 4 +- src/drivers/net/sky2.c | 14 ++--- src/drivers/net/tg3/tg3.c | 20 +++---- src/drivers/net/velocity.c | 12 +++-- src/drivers/net/vmxnet3.c | 7 +-- src/drivers/net/vxge/vxge_config.c | 12 ++--- src/drivers/usb/ehci.c | 29 +++++----- src/drivers/usb/uhci.c | 26 ++++----- src/drivers/usb/xhci.c | 42 +++++++-------- src/include/ipxe/malloc.h | 32 +++++------ src/interface/hyperv/vmbus.c | 6 +-- 48 files changed, 350 insertions(+), 350 deletions(-) (limited to 'src/drivers') diff --git a/src/arch/x86/drivers/hyperv/hyperv.c b/src/arch/x86/drivers/hyperv/hyperv.c index 1903d1db2..9d3a42da0 100644 --- a/src/arch/x86/drivers/hyperv/hyperv.c +++ b/src/arch/x86/drivers/hyperv/hyperv.c @@ -83,7 +83,7 @@ hv_alloc_pages ( struct hv_hypervisor *hv, ... ) { /* Allocate and zero pages */ va_start ( args, hv ); for ( i = 0 ; ( ( page = va_arg ( args, void ** ) ) != NULL ); i++ ) { - *page = malloc_dma ( PAGE_SIZE, PAGE_SIZE ); + *page = malloc_phys ( PAGE_SIZE, PAGE_SIZE ); if ( ! *page ) goto err_alloc; memset ( *page, 0, PAGE_SIZE ); @@ -97,7 +97,7 @@ hv_alloc_pages ( struct hv_hypervisor *hv, ... ) { va_start ( args, hv ); for ( ; i >= 0 ; i-- ) { page = va_arg ( args, void ** ); - free_dma ( *page, PAGE_SIZE ); + free_phys ( *page, PAGE_SIZE ); } va_end ( args ); return -ENOMEM; @@ -116,7 +116,7 @@ hv_free_pages ( struct hv_hypervisor *hv, ... ) { va_start ( args, hv ); while ( ( page = va_arg ( args, void * ) ) != NULL ) - free_dma ( page, PAGE_SIZE ); + free_phys ( page, PAGE_SIZE ); va_end ( args ); } @@ -131,8 +131,8 @@ static int hv_alloc_message ( struct hv_hypervisor *hv ) { /* Allocate buffer. Must be aligned to at least 8 bytes and * must not cross a page boundary, so align on its own size. */ - hv->message = malloc_dma ( sizeof ( *hv->message ), - sizeof ( *hv->message ) ); + hv->message = malloc_phys ( sizeof ( *hv->message ), + sizeof ( *hv->message ) ); if ( ! hv->message ) return -ENOMEM; @@ -147,7 +147,7 @@ static int hv_alloc_message ( struct hv_hypervisor *hv ) { static void hv_free_message ( struct hv_hypervisor *hv ) { /* Free buffer */ - free_dma ( hv->message, sizeof ( *hv->message ) ); + free_phys ( hv->message, sizeof ( *hv->message ) ); } /** diff --git a/src/arch/x86/drivers/xen/hvm.c b/src/arch/x86/drivers/xen/hvm.c index 311f343ca..b77cdd14c 100644 --- a/src/arch/x86/drivers/xen/hvm.c +++ b/src/arch/x86/drivers/xen/hvm.c @@ -106,7 +106,7 @@ static int hvm_map_hypercall ( struct hvm_device *hvm ) { /* Allocate pages */ hvm->hypercall_len = ( pages * PAGE_SIZE ); - hvm->xen.hypercall = malloc_dma ( hvm->hypercall_len, PAGE_SIZE ); + hvm->xen.hypercall = malloc_phys ( hvm->hypercall_len, PAGE_SIZE ); if ( ! hvm->xen.hypercall ) { DBGC ( hvm, "HVM could not allocate %d hypercall page(s)\n", pages ); @@ -141,7 +141,7 @@ static int hvm_map_hypercall ( struct hvm_device *hvm ) { static void hvm_unmap_hypercall ( struct hvm_device *hvm ) { /* Free pages */ - free_dma ( hvm->xen.hypercall, hvm->hypercall_len ); + free_phys ( hvm->xen.hypercall, hvm->hypercall_len ); } /** diff --git a/src/core/iobuf.c b/src/core/iobuf.c index 0ee53e038..941bb3446 100644 --- a/src/core/iobuf.c +++ b/src/core/iobuf.c @@ -88,8 +88,8 @@ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { len += ( ( - len - offset ) & ( __alignof__ ( *iobuf ) - 1 ) ); /* Allocate memory for buffer plus descriptor */ - data = malloc_dma_offset ( len + sizeof ( *iobuf ), align, - offset ); + data = malloc_phys_offset ( len + sizeof ( *iobuf ), align, + offset ); if ( ! data ) return NULL; iobuf = ( data + len ); @@ -97,14 +97,14 @@ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { } else { /* Allocate memory for buffer */ - data = malloc_dma_offset ( len, align, offset ); + data = malloc_phys_offset ( len, align, offset ); if ( ! data ) return NULL; /* Allocate memory for descriptor */ iobuf = malloc ( sizeof ( *iobuf ) ); if ( ! iobuf ) { - free_dma ( data, len ); + free_phys ( data, len ); return NULL; } } @@ -159,12 +159,12 @@ void free_iob ( struct io_buffer *iobuf ) { if ( iobuf->end == iobuf ) { /* Descriptor is inline */ - free_dma ( iobuf->head, ( len + sizeof ( *iobuf ) ) ); + free_phys ( iobuf->head, ( len + sizeof ( *iobuf ) ) ); } else { /* Descriptor is detached */ - free_dma ( iobuf->head, len ); + free_phys ( iobuf->head, len ); free ( iobuf ); } } diff --git a/src/core/malloc.c b/src/core/malloc.c index 0a7843a14..8499ab45a 100644 --- a/src/core/malloc.c +++ b/src/core/malloc.c @@ -596,8 +596,8 @@ void * malloc ( size_t size ) { * * @v ptr Memory allocated by malloc(), or NULL * - * Memory allocated with malloc_dma() cannot be freed with free(); it - * must be freed with free_dma() instead. + * Memory allocated with malloc_phys() cannot be freed with free(); it + * must be freed with free_phys() instead. * * If @c ptr is NULL, no action is taken. */ diff --git a/src/drivers/infiniband/arbel.c b/src/drivers/infiniband/arbel.c index eb7911aa4..fb48487f3 100644 --- a/src/drivers/infiniband/arbel.c +++ b/src/drivers/infiniband/arbel.c @@ -639,8 +639,8 @@ static int arbel_create_cq ( struct ib_device *ibdev, /* Allocate completion queue itself */ arbel_cq->cqe_size = ( cq->num_cqes * sizeof ( arbel_cq->cqe[0] ) ); - arbel_cq->cqe = malloc_dma ( arbel_cq->cqe_size, - sizeof ( arbel_cq->cqe[0] ) ); + arbel_cq->cqe = malloc_phys ( arbel_cq->cqe_size, + sizeof ( arbel_cq->cqe[0] ) ); if ( ! arbel_cq->cqe ) { rc = -ENOMEM; goto err_cqe; @@ -697,7 +697,7 @@ static int arbel_create_cq ( struct ib_device *ibdev, err_sw2hw_cq: MLX_FILL_1 ( ci_db_rec, 1, res, ARBEL_UAR_RES_NONE ); MLX_FILL_1 ( arm_db_rec, 1, res, ARBEL_UAR_RES_NONE ); - free_dma ( arbel_cq->cqe, arbel_cq->cqe_size ); + free_phys ( arbel_cq->cqe, arbel_cq->cqe_size ); err_cqe: free ( arbel_cq ); err_arbel_cq: @@ -737,7 +737,7 @@ static void arbel_destroy_cq ( struct ib_device *ibdev, MLX_FILL_1 ( arm_db_rec, 1, res, ARBEL_UAR_RES_NONE ); /* Free memory */ - free_dma ( arbel_cq->cqe, arbel_cq->cqe_size ); + free_phys ( arbel_cq->cqe, arbel_cq->cqe_size ); free ( arbel_cq ); /* Mark queue number as free */ @@ -873,8 +873,8 @@ static int arbel_create_send_wq ( struct arbel_send_work_queue *arbel_send_wq, /* Allocate work queue */ arbel_send_wq->wqe_size = ( num_wqes * sizeof ( arbel_send_wq->wqe[0] ) ); - arbel_send_wq->wqe = malloc_dma ( arbel_send_wq->wqe_size, - sizeof ( arbel_send_wq->wqe[0] ) ); + arbel_send_wq->wqe = malloc_phys ( arbel_send_wq->wqe_size, + sizeof ( arbel_send_wq->wqe[0] ) ); if ( ! arbel_send_wq->wqe ) return -ENOMEM; memset ( arbel_send_wq->wqe, 0, arbel_send_wq->wqe_size ); @@ -914,8 +914,8 @@ static int arbel_create_recv_wq ( struct arbel_recv_work_queue *arbel_recv_wq, /* Allocate work queue */ arbel_recv_wq->wqe_size = ( num_wqes * sizeof ( arbel_recv_wq->wqe[0] ) ); - arbel_recv_wq->wqe = malloc_dma ( arbel_recv_wq->wqe_size, - sizeof ( arbel_recv_wq->wqe[0] ) ); + arbel_recv_wq->wqe = malloc_phys ( arbel_recv_wq->wqe_size, + sizeof ( arbel_recv_wq->wqe[0] ) ); if ( ! arbel_recv_wq->wqe ) { rc = -ENOMEM; goto err_alloc_wqe; @@ -927,8 +927,8 @@ static int arbel_create_recv_wq ( struct arbel_recv_work_queue *arbel_recv_wq, ( type == IB_QPT_UD ) ) { arbel_recv_wq->grh_size = ( num_wqes * sizeof ( arbel_recv_wq->grh[0] ) ); - arbel_recv_wq->grh = malloc_dma ( arbel_recv_wq->grh_size, - sizeof ( void * ) ); + arbel_recv_wq->grh = malloc_phys ( arbel_recv_wq->grh_size, + sizeof ( void * ) ); if ( ! arbel_recv_wq->grh ) { rc = -ENOMEM; goto err_alloc_grh; @@ -954,9 +954,9 @@ static int arbel_create_recv_wq ( struct arbel_recv_work_queue *arbel_recv_wq, return 0; - free_dma ( arbel_recv_wq->grh, arbel_recv_wq->grh_size ); + free_phys ( arbel_recv_wq->grh, arbel_recv_wq->grh_size ); err_alloc_grh: - free_dma ( arbel_recv_wq->wqe, arbel_recv_wq->wqe_size ); + free_phys ( arbel_recv_wq->wqe, arbel_recv_wq->wqe_size ); err_alloc_wqe: return rc; } @@ -1102,10 +1102,10 @@ static int arbel_create_qp ( struct ib_device *ibdev, MLX_FILL_1 ( send_db_rec, 1, res, ARBEL_UAR_RES_NONE ); MLX_FILL_1 ( recv_db_rec, 1, res, ARBEL_UAR_RES_NONE ); err_unsupported_address_split: - free_dma ( arbel_qp->recv.grh, arbel_qp->recv.grh_size ); - free_dma ( arbel_qp->recv.wqe, arbel_qp->recv.wqe_size ); + free_phys ( arbel_qp->recv.grh, arbel_qp->recv.grh_size ); + free_phys ( arbel_qp->recv.wqe, arbel_qp->recv.wqe_size ); err_create_recv_wq: - free_dma ( arbel_qp->send.wqe, arbel_qp->send.wqe_size ); + free_phys ( arbel_qp->send.wqe, arbel_qp->send.wqe_size ); err_create_send_wq: free ( arbel_qp ); err_arbel_qp: @@ -1231,9 +1231,9 @@ static void arbel_destroy_qp ( struct ib_device *ibdev, MLX_FILL_1 ( recv_db_rec, 1, res, ARBEL_UAR_RES_NONE ); /* Free memory */ - free_dma ( arbel_qp->recv.grh, arbel_qp->recv.grh_size ); - free_dma ( arbel_qp->recv.wqe, arbel_qp->recv.wqe_size ); - free_dma ( arbel_qp->send.wqe, arbel_qp->send.wqe_size ); + free_phys ( arbel_qp->recv.grh, arbel_qp->recv.grh_size ); + free_phys ( arbel_qp->recv.wqe, arbel_qp->recv.wqe_size ); + free_phys ( arbel_qp->send.wqe, arbel_qp->send.wqe_size ); free ( arbel_qp ); /* Mark queue number as free */ @@ -1758,8 +1758,8 @@ static int arbel_create_eq ( struct arbel *arbel ) { /* Allocate event queue itself */ arbel_eq->eqe_size = ( ARBEL_NUM_EQES * sizeof ( arbel_eq->eqe[0] ) ); - arbel_eq->eqe = malloc_dma ( arbel_eq->eqe_size, - sizeof ( arbel_eq->eqe[0] ) ); + arbel_eq->eqe = malloc_phys ( arbel_eq->eqe_size, + sizeof ( arbel_eq->eqe[0] ) ); if ( ! arbel_eq->eqe ) { rc = -ENOMEM; goto err_eqe; @@ -1806,7 +1806,7 @@ static int arbel_create_eq ( struct arbel *arbel ) { err_map_eq: arbel_cmd_hw2sw_eq ( arbel, arbel_eq->eqn, &eqctx ); err_sw2hw_eq: - free_dma ( arbel_eq->eqe, arbel_eq->eqe_size ); + free_phys ( arbel_eq->eqe, arbel_eq->eqe_size ); err_eqe: memset ( arbel_eq, 0, sizeof ( *arbel_eq ) ); return rc; @@ -1844,7 +1844,7 @@ static void arbel_destroy_eq ( struct arbel *arbel ) { } /* Free memory */ - free_dma ( arbel_eq->eqe, arbel_eq->eqe_size ); + free_phys ( arbel_eq->eqe, arbel_eq->eqe_size ); memset ( arbel_eq, 0, sizeof ( *arbel_eq ) ); } @@ -2455,7 +2455,7 @@ static int arbel_alloc_icm ( struct arbel *arbel, icm_phys = user_to_phys ( arbel->icm, 0 ); /* Allocate doorbell UAR */ - arbel->db_rec = malloc_dma ( ARBEL_PAGE_SIZE, ARBEL_PAGE_SIZE ); + arbel->db_rec = malloc_phys ( ARBEL_PAGE_SIZE, ARBEL_PAGE_SIZE ); if ( ! arbel->db_rec ) { rc = -ENOMEM; goto err_alloc_doorbell; @@ -2513,7 +2513,7 @@ static int arbel_alloc_icm ( struct arbel *arbel, err_map_icm: arbel_cmd_unmap_icm_aux ( arbel ); err_map_icm_aux: - free_dma ( arbel->db_rec, ARBEL_PAGE_SIZE ); + free_phys ( arbel->db_rec, ARBEL_PAGE_SIZE ); arbel->db_rec= NULL; err_alloc_doorbell: err_alloc_icm: @@ -2536,7 +2536,7 @@ static void arbel_free_icm ( struct arbel *arbel ) { arbel_cmd_unmap_icm ( arbel, ( arbel->icm_len / ARBEL_PAGE_SIZE ), &unmap_icm ); arbel_cmd_unmap_icm_aux ( arbel ); - free_dma ( arbel->db_rec, ARBEL_PAGE_SIZE ); + free_phys ( arbel->db_rec, ARBEL_PAGE_SIZE ); arbel->db_rec = NULL; } @@ -2984,18 +2984,18 @@ static struct arbel * arbel_alloc ( void ) { goto err_arbel; /* Allocate space for mailboxes */ - arbel->mailbox_in = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN ); + arbel->mailbox_in = malloc_phys ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN ); if ( ! arbel->mailbox_in ) goto err_mailbox_in; - arbel->mailbox_out = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN ); + arbel->mailbox_out = malloc_phys ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN ); if ( ! arbel->mailbox_out ) goto err_mailbox_out; return arbel; - free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE ); + free_phys ( arbel->mailbox_out, ARBEL_MBOX_SIZE ); err_mailbox_out: - free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE ); + free_phys ( arbel->mailbox_in, ARBEL_MBOX_SIZE ); err_mailbox_in: free ( arbel ); err_arbel: @@ -3011,8 +3011,8 @@ static void arbel_free ( struct arbel *arbel ) { ufree ( arbel->icm ); ufree ( arbel->firmware_area ); - free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE ); - free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE ); + free_phys ( arbel->mailbox_out, ARBEL_MBOX_SIZE ); + free_phys ( arbel->mailbox_in, ARBEL_MBOX_SIZE ); free ( arbel ); } diff --git a/src/drivers/infiniband/golan.c b/src/drivers/infiniband/golan.c index 7ab4a4ee6..9bd810e23 100755 --- a/src/drivers/infiniband/golan.c +++ b/src/drivers/infiniband/golan.c @@ -585,9 +585,9 @@ static inline int golan_set_access_reg ( struct golan *golan __attribute__ (( un static inline void golan_cmd_uninit ( struct golan *golan ) { - free_dma(golan->mboxes.outbox, GOLAN_PAGE_SIZE); - free_dma(golan->mboxes.inbox, GOLAN_PAGE_SIZE); - free_dma(golan->cmd.addr, GOLAN_PAGE_SIZE); + free_phys(golan->mboxes.outbox, GOLAN_PAGE_SIZE); + free_phys(golan->mboxes.inbox, GOLAN_PAGE_SIZE); + free_phys(golan->cmd.addr, GOLAN_PAGE_SIZE); } /** @@ -602,17 +602,17 @@ static inline int golan_cmd_init ( struct golan *golan ) int rc = 0; uint32_t addr_l_sz; - if (!(golan->cmd.addr = malloc_dma(GOLAN_PAGE_SIZE , GOLAN_PAGE_SIZE))) { + if (!(golan->cmd.addr = malloc_phys(GOLAN_PAGE_SIZE , GOLAN_PAGE_SIZE))) { rc = -ENOMEM; - goto malloc_dma_failed; + goto malloc_phys_failed; } - if (!(golan->mboxes.inbox = malloc_dma(GOLAN_PAGE_SIZE , GOLAN_PAGE_SIZE))) { + if (!(golan->mboxes.inbox = malloc_phys(GOLAN_PAGE_SIZE , GOLAN_PAGE_SIZE))) { rc = -ENOMEM; - goto malloc_dma_inbox_failed; + goto malloc_phys_inbox_failed; } - if (!(golan->mboxes.outbox = malloc_dma(GOLAN_PAGE_SIZE , GOLAN_PAGE_SIZE))) { + if (!(golan->mboxes.outbox = malloc_phys(GOLAN_PAGE_SIZE , GOLAN_PAGE_SIZE))) { rc = -ENOMEM; - goto malloc_dma_outbox_failed; + goto malloc_phys_outbox_failed; } addr_l_sz = be32_to_cpu(readl(&golan->iseg->cmdq_addr_l_sz)); @@ -629,11 +629,11 @@ static inline int golan_cmd_init ( struct golan *golan ) DBGC( golan , "%s Command interface was initialized\n", __FUNCTION__); return 0; -malloc_dma_outbox_failed: - free_dma(golan->mboxes.inbox, GOLAN_PAGE_SIZE); -malloc_dma_inbox_failed: - free_dma(golan->cmd.addr, GOLAN_PAGE_SIZE); -malloc_dma_failed: +malloc_phys_outbox_failed: + free_phys(golan->mboxes.inbox, GOLAN_PAGE_SIZE); +malloc_phys_inbox_failed: + free_phys(golan->cmd.addr, GOLAN_PAGE_SIZE); +malloc_phys_failed: DBGC (golan ,"%s Failed to initialize command interface (rc = 0x%x)\n", __FUNCTION__, rc); return rc; @@ -743,7 +743,7 @@ static int golan_create_eq(struct golan *golan) eq->cons_index = 0; eq->size = GOLAN_NUM_EQES * sizeof(eq->eqes[0]); - eq->eqes = malloc_dma ( GOLAN_PAGE_SIZE, GOLAN_PAGE_SIZE ); + eq->eqes = malloc_phys ( GOLAN_PAGE_SIZE, GOLAN_PAGE_SIZE ); if (!eq->eqes) { rc = -ENOMEM; goto err_create_eq_eqe_alloc; @@ -781,7 +781,7 @@ static int golan_create_eq(struct golan *golan) return 0; err_create_eq_cmd: - free_dma ( eq->eqes , GOLAN_PAGE_SIZE ); + free_phys ( eq->eqes , GOLAN_PAGE_SIZE ); err_create_eq_eqe_alloc: DBGC (golan ,"%s [%d] out\n", __FUNCTION__, rc); return rc; @@ -806,7 +806,7 @@ static void golan_destory_eq(struct golan *golan) rc = send_command_and_wait(golan, DEF_CMD_IDX, NO_MBOX, NO_MBOX, __FUNCTION__); GOLAN_PRINT_RC_AND_CMD_STATUS; - free_dma ( golan->eq.eqes , GOLAN_PAGE_SIZE ); + free_phys ( golan->eq.eqes , GOLAN_PAGE_SIZE ); golan->eq.eqn = 0; DBGC( golan, "%s Event queue (0x%x) was destroyed\n", __FUNCTION__, eqn); @@ -962,14 +962,14 @@ static int golan_create_cq(struct ib_device *ibdev, goto err_create_cq; } golan_cq->size = sizeof(golan_cq->cqes[0]) * cq->num_cqes; - golan_cq->doorbell_record = malloc_dma(GOLAN_CQ_DB_RECORD_SIZE, + golan_cq->doorbell_record = malloc_phys(GOLAN_CQ_DB_RECORD_SIZE, GOLAN_CQ_DB_RECORD_SIZE); if (!golan_cq->doorbell_record) { rc = -ENOMEM; goto err_create_cq_db_alloc; } - golan_cq->cqes = malloc_dma ( GOLAN_PAGE_SIZE, GOLAN_PAGE_SIZE ); + golan_cq->cqes = malloc_phys ( GOLAN_PAGE_SIZE, GOLAN_PAGE_SIZE ); if (!golan_cq->cqes) { rc = -ENOMEM; goto err_create_cq_cqe_alloc; @@ -1008,9 +1008,9 @@ static int golan_create_cq(struct ib_device *ibdev, return 0; err_create_cq_cmd: - free_dma( golan_cq->cqes , GOLAN_PAGE_SIZE ); + free_phys( golan_cq->cqes , GOLAN_PAGE_SIZE ); err_create_cq_cqe_alloc: - free_dma(golan_cq->doorbell_record, GOLAN_CQ_DB_RECORD_SIZE); + free_phys(golan_cq->doorbell_record, GOLAN_CQ_DB_RECORD_SIZE); err_create_cq_db_alloc: free ( golan_cq ); err_create_cq: @@ -1045,8 +1045,8 @@ static void golan_destroy_cq(struct ib_device *ibdev, cq->cqn = 0; ib_cq_set_drvdata(cq, NULL); - free_dma ( golan_cq->cqes , GOLAN_PAGE_SIZE ); - free_dma(golan_cq->doorbell_record, GOLAN_CQ_DB_RECORD_SIZE); + free_phys ( golan_cq->cqes , GOLAN_PAGE_SIZE ); + free_phys(golan_cq->doorbell_record, GOLAN_CQ_DB_RECORD_SIZE); free(golan_cq); DBGC (golan, "%s CQ number 0x%x was destroyed\n", __FUNCTION__, cqn); @@ -1138,7 +1138,7 @@ static int golan_create_qp_aux(struct ib_device *ibdev, golan_qp->size = golan_qp->sq.size + golan_qp->rq.size; /* allocate dma memory for WQEs (1 page is enough) - should change it */ - golan_qp->wqes = malloc_dma ( GOLAN_PAGE_SIZE, GOLAN_PAGE_SIZE ); + golan_qp->wqes = malloc_phys ( GOLAN_PAGE_SIZE, GOLAN_PAGE_SIZE ); if (!golan_qp->wqes) { rc = -ENOMEM; goto err_create_qp_wqe_alloc; @@ -1160,7 +1160,7 @@ static int golan_create_qp_aux(struct ib_device *ibdev, data++; } - golan_qp->doorbell_record = malloc_dma(sizeof(struct golan_qp_db), + golan_qp->doorbell_record = malloc_phys(sizeof(struct golan_qp_db), sizeof(struct golan_qp_db)); if (!golan_qp->doorbell_record) { rc = -ENOMEM; @@ -1213,9 +1213,9 @@ static int golan_create_qp_aux(struct ib_device *ibdev, return 0; err_create_qp_cmd: - free_dma(golan_qp->doorbell_record, sizeof(struct golan_qp_db)); + free_phys(golan_qp->doorbell_record, sizeof(struct golan_qp_db)); err_create_qp_db_alloc: - free_dma ( golan_qp->wqes, GOLAN_PAGE_SIZE ); + free_phys ( golan_qp->wqes, GOLAN_PAGE_SIZE ); err_create_qp_wqe_alloc: err_create_qp_sq_size: err_create_qp_sq_wqe_size: @@ -1422,8 +1422,8 @@ static void golan_destroy_qp(struct ib_device *ibdev, qp->qpn = 0; ib_qp_set_drvdata(qp, NULL); - free_dma(golan_qp->doorbell_record, sizeof(struct golan_qp_db)); - free_dma ( golan_qp->wqes, GOLAN_PAGE_SIZE ); + free_phys(golan_qp->doorbell_record, sizeof(struct golan_qp_db)); + free_phys ( golan_qp->wqes, GOLAN_PAGE_SIZE ); free(golan_qp); DBGC( golan ,"%s QP 0x%lx was destroyed\n", __FUNCTION__, qpn); diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index b6599588f..fdf2d9dd8 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -864,8 +864,8 @@ static int hermon_create_cq ( struct ib_device *ibdev, } /* Allocate doorbell */ - hermon_cq->doorbell = malloc_dma ( sizeof ( hermon_cq->doorbell[0] ), - sizeof ( hermon_cq->doorbell[0] ) ); + hermon_cq->doorbell = malloc_phys ( sizeof ( hermon_cq->doorbell[0] ), + sizeof ( hermon_cq->doorbell[0] ) ); if ( ! hermon_cq->doorbell ) { rc = -ENOMEM; goto err_doorbell; @@ -874,8 +874,8 @@ static int hermon_create_cq ( struct ib_device *ibdev, /* Allocate completion queue itself */ hermon_cq->cqe_size = ( cq->num_cqes * sizeof ( hermon_cq->cqe[0] ) ); - hermon_cq->cqe = malloc_dma ( hermon_cq->cqe_size, - sizeof ( hermon_cq->cqe[0] ) ); + hermon_cq->cqe = malloc_phys ( hermon_cq->cqe_size, + sizeof ( hermon_cq->cqe[0] ) ); if ( ! hermon_cq->cqe ) { rc = -ENOMEM; goto err_cqe; @@ -925,9 +925,9 @@ static int hermon_create_cq ( struct ib_device *ibdev, err_sw2hw_cq: hermon_free_mtt ( hermon, &hermon_cq->mtt ); err_alloc_mtt: - free_dma ( hermon_cq->cqe, hermon_cq->cqe_size ); + free_phys ( hermon_cq->cqe, hermon_cq->cqe_size ); err_cqe: - free_dma ( hermon_cq->doorbell, sizeof ( hermon_cq->doorbell[0] ) ); + free_phys ( hermon_cq->doorbell, sizeof ( hermon_cq->doorbell[0] ) ); err_doorbell: free ( hermon_cq ); err_hermon_cq: @@ -962,8 +962,8 @@ static void hermon_destroy_cq ( struct ib_device *ibdev, hermon_free_mtt ( hermon, &hermon_cq->mtt ); /* Free memory */ - free_dma ( hermon_cq->cqe, hermon_cq->cqe_size ); - free_dma ( hermon_cq->doorbell, sizeof ( hermon_cq->doorbell[0] ) ); + free_phys ( hermon_cq->cqe, hermon_cq->cqe_size ); + free_phys ( hermon_cq->doorbell, sizeof ( hermon_cq->doorbell[0] ) ); free ( hermon_cq ); /* Mark queue number as free */ @@ -1128,8 +1128,8 @@ static int hermon_create_qp ( struct ib_device *ibdev, /* Allocate doorbells */ hermon_qp->recv.doorbell = - malloc_dma ( sizeof ( hermon_qp->recv.doorbell[0] ), - sizeof ( hermon_qp->recv.doorbell[0] ) ); + malloc_phys ( sizeof ( hermon_qp->recv.doorbell[0] ), + sizeof ( hermon_qp->recv.doorbell[0] ) ); if ( ! hermon_qp->recv.doorbell ) { rc = -ENOMEM; goto err_recv_doorbell; @@ -1157,8 +1157,8 @@ static int hermon_create_qp ( struct ib_device *ibdev, hermon_qp->wqe_size = ( hermon_qp->send.wqe_size + hermon_qp->recv.wqe_size + hermon_qp->recv.grh_size ); - hermon_qp->wqe = malloc_dma ( hermon_qp->wqe_size, - sizeof ( hermon_qp->send.wqe[0] ) ); + hermon_qp->wqe = malloc_phys ( hermon_qp->wqe_size, + sizeof ( hermon_qp->send.wqe[0] ) ); if ( ! hermon_qp->wqe ) { rc = -ENOMEM; goto err_alloc_wqe; @@ -1248,10 +1248,10 @@ static int hermon_create_qp ( struct ib_device *ibdev, err_rst2init_qp: hermon_free_mtt ( hermon, &hermon_qp->mtt ); err_alloc_mtt: - free_dma ( hermon_qp->wqe, hermon_qp->wqe_size ); + free_phys ( hermon_qp->wqe, hermon_qp->wqe_size ); err_alloc_wqe: - free_dma ( hermon_qp->recv.doorbell, - sizeof ( hermon_qp->recv.doorbell[0] ) ); + free_phys ( hermon_qp->recv.doorbell, + sizeof ( hermon_qp->recv.doorbell[0] ) ); err_recv_doorbell: free ( hermon_qp ); err_hermon_qp: @@ -1363,9 +1363,9 @@ static void hermon_destroy_qp ( struct ib_device *ibdev, hermon_free_mtt ( hermon, &hermon_qp->mtt ); /* Free memory */ - free_dma ( hermon_qp->wqe, hermon_qp->wqe_size ); - free_dma ( hermon_qp->recv.doorbell, - sizeof ( hermon_qp->recv.doorbell[0] ) ); + free_phys ( hermon_qp->wqe, hermon_qp->wqe_size ); + free_phys ( hermon_qp->recv.doorbell, + sizeof ( hermon_qp->recv.doorbell[0] ) ); free ( hermon_qp ); /* Mark queue number as free */ @@ -1887,8 +1887,8 @@ static int hermon_create_eq ( struct hermon *hermon ) { /* Allocate event queue itself */ hermon_eq->eqe_size = ( HERMON_NUM_EQES * sizeof ( hermon_eq->eqe[0] ) ); - hermon_eq->eqe = malloc_dma ( hermon_eq->eqe_size, - sizeof ( hermon_eq->eqe[0] ) ); + hermon_eq->eqe = malloc_phys ( hermon_eq->eqe_size, + sizeof ( hermon_eq->eqe[0] ) ); if ( ! hermon_eq->eqe ) { rc = -ENOMEM; goto err_eqe; @@ -1946,7 +1946,7 @@ static int hermon_create_eq ( struct hermon *hermon ) { err_sw2hw_eq: hermon_free_mtt ( hermon, &hermon_eq->mtt ); err_alloc_mtt: - free_dma ( hermon_eq->eqe, hermon_eq->eqe_size ); + free_phys ( hermon_eq->eqe, hermon_eq->eqe_size ); err_eqe: memset ( hermon_eq, 0, sizeof ( *hermon_eq ) ); return rc; @@ -1986,7 +1986,7 @@ static void hermon_destroy_eq ( struct hermon *hermon ) { hermon_free_mtt ( hermon, &hermon_eq->mtt ); /* Free memory */ - free_dma ( hermon_eq->eqe, hermon_eq->eqe_size ); + free_phys ( hermon_eq->eqe, hermon_eq->eqe_size ); memset ( hermon_eq, 0, sizeof ( *hermon_eq ) ); } @@ -3736,20 +3736,20 @@ static struct hermon * hermon_alloc ( void ) { goto err_hermon; /* Allocate space for mailboxes */ - hermon->mailbox_in = malloc_dma ( HERMON_MBOX_SIZE, - HERMON_MBOX_ALIGN ); + hermon->mailbox_in = malloc_phys ( HERMON_MBOX_SIZE, + HERMON_MBOX_ALIGN ); if ( ! hermon->mailbox_in ) goto err_mailbox_in; - hermon->mailbox_out = malloc_dma ( HERMON_MBOX_SIZE, - HERMON_MBOX_ALIGN ); + hermon->mailbox_out = malloc_phys ( HERMON_MBOX_SIZE, + HERMON_MBOX_ALIGN ); if ( ! hermon->mailbox_out ) goto err_mailbox_out; return hermon; - free_dma ( hermon->mailbox_out, HERMON_MBOX_SIZE ); + free_phys ( hermon->mailbox_out, HERMON_MBOX_SIZE ); err_mailbox_out: - free_dma ( hermon->mailbox_in, HERMON_MBOX_SIZE ); + free_phys ( hermon->mailbox_in, HERMON_MBOX_SIZE ); err_mailbox_in: free ( hermon ); err_hermon: @@ -3765,8 +3765,8 @@ static void hermon_free ( struct hermon *hermon ) { ufree ( hermon->icm ); ufree ( hermon->firmware_area ); - free_dma ( hermon->mailbox_out, HERMON_MBOX_SIZE ); - free_dma ( hermon->mailbox_in, HERMON_MBOX_SIZE ); + free_phys ( hermon->mailbox_out, HERMON_MBOX_SIZE ); + free_phys ( hermon->mailbox_in, HERMON_MBOX_SIZE ); free ( hermon ); } diff --git a/src/drivers/infiniband/linda.c b/src/drivers/infiniband/linda.c index 8c2c090bc..b275268a2 100644 --- a/src/drivers/infiniband/linda.c +++ b/src/drivers/infiniband/linda.c @@ -531,8 +531,8 @@ static int linda_init_send ( struct linda *linda ) { linda->send_buf[i] = i; /* Allocate space for the SendBufAvail array */ - linda->sendbufavail = malloc_dma ( sizeof ( *linda->sendbufavail ), - LINDA_SENDBUFAVAIL_ALIGN ); + linda->sendbufavail = malloc_phys ( sizeof ( *linda->sendbufavail ), + LINDA_SENDBUFAVAIL_ALIGN ); if ( ! linda->sendbufavail ) { rc = -ENOMEM; goto err_alloc_sendbufavail; @@ -555,7 +555,7 @@ static int linda_init_send ( struct linda *linda ) { return 0; - free_dma ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) ); + free_phys ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) ); err_alloc_sendbufavail: return rc; } @@ -576,7 +576,7 @@ static void linda_fini_send ( struct linda *linda ) { /* Ensure hardware has seen this disable */ linda_readq ( linda, &sendctrl, QIB_7220_SendCtrl_offset ); - free_dma ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) ); + free_phys ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) ); } /*************************************************************************** @@ -613,8 +613,8 @@ static int linda_create_recv_wq ( struct linda *linda, linda_wq->eager_cons = 0; /* Allocate receive header buffer */ - linda_wq->header = malloc_dma ( LINDA_RECV_HEADERS_SIZE, - LINDA_RECV_HEADERS_ALIGN ); + linda_wq->header = malloc_phys ( LINDA_RECV_HEADERS_SIZE, + LINDA_RECV_HEADERS_ALIGN ); if ( ! linda_wq->header ) { rc = -ENOMEM; goto err_alloc_header; @@ -650,7 +650,7 @@ static int linda_create_recv_wq ( struct linda *linda, virt_to_bus ( &linda_wq->header_prod ) ); return 0; - free_dma ( linda_wq->header, LINDA_RECV_HEADERS_SIZE ); + free_phys ( linda_wq->header, LINDA_RECV_HEADERS_SIZE ); err_alloc_header: return rc; } @@ -679,7 +679,7 @@ static void linda_destroy_recv_wq ( struct linda *linda, mb(); /* Free headers ring */ - free_dma ( linda_wq->header, LINDA_RECV_HEADERS_SIZE ); + free_phys ( linda_wq->header, LINDA_RECV_HEADERS_SIZE ); /* Free context */ linda_free_ctx ( linda, ctx ); diff --git a/src/drivers/infiniband/mlx_utils_flexboot/src/mlx_memory_priv.c b/src/drivers/infiniband/mlx_utils_flexboot/src/mlx_memory_priv.c index cb9e759bf..e368d459b 100644 --- a/src/drivers/infiniband/mlx_utils_flexboot/src/mlx_memory_priv.c +++ b/src/drivers/infiniband/mlx_utils_flexboot/src/mlx_memory_priv.c @@ -61,7 +61,7 @@ mlx_memory_alloc_dma_priv( ) { mlx_status status = MLX_SUCCESS; - *ptr = malloc_dma(size, align); + *ptr = malloc_phys(size, align); if (*ptr == NULL) { status = MLX_OUT_OF_RESOURCES; } else { @@ -78,7 +78,7 @@ mlx_memory_free_dma_priv( ) { mlx_status status = MLX_SUCCESS; - free_dma(ptr, size); + free_phys(ptr, size); return status; } mlx_status diff --git a/src/drivers/infiniband/qib7322.c b/src/drivers/infiniband/qib7322.c index a5606dd03..e3250147d 100644 --- a/src/drivers/infiniband/qib7322.c +++ b/src/drivers/infiniband/qib7322.c @@ -669,8 +669,8 @@ static int qib7322_init_send ( struct qib7322 *qib7322 ) { } /* Allocate space for the SendBufAvail array */ - qib7322->sendbufavail = malloc_dma ( sizeof ( *qib7322->sendbufavail ), - QIB7322_SENDBUFAVAIL_ALIGN ); + qib7322->sendbufavail = malloc_phys ( sizeof ( *qib7322->sendbufavail ), + QIB7322_SENDBUFAVAIL_ALIGN ); if ( ! qib7322->sendbufavail ) { rc = -ENOMEM; goto err_alloc_sendbufavail; @@ -697,7 +697,7 @@ static int qib7322_init_send ( struct qib7322 *qib7322 ) { return 0; - free_dma ( qib7322->sendbufavail, sizeof ( *qib7322->sendbufavail ) ); + free_phys ( qib7322->sendbufavail, sizeof ( *qib7322->sendbufavail ) ); err_alloc_sendbufavail: qib7322_destroy_send_bufs ( qib7322, qib7322->send_bufs_vl15_port1 ); err_create_send_bufs_vl15_port1: @@ -724,7 +724,7 @@ static void qib7322_fini_send ( struct qib7322 *qib7322 ) { /* Ensure hardware has seen this disable */ qib7322_readq ( qib7322, &sendctrl, QIB_7322_SendCtrl_offset ); - free_dma ( qib7322->sendbufavail, sizeof ( *qib7322->sendbufavail ) ); + free_phys ( qib7322->sendbufavail, sizeof ( *qib7322->sendbufavail ) ); qib7322_destroy_send_bufs ( qib7322, qib7322->send_bufs_vl15_port1 ); qib7322_destroy_send_bufs ( qib7322, qib7322->send_bufs_vl15_port0 ); qib7322_destroy_send_bufs ( qib7322, qib7322->send_bufs_small ); @@ -767,8 +767,8 @@ static int qib7322_create_recv_wq ( struct ib_device *ibdev, qib7322_wq->eager_cons = 0; /* Allocate receive header buffer */ - qib7322_wq->header = malloc_dma ( QIB7322_RECV_HEADERS_SIZE, - QIB7322_RECV_HEADERS_ALIGN ); + qib7322_wq->header = malloc_phys ( QIB7322_RECV_HEADERS_SIZE, + QIB7322_RECV_HEADERS_ALIGN ); if ( ! qib7322_wq->header ) { rc = -ENOMEM; goto err_alloc_header; @@ -810,7 +810,7 @@ static int qib7322_create_recv_wq ( struct ib_device *ibdev, virt_to_bus ( &qib7322_wq->header_prod ) ); return 0; - free_dma ( qib7322_wq->header, QIB7322_RECV_HEADERS_SIZE ); + free_phys ( qib7322_wq->header, QIB7322_RECV_HEADERS_SIZE ); err_alloc_header: return rc; } @@ -846,7 +846,7 @@ static void qib7322_destroy_recv_wq ( struct ib_device *ibdev, mb(); /* Free headers ring */ - free_dma ( qib7322_wq->header, QIB7322_RECV_HEADERS_SIZE ); + free_phys ( qib7322_wq->header, QIB7322_RECV_HEADERS_SIZE ); } /** diff --git a/src/drivers/net/3c90x.c b/src/drivers/net/3c90x.c index 853de2b52..63e07777f 100644 --- a/src/drivers/net/3c90x.c +++ b/src/drivers/net/3c90x.c @@ -249,7 +249,7 @@ static int a3c90x_setup_tx_ring(struct INF_3C90X *p) { DBGP("a3c90x_setup_tx_ring\n"); p->tx_ring = - malloc_dma(TX_RING_SIZE * sizeof(struct TXD), TX_RING_ALIGN); + malloc_phys(TX_RING_SIZE * sizeof(struct TXD), TX_RING_ALIGN); if (!p->tx_ring) { DBG("Could not allocate TX-ring\n"); @@ -304,7 +304,7 @@ static void a3c90x_free_tx_ring(struct INF_3C90X *p) { DBGP("a3c90x_free_tx_ring\n"); - free_dma(p->tx_ring, TX_RING_SIZE * sizeof(struct TXD)); + free_phys(p->tx_ring, TX_RING_SIZE * sizeof(struct TXD)); p->tx_ring = NULL; /* io_buffers are free()ed by netdev_tx_complete[,_err]() */ } @@ -461,7 +461,7 @@ static int a3c90x_setup_rx_ring(struct INF_3C90X *p) DBGP("a3c90x_setup_rx_ring\n"); p->rx_ring = - malloc_dma(RX_RING_SIZE * sizeof(struct RXD), RX_RING_ALIGN); + malloc_phys(RX_RING_SIZE * sizeof(struct RXD), RX_RING_ALIGN); if (!p->rx_ring) { DBG("Could not allocate RX-ring\n"); @@ -491,7 +491,7 @@ static void a3c90x_free_rx_ring(struct INF_3C90X *p) { DBGP("a3c90x_free_rx_ring\n"); - free_dma(p->rx_ring, RX_RING_SIZE * sizeof(struct RXD)); + free_phys(p->rx_ring, RX_RING_SIZE * sizeof(struct RXD)); p->rx_ring = NULL; } diff --git a/src/drivers/net/ath/ath5k/ath5k.c b/src/drivers/net/ath/ath5k/ath5k.c index d8c47909d..e43eb0aaf 100644 --- a/src/drivers/net/ath/ath5k/ath5k.c +++ b/src/drivers/net/ath/ath5k/ath5k.c @@ -877,7 +877,7 @@ ath5k_desc_alloc(struct ath5k_softc *sc) /* allocate descriptors */ sc->desc_len = sizeof(struct ath5k_desc) * (ATH_TXBUF + ATH_RXBUF + 1); - sc->desc = malloc_dma(sc->desc_len, ATH5K_DESC_ALIGN); + sc->desc = malloc_phys(sc->desc_len, ATH5K_DESC_ALIGN); if (sc->desc == NULL) { DBG("ath5k: can't allocate descriptors\n"); ret = -ENOMEM; @@ -915,7 +915,7 @@ ath5k_desc_alloc(struct ath5k_softc *sc) return 0; err_free: - free_dma(sc->desc, sc->desc_len); + free_phys(sc->desc, sc->desc_len); err: sc->desc = NULL; return ret; @@ -932,7 +932,7 @@ ath5k_desc_free(struct ath5k_softc *sc) ath5k_rxbuf_free(sc, bf); /* Free memory associated with all descriptors */ - free_dma(sc->desc, sc->desc_len); + free_phys(sc->desc, sc->desc_len); free(sc->bufptr); sc->bufptr = NULL; diff --git a/src/drivers/net/ath/ath9k/ath9k_init.c b/src/drivers/net/ath/ath9k/ath9k_init.c index 98a0d6d59..05ed3336a 100644 --- a/src/drivers/net/ath/ath9k/ath9k_init.c +++ b/src/drivers/net/ath/ath9k/ath9k_init.c @@ -223,7 +223,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, } /* allocate descriptors */ - dd->dd_desc = malloc_dma(dd->dd_desc_len, 16); + dd->dd_desc = malloc_phys(dd->dd_desc_len, 16); if (dd->dd_desc == NULL) { error = -ENOMEM; goto fail; @@ -264,7 +264,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, } return 0; fail2: - free_dma(dd->dd_desc, dd->dd_desc_len); + free_phys(dd->dd_desc, dd->dd_desc_len); fail: memset(dd, 0, sizeof(*dd)); return error; @@ -588,7 +588,7 @@ void ath_descdma_cleanup(struct ath_softc *sc __unused, struct ath_descdma *dd, struct list_head *head) { - free_dma(dd->dd_desc, dd->dd_desc_len); + free_phys(dd->dd_desc, dd->dd_desc_len); INIT_LIST_HEAD(head); free(dd->dd_bufptr); diff --git a/src/drivers/net/atl1e.c b/src/drivers/net/atl1e.c index d010d8c4a..0f0df5326 100644 --- a/src/drivers/net/atl1e.c +++ b/src/drivers/net/atl1e.c @@ -370,7 +370,7 @@ static void atl1e_free_ring_resources(struct atl1e_adapter *adapter) atl1e_clean_rx_ring(adapter); if (adapter->ring_vir_addr) { - free_dma(adapter->ring_vir_addr, adapter->ring_size); + free_phys(adapter->ring_vir_addr, adapter->ring_size); adapter->ring_vir_addr = NULL; adapter->ring_dma = 0; } @@ -405,7 +405,7 @@ static int atl1e_setup_ring_resources(struct atl1e_adapter *adapter) /* real ring DMA buffer */ size = adapter->ring_size; - adapter->ring_vir_addr = malloc_dma(adapter->ring_size, 32); + adapter->ring_vir_addr = malloc_phys(adapter->ring_size, 32); if (adapter->ring_vir_addr == NULL) { DBG("atl1e: out of memory allocating %d bytes for %s ring\n", diff --git a/src/drivers/net/b44.c b/src/drivers/net/b44.c index e0e6f4642..eaf6d35ce 100644 --- a/src/drivers/net/b44.c +++ b/src/drivers/net/b44.c @@ -436,7 +436,7 @@ static void b44_free_rx_ring(struct b44_private *bp) free_iob(bp->rx_iobuf[i]); bp->rx_iobuf[i] = NULL; } - free_dma(bp->rx, B44_RX_RING_LEN_BYTES); + free_phys(bp->rx, B44_RX_RING_LEN_BYTES); bp->rx = NULL; } } @@ -446,11 +446,11 @@ static int b44_init_rx_ring(struct b44_private *bp) { b44_free_rx_ring(bp); - bp->rx = malloc_dma(B44_RX_RING_LEN_BYTES, B44_DMA_ALIGNMENT); + bp->rx = malloc_phys(B44_RX_RING_LEN_BYTES, B44_DMA_ALIGNMENT); if (!bp->rx) return -ENOMEM; if (!b44_address_ok(bp->rx)) { - free_dma(bp->rx, B44_RX_RING_LEN_BYTES); + free_phys(bp->rx, B44_RX_RING_LEN_BYTES); return -ENOTSUP; } @@ -468,7 +468,7 @@ static int b44_init_rx_ring(struct b44_private *bp) static void b44_free_tx_ring(struct b44_private *bp) { if (bp->tx) { - free_dma(bp->tx, B44_TX_RING_LEN_BYTES); + free_phys(bp->tx, B44_TX_RING_LEN_BYTES); bp->tx = NULL; } } @@ -478,11 +478,11 @@ static int b44_init_tx_ring(struct b44_private *bp) { b44_free_tx_ring(bp); - bp->tx = malloc_dma(B44_TX_RING_LEN_BYTES, B44_DMA_ALIGNMENT); + bp->tx = malloc_phys(B44_TX_RING_LEN_BYTES, B44_DMA_ALIGNMENT); if (!bp->tx) return -ENOMEM; if (!b44_address_ok(bp->tx)) { - free_dma(bp->tx, B44_TX_RING_LEN_BYTES); + free_phys(bp->tx, B44_TX_RING_LEN_BYTES); return -ENOTSUP; } diff --git a/src/drivers/net/bnxt/bnxt.c b/src/drivers/net/bnxt/bnxt.c index fe84ea0e4..b8663c00a 100644 --- a/src/drivers/net/bnxt/bnxt.c +++ b/src/drivers/net/bnxt/bnxt.c @@ -495,39 +495,39 @@ void bnxt_free_mem ( struct bnxt *bp ) { DBGP ( "%s\n", __func__ ); if ( bp->nq.bd_virt ) { - free_dma ( bp->nq.bd_virt, NQ_RING_BUFFER_SIZE ); + free_phys ( bp->nq.bd_virt, NQ_RING_BUFFER_SIZE ); bp->nq.bd_virt = NULL; } if ( bp->cq.bd_virt ) { - free_dma ( bp->cq.bd_virt, CQ_RING_BUFFER_SIZE ); + free_phys ( bp->cq.bd_virt, CQ_RING_BUFFER_SIZE ); bp->cq.bd_virt = NULL; } if ( bp->rx.bd_virt ) { - free_dma ( bp->rx.bd_virt, RX_RING_BUFFER_SIZE ); + free_phys ( bp->rx.bd_virt, RX_RING_BUFFER_SIZE ); bp->rx.bd_virt = NULL; } if ( bp->tx.bd_virt ) { - free_dma ( bp->tx.bd_virt, TX_RING_BUFFER_SIZE ); + free_phys ( bp->tx.bd_virt, TX_RING_BUFFER_SIZE ); bp->tx.bd_virt = NULL; } if ( bp->hwrm_addr_dma ) { - free_dma ( bp->hwrm_addr_dma, DMA_BUFFER_SIZE ); + free_phys ( bp->hwrm_addr_dma, DMA_BUFFER_SIZE ); bp->dma_addr_mapping = 0; bp->hwrm_addr_dma = NULL; } if ( bp->hwrm_addr_resp ) { - free_dma ( bp->hwrm_addr_resp, RESP_BUFFER_SIZE ); + free_phys ( bp->hwrm_addr_resp, RESP_BUFFER_SIZE ); bp->resp_addr_mapping = 0; bp->hwrm_addr_resp = NULL; } if ( bp->hwrm_addr_req ) { - free_dma ( bp->hwrm_addr_req, REQ_BUFFER_SIZE ); + free_phys ( bp->hwrm_addr_req, REQ_BUFFER_SIZE ); bp->req_addr_mapping = 0; bp->hwrm_addr_req = NULL; } @@ -537,14 +537,14 @@ void bnxt_free_mem ( struct bnxt *bp ) int bnxt_alloc_mem ( struct bnxt *bp ) { DBGP ( "%s\n", __func__ ); - bp->hwrm_addr_req = malloc_dma ( REQ_BUFFER_SIZE, BNXT_DMA_ALIGNMENT ); - bp->hwrm_addr_resp = malloc_dma ( RESP_BUFFER_SIZE, - BNXT_DMA_ALIGNMENT ); - bp->hwrm_addr_dma = malloc_dma ( DMA_BUFFER_SIZE, BNXT_DMA_ALIGNMENT ); - bp->tx.bd_virt = malloc_dma ( TX_RING_BUFFER_SIZE, DMA_ALIGN_4K ); - bp->rx.bd_virt = malloc_dma ( RX_RING_BUFFER_SIZE, DMA_ALIGN_4K ); - bp->cq.bd_virt = malloc_dma ( CQ_RING_BUFFER_SIZE, BNXT_DMA_ALIGNMENT ); - bp->nq.bd_virt = malloc_dma ( NQ_RING_BUFFER_SIZE, BNXT_DMA_ALIGNMENT ); + bp->hwrm_addr_req = malloc_phys ( REQ_BUFFER_SIZE, BNXT_DMA_ALIGNMENT ); + bp->hwrm_addr_resp = malloc_phys ( RESP_BUFFER_SIZE, + BNXT_DMA_ALIGNMENT ); + bp->hwrm_addr_dma = malloc_phys ( DMA_BUFFER_SIZE, BNXT_DMA_ALIGNMENT ); + bp->tx.bd_virt = malloc_phys ( TX_RING_BUFFER_SIZE, DMA_ALIGN_4K ); + bp->rx.bd_virt = malloc_phys ( RX_RING_BUFFER_SIZE, DMA_ALIGN_4K ); + bp->cq.bd_virt = malloc_phys ( CQ_RING_BUFFER_SIZE, BNXT_DMA_ALIGNMENT ); + bp->nq.bd_virt = malloc_phys ( NQ_RING_BUFFER_SIZE, BNXT_DMA_ALIGNMENT ); test_if ( bp->hwrm_addr_req && bp->hwrm_addr_resp && bp->hwrm_addr_dma && diff --git a/src/drivers/net/eepro100.c b/src/drivers/net/eepro100.c index 1046cda39..1a802b590 100644 --- a/src/drivers/net/eepro100.c +++ b/src/drivers/net/eepro100.c @@ -93,7 +93,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /* * Debugging levels: - * - DBG() is for any errors, i.e. failed alloc_iob(), malloc_dma(), + * - DBG() is for any errors, i.e. failed alloc_iob(), malloc_phys(), * TX overflow, corrupted packets, ... * - DBG2() is for successful events, like packet received, * packet transmitted, and other general notifications. @@ -335,7 +335,7 @@ static int ifec_net_open ( struct net_device *netdev ) ifec_mdio_setup ( netdev, options ); /* Prepare MAC address w/ Individual Address Setup (ias) command.*/ - ias = malloc_dma ( sizeof ( *ias ), CB_ALIGN ); + ias = malloc_phys ( sizeof ( *ias ), CB_ALIGN ); if ( !ias ) { rc = -ENOMEM; goto error; @@ -345,7 +345,7 @@ static int ifec_net_open ( struct net_device *netdev ) memcpy ( ias->ia, netdev->ll_addr, ETH_ALEN ); /* Prepare operating parameters w/ a configure command. */ - cfg = malloc_dma ( sizeof ( *cfg ), CB_ALIGN ); + cfg = malloc_phys ( sizeof ( *cfg ), CB_ALIGN ); if ( !cfg ) { rc = -ENOMEM; goto error; @@ -367,8 +367,8 @@ static int ifec_net_open ( struct net_device *netdev ) DBG ( "Failed to initiate!\n" ); goto error; } - free_dma ( ias, sizeof ( *ias ) ); - free_dma ( cfg, sizeof ( *cfg ) ); + free_phys ( ias, sizeof ( *ias ) ); + free_phys ( cfg, sizeof ( *cfg ) ); DBG2 ( "cfg " ); /* Enable rx by sending ring address to card */ @@ -381,8 +381,8 @@ static int ifec_net_open ( struct net_device *netdev ) return 0; error: - free_dma ( cfg, sizeof ( *cfg ) ); - free_dma ( ias, sizeof ( *ias ) ); + free_phys ( cfg, sizeof ( *cfg ) ); + free_phys ( ias, sizeof ( *ias ) ); ifec_free ( netdev ); ifec_reset ( netdev ); return rc; @@ -703,7 +703,7 @@ static void ifec_free ( struct net_device *netdev ) } /* free TX ring buffer */ - free_dma ( priv->tcbs, TX_RING_BYTES ); + free_phys ( priv->tcbs, TX_RING_BYTES ); priv->tcbs = NULL; } @@ -1025,7 +1025,7 @@ static int ifec_tx_setup ( struct net_device *netdev ) DBGP ( "ifec_tx_setup\n" ); /* allocate tx ring */ - priv->tcbs = malloc_dma ( TX_RING_BYTES, CB_ALIGN ); + priv->tcbs = malloc_phys ( TX_RING_BYTES, CB_ALIGN ); if ( !priv->tcbs ) { DBG ( "TX-ring allocation failed\n" ); return -ENOMEM; diff --git a/src/drivers/net/ena.c b/src/drivers/net/ena.c index 5c76eb6fd..12c161522 100644 --- a/src/drivers/net/ena.c +++ b/src/drivers/net/ena.c @@ -164,7 +164,7 @@ static int ena_create_admin ( struct ena_nic *ena ) { int rc; /* Allocate admin completion queue */ - ena->acq.rsp = malloc_dma ( acq_len, acq_len ); + ena->acq.rsp = malloc_phys ( acq_len, acq_len ); if ( ! ena->acq.rsp ) { rc = -ENOMEM; goto err_alloc_acq; @@ -172,7 +172,7 @@ static int ena_create_admin ( struct ena_nic *ena ) { memset ( ena->acq.rsp, 0, acq_len ); /* Allocate admin queue */ - ena->aq.req = malloc_dma ( aq_len, aq_len ); + ena->aq.req = malloc_phys ( aq_len, aq_len ); if ( ! ena->aq.req ) { rc = -ENOMEM; goto err_alloc_aq; @@ -196,9 +196,9 @@ static int ena_create_admin ( struct ena_nic *ena ) { ena_clear_caps ( ena, ENA_AQ_CAPS ); ena_clear_caps ( ena, ENA_ACQ_CAPS ); - free_dma ( ena->aq.req, aq_len ); + free_phys ( ena->aq.req, aq_len ); err_alloc_aq: - free_dma ( ena->acq.rsp, acq_len ); + free_phys ( ena->acq.rsp, acq_len ); err_alloc_acq: return rc; } @@ -218,8 +218,8 @@ static void ena_destroy_admin ( struct ena_nic *ena ) { wmb(); /* Free queues */ - free_dma ( ena->aq.req, aq_len ); - free_dma ( ena->acq.rsp, acq_len ); + free_phys ( ena->aq.req, aq_len ); + free_phys ( ena->acq.rsp, acq_len ); DBGC ( ena, "ENA %p AQ and ACQ destroyed\n", ena ); } @@ -338,7 +338,7 @@ static int ena_create_sq ( struct ena_nic *ena, struct ena_sq *sq, int rc; /* Allocate submission queue entries */ - sq->sqe.raw = malloc_dma ( sq->len, ENA_ALIGN ); + sq->sqe.raw = malloc_phys ( sq->len, ENA_ALIGN ); if ( ! sq->sqe.raw ) { rc = -ENOMEM; goto err_alloc; @@ -375,7 +375,7 @@ static int ena_create_sq ( struct ena_nic *ena, struct ena_sq *sq, return 0; err_admin: - free_dma ( sq->sqe.raw, sq->len ); + free_phys ( sq->sqe.raw, sq->len ); err_alloc: return rc; } @@ -403,7 +403,7 @@ static int ena_destroy_sq ( struct ena_nic *ena, struct ena_sq *sq ) { return rc; /* Free submission queue entries */ - free_dma ( sq->sqe.raw, sq->len ); + free_phys ( sq->sqe.raw, sq->len ); DBGC ( ena, "ENA %p %s SQ%d destroyed\n", ena, ena_direction ( sq->direction ), sq->id ); @@ -423,7 +423,7 @@ static int ena_create_cq ( struct ena_nic *ena, struct ena_cq *cq ) { int rc; /* Allocate completion queue entries */ - cq->cqe.raw = malloc_dma ( cq->len, ENA_ALIGN ); + cq->cqe.raw = malloc_phys ( cq->len, ENA_ALIGN ); if ( ! cq->cqe.raw ) { rc = -ENOMEM; goto err_alloc; @@ -461,7 +461,7 @@ static int ena_create_cq ( struct ena_nic *ena, struct ena_cq *cq ) { return 0; err_admin: - free_dma ( cq->cqe.raw, cq->len ); + free_phys ( cq->cqe.raw, cq->len ); err_alloc: return rc; } @@ -488,7 +488,7 @@ static int ena_destroy_cq ( struct ena_nic *ena, struct ena_cq *cq ) { return rc; /* Free completion queue entries */ - free_dma ( cq->cqe.raw, cq->len ); + free_phys ( cq->cqe.raw, cq->len ); DBGC ( ena, "ENA %p CQ%d destroyed\n", ena, cq->id ); return 0; diff --git a/src/drivers/net/etherfabric.c b/src/drivers/net/etherfabric.c index cd567f1d9..e43d4336e 100644 --- a/src/drivers/net/etherfabric.c +++ b/src/drivers/net/etherfabric.c @@ -3025,7 +3025,7 @@ falcon_free_special_buffer ( void *p ) { /* We don't bother cleaning up the buffer table entries - * we're hardly limited */ - free_dma ( p, EFAB_BUF_ALIGN ); + free_phys ( p, EFAB_BUF_ALIGN ); } static void* @@ -3038,7 +3038,7 @@ falcon_alloc_special_buffer ( struct efab_nic *efab, int bytes, unsigned long dma_addr; /* Allocate the buffer, aligned on a buffer address boundary */ - buffer = malloc_dma ( bytes, EFAB_BUF_ALIGN ); + buffer = malloc_phys ( bytes, EFAB_BUF_ALIGN ); if ( ! buffer ) return NULL; diff --git a/src/drivers/net/exanic.c b/src/drivers/net/exanic.c index 8849da285..aaa6a28a1 100644 --- a/src/drivers/net/exanic.c +++ b/src/drivers/net/exanic.c @@ -831,7 +831,7 @@ static int exanic_probe ( struct pci_device *pci ) { } /* Allocate transmit feedback region (shared between all ports) */ - exanic->txf = malloc_dma ( EXANIC_TXF_LEN, EXANIC_ALIGN ); + exanic->txf = malloc_phys ( EXANIC_TXF_LEN, EXANIC_ALIGN ); if ( ! exanic->txf ) { rc = -ENOMEM; goto err_alloc_txf; @@ -853,7 +853,7 @@ static int exanic_probe ( struct pci_device *pci ) { for ( i-- ; i >= 0 ; i-- ) exanic_remove_port ( exanic, i ); exanic_reset ( exanic ); - free_dma ( exanic->txf, EXANIC_TXF_LEN ); + free_phys ( exanic->txf, EXANIC_TXF_LEN ); err_alloc_txf: iounmap ( exanic->tx ); err_ioremap_tx: @@ -882,7 +882,7 @@ static void exanic_remove ( struct pci_device *pci ) { exanic_reset ( exanic ); /* Free transmit feedback region */ - free_dma ( exanic->txf, EXANIC_TXF_LEN ); + free_phys ( exanic->txf, EXANIC_TXF_LEN ); /* Unmap transmit region */ iounmap ( exanic->tx ); diff --git a/src/drivers/net/forcedeth.c b/src/drivers/net/forcedeth.c index 94cc6063b..7fba08a08 100644 --- a/src/drivers/net/forcedeth.c +++ b/src/drivers/net/forcedeth.c @@ -267,7 +267,7 @@ nv_init_rings ( struct forcedeth_private *priv ) /* Allocate ring for both TX and RX */ priv->rx_ring = - malloc_dma ( sizeof(struct ring_desc) * RXTX_RING_SIZE, 32 ); + malloc_phys ( sizeof(struct ring_desc) * RXTX_RING_SIZE, 32 ); if ( ! priv->rx_ring ) goto err_malloc; priv->tx_ring = &priv->rx_ring[RX_RING_SIZE]; @@ -308,7 +308,7 @@ nv_free_rxtx_resources ( struct forcedeth_private *priv ) DBGP ( "nv_free_rxtx_resources\n" ); - free_dma ( priv->rx_ring, sizeof(struct ring_desc) * RXTX_RING_SIZE ); + free_phys ( priv->rx_ring, sizeof(struct ring_desc) * RXTX_RING_SIZE ); for ( i = 0; i < RX_RING_SIZE; i++ ) { free_iob ( priv->rx_iobuf[i] ); diff --git a/src/drivers/net/icplus.c b/src/drivers/net/icplus.c index 58092fade..acd2e2363 100644 --- a/src/drivers/net/icplus.c +++ b/src/drivers/net/icplus.c @@ -343,7 +343,7 @@ static int icplus_create_ring ( struct icplus_nic *icp, struct icplus_ring *ring struct icplus_descriptor *next; /* Allocate descriptor ring */ - ring->entry = malloc_dma ( len, ICP_ALIGN ); + ring->entry = malloc_phys ( len, ICP_ALIGN ); if ( ! ring->entry ) { rc = -ENOMEM; goto err_alloc; @@ -369,7 +369,7 @@ static int icplus_create_ring ( struct icplus_nic *icp, struct icplus_ring *ring ( virt_to_bus ( ring->entry ) + len ) ); return 0; - free_dma ( ring->entry, len ); + free_phys ( ring->entry, len ); ring->entry = NULL; err_alloc: return rc; @@ -386,7 +386,7 @@ static void icplus_destroy_ring ( struct icplus_nic *icp __unused, size_t len = ( sizeof ( ring->entry[0] ) * ICP_NUM_DESC ); /* Free descriptor ring */ - free_dma ( ring->entry, len ); + free_phys ( ring->entry, len ); ring->entry = NULL; } diff --git a/src/drivers/net/igbvf/igbvf_main.c b/src/drivers/net/igbvf/igbvf_main.c index 39d4e7f8a..a5ed0c451 100644 --- a/src/drivers/net/igbvf/igbvf_main.c +++ b/src/drivers/net/igbvf/igbvf_main.c @@ -46,7 +46,7 @@ int igbvf_setup_tx_resources ( struct igbvf_adapter *adapter ) /* Allocate transmit descriptor ring memory. It must not cross a 64K boundary because of hardware errata #23 - so we use malloc_dma() requesting a 128 byte block that is + so we use malloc_phys() requesting a 128 byte block that is 128 byte aligned. This should guarantee that the memory allocated will not cross a 64K boundary, because 128 is an even multiple of 65536 ( 65536 / 128 == 512 ), so all possible @@ -55,7 +55,7 @@ int igbvf_setup_tx_resources ( struct igbvf_adapter *adapter ) */ adapter->tx_base = - malloc_dma ( adapter->tx_ring_size, adapter->tx_ring_size ); + malloc_phys ( adapter->tx_ring_size, adapter->tx_ring_size ); if ( ! adapter->tx_base ) { return -ENOMEM; @@ -78,7 +78,7 @@ void igbvf_free_tx_resources ( struct igbvf_adapter *adapter ) { DBG ( "igbvf_free_tx_resources\n" ); - free_dma ( adapter->tx_base, adapter->tx_ring_size ); + free_phys ( adapter->tx_base, adapter->tx_ring_size ); } /** @@ -93,7 +93,7 @@ void igbvf_free_rx_resources ( struct igbvf_adapter *adapter ) DBG ( "igbvf_free_rx_resources\n" ); - free_dma ( adapter->rx_base, adapter->rx_ring_size ); + free_phys ( adapter->rx_base, adapter->rx_ring_size ); for ( i = 0; i < NUM_RX_DESC; i++ ) { free_iob ( adapter->rx_iobuf[i] ); @@ -574,7 +574,7 @@ int igbvf_setup_rx_resources ( struct igbvf_adapter *adapter ) */ adapter->rx_base = - malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size ); + malloc_phys ( adapter->rx_ring_size, adapter->rx_ring_size ); if ( ! adapter->rx_base ) { return -ENOMEM; diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c index 97f50a943..3a4e4341b 100644 --- a/src/drivers/net/intel.c +++ b/src/drivers/net/intel.c @@ -504,7 +504,7 @@ int intel_create_ring ( struct intel_nic *intel, struct intel_ring *ring ) { * prevent any possible page-crossing errors due to hardware * errata. */ - ring->desc = malloc_dma ( ring->len, ring->len ); + ring->desc = malloc_phys ( ring->len, ring->len ); if ( ! ring->desc ) return -ENOMEM; @@ -553,7 +553,7 @@ void intel_destroy_ring ( struct intel_nic *intel, struct intel_ring *ring ) { intel_reset_ring ( intel, ring->reg ); /* Free descriptor ring */ - free_dma ( ring->desc, ring->len ); + free_phys ( ring->desc, ring->len ); ring->desc = NULL; ring->prod = 0; ring->cons = 0; diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c index 08c90bc48..d16b759e7 100644 --- a/src/drivers/net/intelxl.c +++ b/src/drivers/net/intelxl.c @@ -195,7 +195,7 @@ static int intelxl_alloc_admin ( struct intelxl_nic *intelxl, size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC ); /* Allocate admin queue */ - admin->buf = malloc_dma ( ( buf_len + len ), INTELXL_ALIGN ); + admin->buf = malloc_phys ( ( buf_len + len ), INTELXL_ALIGN ); if ( ! admin->buf ) return -ENOMEM; admin->desc = ( ( ( void * ) admin->buf ) + buf_len ); @@ -277,7 +277,7 @@ static void intelxl_free_admin ( struct intelxl_nic *intelxl __unused, size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC ); /* Free queue */ - free_dma ( admin->buf, ( buf_len + len ) ); + free_phys ( admin->buf, ( buf_len + len ) ); } /** @@ -926,7 +926,7 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl, int rc; /* Allocate descriptor ring */ - ring->desc.raw = malloc_dma ( ring->len, INTELXL_ALIGN ); + ring->desc.raw = malloc_phys ( ring->len, INTELXL_ALIGN ); if ( ! ring->desc.raw ) { rc = -ENOMEM; goto err_alloc; @@ -950,7 +950,7 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl, return 0; - free_dma ( ring->desc.raw, ring->len ); + free_phys ( ring->desc.raw, ring->len ); err_alloc: return rc; } @@ -965,7 +965,7 @@ void intelxl_free_ring ( struct intelxl_nic *intelxl __unused, struct intelxl_ring *ring ) { /* Free descriptor ring */ - free_dma ( ring->desc.raw, ring->len ); + free_phys ( ring->desc.raw, ring->len ); ring->desc.raw = NULL; } diff --git a/src/drivers/net/jme.c b/src/drivers/net/jme.c index b68b96c88..c7307728d 100644 --- a/src/drivers/net/jme.c +++ b/src/drivers/net/jme.c @@ -262,7 +262,7 @@ jme_free_tx_resources(struct jme_adapter *jme) sizeof(struct io_buffer *) * jme->tx_ring_size); free(txring->bufinf); } - free_dma(txring->desc, jme->tx_ring_size * TX_DESC_SIZE); + free_phys(txring->desc, jme->tx_ring_size * TX_DESC_SIZE); txring->desc = NULL; txring->dma = 0; txring->bufinf = NULL; @@ -277,7 +277,7 @@ jme_alloc_tx_resources(struct jme_adapter *jme) { struct jme_ring *txring = &jme->txring; - txring->desc = malloc_dma(jme->tx_ring_size * TX_DESC_SIZE, + txring->desc = malloc_phys(jme->tx_ring_size * TX_DESC_SIZE, RING_DESC_ALIGN); if (!txring->desc) { DBG("Can not allocate transmit ring descriptors.\n"); @@ -442,7 +442,7 @@ jme_free_rx_resources(struct jme_adapter *jme) free(rxring->bufinf); } - free_dma(rxring->desc, jme->rx_ring_size * RX_DESC_SIZE); + free_phys(rxring->desc, jme->rx_ring_size * RX_DESC_SIZE); rxring->desc = NULL; rxring->dma = 0; rxring->bufinf = NULL; @@ -458,7 +458,7 @@ jme_alloc_rx_resources(struct jme_adapter *jme) struct jme_ring *rxring = &jme->rxring; struct io_buffer **bufinf; - rxring->desc = malloc_dma(jme->rx_ring_size * RX_DESC_SIZE, + rxring->desc = malloc_phys(jme->rx_ring_size * RX_DESC_SIZE, RING_DESC_ALIGN); if (!rxring->desc) { DBG("Can not allocate receive ring descriptors.\n"); diff --git a/src/drivers/net/myri10ge.c b/src/drivers/net/myri10ge.c index ae6b6c21e..6d0f723f2 100644 --- a/src/drivers/net/myri10ge.c +++ b/src/drivers/net/myri10ge.c @@ -66,7 +66,7 @@ FILE_LICENCE ( GPL2_ONLY ); /* * Debugging levels: - * - DBG() is for any errors, i.e. failed alloc_iob(), malloc_dma(), + * - DBG() is for any errors, i.e. failed alloc_iob(), malloc_phys(), * TX overflow, corrupted packets, ... * - DBG2() is for successful events, like packet received, * packet transmitted, and other general notifications. @@ -918,7 +918,7 @@ static void myri10ge_net_close ( struct net_device *netdev ) /* Release DMAable memory. */ - free_dma ( priv->dma, sizeof ( *priv->dma ) ); + free_phys ( priv->dma, sizeof ( *priv->dma ) ); /* Erase all state from the open. */ @@ -988,7 +988,7 @@ static int myri10ge_net_open ( struct net_device *netdev ) /* Allocate cleared DMAable buffers. */ - priv->dma = malloc_dma ( sizeof ( *priv->dma ) , 128 ); + priv->dma = malloc_phys ( sizeof ( *priv->dma ) , 128 ); if ( !priv->dma ) { rc = -ENOMEM; dbg = "DMA"; @@ -1152,7 +1152,7 @@ abort_with_receives_posted: free_iob ( priv->receive_iob[priv->receives_posted] ); abort_with_dma: /* Because the link is not up, we don't have to reset the NIC here. */ - free_dma ( priv->dma, sizeof ( *priv->dma ) ); + free_phys ( priv->dma, sizeof ( *priv->dma ) ); abort_with_nothing: /* Erase all signs of the failed open. */ memset ( priv, 0, sizeof ( *priv ) ); diff --git a/src/drivers/net/myson.c b/src/drivers/net/myson.c index 4dd0aab4a..4ab2bf345 100644 --- a/src/drivers/net/myson.c +++ b/src/drivers/net/myson.c @@ -165,7 +165,7 @@ static int myson_create_ring ( struct myson_nic *myson, int rc; /* Allocate descriptor ring */ - ring->desc = malloc_dma ( len, MYSON_RING_ALIGN ); + ring->desc = malloc_phys ( len, MYSON_RING_ALIGN ); if ( ! ring->desc ) { rc = -ENOMEM; goto err_alloc; @@ -197,7 +197,7 @@ static int myson_create_ring ( struct myson_nic *myson, return 0; err_64bit: - free_dma ( ring->desc, len ); + free_phys ( ring->desc, len ); ring->desc = NULL; err_alloc: return rc; @@ -217,7 +217,7 @@ static void myson_destroy_ring ( struct myson_nic *myson, writel ( 0, myson->regs + ring->reg ); /* Free descriptor ring */ - free_dma ( ring->desc, len ); + free_phys ( ring->desc, len ); ring->desc = NULL; ring->prod = 0; ring->cons = 0; diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 33cf68b3c..ba99bc2fe 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -408,7 +408,7 @@ static int natsemi_create_ring ( struct natsemi_nic *natsemi, * ensure that it can't possibly cross the boundary of 32-bit * address space. */ - ring->desc = malloc_dma ( len, len ); + ring->desc = malloc_phys ( len, len ); if ( ! ring->desc ) { rc = -ENOMEM; goto err_alloc; @@ -454,7 +454,7 @@ static int natsemi_create_ring ( struct natsemi_nic *natsemi, return 0; err_64bit: - free_dma ( ring->desc, len ); + free_phys ( ring->desc, len ); ring->desc = NULL; err_alloc: return rc; @@ -476,7 +476,7 @@ static void natsemi_destroy_ring ( struct natsemi_nic *natsemi, writel ( 0, natsemi->regs + ring->reg + 4 ); /* Free descriptor ring */ - free_dma ( ring->desc, len ); + free_phys ( ring->desc, len ); ring->desc = NULL; ring->prod = 0; ring->cons = 0; diff --git a/src/drivers/net/netfront.c b/src/drivers/net/netfront.c index b6205542b..be210850a 100644 --- a/src/drivers/net/netfront.c +++ b/src/drivers/net/netfront.c @@ -338,7 +338,7 @@ static int netfront_create_ring ( struct netfront_nic *netfront, ring->id_cons = 0; /* Allocate and initialise shared ring */ - ring->sring.raw = malloc_dma ( PAGE_SIZE, PAGE_SIZE ); + ring->sring.raw = malloc_phys ( PAGE_SIZE, PAGE_SIZE ); if ( ! ring->sring.raw ) { rc = -ENOMEM; goto err_alloc; @@ -368,7 +368,7 @@ static int netfront_create_ring ( struct netfront_nic *netfront, err_write_num: xengrant_invalidate ( xen, ring->ref ); err_permit_access: - free_dma ( ring->sring.raw, PAGE_SIZE ); + free_phys ( ring->sring.raw, PAGE_SIZE ); err_alloc: return rc; } @@ -490,7 +490,7 @@ static void netfront_destroy_ring ( struct netfront_nic *netfront, xengrant_invalidate ( xen, ring->ref ); /* Free page */ - free_dma ( ring->sring.raw, PAGE_SIZE ); + free_phys ( ring->sring.raw, PAGE_SIZE ); ring->sring.raw = NULL; } diff --git a/src/drivers/net/pcnet32.c b/src/drivers/net/pcnet32.c index 2635aaca2..c0dea86a8 100644 --- a/src/drivers/net/pcnet32.c +++ b/src/drivers/net/pcnet32.c @@ -246,7 +246,7 @@ pcnet32_setup_rx_resources ( struct pcnet32_private *priv ) { DBGP ( "pcnet32_setup_rx_resources\n" ); - priv->rx_base = malloc_dma ( RX_RING_BYTES, RX_RING_ALIGN ); + priv->rx_base = malloc_phys ( RX_RING_BYTES, RX_RING_ALIGN ); DBG ( "priv->rx_base = %#08lx\n", virt_to_bus ( priv->rx_base ) ); @@ -270,7 +270,7 @@ pcnet32_free_rx_resources ( struct pcnet32_private *priv ) DBGP ( "pcnet32_free_rx_resources\n" ); - free_dma ( priv->rx_base, RX_RING_BYTES ); + free_phys ( priv->rx_base, RX_RING_BYTES ); for ( i = 0; i < RX_RING_SIZE; i++ ) { free_iob ( priv->rx_iobuf[i] ); @@ -290,7 +290,7 @@ pcnet32_setup_tx_resources ( struct pcnet32_private *priv ) { DBGP ( "pcnet32_setup_tx_resources\n" ); - priv->tx_base = malloc_dma ( TX_RING_BYTES, TX_RING_ALIGN ); + priv->tx_base = malloc_phys ( TX_RING_BYTES, TX_RING_ALIGN ); if ( ! priv->tx_base ) { return -ENOMEM; @@ -312,7 +312,7 @@ pcnet32_free_tx_resources ( struct pcnet32_private *priv ) { DBGP ( "pcnet32_free_tx_resources\n" ); - free_dma ( priv->tx_base, TX_RING_BYTES ); + free_phys ( priv->tx_base, TX_RING_BYTES ); } static int diff --git a/src/drivers/net/phantom/phantom.c b/src/drivers/net/phantom/phantom.c index 8f247ff8e..843459059 100644 --- a/src/drivers/net/phantom/phantom.c +++ b/src/drivers/net/phantom/phantom.c @@ -640,7 +640,7 @@ static int phantom_create_rx_ctx ( struct phantom_nic *phantom ) { int rc; /* Allocate context creation buffer */ - buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN ); + buf = malloc_phys ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN ); if ( ! buf ) { rc = -ENOMEM; goto out; @@ -716,7 +716,7 @@ static int phantom_create_rx_ctx ( struct phantom_nic *phantom ) { phantom, phantom->sds_irq_mask_crb ); out: - free_dma ( buf, sizeof ( *buf ) ); + free_phys ( buf, sizeof ( *buf ) ); return rc; } @@ -765,7 +765,7 @@ static int phantom_create_tx_ctx ( struct phantom_nic *phantom ) { int rc; /* Allocate context creation buffer */ - buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN ); + buf = malloc_phys ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN ); if ( ! buf ) { rc = -ENOMEM; goto out; @@ -821,7 +821,7 @@ static int phantom_create_tx_ctx ( struct phantom_nic *phantom ) { phantom, phantom->cds_producer_crb ); out: - free_dma ( buf, sizeof ( *buf ) ); + free_phys ( buf, sizeof ( *buf ) ); return rc; } @@ -1164,8 +1164,8 @@ static int phantom_open ( struct net_device *netdev ) { int rc; /* Allocate and zero descriptor rings */ - phantom->desc = malloc_dma ( sizeof ( *(phantom->desc) ), - UNM_DMA_BUFFER_ALIGN ); + phantom->desc = malloc_phys ( sizeof ( *(phantom->desc) ), + UNM_DMA_BUFFER_ALIGN ); if ( ! phantom->desc ) { rc = -ENOMEM; goto err_alloc_desc; @@ -1208,7 +1208,7 @@ static int phantom_open ( struct net_device *netdev ) { err_create_tx_ctx: phantom_destroy_rx_ctx ( phantom ); err_create_rx_ctx: - free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) ); + free_phys ( phantom->desc, sizeof ( *(phantom->desc) ) ); phantom->desc = NULL; err_alloc_desc: return rc; @@ -1229,7 +1229,7 @@ static void phantom_close ( struct net_device *netdev ) { phantom_del_macaddr ( phantom, netdev->ll_broadcast ); phantom_destroy_tx_ctx ( phantom ); phantom_destroy_rx_ctx ( phantom ); - free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) ); + free_phys ( phantom->desc, sizeof ( *(phantom->desc) ) ); phantom->desc = NULL; /* Flush any uncompleted descriptors */ diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index e74128c4c..f432dce5f 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -514,7 +514,7 @@ static int realtek_create_buffer ( struct realtek_nic *rtl ) { return 0; /* Allocate buffer */ - rtl->rx_buffer = malloc_dma ( len, RTL_RXBUF_ALIGN ); + rtl->rx_buffer = malloc_phys ( len, RTL_RXBUF_ALIGN ); if ( ! rtl->rx_buffer ) { rc = -ENOMEM; goto err_alloc; @@ -539,7 +539,7 @@ static int realtek_create_buffer ( struct realtek_nic *rtl ) { return 0; err_64bit: - free_dma ( rtl->rx_buffer, len ); + free_phys ( rtl->rx_buffer, len ); rtl->rx_buffer = NULL; err_alloc: return rc; @@ -561,7 +561,7 @@ static void realtek_destroy_buffer ( struct realtek_nic *rtl ) { writel ( 0, rtl->regs + RTL_RBSTART ); /* Free buffer */ - free_dma ( rtl->rx_buffer, len ); + free_phys ( rtl->rx_buffer, len ); rtl->rx_buffer = NULL; rtl->rx_offset = 0; } @@ -582,7 +582,7 @@ static int realtek_create_ring ( struct realtek_nic *rtl, return 0; /* Allocate descriptor ring */ - ring->desc = malloc_dma ( ring->len, RTL_RING_ALIGN ); + ring->desc = malloc_phys ( ring->len, RTL_RING_ALIGN ); if ( ! ring->desc ) return -ENOMEM; @@ -623,7 +623,7 @@ static void realtek_destroy_ring ( struct realtek_nic *rtl, writel ( 0, rtl->regs + ring->reg + 4 ); /* Free descriptor ring */ - free_dma ( ring->desc, ring->len ); + free_phys ( ring->desc, ring->len ); ring->desc = NULL; } diff --git a/src/drivers/net/rhine.c b/src/drivers/net/rhine.c index cbe21c316..f4d3a2580 100644 --- a/src/drivers/net/rhine.c +++ b/src/drivers/net/rhine.c @@ -292,7 +292,7 @@ static int rhine_create_ring ( struct rhine_nic *rhn, unsigned int i; /* Allocate descriptors */ - ring->desc = malloc_dma ( len, RHINE_RING_ALIGN ); + ring->desc = malloc_phys ( len, RHINE_RING_ALIGN ); if ( ! ring->desc ) return -ENOMEM; @@ -328,7 +328,7 @@ static void rhine_destroy_ring ( struct rhine_nic *rhn, writel ( 0, rhn->regs + ring->reg ); /* Free descriptor ring */ - free_dma ( ring->desc, len ); + free_phys ( ring->desc, len ); ring->desc = NULL; ring->prod = 0; ring->cons = 0; diff --git a/src/drivers/net/rtl818x/rtl818x.c b/src/drivers/net/rtl818x/rtl818x.c index f5082084e..599d36fad 100644 --- a/src/drivers/net/rtl818x/rtl818x.c +++ b/src/drivers/net/rtl818x/rtl818x.c @@ -328,8 +328,8 @@ static int rtl818x_init_rx_ring(struct net80211_device *dev) struct rtl818x_rx_desc *entry; int i; - priv->rx_ring = malloc_dma(sizeof(*priv->rx_ring) * RTL818X_RX_RING_SIZE, - RTL818X_RING_ALIGN); + priv->rx_ring = malloc_phys(sizeof(*priv->rx_ring) * RTL818X_RX_RING_SIZE, + RTL818X_RING_ALIGN); priv->rx_ring_dma = virt_to_bus(priv->rx_ring); if (!priv->rx_ring) { DBG("rtl818x %s: cannot allocate RX ring\n", dev->netdev->name); @@ -364,7 +364,7 @@ static void rtl818x_free_rx_ring(struct net80211_device *dev) priv->rx_buf[i] = NULL; } - free_dma(priv->rx_ring, sizeof(*priv->rx_ring) * RTL818X_RX_RING_SIZE); + free_phys(priv->rx_ring, sizeof(*priv->rx_ring) * RTL818X_RX_RING_SIZE); priv->rx_ring = NULL; } @@ -373,8 +373,8 @@ static int rtl818x_init_tx_ring(struct net80211_device *dev) struct rtl818x_priv *priv = dev->priv; int i; - priv->tx_ring = malloc_dma(sizeof(*priv->tx_ring) * RTL818X_TX_RING_SIZE, - RTL818X_RING_ALIGN); + priv->tx_ring = malloc_phys(sizeof(*priv->tx_ring) * RTL818X_TX_RING_SIZE, + RTL818X_RING_ALIGN); priv->tx_ring_dma = virt_to_bus(priv->tx_ring); if (!priv->tx_ring) { DBG("rtl818x %s: cannot allocate TX ring\n", dev->netdev->name); @@ -402,7 +402,7 @@ static void rtl818x_free_tx_ring(struct net80211_device *dev) priv->tx_buf[i] = NULL; } - free_dma(priv->tx_ring, sizeof(*priv->tx_ring) * RTL818X_TX_RING_SIZE); + free_phys(priv->tx_ring, sizeof(*priv->tx_ring) * RTL818X_TX_RING_SIZE); priv->tx_ring = NULL; } diff --git a/src/drivers/net/sfc/efx_hunt.c b/src/drivers/net/sfc/efx_hunt.c index 07dd7dfea..c846379af 100644 --- a/src/drivers/net/sfc/efx_hunt.c +++ b/src/drivers/net/sfc/efx_hunt.c @@ -37,7 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); void efx_hunt_free_special_buffer(void *buf, int bytes) { - free_dma(buf, bytes); + free_phys(buf, bytes); } static void *efx_hunt_alloc_special_buffer(int bytes, @@ -50,7 +50,7 @@ static void *efx_hunt_alloc_special_buffer(int bytes, * buffer will be passed into an MC_CMD_INIT_*Q command to setup the * appropriate type of queue via MCDI. */ - buffer = malloc_dma(bytes, EFX_BUF_ALIGN); + buffer = malloc_phys(bytes, EFX_BUF_ALIGN); if (!buffer) return NULL; diff --git a/src/drivers/net/sis190.c b/src/drivers/net/sis190.c index 11dda1c97..0e4f0762e 100644 --- a/src/drivers/net/sis190.c +++ b/src/drivers/net/sis190.c @@ -552,7 +552,7 @@ static int sis190_open(struct net_device *dev) int rc; /* Allocate TX ring */ - tp->TxDescRing = malloc_dma(TX_RING_BYTES, RING_ALIGNMENT); + tp->TxDescRing = malloc_phys(TX_RING_BYTES, RING_ALIGNMENT); if (!tp->TxDescRing) { DBG("sis190: TX ring allocation failed\n"); rc = -ENOMEM; @@ -561,7 +561,7 @@ static int sis190_open(struct net_device *dev) tp->tx_dma = cpu_to_le32(virt_to_bus(tp->TxDescRing)); /* Allocate RX ring */ - tp->RxDescRing = malloc_dma(RX_RING_BYTES, RING_ALIGNMENT); + tp->RxDescRing = malloc_phys(RX_RING_BYTES, RING_ALIGNMENT); if (!tp->RxDescRing) { DBG("sis190: RX ring allocation failed\n"); rc = -ENOMEM; @@ -600,8 +600,8 @@ static void sis190_free(struct net_device *dev) struct sis190_private *tp = netdev_priv(dev); int i; - free_dma(tp->TxDescRing, TX_RING_BYTES); - free_dma(tp->RxDescRing, RX_RING_BYTES); + free_phys(tp->TxDescRing, TX_RING_BYTES); + free_phys(tp->RxDescRing, RX_RING_BYTES); tp->TxDescRing = NULL; tp->RxDescRing = NULL; diff --git a/src/drivers/net/skge.c b/src/drivers/net/skge.c index c9a7891ba..5aa5e2a6a 100755 --- a/src/drivers/net/skge.c +++ b/src/drivers/net/skge.c @@ -1699,7 +1699,7 @@ void skge_free(struct net_device *dev) free(skge->tx_ring.start); skge->tx_ring.start = NULL; - free_dma(skge->mem, RING_SIZE); + free_phys(skge->mem, RING_SIZE); skge->mem = NULL; skge->dma = 0; } @@ -1714,7 +1714,7 @@ static int skge_up(struct net_device *dev) DBG2(PFX "%s: enabling interface\n", dev->name); - skge->mem = malloc_dma(RING_SIZE, SKGE_RING_ALIGN); + skge->mem = malloc_phys(RING_SIZE, SKGE_RING_ALIGN); skge->dma = virt_to_bus(skge->mem); if (!skge->mem) return -ENOMEM; diff --git a/src/drivers/net/sky2.c b/src/drivers/net/sky2.c index 0d11e17df..9d612c997 100644 --- a/src/drivers/net/sky2.c +++ b/src/drivers/net/sky2.c @@ -1112,10 +1112,10 @@ nomem: /* Free the le and ring buffers */ static void sky2_free_rings(struct sky2_port *sky2) { - free_dma(sky2->rx_le, RX_LE_BYTES); + free_phys(sky2->rx_le, RX_LE_BYTES); free(sky2->rx_ring); - free_dma(sky2->tx_le, TX_RING_SIZE * sizeof(struct sky2_tx_le)); + free_phys(sky2->tx_le, TX_RING_SIZE * sizeof(struct sky2_tx_le)); free(sky2->tx_ring); sky2->tx_le = NULL; @@ -1137,7 +1137,7 @@ static int sky2_up(struct net_device *dev) netdev_link_down(dev); /* must be power of 2 */ - sky2->tx_le = malloc_dma(TX_RING_SIZE * sizeof(struct sky2_tx_le), TX_RING_ALIGN); + sky2->tx_le = malloc_phys(TX_RING_SIZE * sizeof(struct sky2_tx_le), TX_RING_ALIGN); sky2->tx_le_map = virt_to_bus(sky2->tx_le); if (!sky2->tx_le) goto err_out; @@ -1149,7 +1149,7 @@ static int sky2_up(struct net_device *dev) tx_init(sky2); - sky2->rx_le = malloc_dma(RX_LE_BYTES, RX_RING_ALIGN); + sky2->rx_le = malloc_phys(RX_LE_BYTES, RX_RING_ALIGN); sky2->rx_le_map = virt_to_bus(sky2->rx_le); if (!sky2->rx_le) goto err_out; @@ -2285,7 +2285,7 @@ static int sky2_probe(struct pci_device *pdev) } /* ring for status responses */ - hw->st_le = malloc_dma(STATUS_LE_BYTES, STATUS_RING_ALIGN); + hw->st_le = malloc_phys(STATUS_LE_BYTES, STATUS_RING_ALIGN); if (!hw->st_le) goto err_out_iounmap; hw->st_dma = virt_to_bus(hw->st_le); @@ -2344,7 +2344,7 @@ err_out_free_netdev: netdev_put(dev); err_out_free_pci: sky2_write8(hw, B0_CTST, CS_RST_SET); - free_dma(hw->st_le, STATUS_LE_BYTES); + free_phys(hw->st_le, STATUS_LE_BYTES); err_out_iounmap: iounmap((void *)hw->regs); err_out_free_hw: @@ -2373,7 +2373,7 @@ static void sky2_remove(struct pci_device *pdev) sky2_write8(hw, B0_CTST, CS_RST_SET); sky2_read8(hw, B0_CTST); - free_dma(hw->st_le, STATUS_LE_BYTES); + free_phys(hw->st_le, STATUS_LE_BYTES); for (i = hw->ports-1; i >= 0; --i) { netdev_nullify(hw->dev[i]); diff --git a/src/drivers/net/tg3/tg3.c b/src/drivers/net/tg3/tg3.c index f6c038112..cec599c1c 100644 --- a/src/drivers/net/tg3/tg3.c +++ b/src/drivers/net/tg3/tg3.c @@ -42,7 +42,7 @@ void tg3_rx_prodring_fini(struct tg3_rx_prodring_set *tpr) { DBGP("%s\n", __func__); if (tpr->rx_std) { - free_dma(tpr->rx_std, TG3_RX_STD_RING_BYTES(tp)); + free_phys(tpr->rx_std, TG3_RX_STD_RING_BYTES(tp)); tpr->rx_std = NULL; } } @@ -55,7 +55,7 @@ static void tg3_free_consistent(struct tg3 *tp) { DBGP("%s\n", __func__); if (tp->tx_ring) { - free_dma(tp->tx_ring, TG3_TX_RING_BYTES); + free_phys(tp->tx_ring, TG3_TX_RING_BYTES); tp->tx_ring = NULL; } @@ -63,7 +63,7 @@ static void tg3_free_consistent(struct tg3 *tp) tp->tx_buffers = NULL; if (tp->rx_rcb) { - free_dma(tp->rx_rcb, TG3_RX_RCB_RING_BYTES(tp)); + free_phys(tp->rx_rcb, TG3_RX_RCB_RING_BYTES(tp)); tp->rx_rcb_mapping = 0; tp->rx_rcb = NULL; } @@ -71,7 +71,7 @@ static void tg3_free_consistent(struct tg3 *tp) tg3_rx_prodring_fini(&tp->prodring); if (tp->hw_status) { - free_dma(tp->hw_status, TG3_HW_STATUS_SIZE); + free_phys(tp->hw_status, TG3_HW_STATUS_SIZE); tp->status_mapping = 0; tp->hw_status = NULL; } @@ -87,7 +87,7 @@ int tg3_alloc_consistent(struct tg3 *tp) struct tg3_hw_status *sblk; struct tg3_rx_prodring_set *tpr = &tp->prodring; - tp->hw_status = malloc_dma(TG3_HW_STATUS_SIZE, TG3_DMA_ALIGNMENT); + tp->hw_status = malloc_phys(TG3_HW_STATUS_SIZE, TG3_DMA_ALIGNMENT); if (!tp->hw_status) { DBGC(tp->dev, "hw_status alloc failed\n"); goto err_out; @@ -97,7 +97,7 @@ int tg3_alloc_consistent(struct tg3 *tp) memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE); sblk = tp->hw_status; - tpr->rx_std = malloc_dma(TG3_RX_STD_RING_BYTES(tp), TG3_DMA_ALIGNMENT); + tpr->rx_std = malloc_phys(TG3_RX_STD_RING_BYTES(tp), TG3_DMA_ALIGNMENT); if (!tpr->rx_std) { DBGC(tp->dev, "rx prodring alloc failed\n"); goto err_out; @@ -109,7 +109,7 @@ int tg3_alloc_consistent(struct tg3 *tp) if (!tp->tx_buffers) goto err_out; - tp->tx_ring = malloc_dma(TG3_TX_RING_BYTES, TG3_DMA_ALIGNMENT); + tp->tx_ring = malloc_phys(TG3_TX_RING_BYTES, TG3_DMA_ALIGNMENT); if (!tp->tx_ring) goto err_out; tp->tx_desc_mapping = virt_to_bus(tp->tx_ring); @@ -123,7 +123,7 @@ int tg3_alloc_consistent(struct tg3 *tp) tp->rx_rcb_prod_idx = &sblk->idx[0].rx_producer; - tp->rx_rcb = malloc_dma(TG3_RX_RCB_RING_BYTES(tp), TG3_DMA_ALIGNMENT); + tp->rx_rcb = malloc_phys(TG3_RX_RCB_RING_BYTES(tp), TG3_DMA_ALIGNMENT); if (!tp->rx_rcb) goto err_out; tp->rx_rcb_mapping = virt_to_bus(tp->rx_rcb); @@ -541,7 +541,7 @@ static int tg3_test_dma(struct tg3 *tp) u32 *buf; int ret = 0; - buf = malloc_dma(TEST_BUFFER_SIZE, TG3_DMA_ALIGNMENT); + buf = malloc_phys(TEST_BUFFER_SIZE, TG3_DMA_ALIGNMENT); if (!buf) { ret = -ENOMEM; goto out_nofree; @@ -708,7 +708,7 @@ static int tg3_test_dma(struct tg3 *tp) } out: - free_dma(buf, TEST_BUFFER_SIZE); + free_phys(buf, TEST_BUFFER_SIZE); out_nofree: return ret; } diff --git a/src/drivers/net/velocity.c b/src/drivers/net/velocity.c index 994e07a64..373714293 100644 --- a/src/drivers/net/velocity.c +++ b/src/drivers/net/velocity.c @@ -320,7 +320,8 @@ static int velocity_alloc_rings ( struct velocity_nic *vlc ) { vlc->rx_prod = 0; vlc->rx_cons = 0; vlc->rx_commit = 0; - vlc->rx_ring = malloc_dma ( VELOCITY_RXDESC_SIZE, VELOCITY_RING_ALIGN ); + vlc->rx_ring = malloc_phys ( VELOCITY_RXDESC_SIZE, + VELOCITY_RING_ALIGN ); if ( ! vlc->rx_ring ) return -ENOMEM; @@ -332,7 +333,8 @@ static int velocity_alloc_rings ( struct velocity_nic *vlc ) { /* Allocate TX descriptor ring */ vlc->tx_prod = 0; vlc->tx_cons = 0; - vlc->tx_ring = malloc_dma ( VELOCITY_TXDESC_SIZE, VELOCITY_RING_ALIGN ); + vlc->tx_ring = malloc_phys ( VELOCITY_TXDESC_SIZE, + VELOCITY_RING_ALIGN ); if ( ! vlc->tx_ring ) { rc = -ENOMEM; goto err_tx_alloc; @@ -356,7 +358,7 @@ static int velocity_alloc_rings ( struct velocity_nic *vlc ) { return 0; err_tx_alloc: - free_dma ( vlc->rx_ring, VELOCITY_RXDESC_SIZE ); + free_phys ( vlc->rx_ring, VELOCITY_RXDESC_SIZE ); return rc; } @@ -482,7 +484,7 @@ static void velocity_close ( struct net_device *netdev ) { writew ( 0, vlc->regs + VELOCITY_RXDESCNUM ); /* Destroy RX ring */ - free_dma ( vlc->rx_ring, VELOCITY_RXDESC_SIZE ); + free_phys ( vlc->rx_ring, VELOCITY_RXDESC_SIZE ); vlc->rx_ring = NULL; vlc->rx_prod = 0; vlc->rx_cons = 0; @@ -499,7 +501,7 @@ static void velocity_close ( struct net_device *netdev ) { writew ( 0, vlc->regs + VELOCITY_TXDESCNUM ); /* Destroy TX ring */ - free_dma ( vlc->tx_ring, VELOCITY_TXDESC_SIZE ); + free_phys ( vlc->tx_ring, VELOCITY_TXDESC_SIZE ); vlc->tx_ring = NULL; vlc->tx_prod = 0; vlc->tx_cons = 0; diff --git a/src/drivers/net/vmxnet3.c b/src/drivers/net/vmxnet3.c index 3e0ab03cd..63bcf0e01 100644 --- a/src/drivers/net/vmxnet3.c +++ b/src/drivers/net/vmxnet3.c @@ -465,7 +465,8 @@ static int vmxnet3_open ( struct net_device *netdev ) { int rc; /* Allocate DMA areas */ - vmxnet->dma = malloc_dma ( sizeof ( *vmxnet->dma ), VMXNET3_DMA_ALIGN ); + vmxnet->dma = malloc_phys ( sizeof ( *vmxnet->dma ), + VMXNET3_DMA_ALIGN ); if ( ! vmxnet->dma ) { DBGC ( vmxnet, "VMXNET3 %p could not allocate DMA area\n", vmxnet ); @@ -542,7 +543,7 @@ static int vmxnet3_open ( struct net_device *netdev ) { err_activate: vmxnet3_flush_tx ( netdev ); vmxnet3_flush_rx ( netdev ); - free_dma ( vmxnet->dma, sizeof ( *vmxnet->dma ) ); + free_phys ( vmxnet->dma, sizeof ( *vmxnet->dma ) ); err_alloc_dma: return rc; } @@ -559,7 +560,7 @@ static void vmxnet3_close ( struct net_device *netdev ) { vmxnet3_command ( vmxnet, VMXNET3_CMD_RESET_DEV ); vmxnet3_flush_tx ( netdev ); vmxnet3_flush_rx ( netdev ); - free_dma ( vmxnet->dma, sizeof ( *vmxnet->dma ) ); + free_phys ( vmxnet->dma, sizeof ( *vmxnet->dma ) ); } /** vmxnet3 net device operations */ diff --git a/src/drivers/net/vxge/vxge_config.c b/src/drivers/net/vxge/vxge_config.c index ba62b508e..f4d217097 100644 --- a/src/drivers/net/vxge/vxge_config.c +++ b/src/drivers/net/vxge/vxge_config.c @@ -624,10 +624,10 @@ __vxge_hw_ring_create(struct __vxge_hw_virtualpath *vpath, hldev = vpath->hldev; vp_id = vpath->vp_id; - ring->rxdl = malloc_dma(sizeof(struct __vxge_hw_ring_block), + ring->rxdl = malloc_phys(sizeof(struct __vxge_hw_ring_block), sizeof(struct __vxge_hw_ring_block)); if (!ring->rxdl) { - vxge_debug(VXGE_ERR, "%s:%d malloc_dma error\n", + vxge_debug(VXGE_ERR, "%s:%d malloc_phys error\n", __func__, __LINE__); status = VXGE_HW_ERR_OUT_OF_MEMORY; goto exit; @@ -667,7 +667,7 @@ enum vxge_hw_status __vxge_hw_ring_delete(struct __vxge_hw_ring *ring) } if (ring->rxdl) { - free_dma(ring->rxdl, sizeof(struct __vxge_hw_ring_block)); + free_phys(ring->rxdl, sizeof(struct __vxge_hw_ring_block)); ring->rxdl = NULL; } ring->rxd_offset = 0; @@ -826,10 +826,10 @@ __vxge_hw_fifo_create(struct __vxge_hw_virtualpath *vpath, fifo->tx_intr_num = (vpath->vp_id * VXGE_HW_MAX_INTR_PER_VP) + VXGE_HW_VPATH_INTR_TX; - fifo->txdl = malloc_dma(sizeof(struct vxge_hw_fifo_txd) + fifo->txdl = malloc_phys(sizeof(struct vxge_hw_fifo_txd) * fifo->depth, fifo->depth); if (!fifo->txdl) { - vxge_debug(VXGE_ERR, "%s:%d malloc_dma error\n", + vxge_debug(VXGE_ERR, "%s:%d malloc_phys error\n", __func__, __LINE__); return VXGE_HW_ERR_OUT_OF_MEMORY; } @@ -846,7 +846,7 @@ enum vxge_hw_status __vxge_hw_fifo_delete(struct __vxge_hw_fifo *fifo) vxge_trace(); if (fifo->txdl) - free_dma(fifo->txdl, + free_phys(fifo->txdl, sizeof(struct vxge_hw_fifo_txd) * fifo->depth); fifo->txdl = NULL; diff --git a/src/drivers/usb/ehci.c b/src/drivers/usb/ehci.c index 15193efe1..77022a47d 100644 --- a/src/drivers/usb/ehci.c +++ b/src/drivers/usb/ehci.c @@ -565,8 +565,8 @@ static int ehci_ring_alloc ( struct ehci_device *ehci, } /* Allocate queue head */ - ring->head = malloc_dma ( sizeof ( *ring->head ), - ehci_align ( sizeof ( *ring->head ) ) ); + ring->head = malloc_phys ( sizeof ( *ring->head ), + ehci_align ( sizeof ( *ring->head ) ) ); if ( ! ring->head ) { rc = -ENOMEM; goto err_alloc_queue; @@ -579,7 +579,7 @@ static int ehci_ring_alloc ( struct ehci_device *ehci, /* Allocate transfer descriptors */ len = ( EHCI_RING_COUNT * sizeof ( ring->desc[0] ) ); - ring->desc = malloc_dma ( len, sizeof ( ring->desc[0] ) ); + ring->desc = malloc_phys ( len, sizeof ( ring->desc[0] ) ); if ( ! ring->desc ) { rc = -ENOMEM; goto err_alloc_desc; @@ -607,10 +607,10 @@ static int ehci_ring_alloc ( struct ehci_device *ehci, return 0; err_unreachable_desc: - free_dma ( ring->desc, len ); + free_phys ( ring->desc, len ); err_alloc_desc: err_unreachable_queue: - free_dma ( ring->head, sizeof ( *ring->head ) ); + free_phys ( ring->head, sizeof ( *ring->head ) ); err_alloc_queue: free ( ring->iobuf ); err_alloc_iobuf: @@ -631,10 +631,11 @@ static void ehci_ring_free ( struct ehci_ring *ring ) { assert ( ring->iobuf[i] == NULL ); /* Free transfer descriptors */ - free_dma ( ring->desc, ( EHCI_RING_COUNT * sizeof ( ring->desc[0] ) ) ); + free_phys ( ring->desc, ( EHCI_RING_COUNT * + sizeof ( ring->desc[0] ) ) ); /* Free queue head */ - free_dma ( ring->head, sizeof ( *ring->head ) ); + free_phys ( ring->head, sizeof ( *ring->head ) ); /* Free I/O buffers */ free ( ring->iobuf ); @@ -1787,8 +1788,8 @@ static int ehci_bus_open ( struct usb_bus *bus ) { assert ( list_empty ( &ehci->periodic ) ); /* Allocate and initialise asynchronous queue head */ - ehci->head = malloc_dma ( sizeof ( *ehci->head ), - ehci_align ( sizeof ( *ehci->head ) ) ); + ehci->head = malloc_phys ( sizeof ( *ehci->head ), + ehci_align ( sizeof ( *ehci->head ) ) ); if ( ! ehci->head ) { rc = -ENOMEM; goto err_alloc_head; @@ -1816,7 +1817,7 @@ static int ehci_bus_open ( struct usb_bus *bus ) { /* Allocate periodic frame list */ frames = EHCI_PERIODIC_FRAMES ( ehci->flsize ); len = ( frames * sizeof ( ehci->frame[0] ) ); - ehci->frame = malloc_dma ( len, EHCI_PAGE_ALIGN ); + ehci->frame = malloc_phys ( len, EHCI_PAGE_ALIGN ); if ( ! ehci->frame ) { rc = -ENOMEM; goto err_alloc_frame; @@ -1836,10 +1837,10 @@ static int ehci_bus_open ( struct usb_bus *bus ) { ehci_stop ( ehci ); err_unreachable_frame: - free_dma ( ehci->frame, len ); + free_phys ( ehci->frame, len ); err_alloc_frame: err_ctrldssegment: - free_dma ( ehci->head, sizeof ( *ehci->head ) ); + free_phys ( ehci->head, sizeof ( *ehci->head ) ); err_alloc_head: return rc; } @@ -1861,10 +1862,10 @@ static void ehci_bus_close ( struct usb_bus *bus ) { ehci_stop ( ehci ); /* Free periodic frame list */ - free_dma ( ehci->frame, ( frames * sizeof ( ehci->frame[0] ) ) ); + free_phys ( ehci->frame, ( frames * sizeof ( ehci->frame[0] ) ) ); /* Free asynchronous schedule */ - free_dma ( ehci->head, sizeof ( *ehci->head ) ); + free_phys ( ehci->head, sizeof ( *ehci->head ) ); } /** diff --git a/src/drivers/usb/uhci.c b/src/drivers/usb/uhci.c index ce2962d36..47474bdc7 100644 --- a/src/drivers/usb/uhci.c +++ b/src/drivers/usb/uhci.c @@ -179,7 +179,7 @@ static int uhci_ring_alloc ( struct uhci_ring *ring ) { memset ( ring, 0, sizeof ( *ring ) ); /* Allocate queue head */ - ring->head = malloc_dma ( sizeof ( *ring->head ), UHCI_ALIGN ); + ring->head = malloc_phys ( sizeof ( *ring->head ), UHCI_ALIGN ); if ( ! ring->head ) { rc = -ENOMEM; goto err_alloc; @@ -194,7 +194,7 @@ static int uhci_ring_alloc ( struct uhci_ring *ring ) { return 0; err_unreachable: - free_dma ( ring->head, sizeof ( *ring->head ) ); + free_phys ( ring->head, sizeof ( *ring->head ) ); err_alloc: return rc; } @@ -213,7 +213,7 @@ static void uhci_ring_free ( struct uhci_ring *ring ) { assert ( ring->xfer[i] == NULL ); /* Free queue head */ - free_dma ( ring->head, sizeof ( *ring->head ) ); + free_phys ( ring->head, sizeof ( *ring->head ) ); } /** @@ -263,7 +263,7 @@ static int uhci_enqueue ( struct uhci_ring *ring, struct io_buffer *iobuf, /* Allocate transfer descriptors */ len = ( count * sizeof ( xfer->desc[0] ) ); - xfer->desc = malloc_dma ( len, UHCI_ALIGN ); + xfer->desc = malloc_phys ( len, UHCI_ALIGN ); if ( ! xfer->desc ) { rc = -ENOMEM; goto err_alloc_desc; @@ -299,7 +299,7 @@ static int uhci_enqueue ( struct uhci_ring *ring, struct io_buffer *iobuf, return 0; err_unreachable_desc: - free_dma ( xfer->desc, len ); + free_phys ( xfer->desc, len ); err_alloc_desc: free ( xfer ); err_alloc_xfer: @@ -377,7 +377,7 @@ static struct io_buffer * uhci_dequeue ( struct uhci_ring *ring ) { /* Free transfer descriptors */ len = ( xfer->prod * sizeof ( xfer->desc[0] ) ); - free_dma ( xfer->desc, len ); + free_phys ( xfer->desc, len ); /* Free transfer */ free ( xfer ); @@ -1312,7 +1312,7 @@ static int uhci_bus_open ( struct usb_bus *bus ) { assert ( list_empty ( &uhci->periodic ) ); /* Allocate and initialise asynchronous queue head */ - uhci->head = malloc_dma ( sizeof ( *uhci->head ), UHCI_ALIGN ); + uhci->head = malloc_phys ( sizeof ( *uhci->head ), UHCI_ALIGN ); if ( ! uhci->head ) { rc = -ENOMEM; goto err_alloc_head; @@ -1324,8 +1324,8 @@ static int uhci_bus_open ( struct usb_bus *bus ) { uhci_async_schedule ( uhci ); /* Allocate periodic frame list */ - uhci->frame = malloc_dma ( sizeof ( *uhci->frame ), - sizeof ( *uhci->frame ) ); + uhci->frame = malloc_phys ( sizeof ( *uhci->frame ), + sizeof ( *uhci->frame ) ); if ( ! uhci->frame ) { rc = -ENOMEM; goto err_alloc_frame; @@ -1343,10 +1343,10 @@ static int uhci_bus_open ( struct usb_bus *bus ) { uhci_stop ( uhci ); err_unreachable_frame: - free_dma ( uhci->frame, sizeof ( *uhci->frame ) ); + free_phys ( uhci->frame, sizeof ( *uhci->frame ) ); err_alloc_frame: err_unreachable_head: - free_dma ( uhci->head, sizeof ( *uhci->head ) ); + free_phys ( uhci->head, sizeof ( *uhci->head ) ); err_alloc_head: return rc; } @@ -1367,10 +1367,10 @@ static void uhci_bus_close ( struct usb_bus *bus ) { uhci_stop ( uhci ); /* Free periodic frame list */ - free_dma ( uhci->frame, sizeof ( *uhci->frame ) ); + free_phys ( uhci->frame, sizeof ( *uhci->frame ) ); /* Free asynchronous schedule */ - free_dma ( uhci->head, sizeof ( *uhci->head ) ); + free_phys ( uhci->head, sizeof ( *uhci->head ) ); } /** diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index c4a1dc337..7f55a90f2 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -919,7 +919,7 @@ static int xhci_dcbaa_alloc ( struct xhci_device *xhci ) { * with a minimum of 64 bytes). */ len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa[0] ) ); - xhci->dcbaa = malloc_dma ( len, xhci_align ( len ) ); + xhci->dcbaa = malloc_phys ( len, xhci_align ( len ) ); if ( ! xhci->dcbaa ) { DBGC ( xhci, "XHCI %s could not allocate DCBAA\n", xhci->name ); rc = -ENOMEM; @@ -938,7 +938,7 @@ static int xhci_dcbaa_alloc ( struct xhci_device *xhci ) { return 0; err_writeq: - free_dma ( xhci->dcbaa, len ); + free_phys ( xhci->dcbaa, len ); err_alloc: return rc; } @@ -961,7 +961,7 @@ static void xhci_dcbaa_free ( struct xhci_device *xhci ) { /* Free DCBAA */ len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa[0] ) ); - free_dma ( xhci->dcbaa, len ); + free_phys ( xhci->dcbaa, len ); } /****************************************************************************** @@ -1002,7 +1002,7 @@ static int xhci_scratchpad_alloc ( struct xhci_device *xhci ) { /* Allocate scratchpad array */ array_len = ( xhci->scratchpads * sizeof ( xhci->scratchpad_array[0] )); xhci->scratchpad_array = - malloc_dma ( array_len, xhci_align ( array_len ) ); + malloc_phys ( array_len, xhci_align ( array_len ) ); if ( ! xhci->scratchpad_array ) { DBGC ( xhci, "XHCI %s could not allocate scratchpad buffer " "array\n", xhci->name ); @@ -1027,7 +1027,7 @@ static int xhci_scratchpad_alloc ( struct xhci_device *xhci ) { ( virt_to_phys ( xhci->scratchpad_array ) + array_len ) ); return 0; - free_dma ( xhci->scratchpad_array, array_len ); + free_phys ( xhci->scratchpad_array, array_len ); err_alloc_array: ufree ( xhci->scratchpad ); err_alloc: @@ -1052,7 +1052,7 @@ static void xhci_scratchpad_free ( struct xhci_device *xhci ) { /* Free scratchpad array */ array_len = ( xhci->scratchpads * sizeof ( xhci->scratchpad_array[0] )); - free_dma ( xhci->scratchpad_array, array_len ); + free_phys ( xhci->scratchpad_array, array_len ); /* Free scratchpads */ ufree ( xhci->scratchpad ); @@ -1202,7 +1202,7 @@ static int xhci_ring_alloc ( struct xhci_device *xhci, } /* Allocate TRBs */ - ring->trb = malloc_dma ( ring->len, xhci_align ( ring->len ) ); + ring->trb = malloc_phys ( ring->len, xhci_align ( ring->len ) ); if ( ! ring->trb ) { rc = -ENOMEM; goto err_alloc_trb; @@ -1218,7 +1218,7 @@ static int xhci_ring_alloc ( struct xhci_device *xhci, return 0; - free_dma ( ring->trb, ring->len ); + free_phys ( ring->trb, ring->len ); err_alloc_trb: free ( ring->iobuf ); err_alloc_iobuf: @@ -1256,7 +1256,7 @@ static void xhci_ring_free ( struct xhci_trb_ring *ring ) { assert ( ring->iobuf[i] == NULL ); /* Free TRBs */ - free_dma ( ring->trb, ring->len ); + free_phys ( ring->trb, ring->len ); /* Free I/O buffers */ free ( ring->iobuf ); @@ -1469,7 +1469,7 @@ static int xhci_event_alloc ( struct xhci_device *xhci ) { /* Allocate event ring */ count = ( 1 << XHCI_EVENT_TRBS_LOG2 ); len = ( count * sizeof ( event->trb[0] ) ); - event->trb = malloc_dma ( len, xhci_align ( len ) ); + event->trb = malloc_phys ( len, xhci_align ( len ) ); if ( ! event->trb ) { rc = -ENOMEM; goto err_alloc_trb; @@ -1477,8 +1477,8 @@ static int xhci_event_alloc ( struct xhci_device *xhci ) { memset ( event->trb, 0, len ); /* Allocate event ring segment table */ - event->segment = malloc_dma ( sizeof ( event->segment[0] ), - xhci_align ( sizeof (event->segment[0]))); + event->segment = malloc_phys ( sizeof ( event->segment[0] ), + xhci_align ( sizeof(event->segment[0]))); if ( ! event->segment ) { rc = -ENOMEM; goto err_alloc_segment; @@ -1508,9 +1508,9 @@ static int xhci_event_alloc ( struct xhci_device *xhci ) { err_writeq_erstba: xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERDP ( 0 ) ); err_writeq_erdp: - free_dma ( event->trb, len ); + free_phys ( event->trb, len ); err_alloc_segment: - free_dma ( event->segment, sizeof ( event->segment[0] ) ); + free_phys ( event->segment, sizeof ( event->segment[0] ) ); err_alloc_trb: return rc; } @@ -1531,12 +1531,12 @@ static void xhci_event_free ( struct xhci_device *xhci ) { xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERDP ( 0 ) ); /* Free event ring segment table */ - free_dma ( event->segment, sizeof ( event->segment[0] ) ); + free_phys ( event->segment, sizeof ( event->segment[0] ) ); /* Free event ring */ count = ( 1 << XHCI_EVENT_TRBS_LOG2 ); len = ( count * sizeof ( event->trb[0] ) ); - free_dma ( event->trb, len ); + free_phys ( event->trb, len ); } /** @@ -1948,7 +1948,7 @@ static int xhci_context ( struct xhci_device *xhci, struct xhci_slot *slot, /* Allocate an input context */ len = xhci_input_context_offset ( xhci, XHCI_CTX_END ); - input = malloc_dma ( len, xhci_align ( len ) ); + input = malloc_phys ( len, xhci_align ( len ) ); if ( ! input ) { rc = -ENOMEM; goto err_alloc; @@ -1969,7 +1969,7 @@ static int xhci_context ( struct xhci_device *xhci, struct xhci_slot *slot, goto err_command; err_command: - free_dma ( input, len ); + free_phys ( input, len ); err_alloc: return rc; } @@ -2693,7 +2693,7 @@ static int xhci_device_open ( struct usb_device *usb ) { /* Allocate a device context */ len = xhci_device_context_offset ( xhci, XHCI_CTX_END ); - slot->context = malloc_dma ( len, xhci_align ( len ) ); + slot->context = malloc_phys ( len, xhci_align ( len ) ); if ( ! slot->context ) { rc = -ENOMEM; goto err_alloc_context; @@ -2710,7 +2710,7 @@ static int xhci_device_open ( struct usb_device *usb ) { return 0; xhci->dcbaa[id] = 0; - free_dma ( slot->context, len ); + free_phys ( slot->context, len ); err_alloc_context: xhci->slot[id] = NULL; free ( slot ); @@ -2750,7 +2750,7 @@ static void xhci_device_close ( struct usb_device *usb ) { /* Free slot */ if ( slot->context ) { - free_dma ( slot->context, len ); + free_phys ( slot->context, len ); xhci->dcbaa[id] = 0; } xhci->slot[id] = NULL; diff --git a/src/include/ipxe/malloc.h b/src/include/ipxe/malloc.h index 1878978fd..180ca001d 100644 --- a/src/include/ipxe/malloc.h +++ b/src/include/ipxe/malloc.h @@ -14,7 +14,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /* * Prototypes for the standard functions (malloc() et al) are in * stdlib.h. Include only if you need the - * non-standard functions, such as malloc_dma(). + * non-standard functions, such as malloc_phys(). * */ #include @@ -32,20 +32,18 @@ extern void mpopulate ( void *start, size_t len ); extern void mdumpfree ( void ); /** - * Allocate memory for DMA + * Allocate memory with specified physical alignment and offset * * @v size Requested size * @v align Physical alignment * @v offset Offset from physical alignment * @ret ptr Memory, or NULL * - * Allocates physically-aligned memory for DMA. - * * @c align must be a power of two. @c size may not be zero. */ -static inline void * __malloc malloc_dma_offset ( size_t size, - size_t phys_align, - size_t offset ) { +static inline void * __malloc malloc_phys_offset ( size_t size, + size_t phys_align, + size_t offset ) { void * ptr = alloc_memblock ( size, phys_align, offset ); if ( ptr && size ) VALGRIND_MALLOCLIKE_BLOCK ( ptr, size, 0, 0 ); @@ -53,32 +51,30 @@ static inline void * __malloc malloc_dma_offset ( size_t size, } /** - * Allocate memory for DMA + * Allocate memory with specified physical alignment * * @v size Requested size * @v align Physical alignment * @ret ptr Memory, or NULL * - * Allocates physically-aligned memory for DMA. - * * @c align must be a power of two. @c size may not be zero. */ -static inline void * __malloc malloc_dma ( size_t size, size_t phys_align ) { - return malloc_dma_offset ( size, phys_align, 0 ); +static inline void * __malloc malloc_phys ( size_t size, size_t phys_align ) { + return malloc_phys_offset ( size, phys_align, 0 ); } /** - * Free memory allocated with malloc_dma() + * Free memory allocated with malloc_phys() * - * @v ptr Memory allocated by malloc_dma(), or NULL - * @v size Size of memory, as passed to malloc_dma() + * @v ptr Memory allocated by malloc_phys(), or NULL + * @v size Size of memory, as passed to malloc_phys() * - * Memory allocated with malloc_dma() can only be freed with - * free_dma(); it cannot be freed with the standard free(). + * Memory allocated with malloc_phys() can only be freed with + * free_phys(); it cannot be freed with the standard free(). * * If @c ptr is NULL, no action is taken. */ -static inline void free_dma ( void *ptr, size_t size ) { +static inline void free_phys ( void *ptr, size_t size ) { VALGRIND_FREELIKE_BLOCK ( ptr, 0 ); free_memblock ( ptr, size ); } diff --git a/src/interface/hyperv/vmbus.c b/src/interface/hyperv/vmbus.c index e50fe9951..86d2a08d7 100644 --- a/src/interface/hyperv/vmbus.c +++ b/src/interface/hyperv/vmbus.c @@ -434,7 +434,7 @@ int vmbus_open ( struct vmbus_device *vmdev, len = ( sizeof ( *vmdev->out ) + out_len + sizeof ( *vmdev->in ) + in_len ); assert ( ( len % PAGE_SIZE ) == 0 ); - ring = malloc_dma ( len, PAGE_SIZE ); + ring = malloc_phys ( len, PAGE_SIZE ); if ( ! ring ) { rc = -ENOMEM; goto err_alloc_ring; @@ -509,7 +509,7 @@ int vmbus_open ( struct vmbus_device *vmdev, err_post_message: vmbus_gpadl_teardown ( vmdev, vmdev->gpadl ); err_establish: - free_dma ( ring, len ); + free_phys ( ring, len ); err_alloc_ring: free ( packet ); err_alloc_packet: @@ -555,7 +555,7 @@ void vmbus_close ( struct vmbus_device *vmdev ) { /* Free ring buffer */ len = ( sizeof ( *vmdev->out ) + vmdev->out_len + sizeof ( *vmdev->in ) + vmdev->in_len ); - free_dma ( vmdev->out, len ); + free_phys ( vmdev->out, len ); vmdev->out = NULL; vmdev->in = NULL; -- cgit v1.2.3-55-g7522 From 580d9b00da73529cad3596a64d6d908b6e0601f6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 4 Nov 2020 15:25:30 +0000 Subject: [realtek] Update driver to use DMA API Signed-off-by: Michael Brown --- src/drivers/net/realtek.c | 180 +++++++++++++++++++++++----------------------- src/drivers/net/realtek.h | 42 +++++++++-- 2 files changed, 127 insertions(+), 95 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index f432dce5f..afca089ad 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -507,27 +508,17 @@ static void realtek_check_link ( struct net_device *netdev ) { static int realtek_create_buffer ( struct realtek_nic *rtl ) { size_t len = ( RTL_RXBUF_LEN + RTL_RXBUF_PAD ); physaddr_t address; - int rc; /* Do nothing unless in legacy mode */ if ( ! rtl->legacy ) return 0; /* Allocate buffer */ - rtl->rx_buffer = malloc_phys ( len, RTL_RXBUF_ALIGN ); - if ( ! rtl->rx_buffer ) { - rc = -ENOMEM; - goto err_alloc; - } - address = virt_to_bus ( rtl->rx_buffer ); - - /* Check that card can support address */ - if ( address & ~0xffffffffULL ) { - DBGC ( rtl, "REALTEK %p cannot support 64-bit RX buffer " - "address\n", rtl ); - rc = -ENOTSUP; - goto err_64bit; - } + rtl->rxbuf.data = dma_alloc ( rtl->dma, len, RTL_RXBUF_ALIGN, + &rtl->rxbuf.map ); + if ( ! rtl->rxbuf.data ) + return -ENOMEM; + address = rtl->rxbuf.map.addr; /* Program buffer address */ writel ( address, rtl->regs + RTL_RBSTART ); @@ -537,12 +528,6 @@ static int realtek_create_buffer ( struct realtek_nic *rtl ) { ( ( unsigned long long ) address + len ) ); return 0; - - err_64bit: - free_phys ( rtl->rx_buffer, len ); - rtl->rx_buffer = NULL; - err_alloc: - return rc; } /** @@ -561,9 +546,9 @@ static void realtek_destroy_buffer ( struct realtek_nic *rtl ) { writel ( 0, rtl->regs + RTL_RBSTART ); /* Free buffer */ - free_phys ( rtl->rx_buffer, len ); - rtl->rx_buffer = NULL; - rtl->rx_offset = 0; + dma_free ( rtl->dma, rtl->rxbuf.data, len, &rtl->rxbuf.map ); + rtl->rxbuf.data = NULL; + rtl->rxbuf.offset = 0; } /** @@ -582,7 +567,8 @@ static int realtek_create_ring ( struct realtek_nic *rtl, return 0; /* Allocate descriptor ring */ - ring->desc = malloc_phys ( ring->len, RTL_RING_ALIGN ); + ring->desc = dma_alloc ( rtl->dma, ring->len, RTL_RING_ALIGN, + &ring->map ); if ( ! ring->desc ) return -ENOMEM; @@ -590,7 +576,7 @@ static int realtek_create_ring ( struct realtek_nic *rtl, memset ( ring->desc, 0, ring->len ); /* Program ring address */ - address = virt_to_bus ( ring->desc ); + address = ring->map.addr; writel ( ( ( ( uint64_t ) address ) >> 32 ), rtl->regs + ring->reg + 4 ); writel ( ( address & 0xffffffffUL ), rtl->regs + ring->reg ); @@ -623,7 +609,7 @@ static void realtek_destroy_ring ( struct realtek_nic *rtl, writel ( 0, rtl->regs + ring->reg + 4 ); /* Free descriptor ring */ - free_phys ( ring->desc, ring->len ); + dma_free ( rtl->dma, ring->desc, ring->len, &ring->map ); ring->desc = NULL; } @@ -635,44 +621,45 @@ static void realtek_destroy_ring ( struct realtek_nic *rtl, static void realtek_refill_rx ( struct realtek_nic *rtl ) { struct realtek_descriptor *rx; struct io_buffer *iobuf; + struct dma_mapping *map; unsigned int rx_idx; - physaddr_t address; int is_last; /* Do nothing in legacy mode */ if ( rtl->legacy ) return; - while ( ( rtl->rx.prod - rtl->rx.cons ) < RTL_NUM_RX_DESC ) { + while ( ( rtl->rx.ring.prod - rtl->rx.ring.cons ) < RTL_NUM_RX_DESC ) { + + /* Get next receive descriptor */ + rx_idx = ( rtl->rx.ring.prod % RTL_NUM_RX_DESC ); + is_last = ( rx_idx == ( RTL_NUM_RX_DESC - 1 ) ); + rx = &rtl->rx.ring.desc[rx_idx]; + map = &rtl->rx.map[rx_idx]; + assert ( rtl->rx.iobuf[rx_idx] == NULL ); /* Allocate I/O buffer */ - iobuf = alloc_iob ( RTL_RX_MAX_LEN ); + iobuf = dma_alloc_rx_iob ( rtl->dma, RTL_RX_MAX_LEN, map ); if ( ! iobuf ) { /* Wait for next refill */ return; } + rtl->rx.iobuf[rx_idx] = iobuf; - /* Get next receive descriptor */ - rx_idx = ( rtl->rx.prod++ % RTL_NUM_RX_DESC ); - is_last = ( rx_idx == ( RTL_NUM_RX_DESC - 1 ) ); - rx = &rtl->rx.desc[rx_idx]; + /* Update producer index */ + rtl->rx.ring.prod++; /* Populate receive descriptor */ - address = virt_to_bus ( iobuf->data ); - rx->address = cpu_to_le64 ( address ); + rx->address = cpu_to_le64 ( map->addr ); rx->length = cpu_to_le16 ( RTL_RX_MAX_LEN ); wmb(); rx->flags = ( cpu_to_le16 ( RTL_DESC_OWN ) | ( is_last ? cpu_to_le16 ( RTL_DESC_EOR ) : 0 ) ); wmb(); - /* Record I/O buffer */ - assert ( rtl->rx_iobuf[rx_idx] == NULL ); - rtl->rx_iobuf[rx_idx] = iobuf; - DBGC2 ( rtl, "REALTEK %p RX %d is [%llx,%llx)\n", rtl, rx_idx, - ( ( unsigned long long ) address ), - ( ( unsigned long long ) address + RTL_RX_MAX_LEN ) ); + ( ( unsigned long long ) map->addr ), + ( ( unsigned long long ) map->addr + RTL_RX_MAX_LEN ) ); } } @@ -689,11 +676,11 @@ static int realtek_open ( struct net_device *netdev ) { int rc; /* Create transmit descriptor ring */ - if ( ( rc = realtek_create_ring ( rtl, &rtl->tx ) ) != 0 ) + if ( ( rc = realtek_create_ring ( rtl, &rtl->tx.ring ) ) != 0 ) goto err_create_tx; /* Create receive descriptor ring */ - if ( ( rc = realtek_create_ring ( rtl, &rtl->rx ) ) != 0 ) + if ( ( rc = realtek_create_ring ( rtl, &rtl->rx.ring ) ) != 0 ) goto err_create_rx; /* Create receive buffer */ @@ -734,9 +721,9 @@ static int realtek_open ( struct net_device *netdev ) { realtek_destroy_buffer ( rtl ); err_create_buffer: - realtek_destroy_ring ( rtl, &rtl->rx ); + realtek_destroy_ring ( rtl, &rtl->rx.ring ); err_create_rx: - realtek_destroy_ring ( rtl, &rtl->tx ); + realtek_destroy_ring ( rtl, &rtl->tx.ring ); err_create_tx: return rc; } @@ -757,17 +744,23 @@ static void realtek_close ( struct net_device *netdev ) { realtek_destroy_buffer ( rtl ); /* Destroy receive descriptor ring */ - realtek_destroy_ring ( rtl, &rtl->rx ); + realtek_destroy_ring ( rtl, &rtl->rx.ring ); /* Discard any unused receive buffers */ for ( i = 0 ; i < RTL_NUM_RX_DESC ; i++ ) { - if ( rtl->rx_iobuf[i] ) - free_iob ( rtl->rx_iobuf[i] ); - rtl->rx_iobuf[i] = NULL; + if ( rtl->rx.iobuf[i] ) { + dma_unmap ( rtl->dma, &rtl->rx.map[i] ); + free_iob ( rtl->rx.iobuf[i] ); + } + rtl->rx.iobuf[i] = NULL; } + /* Unmap any incomplete transmit buffers */ + for ( i = rtl->tx.ring.cons ; i != rtl->tx.ring.prod ; i++ ) + dma_unmap ( rtl->dma, &rtl->tx.map[ i % RTL_NUM_TX_DESC ] ); + /* Destroy transmit descriptor ring */ - realtek_destroy_ring ( rtl, &rtl->tx ); + realtek_destroy_ring ( rtl, &rtl->tx.ring ); /* Reset legacy transmit descriptor index, if applicable */ if ( rtl->legacy ) @@ -785,30 +778,34 @@ static int realtek_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct realtek_nic *rtl = netdev->priv; struct realtek_descriptor *tx; + struct dma_mapping *map; unsigned int tx_idx; physaddr_t address; int is_last; + int rc; /* Get next transmit descriptor */ - if ( ( rtl->tx.prod - rtl->tx.cons ) >= RTL_NUM_TX_DESC ) { + if ( ( rtl->tx.ring.prod - rtl->tx.ring.cons ) >= RTL_NUM_TX_DESC ) { netdev_tx_defer ( netdev, iobuf ); return 0; } - tx_idx = ( rtl->tx.prod++ % RTL_NUM_TX_DESC ); - - /* Transmit packet */ - if ( rtl->legacy ) { + tx_idx = ( rtl->tx.ring.prod % RTL_NUM_TX_DESC ); + map = &rtl->tx.map[tx_idx]; - /* Pad and align packet */ + /* Pad and align packet, if needed */ + if ( rtl->legacy ) iob_pad ( iobuf, ETH_ZLEN ); - address = virt_to_bus ( iobuf->data ); - /* Check that card can support address */ - if ( address & ~0xffffffffULL ) { - DBGC ( rtl, "REALTEK %p cannot support 64-bit TX " - "buffer address\n", rtl ); - return -ENOTSUP; - } + /* Map I/O buffer */ + if ( ( rc = dma_map_tx_iob ( rtl->dma, iobuf, map ) ) != 0 ) + return rc; + address = map->addr; + + /* Update producer index */ + rtl->tx.ring.prod++; + + /* Transmit packet */ + if ( rtl->legacy ) { /* Add to transmit ring */ writel ( address, rtl->regs + RTL_TSAD ( tx_idx ) ); @@ -818,9 +815,8 @@ static int realtek_transmit ( struct net_device *netdev, } else { /* Populate transmit descriptor */ - address = virt_to_bus ( iobuf->data ); is_last = ( tx_idx == ( RTL_NUM_TX_DESC - 1 ) ); - tx = &rtl->tx.desc[tx_idx]; + tx = &rtl->tx.ring.desc[tx_idx]; tx->address = cpu_to_le64 ( address ); tx->length = cpu_to_le16 ( iob_len ( iobuf ) ); wmb(); @@ -834,9 +830,8 @@ static int realtek_transmit ( struct net_device *netdev, } DBGC2 ( rtl, "REALTEK %p TX %d is [%llx,%llx)\n", rtl, tx_idx, - ( ( unsigned long long ) virt_to_bus ( iobuf->data ) ), - ( ( ( unsigned long long ) virt_to_bus ( iobuf->data ) ) + - iob_len ( iobuf ) ) ); + ( ( unsigned long long ) address ), + ( ( ( unsigned long long ) address ) + iob_len ( iobuf ) ) ); return 0; } @@ -852,10 +847,10 @@ static void realtek_poll_tx ( struct net_device *netdev ) { unsigned int tx_idx; /* Check for completed packets */ - while ( rtl->tx.cons != rtl->tx.prod ) { + while ( rtl->tx.ring.cons != rtl->tx.ring.prod ) { /* Get next transmit descriptor */ - tx_idx = ( rtl->tx.cons % RTL_NUM_TX_DESC ); + tx_idx = ( rtl->tx.ring.cons % RTL_NUM_TX_DESC ); /* Stop if descriptor is still in use */ if ( rtl->legacy ) { @@ -868,15 +863,18 @@ static void realtek_poll_tx ( struct net_device *netdev ) { } else { /* Check ownership bit in descriptor */ - tx = &rtl->tx.desc[tx_idx]; + tx = &rtl->tx.ring.desc[tx_idx]; if ( tx->flags & cpu_to_le16 ( RTL_DESC_OWN ) ) return; } DBGC2 ( rtl, "REALTEK %p TX %d complete\n", rtl, tx_idx ); + /* Unmap I/O buffer */ + dma_unmap ( rtl->dma, &rtl->tx.map[tx_idx] ); + /* Complete TX descriptor */ - rtl->tx.cons++; + rtl->tx.ring.cons++; netdev_tx_complete_next ( netdev ); } } @@ -896,12 +894,12 @@ static void realtek_legacy_poll_rx ( struct net_device *netdev ) { while ( ! ( readb ( rtl->regs + RTL_CR ) & RTL_CR_BUFE ) ) { /* Extract packet from receive buffer */ - rx = ( rtl->rx_buffer + rtl->rx_offset ); + rx = ( rtl->rxbuf.data + rtl->rxbuf.offset ); len = le16_to_cpu ( rx->length ); if ( rx->status & cpu_to_le16 ( RTL_STAT_ROK ) ) { DBGC2 ( rtl, "REALTEK %p RX offset %x+%zx\n", - rtl, rtl->rx_offset, len ); + rtl, rtl->rxbuf.offset, len ); /* Allocate I/O buffer */ iobuf = alloc_iob ( len ); @@ -921,16 +919,16 @@ static void realtek_legacy_poll_rx ( struct net_device *netdev ) { } else { DBGC ( rtl, "REALTEK %p RX offset %x+%zx error %04x\n", - rtl, rtl->rx_offset, len, + rtl, rtl->rxbuf.offset, len, le16_to_cpu ( rx->status ) ); netdev_rx_err ( netdev, NULL, -EIO ); } /* Update buffer offset */ - rtl->rx_offset = ( rtl->rx_offset + sizeof ( *rx ) + len ); - rtl->rx_offset = ( ( rtl->rx_offset + 3 ) & ~3 ); - rtl->rx_offset = ( rtl->rx_offset % RTL_RXBUF_LEN ); - writew ( ( rtl->rx_offset - 16 ), rtl->regs + RTL_CAPR ); + rtl->rxbuf.offset += ( sizeof ( *rx ) + len ); + rtl->rxbuf.offset = ( ( rtl->rxbuf.offset + 3 ) & ~3 ); + rtl->rxbuf.offset = ( rtl->rxbuf.offset % RTL_RXBUF_LEN ); + writew ( ( rtl->rxbuf.offset - 16 ), rtl->regs + RTL_CAPR ); /* Give chip time to react before rechecking RTL_CR */ readw ( rtl->regs + RTL_CAPR ); @@ -956,19 +954,22 @@ static void realtek_poll_rx ( struct net_device *netdev ) { } /* Check for received packets */ - while ( rtl->rx.cons != rtl->rx.prod ) { + while ( rtl->rx.ring.cons != rtl->rx.ring.prod ) { /* Get next receive descriptor */ - rx_idx = ( rtl->rx.cons % RTL_NUM_RX_DESC ); - rx = &rtl->rx.desc[rx_idx]; + rx_idx = ( rtl->rx.ring.cons % RTL_NUM_RX_DESC ); + rx = &rtl->rx.ring.desc[rx_idx]; /* Stop if descriptor is still in use */ if ( rx->flags & cpu_to_le16 ( RTL_DESC_OWN ) ) return; + /* Unmap buffer */ + dma_unmap ( rtl->dma, &rtl->rx.map[rx_idx] ); + /* Populate I/O buffer */ - iobuf = rtl->rx_iobuf[rx_idx]; - rtl->rx_iobuf[rx_idx] = NULL; + iobuf = rtl->rx.iobuf[rx_idx]; + rtl->rx.iobuf[rx_idx] = NULL; len = ( le16_to_cpu ( rx->length ) & RTL_DESC_SIZE_MASK ); iob_put ( iobuf, ( len - 4 /* strip CRC */ ) ); @@ -983,7 +984,7 @@ static void realtek_poll_rx ( struct net_device *netdev ) { "%zd)\n", rtl, rx_idx, len ); netdev_rx ( netdev, iobuf ); } - rtl->rx.cons++; + rtl->rx.ring.cons++; } } @@ -1088,11 +1089,13 @@ static void realtek_detect ( struct realtek_nic *rtl ) { DBGC ( rtl, "REALTEK %p appears to be an RTL8169\n", rtl ); rtl->have_phy_regs = 1; rtl->tppoll = RTL_TPPOLL_8169; + dma_set_mask_64bit ( rtl->dma ); } else { if ( ( check_cpcr == cpcr ) && ( cpcr != 0xffff ) ) { DBGC ( rtl, "REALTEK %p appears to be an RTL8139C+\n", rtl ); rtl->tppoll = RTL_TPPOLL_8139CP; + dma_set_mask_64bit ( rtl->dma ); } else { DBGC ( rtl, "REALTEK %p appears to be an RTL8139\n", rtl ); @@ -1125,8 +1128,9 @@ static int realtek_probe ( struct pci_device *pci ) { pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( rtl, 0, sizeof ( *rtl ) ); - realtek_init_ring ( &rtl->tx, RTL_NUM_TX_DESC, RTL_TNPDS ); - realtek_init_ring ( &rtl->rx, RTL_NUM_RX_DESC, RTL_RDSAR ); + rtl->dma = &pci->dma; + realtek_init_ring ( &rtl->tx.ring, RTL_NUM_TX_DESC, RTL_TNPDS ); + realtek_init_ring ( &rtl->rx.ring, RTL_NUM_RX_DESC, RTL_RDSAR ); /* Fix up PCI device */ adjust_pci_device ( pci ); diff --git a/src/drivers/net/realtek.h b/src/drivers/net/realtek.h index 4d13784c4..c7cb7e422 100644 --- a/src/drivers/net/realtek.h +++ b/src/drivers/net/realtek.h @@ -247,6 +247,8 @@ enum realtek_legacy_status { struct realtek_ring { /** Descriptors */ struct realtek_descriptor *desc; + /** Descriptor ring DMA mapping */ + struct dma_mapping map; /** Producer index */ unsigned int prod; /** Consumer index */ @@ -272,10 +274,40 @@ realtek_init_ring ( struct realtek_ring *ring, unsigned int count, ring->reg = reg; } +/** Transmit ring */ +struct realtek_tx_ring { + /** Descriptor ring */ + struct realtek_ring ring; + /** DMA mappings */ + struct dma_mapping map[RTL_NUM_TX_DESC]; +}; + +/** Receive ring */ +struct realtek_rx_ring { + /** Descriptor ring */ + struct realtek_ring ring; + /** I/O buffers */ + struct io_buffer *iobuf[RTL_NUM_RX_DESC]; + /** DMA mappings */ + struct dma_mapping map[RTL_NUM_RX_DESC]; +}; + +/** Receive buffer (legacy mode *) */ +struct realtek_rx_buffer { + /** Buffer */ + void *data; + /** Buffer DMA mapping */ + struct dma_mapping map; + /** Offset within buffer */ + unsigned int offset; +}; + /** A Realtek network card */ struct realtek_nic { /** Registers */ void *regs; + /** DMA device */ + struct dma_device *dma; /** SPI bit-bashing interface */ struct spi_bit_basher spibit; /** EEPROM */ @@ -295,15 +327,11 @@ struct realtek_nic { unsigned int tppoll; /** Transmit descriptor ring */ - struct realtek_ring tx; + struct realtek_tx_ring tx; /** Receive descriptor ring */ - struct realtek_ring rx; - /** Receive I/O buffers */ - struct io_buffer *rx_iobuf[RTL_NUM_RX_DESC]; + struct realtek_rx_ring rx; /** Receive buffer (legacy mode) */ - void *rx_buffer; - /** Offset within receive buffer (legacy mode) */ - unsigned int rx_offset; + struct realtek_rx_buffer rxbuf; }; #endif /* _REALTEK_H */ -- cgit v1.2.3-55-g7522 From 5439329c9964eca519017d1c550deb55e0746893 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 13 Nov 2020 19:55:22 +0000 Subject: [intel] Update driver to use DMA API Signed-off-by: Michael Brown --- src/drivers/net/intel.c | 134 ++++++++++++++++++++++++++++----------------- src/drivers/net/intel.h | 51 ++++++++++++----- src/drivers/net/intelx.c | 22 ++++---- src/drivers/net/intelxvf.c | 21 +++---- 4 files changed, 143 insertions(+), 85 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c index 3a4e4341b..4afe43938 100644 --- a/src/drivers/net/intel.c +++ b/src/drivers/net/intel.c @@ -32,7 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include +#include #include #include #include "intel.h" @@ -504,7 +504,8 @@ int intel_create_ring ( struct intel_nic *intel, struct intel_ring *ring ) { * prevent any possible page-crossing errors due to hardware * errata. */ - ring->desc = malloc_phys ( ring->len, ring->len ); + ring->desc = dma_alloc ( intel->dma, ring->len, ring->len, + &ring->map ); if ( ! ring->desc ) return -ENOMEM; @@ -512,7 +513,7 @@ int intel_create_ring ( struct intel_nic *intel, struct intel_ring *ring ) { memset ( ring->desc, 0, ring->len ); /* Program ring address */ - address = virt_to_bus ( ring->desc ); + address = ring->map.addr; writel ( ( address & 0xffffffffUL ), ( intel->regs + ring->reg + INTEL_xDBAL ) ); if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) { @@ -553,7 +554,7 @@ void intel_destroy_ring ( struct intel_nic *intel, struct intel_ring *ring ) { intel_reset_ring ( intel, ring->reg ); /* Free descriptor ring */ - free_phys ( ring->desc, ring->len ); + dma_free ( intel->dma, ring->desc, ring->len, &ring->map ); ring->desc = NULL; ring->prod = 0; ring->cons = 0; @@ -567,32 +568,36 @@ void intel_destroy_ring ( struct intel_nic *intel, struct intel_ring *ring ) { void intel_refill_rx ( struct intel_nic *intel ) { struct intel_descriptor *rx; struct io_buffer *iobuf; + struct dma_mapping *map; unsigned int rx_idx; unsigned int rx_tail; physaddr_t address; unsigned int refilled = 0; /* Refill ring */ - while ( ( intel->rx.prod - intel->rx.cons ) < INTEL_RX_FILL ) { + while ( ( intel->rx.ring.prod - + intel->rx.ring.cons ) < INTEL_RX_FILL ) { + + /* Get next receive descriptor */ + rx_idx = ( intel->rx.ring.prod % INTEL_NUM_RX_DESC ); + rx = &intel->rx.ring.desc[rx_idx]; + map = &intel->rx.map[rx_idx]; + assert ( intel->rx.iobuf[rx_idx] == NULL ); /* Allocate I/O buffer */ - iobuf = alloc_iob ( INTEL_RX_MAX_LEN ); + iobuf = dma_alloc_rx_iob ( intel->dma, INTEL_RX_MAX_LEN, map ); if ( ! iobuf ) { /* Wait for next refill */ break; } + intel->rx.iobuf[rx_idx] = iobuf; - /* Get next receive descriptor */ - rx_idx = ( intel->rx.prod++ % INTEL_NUM_RX_DESC ); - rx = &intel->rx.desc[rx_idx]; + /* Update producer index */ + intel->rx.ring.prod++; /* Populate receive descriptor */ - address = virt_to_bus ( iobuf->data ); - intel->rx.describe ( rx, address, 0 ); - - /* Record I/O buffer */ - assert ( intel->rx_iobuf[rx_idx] == NULL ); - intel->rx_iobuf[rx_idx] = iobuf; + address = map->addr; + intel->rx.ring.describe ( rx, address, 0 ); DBGC2 ( intel, "INTEL %p RX %d is [%llx,%llx)\n", intel, rx_idx, ( ( unsigned long long ) address ), @@ -603,26 +608,40 @@ void intel_refill_rx ( struct intel_nic *intel ) { /* Push descriptors to card, if applicable */ if ( refilled ) { wmb(); - rx_tail = ( intel->rx.prod % INTEL_NUM_RX_DESC ); + rx_tail = ( intel->rx.ring.prod % INTEL_NUM_RX_DESC ); profile_start ( &intel_vm_refill_profiler ); - writel ( rx_tail, intel->regs + intel->rx.reg + INTEL_xDT ); + writel ( rx_tail, + intel->regs + intel->rx.ring.reg + INTEL_xDT ); profile_stop ( &intel_vm_refill_profiler ); profile_exclude ( &intel_vm_refill_profiler ); } } /** - * Discard unused receive I/O buffers + * Flush unused I/O buffers * * @v intel Intel device + * + * Discard any unused receive I/O buffers and unmap any incomplete + * transmit I/O buffers. */ -void intel_empty_rx ( struct intel_nic *intel ) { +void intel_flush ( struct intel_nic *intel ) { unsigned int i; + unsigned int tx_idx; + /* Discard unused receive buffers */ for ( i = 0 ; i < INTEL_NUM_RX_DESC ; i++ ) { - if ( intel->rx_iobuf[i] ) - free_iob ( intel->rx_iobuf[i] ); - intel->rx_iobuf[i] = NULL; + if ( intel->rx.iobuf[i] ) { + dma_unmap ( intel->dma, &intel->rx.map[i] ); + free_iob ( intel->rx.iobuf[i] ); + } + intel->rx.iobuf[i] = NULL; + } + + /* Unmap incomplete transmit buffers */ + for ( i = intel->tx.ring.cons ; i != intel->tx.ring.prod ; i++ ) { + tx_idx = ( i % INTEL_NUM_TX_DESC ); + dma_unmap ( intel->dma, &intel->tx.map[tx_idx] ); } } @@ -653,11 +672,11 @@ static int intel_open ( struct net_device *netdev ) { } /* Create transmit descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->tx.ring ) ) != 0 ) goto err_create_tx; /* Create receive descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->rx.ring ) ) != 0 ) goto err_create_rx; /* Program MAC address */ @@ -696,9 +715,9 @@ static int intel_open ( struct net_device *netdev ) { return 0; - intel_destroy_ring ( intel, &intel->rx ); + intel_destroy_ring ( intel, &intel->rx.ring ); err_create_rx: - intel_destroy_ring ( intel, &intel->tx ); + intel_destroy_ring ( intel, &intel->tx.ring ); err_create_tx: return rc; } @@ -718,13 +737,13 @@ static void intel_close ( struct net_device *netdev ) { writel ( 0, intel->regs + INTEL_TCTL ); /* Destroy receive descriptor ring */ - intel_destroy_ring ( intel, &intel->rx ); + intel_destroy_ring ( intel, &intel->rx.ring ); - /* Discard any unused receive buffers */ - intel_empty_rx ( intel ); + /* Flush unused buffers */ + intel_flush ( intel ); /* Destroy transmit descriptor ring */ - intel_destroy_ring ( intel, &intel->tx ); + intel_destroy_ring ( intel, &intel->tx.ring ); /* Reset the NIC, to flush the transmit and receive FIFOs */ intel_reset ( intel ); @@ -740,29 +759,39 @@ static void intel_close ( struct net_device *netdev ) { int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct intel_nic *intel = netdev->priv; struct intel_descriptor *tx; + struct dma_mapping *map; unsigned int tx_idx; unsigned int tx_tail; physaddr_t address; size_t len; + int rc; /* Get next transmit descriptor */ - if ( ( intel->tx.prod - intel->tx.cons ) >= INTEL_TX_FILL ) { + if ( ( intel->tx.ring.prod - intel->tx.ring.cons ) >= INTEL_TX_FILL ) { DBGC ( intel, "INTEL %p out of transmit descriptors\n", intel ); return -ENOBUFS; } - tx_idx = ( intel->tx.prod++ % INTEL_NUM_TX_DESC ); - tx_tail = ( intel->tx.prod % INTEL_NUM_TX_DESC ); - tx = &intel->tx.desc[tx_idx]; + tx_idx = ( intel->tx.ring.prod % INTEL_NUM_TX_DESC ); + tx = &intel->tx.ring.desc[tx_idx]; + map = &intel->tx.map[tx_idx]; + + /* Map I/O buffer */ + if ( ( rc = dma_map_tx_iob ( intel->dma, iobuf, map ) ) != 0 ) + return rc; + + /* Update producer index */ + intel->tx.ring.prod++; /* Populate transmit descriptor */ - address = virt_to_bus ( iobuf->data ); + address = map->addr; len = iob_len ( iobuf ); - intel->tx.describe ( tx, address, len ); + intel->tx.ring.describe ( tx, address, len ); wmb(); /* Notify card that there are packets ready to transmit */ profile_start ( &intel_vm_tx_profiler ); - writel ( tx_tail, intel->regs + intel->tx.reg + INTEL_xDT ); + tx_tail = ( intel->tx.ring.prod % INTEL_NUM_TX_DESC ); + writel ( tx_tail, intel->regs + intel->tx.ring.reg + INTEL_xDT ); profile_stop ( &intel_vm_tx_profiler ); profile_exclude ( &intel_vm_tx_profiler ); @@ -784,11 +813,11 @@ void intel_poll_tx ( struct net_device *netdev ) { unsigned int tx_idx; /* Check for completed packets */ - while ( intel->tx.cons != intel->tx.prod ) { + while ( intel->tx.ring.cons != intel->tx.ring.prod ) { /* Get next transmit descriptor */ - tx_idx = ( intel->tx.cons % INTEL_NUM_TX_DESC ); - tx = &intel->tx.desc[tx_idx]; + tx_idx = ( intel->tx.ring.cons % INTEL_NUM_TX_DESC ); + tx = &intel->tx.ring.desc[tx_idx]; /* Stop if descriptor is still in use */ if ( ! ( tx->status & cpu_to_le32 ( INTEL_DESC_STATUS_DD ) ) ) @@ -796,9 +825,12 @@ void intel_poll_tx ( struct net_device *netdev ) { DBGC2 ( intel, "INTEL %p TX %d complete\n", intel, tx_idx ); + /* Unmap I/O buffer */ + dma_unmap ( intel->dma, &intel->tx.map[tx_idx] ); + /* Complete TX descriptor */ netdev_tx_complete_next ( netdev ); - intel->tx.cons++; + intel->tx.ring.cons++; } } @@ -815,19 +847,22 @@ void intel_poll_rx ( struct net_device *netdev ) { size_t len; /* Check for received packets */ - while ( intel->rx.cons != intel->rx.prod ) { + while ( intel->rx.ring.cons != intel->rx.ring.prod ) { /* Get next receive descriptor */ - rx_idx = ( intel->rx.cons % INTEL_NUM_RX_DESC ); - rx = &intel->rx.desc[rx_idx]; + rx_idx = ( intel->rx.ring.cons % INTEL_NUM_RX_DESC ); + rx = &intel->rx.ring.desc[rx_idx]; /* Stop if descriptor is still in use */ if ( ! ( rx->status & cpu_to_le32 ( INTEL_DESC_STATUS_DD ) ) ) return; + /* Unmap I/O buffer */ + dma_unmap ( intel->dma, &intel->rx.map[rx_idx] ); + /* Populate I/O buffer */ - iobuf = intel->rx_iobuf[rx_idx]; - intel->rx_iobuf[rx_idx] = NULL; + iobuf = intel->rx.iobuf[rx_idx]; + intel->rx.iobuf[rx_idx] = NULL; len = le16_to_cpu ( rx->length ); iob_put ( iobuf, len ); @@ -842,7 +877,7 @@ void intel_poll_rx ( struct net_device *netdev ) { intel, rx_idx, len ); netdev_rx ( netdev, iobuf ); } - intel->rx.cons++; + intel->rx.ring.cons++; } } @@ -948,11 +983,12 @@ static int intel_probe ( struct pci_device *pci ) { pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( intel, 0, sizeof ( *intel ) ); + intel->dma = &pci->dma; intel->port = PCI_FUNC ( pci->busdevfn ); intel->flags = pci->id->driver_data; - intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTEL_TD, + intel_init_ring ( &intel->tx.ring, INTEL_NUM_TX_DESC, INTEL_TD, intel_describe_tx ); - intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTEL_RD, + intel_init_ring ( &intel->rx.ring, INTEL_NUM_RX_DESC, INTEL_RD, intel_describe_rx ); /* Fix up PCI device */ diff --git a/src/drivers/net/intel.h b/src/drivers/net/intel.h index 9d740efc3..731b5f225 100644 --- a/src/drivers/net/intel.h +++ b/src/drivers/net/intel.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include /** Intel BAR size */ #define INTEL_BAR_SIZE ( 128 * 1024 ) @@ -212,6 +213,8 @@ union intel_receive_address { struct intel_ring { /** Descriptors */ struct intel_descriptor *desc; + /** Descriptor ring DMA mapping */ + struct dma_mapping map; /** Producer index */ unsigned int prod; /** Consumer index */ @@ -273,10 +276,30 @@ intel_init_mbox ( struct intel_mailbox *mbox, unsigned int ctrl, mbox->mem = mem; } +/** Transmit ring */ +struct intel_tx_ring { + /** Descriptor ring */ + struct intel_ring ring; + /** DMA mappings */ + struct dma_mapping map[INTEL_NUM_TX_DESC]; +}; + +/** Receive ring */ +struct intel_rx_ring { + /** Descriptor ring */ + struct intel_ring ring; + /** I/O buffers */ + struct io_buffer *iobuf[INTEL_NUM_RX_DESC]; + /** DMA mappings */ + struct dma_mapping map[INTEL_NUM_RX_DESC]; +}; + /** An Intel network card */ struct intel_nic { /** Registers */ void *regs; + /** DMA device */ + struct dma_device *dma; /** Port number (for multi-port devices) */ unsigned int port; /** Flags */ @@ -294,12 +317,10 @@ struct intel_nic { /** Mailbox */ struct intel_mailbox mbox; - /** Transmit descriptor ring */ - struct intel_ring tx; - /** Receive descriptor ring */ - struct intel_ring rx; - /** Receive I/O buffers */ - struct io_buffer *rx_iobuf[INTEL_NUM_RX_DESC]; + /** Transmit ring */ + struct intel_tx_ring tx; + /** Receive ring */ + struct intel_rx_ring rx; }; /** Driver flags */ @@ -328,14 +349,14 @@ static inline void intel_diag ( struct intel_nic *intel ) { DBGC ( intel, "INTEL %p TX %04x(%02x)/%04x(%02x) " "RX %04x(%02x)/%04x(%02x)\n", intel, - ( intel->tx.cons & 0xffff ), - readl ( intel->regs + intel->tx.reg + INTEL_xDH ), - ( intel->tx.prod & 0xffff ), - readl ( intel->regs + intel->tx.reg + INTEL_xDT ), - ( intel->rx.cons & 0xffff ), - readl ( intel->regs + intel->rx.reg + INTEL_xDH ), - ( intel->rx.prod & 0xffff ), - readl ( intel->regs + intel->rx.reg + INTEL_xDT ) ); + ( intel->tx.ring.cons & 0xffff ), + readl ( intel->regs + intel->tx.ring.reg + INTEL_xDH ), + ( intel->tx.ring.prod & 0xffff ), + readl ( intel->regs + intel->tx.ring.reg + INTEL_xDT ), + ( intel->rx.ring.cons & 0xffff ), + readl ( intel->regs + intel->rx.ring.reg + INTEL_xDH ), + ( intel->rx.ring.prod & 0xffff ), + readl ( intel->regs + intel->rx.ring.reg + INTEL_xDT ) ); } extern void intel_describe_tx ( struct intel_descriptor *tx, @@ -350,7 +371,7 @@ extern int intel_create_ring ( struct intel_nic *intel, extern void intel_destroy_ring ( struct intel_nic *intel, struct intel_ring *ring ); extern void intel_refill_rx ( struct intel_nic *intel ); -extern void intel_empty_rx ( struct intel_nic *intel ); +extern void intel_flush ( struct intel_nic *intel ); extern int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ); extern void intel_poll_tx ( struct net_device *netdev ); diff --git a/src/drivers/net/intelx.c b/src/drivers/net/intelx.c index 38e8467a9..3fa68bb3c 100644 --- a/src/drivers/net/intelx.c +++ b/src/drivers/net/intelx.c @@ -32,7 +32,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include "intelx.h" @@ -186,11 +185,11 @@ static int intelx_open ( struct net_device *netdev ) { int rc; /* Create transmit descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->tx.ring ) ) != 0 ) goto err_create_tx; /* Create receive descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->rx.ring ) ) != 0 ) goto err_create_rx; /* Program MAC address */ @@ -264,9 +263,9 @@ static int intelx_open ( struct net_device *netdev ) { return 0; - intel_destroy_ring ( intel, &intel->rx ); + intel_destroy_ring ( intel, &intel->rx.ring ); err_create_rx: - intel_destroy_ring ( intel, &intel->tx ); + intel_destroy_ring ( intel, &intel->tx.ring ); err_create_tx: return rc; } @@ -292,13 +291,13 @@ static void intelx_close ( struct net_device *netdev ) { writel ( dmatxctl, intel->regs + INTELX_DMATXCTL ); /* Destroy receive descriptor ring */ - intel_destroy_ring ( intel, &intel->rx ); + intel_destroy_ring ( intel, &intel->rx.ring ); - /* Discard any unused receive buffers */ - intel_empty_rx ( intel ); + /* Flush unused buffers */ + intel_flush ( intel ); /* Destroy transmit descriptor ring */ - intel_destroy_ring ( intel, &intel->tx ); + intel_destroy_ring ( intel, &intel->tx.ring ); /* Reset the NIC, to flush the transmit and receive FIFOs */ intelx_reset ( intel ); @@ -395,10 +394,11 @@ static int intelx_probe ( struct pci_device *pci ) { pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( intel, 0, sizeof ( *intel ) ); + intel->dma = &pci->dma; intel->port = PCI_FUNC ( pci->busdevfn ); - intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTELX_TD, + intel_init_ring ( &intel->tx.ring, INTEL_NUM_TX_DESC, INTELX_TD, intel_describe_tx ); - intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTELX_RD, + intel_init_ring ( &intel->rx.ring, INTEL_NUM_RX_DESC, INTELX_RD, intel_describe_rx ); /* Fix up PCI device */ diff --git a/src/drivers/net/intelxvf.c b/src/drivers/net/intelxvf.c index fef3024e9..4941fc57b 100644 --- a/src/drivers/net/intelxvf.c +++ b/src/drivers/net/intelxvf.c @@ -276,11 +276,11 @@ static int intelxvf_open ( struct net_device *netdev ) { } /* Create transmit descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->tx.ring ) ) != 0 ) goto err_create_tx; /* Create receive descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->rx.ring ) ) != 0 ) goto err_create_rx; /* Allocate interrupt vectors */ @@ -317,9 +317,9 @@ static int intelxvf_open ( struct net_device *netdev ) { return 0; - intel_destroy_ring ( intel, &intel->rx ); + intel_destroy_ring ( intel, &intel->rx.ring ); err_create_rx: - intel_destroy_ring ( intel, &intel->tx ); + intel_destroy_ring ( intel, &intel->tx.ring ); err_create_tx: err_mbox_set_mtu: err_mbox_set_mac: @@ -337,13 +337,13 @@ static void intelxvf_close ( struct net_device *netdev ) { struct intel_nic *intel = netdev->priv; /* Destroy receive descriptor ring */ - intel_destroy_ring ( intel, &intel->rx ); + intel_destroy_ring ( intel, &intel->rx.ring ); - /* Discard any unused receive buffers */ - intel_empty_rx ( intel ); + /* Flush unused buffers */ + intel_flush ( intel ); /* Destroy transmit descriptor ring */ - intel_destroy_ring ( intel, &intel->tx ); + intel_destroy_ring ( intel, &intel->tx.ring ); /* Reset the function */ intelxvf_reset ( intel ); @@ -446,10 +446,11 @@ static int intelxvf_probe ( struct pci_device *pci ) { pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( intel, 0, sizeof ( *intel ) ); + intel->dma = &pci->dma; intel_init_mbox ( &intel->mbox, INTELXVF_MBCTRL, INTELXVF_MBMEM ); - intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTELXVF_TD(0), + intel_init_ring ( &intel->tx.ring, INTEL_NUM_TX_DESC, INTELXVF_TD(0), intel_describe_tx_adv ); - intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTELXVF_RD(0), + intel_init_ring ( &intel->rx.ring, INTEL_NUM_RX_DESC, INTELXVF_RD(0), intel_describe_rx ); /* Fix up PCI device */ -- cgit v1.2.3-55-g7522 From 83b8c0e21165d006b877ecfed6fade903b72c402 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 15 Nov 2020 23:17:17 +0000 Subject: [efi] Do not populate media header length in PXE transmit CPB The UEFI specification defines PXE_CPB_TRANSMIT.DataLen as excluding the length of the media header. iPXE currently fills in DataLen as the whole frame length (including the media header), along with placing the media header length separately in MediaheaderLen. On some UNDI implementations (observed using a VMware ESXi 7.0b virtual machine), this causes transmitted packets to include 14 bytes of trailing garbage. Match the behaviour of the EDK2 SnpDxe driver, which fills in DataLen as the whole frame length (including the media header) and leaves MediaheaderLen as zero. This behaviour also violates the UEFI specification, but is likely to work in practice since EDK2 is the reference implementation. Signed-off-by: Michael Brown --- src/drivers/net/efi/nii.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/drivers') diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c index e76e211c1..8f4fbee18 100644 --- a/src/drivers/net/efi/nii.c +++ b/src/drivers/net/efi/nii.c @@ -977,7 +977,6 @@ static int nii_transmit ( struct net_device *netdev, memset ( &cpb, 0, sizeof ( cpb ) ); cpb.FrameAddr = virt_to_bus ( iobuf->data ); cpb.DataLen = iob_len ( iobuf ); - cpb.MediaheaderLen = netdev->ll_protocol->ll_header_len; /* Transmit packet */ op = NII_OP ( PXE_OPCODE_TRANSMIT, -- cgit v1.2.3-55-g7522 From fc5cf18dab3ab88aff00e6ed2915a5e960eeb085 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 15 Nov 2020 23:33:52 +0000 Subject: [efi] Use casts rather than virt_to_bus() for UNDI buffer addresses For a software UNDI, the addresses in PXE_CPB_TRANSMIT.FrameAddr and PXE_CPB_RECEIVE.BufferAddr are host addresses, not bus addresses. Remove the spurious (and no-op) use of virt_to_bus() and replace with a cast via intptr_t. Signed-off-by: Michael Brown --- src/drivers/net/efi/nii.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c index 8f4fbee18..b9f34650e 100644 --- a/src/drivers/net/efi/nii.c +++ b/src/drivers/net/efi/nii.c @@ -975,7 +975,7 @@ static int nii_transmit ( struct net_device *netdev, /* Construct parameter block */ memset ( &cpb, 0, sizeof ( cpb ) ); - cpb.FrameAddr = virt_to_bus ( iobuf->data ); + cpb.FrameAddr = ( ( intptr_t ) iobuf->data ); cpb.DataLen = iob_len ( iobuf ); /* Transmit packet */ @@ -1043,7 +1043,7 @@ static void nii_poll_rx ( struct net_device *netdev ) { /* Construct parameter block */ memset ( &cpb, 0, sizeof ( cpb ) ); - cpb.BufferAddr = virt_to_bus ( nii->rxbuf->data ); + cpb.BufferAddr = ( ( intptr_t ) nii->rxbuf->data ); cpb.BufferLen = iob_tailroom ( nii->rxbuf ); /* Issue command */ -- cgit v1.2.3-55-g7522 From 810dc5d6c33b71ceec3f00f48e64ff337389ed2e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 16 Nov 2020 13:07:31 +0000 Subject: [realtek] Use physical addresses in debug messages Physical addresses in debug messages are more meaningful from an end-user perspective than potentially IOMMU-mapped I/O virtual addresses, and have the advantage of being calculable without access to the original DMA mapping entry (e.g. when displaying an address for a single failed completion within a descriptor ring). Signed-off-by: Michael Brown --- src/drivers/net/realtek.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index afca089ad..0f3038d36 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -507,7 +507,6 @@ static void realtek_check_link ( struct net_device *netdev ) { */ static int realtek_create_buffer ( struct realtek_nic *rtl ) { size_t len = ( RTL_RXBUF_LEN + RTL_RXBUF_PAD ); - physaddr_t address; /* Do nothing unless in legacy mode */ if ( ! rtl->legacy ) @@ -518,14 +517,13 @@ static int realtek_create_buffer ( struct realtek_nic *rtl ) { &rtl->rxbuf.map ); if ( ! rtl->rxbuf.data ) return -ENOMEM; - address = rtl->rxbuf.map.addr; /* Program buffer address */ - writel ( address, rtl->regs + RTL_RBSTART ); - DBGC ( rtl, "REALTEK %p receive buffer is at [%08llx,%08llx,%08llx)\n", - rtl, ( ( unsigned long long ) address ), - ( ( unsigned long long ) address + RTL_RXBUF_LEN ), - ( ( unsigned long long ) address + len ) ); + writel ( rtl->rxbuf.map.addr, rtl->regs + RTL_RBSTART ); + DBGC ( rtl, "REALTEK %p receive buffer is at [%08lx,%08lx,%08lx)\n", + rtl, virt_to_phys ( rtl->rxbuf.data ), + ( virt_to_phys ( rtl->rxbuf.data ) + RTL_RXBUF_LEN ), + ( virt_to_phys ( rtl->rxbuf.data ) + len ) ); return 0; } @@ -580,9 +578,9 @@ static int realtek_create_ring ( struct realtek_nic *rtl, writel ( ( ( ( uint64_t ) address ) >> 32 ), rtl->regs + ring->reg + 4 ); writel ( ( address & 0xffffffffUL ), rtl->regs + ring->reg ); - DBGC ( rtl, "REALTEK %p ring %02x is at [%08llx,%08llx)\n", - rtl, ring->reg, ( ( unsigned long long ) address ), - ( ( unsigned long long ) address + ring->len ) ); + DBGC ( rtl, "REALTEK %p ring %02x is at [%08lx,%08lx)\n", + rtl, ring->reg, virt_to_phys ( ring->desc ), + ( virt_to_phys ( ring->desc ) + ring->len ) ); return 0; } @@ -657,9 +655,9 @@ static void realtek_refill_rx ( struct realtek_nic *rtl ) { ( is_last ? cpu_to_le16 ( RTL_DESC_EOR ) : 0 ) ); wmb(); - DBGC2 ( rtl, "REALTEK %p RX %d is [%llx,%llx)\n", rtl, rx_idx, - ( ( unsigned long long ) map->addr ), - ( ( unsigned long long ) map->addr + RTL_RX_MAX_LEN ) ); + DBGC2 ( rtl, "REALTEK %p RX %d is [%lx,%lx)\n", + rtl, rx_idx, virt_to_phys ( iobuf->data ), + ( virt_to_phys ( iobuf->data ) + RTL_RX_MAX_LEN ) ); } } @@ -829,9 +827,9 @@ static int realtek_transmit ( struct net_device *netdev, writeb ( RTL_TPPOLL_NPQ, rtl->regs + rtl->tppoll ); } - DBGC2 ( rtl, "REALTEK %p TX %d is [%llx,%llx)\n", rtl, tx_idx, - ( ( unsigned long long ) address ), - ( ( ( unsigned long long ) address ) + iob_len ( iobuf ) ) ); + DBGC2 ( rtl, "REALTEK %p TX %d is [%lx,%lx)\n", + rtl, tx_idx, virt_to_phys ( iobuf->data ), + virt_to_phys ( iobuf->data ) + iob_len ( iobuf ) ); return 0; } -- cgit v1.2.3-55-g7522 From 062711f1cfacd0708107933b6a977476a7f7479e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 16 Nov 2020 15:00:05 +0000 Subject: [intel] Use physical addresses in debug messages Signed-off-by: Michael Brown --- src/drivers/net/intel.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c index 4afe43938..2963d9dc8 100644 --- a/src/drivers/net/intel.c +++ b/src/drivers/net/intel.c @@ -535,9 +535,9 @@ int intel_create_ring ( struct intel_nic *intel, struct intel_ring *ring ) { dctl |= INTEL_xDCTL_ENABLE; writel ( dctl, intel->regs + ring->reg + INTEL_xDCTL ); - DBGC ( intel, "INTEL %p ring %05x is at [%08llx,%08llx)\n", - intel, ring->reg, ( ( unsigned long long ) address ), - ( ( unsigned long long ) address + ring->len ) ); + DBGC ( intel, "INTEL %p ring %05x is at [%08lx,%08lx)\n", + intel, ring->reg, virt_to_phys ( ring->desc ), + ( virt_to_phys ( ring->desc ) + ring->len ) ); return 0; } @@ -599,9 +599,9 @@ void intel_refill_rx ( struct intel_nic *intel ) { address = map->addr; intel->rx.ring.describe ( rx, address, 0 ); - DBGC2 ( intel, "INTEL %p RX %d is [%llx,%llx)\n", intel, rx_idx, - ( ( unsigned long long ) address ), - ( ( unsigned long long ) address + INTEL_RX_MAX_LEN ) ); + DBGC2 ( intel, "INTEL %p RX %d is [%lx,%lx)\n", + intel, rx_idx, virt_to_phys ( iobuf->data ), + ( virt_to_phys ( iobuf->data ) + INTEL_RX_MAX_LEN ) ); refilled++; } @@ -795,9 +795,9 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { profile_stop ( &intel_vm_tx_profiler ); profile_exclude ( &intel_vm_tx_profiler ); - DBGC2 ( intel, "INTEL %p TX %d is [%llx,%llx)\n", intel, tx_idx, - ( ( unsigned long long ) address ), - ( ( unsigned long long ) address + len ) ); + DBGC2 ( intel, "INTEL %p TX %d is [%lx,%lx)\n", + intel, tx_idx, virt_to_phys ( iobuf->data ), + ( virt_to_phys ( iobuf->data ) + len ) ); return 0; } -- cgit v1.2.3-55-g7522 From b6eb17cbd790b8336a9a5fe1878008f905642c9b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 20 Nov 2020 19:12:24 +0000 Subject: [intelxl] Read MAC address from PRTPM_SA[HL] instead of PRTGL_SA[HL] The datasheet is fairly incomprehensible in terms of identifying the appropriate MAC address for use by the physical function driver. Choose to read the MAC address from PRTPM_SAH and PRTPM_SAL, which at least matches the MAC address as selected by the Linux i40e driver. Signed-off-by: Michael Brown --- src/drivers/net/intelxl.c | 12 +++++++----- src/drivers/net/intelxl.h | 6 ++++++ 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c index d16b759e7..fda8effbd 100644 --- a/src/drivers/net/intelxl.c +++ b/src/drivers/net/intelxl.c @@ -87,15 +87,16 @@ static int intelxl_reset ( struct intelxl_nic *intelxl ) { static int intelxl_fetch_mac ( struct intelxl_nic *intelxl, struct net_device *netdev ) { union intelxl_receive_address mac; - uint32_t prtgl_sal; + uint32_t prtpm_sal; + uint32_t prtpm_sah; uint32_t prtgl_sah; size_t mfs; /* Read NVM-loaded address */ - prtgl_sal = readl ( intelxl->regs + INTELXL_PRTGL_SAL ); - prtgl_sah = readl ( intelxl->regs + INTELXL_PRTGL_SAH ); - mac.reg.low = cpu_to_le32 ( prtgl_sal ); - mac.reg.high = cpu_to_le32 ( prtgl_sah ); + prtpm_sal = readl ( intelxl->regs + INTELXL_PRTPM_SAL ); + prtpm_sah = readl ( intelxl->regs + INTELXL_PRTPM_SAH ); + mac.reg.low = cpu_to_le32 ( prtpm_sal ); + mac.reg.high = cpu_to_le32 ( prtpm_sah ); /* Check that address is valid */ if ( ! is_valid_ether_addr ( mac.raw ) ) { @@ -110,6 +111,7 @@ static int intelxl_fetch_mac ( struct intelxl_nic *intelxl, memcpy ( netdev->hw_addr, mac.raw, ETH_ALEN ); /* Get maximum frame size */ + prtgl_sah = readl ( intelxl->regs + INTELXL_PRTGL_SAH ); mfs = INTELXL_PRTGL_SAH_MFS_GET ( prtgl_sah ); netdev->max_pkt_len = ( mfs - 4 /* CRC */ ); diff --git a/src/drivers/net/intelxl.h b/src/drivers/net/intelxl.h index 80586cef0..2d33ed8e9 100644 --- a/src/drivers/net/intelxl.h +++ b/src/drivers/net/intelxl.h @@ -1005,6 +1005,12 @@ intelxl_init_ring ( struct intelxl_ring *ring, unsigned int count, size_t len, #define INTELXL_PRTGL_SAH_MFS_GET(x) ( (x) >> 16 ) /**< Max frame size */ #define INTELXL_PRTGL_SAH_MFS_SET(x) ( (x) << 16 ) /**< Max frame size */ +/** Physical Function MAC Address Low Register */ +#define INTELXL_PRTPM_SAL 0x1e4440 + +/** Physical Function MAC Address High Register */ +#define INTELXL_PRTPM_SAH 0x1e44c0 + /** Receive address */ union intelxl_receive_address { struct { -- cgit v1.2.3-55-g7522 From 76a7bfe939b4b6ea88690e8c6960c65d57c01b5e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 21 Nov 2020 13:19:27 +0000 Subject: [intelxl] Read PCI bus:dev.fn number from PFFUNC_RID register For the physical function driver, the transmit queue needs to be configured to be associated with the relevant physical function number. This is currently obtained from the bus:dev.fn address of the underlying PCI device. In the case of a virtual machine using the physical function via PCI passthrough, the PCI bus:dev.fn address within the virtual machine is unrelated to the real physical function number. Such a function will typically be presented to the virtual machine as a single-function device. The function number extracted from the PCI bus:dev.fn address will therefore always be zero. Fix by reading from the Function Requester ID Information Register, which always returns the real PCI bus:dev.fn address as used by the physical host. Signed-off-by: Michael Brown --- src/drivers/net/intelxl.c | 6 ++++-- src/drivers/net/intelxl.h | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c index fda8effbd..d929f48cd 100644 --- a/src/drivers/net/intelxl.c +++ b/src/drivers/net/intelxl.c @@ -1643,6 +1643,7 @@ static struct net_device_operations intelxl_operations = { static int intelxl_probe ( struct pci_device *pci ) { struct net_device *netdev; struct intelxl_nic *intelxl; + uint32_t pffunc_rid; uint32_t pfgen_portnum; uint32_t pflan_qalloc; int rc; @@ -1658,7 +1659,6 @@ static int intelxl_probe ( struct pci_device *pci ) { pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( intelxl, 0, sizeof ( *intelxl ) ); - intelxl->pf = PCI_FUNC ( pci->busdevfn ); intelxl->intr = INTELXL_PFINT_DYN_CTL0; intelxl_init_admin ( &intelxl->command, INTELXL_ADMIN_CMD, &intelxl_admin_offsets ); @@ -1685,7 +1685,9 @@ static int intelxl_probe ( struct pci_device *pci ) { if ( ( rc = intelxl_reset ( intelxl ) ) != 0 ) goto err_reset; - /* Get port number and base queue number */ + /* Get function number, port number and base queue number */ + pffunc_rid = readl ( intelxl->regs + INTELXL_PFFUNC_RID ); + intelxl->pf = INTELXL_PFFUNC_RID_FUNC_NUM ( pffunc_rid ); pfgen_portnum = readl ( intelxl->regs + INTELXL_PFGEN_PORTNUM ); intelxl->port = INTELXL_PFGEN_PORTNUM_PORT_NUM ( pfgen_portnum ); pflan_qalloc = readl ( intelxl->regs + INTELXL_PFLAN_QALLOC ); diff --git a/src/drivers/net/intelxl.h b/src/drivers/net/intelxl.h index 2d33ed8e9..ef9152f6e 100644 --- a/src/drivers/net/intelxl.h +++ b/src/drivers/net/intelxl.h @@ -985,6 +985,11 @@ intelxl_init_ring ( struct intelxl_ring *ring, unsigned int count, size_t len, /** Time to delay for device reset, in milliseconds */ #define INTELXL_RESET_DELAY_MS 100 +/** Function Requester ID Information Register */ +#define INTELXL_PFFUNC_RID 0x09c000 +#define INTELXL_PFFUNC_RID_FUNC_NUM(x) \ + ( ( (x) >> 0 ) & 0x3 ) /**< Function number */ + /** PF Queue Allocation Register */ #define INTELXL_PFLAN_QALLOC 0x1c0400 #define INTELXL_PFLAN_QALLOC_FIRSTQ(x) \ -- cgit v1.2.3-55-g7522 From 03314e8da9a3c387e9bbcf3830e6517377768de4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 17 Nov 2020 01:26:21 +0000 Subject: [intelxl] Update driver to use DMA API Signed-off-by: Michael Brown --- src/drivers/net/intelxl.c | 244 +++++++++++++++++++++++++++----------------- src/drivers/net/intelxl.h | 53 ++++++++-- src/drivers/net/intelxlvf.c | 39 +++---- 3 files changed, 215 insertions(+), 121 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c index d929f48cd..578d6ff02 100644 --- a/src/drivers/net/intelxl.c +++ b/src/drivers/net/intelxl.c @@ -34,7 +34,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include #include "intelxl.h" @@ -136,20 +135,35 @@ int intelxl_msix_enable ( struct intelxl_nic *intelxl, struct pci_device *pci ) { int rc; + /* Map dummy target location */ + if ( ( rc = dma_map ( intelxl->dma, virt_to_phys ( &intelxl->msix.msg ), + sizeof ( intelxl->msix.msg ), DMA_RX, + &intelxl->msix.map ) ) != 0 ) { + DBGC ( intelxl, "INTELXL %p could not map MSI-X target: %s\n", + intelxl, strerror ( rc ) ); + goto err_map; + } + /* Enable MSI-X capability */ - if ( ( rc = pci_msix_enable ( pci, &intelxl->msix ) ) != 0 ) { + if ( ( rc = pci_msix_enable ( pci, &intelxl->msix.cap ) ) != 0 ) { DBGC ( intelxl, "INTELXL %p could not enable MSI-X: %s\n", intelxl, strerror ( rc ) ); - return rc; + goto err_enable; } /* Configure interrupt zero to write to dummy location */ - pci_msix_map ( &intelxl->msix, 0, virt_to_bus ( &intelxl->msg ), 0 ); + pci_msix_map ( &intelxl->msix.cap, 0, intelxl->msix.map.addr, 0 ); /* Enable dummy interrupt zero */ - pci_msix_unmask ( &intelxl->msix, 0 ); + pci_msix_unmask ( &intelxl->msix.cap, 0 ); return 0; + + pci_msix_disable ( pci, &intelxl->msix.cap ); + err_enable: + dma_unmap ( intelxl->dma, &intelxl->msix.map ); + err_map: + return rc; } /** @@ -162,10 +176,13 @@ void intelxl_msix_disable ( struct intelxl_nic *intelxl, struct pci_device *pci ) { /* Disable dummy interrupt zero */ - pci_msix_mask ( &intelxl->msix, 0 ); + pci_msix_mask ( &intelxl->msix.cap, 0 ); /* Disable MSI-X capability */ - pci_msix_disable ( pci, &intelxl->msix ); + pci_msix_disable ( pci, &intelxl->msix.cap ); + + /* Unmap dummy target location */ + dma_unmap ( intelxl->dma, &intelxl->msix.map ); } /****************************************************************************** @@ -197,22 +214,38 @@ static int intelxl_alloc_admin ( struct intelxl_nic *intelxl, size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC ); /* Allocate admin queue */ - admin->buf = malloc_phys ( ( buf_len + len ), INTELXL_ALIGN ); + admin->buf = dma_alloc ( intelxl->dma, ( buf_len + len ), + INTELXL_ALIGN, &admin->map ); if ( ! admin->buf ) return -ENOMEM; admin->desc = ( ( ( void * ) admin->buf ) + buf_len ); - DBGC ( intelxl, "INTELXL %p A%cQ is at [%08llx,%08llx) buf " - "[%08llx,%08llx)\n", intelxl, + DBGC ( intelxl, "INTELXL %p A%cQ is at [%08lx,%08lx) buf " + "[%08lx,%08lx)\n", intelxl, ( ( admin == &intelxl->command ) ? 'T' : 'R' ), - ( ( unsigned long long ) virt_to_bus ( admin->desc ) ), - ( ( unsigned long long ) ( virt_to_bus ( admin->desc ) + len ) ), - ( ( unsigned long long ) virt_to_bus ( admin->buf ) ), - ( ( unsigned long long ) ( virt_to_bus ( admin->buf ) + - buf_len ) ) ); + virt_to_phys ( admin->desc ), + ( virt_to_phys ( admin->desc ) + len ), + virt_to_phys ( admin->buf ), + ( virt_to_phys ( admin->buf ) + buf_len ) ); return 0; } +/** + * Get DMA address for admin descriptor or buffer entry + * + * @v admin Admin queue + * @v addr Virtual address + * @ret addr DMA address + */ +static physaddr_t intelxl_admin_address ( struct intelxl_admin *admin, + void *addr ) { + size_t offset; + + /* Calculate offset within mapped area */ + offset = ( addr - ( ( void * ) admin->buf ) ); + return ( admin->map.addr + offset ); +} + /** * Enable admin queue * @@ -237,7 +270,7 @@ static void intelxl_enable_admin ( struct intelxl_nic *intelxl, admin->index = 0; /* Program queue address */ - address = virt_to_bus ( admin->desc ); + address = intelxl_admin_address ( admin, admin->desc ); writel ( ( address & 0xffffffffUL ), admin_regs + regs->bal ); if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) { writel ( ( ( ( uint64_t ) address ) >> 32 ), @@ -273,13 +306,13 @@ static void intelxl_disable_admin ( struct intelxl_nic *intelxl, * @v intelxl Intel device * @v admin Admin queue */ -static void intelxl_free_admin ( struct intelxl_nic *intelxl __unused, +static void intelxl_free_admin ( struct intelxl_nic *intelxl, struct intelxl_admin *admin ) { size_t buf_len = ( sizeof ( admin->buf[0] ) * INTELXL_ADMIN_NUM_DESC ); size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC ); /* Free queue */ - free_phys ( admin->buf, ( buf_len + len ) ); + dma_free ( intelxl->dma, admin->buf, ( buf_len + len ), &admin->map ); } /** @@ -332,7 +365,7 @@ static void intelxl_admin_event_init ( struct intelxl_nic *intelxl, /* Initialise descriptor */ evt = &admin->desc[ index % INTELXL_ADMIN_NUM_DESC ]; buf = &admin->buf[ index % INTELXL_ADMIN_NUM_DESC ]; - address = virt_to_bus ( buf ); + address = intelxl_admin_address ( admin, buf ); evt->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ); evt->len = cpu_to_le16 ( sizeof ( *buf ) ); evt->params.buffer.high = cpu_to_le32 ( address >> 32 ); @@ -377,7 +410,7 @@ int intelxl_admin_command ( struct intelxl_nic *intelxl ) { /* Populate data buffer address if applicable */ if ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ) ) { - address = virt_to_bus ( buf ); + address = intelxl_admin_address ( admin, buf ); cmd->params.buffer.high = cpu_to_le32 ( address >> 32 ); cmd->params.buffer.low = cpu_to_le32 ( address & 0xffffffffUL ); } @@ -924,16 +957,15 @@ void intelxl_close_admin ( struct intelxl_nic *intelxl ) { */ int intelxl_alloc_ring ( struct intelxl_nic *intelxl, struct intelxl_ring *ring ) { - physaddr_t address; int rc; /* Allocate descriptor ring */ - ring->desc.raw = malloc_phys ( ring->len, INTELXL_ALIGN ); + ring->desc.raw = dma_alloc ( intelxl->dma, ring->len, INTELXL_ALIGN, + &ring->map ); if ( ! ring->desc.raw ) { rc = -ENOMEM; goto err_alloc; } - address = virt_to_bus ( ring->desc.raw ); /* Initialise descriptor ring */ memset ( ring->desc.raw, 0, ring->len ); @@ -945,14 +977,14 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl, ring->prod = 0; ring->cons = 0; - DBGC ( intelxl, "INTELXL %p ring %06x is at [%08llx,%08llx)\n", + DBGC ( intelxl, "INTELXL %p ring %06x is at [%08lx,%08lx)\n", intelxl, ( ring->reg + ring->tail ), - ( ( unsigned long long ) address ), - ( ( unsigned long long ) address + ring->len ) ); + virt_to_phys ( ring->desc.raw ), + ( virt_to_phys ( ring->desc.raw ) + ring->len ) ); return 0; - free_phys ( ring->desc.raw, ring->len ); + dma_free ( intelxl->dma, ring->desc.raw, ring->len, &ring->map ); err_alloc: return rc; } @@ -963,11 +995,11 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl, * @v intelxl Intel device * @v ring Descriptor ring */ -void intelxl_free_ring ( struct intelxl_nic *intelxl __unused, +void intelxl_free_ring ( struct intelxl_nic *intelxl, struct intelxl_ring *ring ) { /* Free descriptor ring */ - free_phys ( ring->desc.raw, ring->len ); + dma_free ( intelxl->dma, ring->desc.raw, ring->len, &ring->map ); ring->desc.raw = NULL; } @@ -1235,7 +1267,6 @@ static int intelxl_disable_ring ( struct intelxl_nic *intelxl, */ static int intelxl_create_ring ( struct intelxl_nic *intelxl, struct intelxl_ring *ring ) { - physaddr_t address; int rc; /* Allocate descriptor ring */ @@ -1243,8 +1274,7 @@ static int intelxl_create_ring ( struct intelxl_nic *intelxl, goto err_alloc; /* Program queue context */ - address = virt_to_bus ( ring->desc.raw ); - if ( ( rc = ring->context ( intelxl, address ) ) != 0 ) + if ( ( rc = ring->context ( intelxl, ring->map.addr ) ) != 0 ) goto err_context; /* Enable ring */ @@ -1289,61 +1319,75 @@ static void intelxl_destroy_ring ( struct intelxl_nic *intelxl, static void intelxl_refill_rx ( struct intelxl_nic *intelxl ) { struct intelxl_rx_data_descriptor *rx; struct io_buffer *iobuf; + struct dma_mapping *map; unsigned int rx_idx; unsigned int rx_tail; - physaddr_t address; unsigned int refilled = 0; /* Refill ring */ - while ( ( intelxl->rx.prod - intelxl->rx.cons ) < INTELXL_RX_FILL ) { + while ( ( intelxl->rx.ring.prod - + intelxl->rx.ring.cons ) < INTELXL_RX_FILL ) { + + /* Get next receive descriptor */ + rx_idx = ( intelxl->rx.ring.prod % INTELXL_RX_NUM_DESC ); + rx = &intelxl->rx.ring.desc.rx[rx_idx].data; + map = &intelxl->rx.map[rx_idx]; + assert ( intelxl->rx.iobuf[rx_idx] == NULL ); /* Allocate I/O buffer */ - iobuf = alloc_iob ( intelxl->mfs ); + iobuf = dma_alloc_rx_iob ( intelxl->dma, intelxl->mfs, map ); if ( ! iobuf ) { /* Wait for next refill */ break; } + intelxl->rx.iobuf[rx_idx] = iobuf; - /* Get next receive descriptor */ - rx_idx = ( intelxl->rx.prod++ % INTELXL_RX_NUM_DESC ); - rx = &intelxl->rx.desc.rx[rx_idx].data; + /* Update producer index */ + intelxl->rx.ring.prod++; /* Populate receive descriptor */ - address = virt_to_bus ( iobuf->data ); - rx->address = cpu_to_le64 ( address ); + rx->address = cpu_to_le64 ( map->addr ); rx->flags = 0; - /* Record I/O buffer */ - assert ( intelxl->rx_iobuf[rx_idx] == NULL ); - intelxl->rx_iobuf[rx_idx] = iobuf; - - DBGC2 ( intelxl, "INTELXL %p RX %d is [%llx,%llx)\n", intelxl, - rx_idx, ( ( unsigned long long ) address ), - ( ( unsigned long long ) address + intelxl->mfs ) ); + DBGC2 ( intelxl, "INTELXL %p RX %d is [%08lx,%08lx)\n", + intelxl, rx_idx, virt_to_phys ( iobuf->data ), + ( virt_to_phys ( iobuf->data ) + intelxl->mfs ) ); refilled++; } /* Push descriptors to card, if applicable */ if ( refilled ) { wmb(); - rx_tail = ( intelxl->rx.prod % INTELXL_RX_NUM_DESC ); - writel ( rx_tail, ( intelxl->regs + intelxl->rx.tail ) ); + rx_tail = ( intelxl->rx.ring.prod % INTELXL_RX_NUM_DESC ); + writel ( rx_tail, ( intelxl->regs + intelxl->rx.ring.tail ) ); } } /** - * Discard unused receive I/O buffers + * Flush unused I/O buffers * * @v intelxl Intel device + * + * Discard any unused receive I/O buffers and unmap any incomplete + * transmit I/O buffers. */ -void intelxl_empty_rx ( struct intelxl_nic *intelxl ) { +void intelxl_flush ( struct intelxl_nic *intelxl ) { unsigned int i; + unsigned int tx_idx; /* Discard any unused receive buffers */ for ( i = 0 ; i < INTELXL_RX_NUM_DESC ; i++ ) { - if ( intelxl->rx_iobuf[i] ) - free_iob ( intelxl->rx_iobuf[i] ); - intelxl->rx_iobuf[i] = NULL; + if ( intelxl->rx.iobuf[i] ) { + dma_unmap ( intelxl->dma, &intelxl->rx.map[i] ); + free_iob ( intelxl->rx.iobuf[i] ); + } + intelxl->rx.iobuf[i] = NULL; + } + + /* Unmap incomplete transmit buffers */ + for ( i = intelxl->tx.ring.cons ; i != intelxl->tx.ring.prod ; i++ ) { + tx_idx = ( i % INTELXL_TX_NUM_DESC ); + dma_unmap ( intelxl->dma, &intelxl->tx.map[tx_idx] ); } } @@ -1384,7 +1428,7 @@ static int intelxl_open ( struct net_device *netdev ) { /* Associate transmit queue to PF */ writel ( ( INTELXL_QXX_CTL_PFVF_Q_PF | INTELXL_QXX_CTL_PFVF_PF_INDX ( intelxl->pf ) ), - ( intelxl->regs + intelxl->tx.reg + INTELXL_QXX_CTL ) ); + ( intelxl->regs + intelxl->tx.ring.reg + INTELXL_QXX_CTL ) ); /* Clear transmit pre queue disable */ queue = ( intelxl->base + intelxl->queue ); @@ -1396,11 +1440,11 @@ static int intelxl_open ( struct net_device *netdev ) { writel ( 0, ( intelxl->regs + INTELXL_QTX_HEAD ( intelxl->queue ) ) ); /* Create receive descriptor ring */ - if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->rx ) ) != 0 ) + if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->rx.ring ) ) != 0 ) goto err_create_rx; /* Create transmit descriptor ring */ - if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->tx ) ) != 0 ) + if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->tx.ring ) ) != 0 ) goto err_create_tx; /* Fill receive ring */ @@ -1418,9 +1462,9 @@ static int intelxl_open ( struct net_device *netdev ) { INTELXL_GLLAN_TXPRE_QDIS_QINDX ( queue ) ), ( intelxl->regs + INTELXL_GLLAN_TXPRE_QDIS ( queue ) ) ); udelay ( INTELXL_QUEUE_PRE_DISABLE_DELAY_US ); - intelxl_destroy_ring ( intelxl, &intelxl->tx ); + intelxl_destroy_ring ( intelxl, &intelxl->tx.ring ); err_create_tx: - intelxl_destroy_ring ( intelxl, &intelxl->rx ); + intelxl_destroy_ring ( intelxl, &intelxl->rx.ring ); err_create_rx: return rc; } @@ -1448,13 +1492,13 @@ static void intelxl_close ( struct net_device *netdev ) { udelay ( INTELXL_QUEUE_PRE_DISABLE_DELAY_US ); /* Destroy transmit descriptor ring */ - intelxl_destroy_ring ( intelxl, &intelxl->tx ); + intelxl_destroy_ring ( intelxl, &intelxl->tx.ring ); /* Destroy receive descriptor ring */ - intelxl_destroy_ring ( intelxl, &intelxl->rx ); + intelxl_destroy_ring ( intelxl, &intelxl->rx.ring ); - /* Discard any unused receive buffers */ - intelxl_empty_rx ( intelxl ); + /* Flush unused buffers */ + intelxl_flush ( intelxl ); } /** @@ -1467,36 +1511,45 @@ static void intelxl_close ( struct net_device *netdev ) { int intelxl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct intelxl_nic *intelxl = netdev->priv; struct intelxl_tx_data_descriptor *tx; + struct dma_mapping *map; unsigned int tx_idx; unsigned int tx_tail; - physaddr_t address; size_t len; + int rc; /* Get next transmit descriptor */ - if ( ( intelxl->tx.prod - intelxl->tx.cons ) >= INTELXL_TX_FILL ) { + if ( ( intelxl->tx.ring.prod - + intelxl->tx.ring.cons ) >= INTELXL_TX_FILL ) { DBGC ( intelxl, "INTELXL %p out of transmit descriptors\n", intelxl ); return -ENOBUFS; } - tx_idx = ( intelxl->tx.prod++ % INTELXL_TX_NUM_DESC ); - tx_tail = ( intelxl->tx.prod % INTELXL_TX_NUM_DESC ); - tx = &intelxl->tx.desc.tx[tx_idx].data; + tx_idx = ( intelxl->tx.ring.prod % INTELXL_TX_NUM_DESC ); + tx = &intelxl->tx.ring.desc.tx[tx_idx].data; + map = &intelxl->tx.map[tx_idx]; + + /* Map I/O buffer */ + if ( ( rc = dma_map_tx_iob ( intelxl->dma, iobuf, map ) ) != 0 ) + return rc; + + /* Update producer index */ + intelxl->tx.ring.prod++; /* Populate transmit descriptor */ - address = virt_to_bus ( iobuf->data ); len = iob_len ( iobuf ); - tx->address = cpu_to_le64 ( address ); + tx->address = cpu_to_le64 ( map->addr ); tx->len = cpu_to_le32 ( INTELXL_TX_DATA_LEN ( len ) ); tx->flags = cpu_to_le32 ( INTELXL_TX_DATA_DTYP | INTELXL_TX_DATA_EOP | INTELXL_TX_DATA_RS | INTELXL_TX_DATA_JFDI ); wmb(); /* Notify card that there are packets ready to transmit */ - writel ( tx_tail, ( intelxl->regs + intelxl->tx.tail ) ); + tx_tail = ( intelxl->tx.ring.prod % INTELXL_TX_NUM_DESC ); + writel ( tx_tail, ( intelxl->regs + intelxl->tx.ring.tail ) ); - DBGC2 ( intelxl, "INTELXL %p TX %d is [%llx,%llx)\n", intelxl, tx_idx, - ( ( unsigned long long ) address ), - ( ( unsigned long long ) address + len ) ); + DBGC2 ( intelxl, "INTELXL %p TX %d is [%08lx,%08lx)\n", + intelxl, tx_idx, virt_to_phys ( iobuf->data ), + ( virt_to_phys ( iobuf->data ) + len ) ); return 0; } @@ -1511,11 +1564,11 @@ static void intelxl_poll_tx ( struct net_device *netdev ) { unsigned int tx_idx; /* Check for completed packets */ - while ( intelxl->tx.cons != intelxl->tx.prod ) { + while ( intelxl->tx.ring.cons != intelxl->tx.ring.prod ) { /* Get next transmit descriptor */ - tx_idx = ( intelxl->tx.cons % INTELXL_TX_NUM_DESC ); - tx_wb = &intelxl->tx.desc.tx[tx_idx].wb; + tx_idx = ( intelxl->tx.ring.cons % INTELXL_TX_NUM_DESC ); + tx_wb = &intelxl->tx.ring.desc.tx[tx_idx].wb; /* Stop if descriptor is still in use */ if ( ! ( tx_wb->flags & INTELXL_TX_WB_FL_DD ) ) @@ -1523,9 +1576,12 @@ static void intelxl_poll_tx ( struct net_device *netdev ) { DBGC2 ( intelxl, "INTELXL %p TX %d complete\n", intelxl, tx_idx ); + /* Unmap I/O buffer */ + dma_unmap ( intelxl->dma, &intelxl->tx.map[tx_idx] ); + /* Complete TX descriptor */ netdev_tx_complete_next ( netdev ); - intelxl->tx.cons++; + intelxl->tx.ring.cons++; } } @@ -1543,19 +1599,22 @@ static void intelxl_poll_rx ( struct net_device *netdev ) { size_t len; /* Check for received packets */ - while ( intelxl->rx.cons != intelxl->rx.prod ) { + while ( intelxl->rx.ring.cons != intelxl->rx.ring.prod ) { /* Get next receive descriptor */ - rx_idx = ( intelxl->rx.cons % INTELXL_RX_NUM_DESC ); - rx_wb = &intelxl->rx.desc.rx[rx_idx].wb; + rx_idx = ( intelxl->rx.ring.cons % INTELXL_RX_NUM_DESC ); + rx_wb = &intelxl->rx.ring.desc.rx[rx_idx].wb; /* Stop if descriptor is still in use */ if ( ! ( rx_wb->flags & cpu_to_le32 ( INTELXL_RX_WB_FL_DD ) ) ) return; + /* Unmap I/O buffer */ + dma_unmap ( intelxl->dma, &intelxl->rx.map[rx_idx] ); + /* Populate I/O buffer */ - iobuf = intelxl->rx_iobuf[rx_idx]; - intelxl->rx_iobuf[rx_idx] = NULL; + iobuf = intelxl->rx.iobuf[rx_idx]; + intelxl->rx.iobuf[rx_idx] = NULL; len = INTELXL_RX_WB_LEN ( le32_to_cpu ( rx_wb->len ) ); iob_put ( iobuf, len ); @@ -1577,7 +1636,7 @@ static void intelxl_poll_rx ( struct net_device *netdev ) { "%zd)\n", intelxl, rx_idx, len ); vlan_netdev_rx ( netdev, tag, iobuf ); } - intelxl->rx.cons++; + intelxl->rx.ring.cons++; } } @@ -1659,16 +1718,17 @@ static int intelxl_probe ( struct pci_device *pci ) { pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( intelxl, 0, sizeof ( *intelxl ) ); + intelxl->dma = &pci->dma; intelxl->intr = INTELXL_PFINT_DYN_CTL0; intelxl_init_admin ( &intelxl->command, INTELXL_ADMIN_CMD, &intelxl_admin_offsets ); intelxl_init_admin ( &intelxl->event, INTELXL_ADMIN_EVT, &intelxl_admin_offsets ); - intelxl_init_ring ( &intelxl->tx, INTELXL_TX_NUM_DESC, - sizeof ( intelxl->tx.desc.tx[0] ), + intelxl_init_ring ( &intelxl->tx.ring, INTELXL_TX_NUM_DESC, + sizeof ( intelxl->tx.ring.desc.tx[0] ), intelxl_context_tx ); - intelxl_init_ring ( &intelxl->rx, INTELXL_RX_NUM_DESC, - sizeof ( intelxl->rx.desc.rx[0] ), + intelxl_init_ring ( &intelxl->rx.ring, INTELXL_RX_NUM_DESC, + sizeof ( intelxl->rx.ring.desc.rx[0] ), intelxl_context_rx ); /* Fix up PCI device */ @@ -1725,10 +1785,10 @@ static int intelxl_probe ( struct pci_device *pci ) { goto err_admin_promisc; /* Configure queue register addresses */ - intelxl->tx.reg = INTELXL_QTX ( intelxl->queue ); - intelxl->tx.tail = ( intelxl->tx.reg + INTELXL_QXX_TAIL ); - intelxl->rx.reg = INTELXL_QRX ( intelxl->queue ); - intelxl->rx.tail = ( intelxl->rx.reg + INTELXL_QXX_TAIL ); + intelxl->tx.ring.reg = INTELXL_QTX ( intelxl->queue ); + intelxl->tx.ring.tail = ( intelxl->tx.ring.reg + INTELXL_QXX_TAIL ); + intelxl->rx.ring.reg = INTELXL_QRX ( intelxl->queue ); + intelxl->rx.ring.tail = ( intelxl->rx.ring.reg + INTELXL_QXX_TAIL ); /* Configure interrupt causes */ writel ( ( INTELXL_QINT_TQCTL_NEXTQ_INDX_NONE | diff --git a/src/drivers/net/intelxl.h b/src/drivers/net/intelxl.h index ef9152f6e..cffc0da96 100644 --- a/src/drivers/net/intelxl.h +++ b/src/drivers/net/intelxl.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include struct intelxl_nic; @@ -562,6 +563,8 @@ struct intelxl_admin { struct intelxl_admin_descriptor *desc; /** Data buffers */ union intelxl_admin_buffer *buf; + /** DMA mapping */ + struct dma_mapping map; /** Queue index */ unsigned int index; @@ -866,6 +869,8 @@ struct intelxl_ring { /** Raw data */ void *raw; } desc; + /** Descriptor ring DMA mapping */ + struct dma_mapping map; /** Producer index */ unsigned int prod; /** Consumer index */ @@ -1025,10 +1030,40 @@ union intelxl_receive_address { uint8_t raw[ETH_ALEN]; }; +/** Transmit ring */ +struct intelxl_tx_ring { + /** Descriptor ring */ + struct intelxl_ring ring; + /** DMA mappings */ + struct dma_mapping map[INTELXL_TX_NUM_DESC]; +}; + +/** Receive ring */ +struct intelxl_rx_ring { + /** Descriptor ring */ + struct intelxl_ring ring; + /** I/O buffers */ + struct io_buffer *iobuf[INTELXL_RX_NUM_DESC]; + /** DMA mappings */ + struct dma_mapping map[INTELXL_RX_NUM_DESC]; +}; + +/** MSI-X interrupt */ +struct intelxl_msix { + /** PCI capability */ + struct pci_msix cap; + /** MSI-X dummy interrupt target */ + uint32_t msg; + /** DMA mapping for dummy interrupt target */ + struct dma_mapping map; +}; + /** An Intel 40Gigabit network card */ struct intelxl_nic { /** Registers */ void *regs; + /** DMA device */ + struct dma_device *dma; /** Maximum frame size */ size_t mfs; @@ -1046,12 +1081,10 @@ struct intelxl_nic { unsigned int qset; /** Interrupt control register */ unsigned int intr; - /** MSI-X capability */ - struct pci_msix msix; - /** MSI-X dummy interrupt target */ - uint32_t msg; /** PCI Express capability offset */ unsigned int exp; + /** MSI-X interrupt */ + struct intelxl_msix msix; /** Admin command queue */ struct intelxl_admin command; @@ -1065,12 +1098,10 @@ struct intelxl_nic { /** Current VF event data buffer */ union intelxl_admin_buffer vbuf; - /** Transmit descriptor ring */ - struct intelxl_ring tx; - /** Receive descriptor ring */ - struct intelxl_ring rx; - /** Receive I/O buffers */ - struct io_buffer *rx_iobuf[INTELXL_RX_NUM_DESC]; + /** Transmit ring */ + struct intelxl_tx_ring tx; + /** Receive ring */ + struct intelxl_rx_ring rx; }; extern int intelxl_msix_enable ( struct intelxl_nic *intelxl, @@ -1090,7 +1121,7 @@ extern int intelxl_alloc_ring ( struct intelxl_nic *intelxl, struct intelxl_ring *ring ); extern void intelxl_free_ring ( struct intelxl_nic *intelxl, struct intelxl_ring *ring ); -extern void intelxl_empty_rx ( struct intelxl_nic *intelxl ); +extern void intelxl_flush ( struct intelxl_nic *intelxl ); extern int intelxl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ); extern void intelxl_poll ( struct net_device *netdev ); diff --git a/src/drivers/net/intelxlvf.c b/src/drivers/net/intelxlvf.c index 83e484c8d..dc2e3bf4e 100644 --- a/src/drivers/net/intelxlvf.c +++ b/src/drivers/net/intelxlvf.c @@ -298,9 +298,9 @@ void intelxlvf_admin_event ( struct net_device *netdev, if ( intelxl->vret != 0 ) { DBGC ( intelxl, "INTELXL %p admin VF command %#x " "error %d\n", intelxl, vopcode, intelxl->vret ); - DBGC_HDA ( intelxl, virt_to_bus ( evt ), evt, + DBGC_HDA ( intelxl, virt_to_phys ( evt ), evt, sizeof ( *evt ) ); - DBGC_HDA ( intelxl, virt_to_bus ( buf ), buf, + DBGC_HDA ( intelxl, virt_to_phys ( buf ), buf, le16_to_cpu ( evt->len ) ); } return; @@ -314,8 +314,10 @@ void intelxlvf_admin_event ( struct net_device *netdev, default: DBGC ( intelxl, "INTELXL %p unrecognised VF event %#x:\n", intelxl, vopcode ); - DBGC_HDA ( intelxl, 0, evt, sizeof ( *evt ) ); - DBGC_HDA ( intelxl, 0, buf, le16_to_cpu ( evt->len ) ); + DBGC_HDA ( intelxl, virt_to_phys ( evt ), evt, + sizeof ( *evt ) ); + DBGC_HDA ( intelxl, virt_to_phys ( buf ), buf, + le16_to_cpu ( evt->len ) ); break; } } @@ -378,12 +380,12 @@ static int intelxlvf_admin_configure ( struct net_device *netdev ) { buf->cfg.count = cpu_to_le16 ( 1 ); buf->cfg.tx.vsi = cpu_to_le16 ( intelxl->vsi ); buf->cfg.tx.count = cpu_to_le16 ( INTELXL_TX_NUM_DESC ); - buf->cfg.tx.base = cpu_to_le64 ( virt_to_bus ( intelxl->tx.desc.raw ) ); + buf->cfg.tx.base = cpu_to_le64 ( intelxl->tx.ring.map.addr ); buf->cfg.rx.vsi = cpu_to_le16 ( intelxl->vsi ); buf->cfg.rx.count = cpu_to_le32 ( INTELXL_RX_NUM_DESC ); buf->cfg.rx.len = cpu_to_le32 ( intelxl->mfs ); buf->cfg.rx.mfs = cpu_to_le32 ( intelxl->mfs ); - buf->cfg.rx.base = cpu_to_le64 ( virt_to_bus ( intelxl->rx.desc.raw ) ); + buf->cfg.rx.base = cpu_to_le64 ( intelxl->rx.ring.map.addr ); /* Issue command */ if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 ) @@ -497,11 +499,11 @@ static int intelxlvf_open ( struct net_device *netdev ) { INTELXL_ALIGN - 1 ) & ~( INTELXL_ALIGN - 1 ) ); /* Allocate transmit descriptor ring */ - if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->tx ) ) != 0 ) + if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->tx.ring ) ) != 0 ) goto err_alloc_tx; /* Allocate receive descriptor ring */ - if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->rx ) ) != 0 ) + if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->rx.ring ) ) != 0 ) goto err_alloc_rx; /* Configure queues */ @@ -527,9 +529,9 @@ static int intelxlvf_open ( struct net_device *netdev ) { err_enable: err_irq_map: err_configure: - intelxl_free_ring ( intelxl, &intelxl->rx ); + intelxl_free_ring ( intelxl, &intelxl->rx.ring ); err_alloc_rx: - intelxl_free_ring ( intelxl, &intelxl->tx ); + intelxl_free_ring ( intelxl, &intelxl->tx.ring ); err_alloc_tx: return rc; } @@ -550,13 +552,13 @@ static void intelxlvf_close ( struct net_device *netdev ) { } /* Free receive descriptor ring */ - intelxl_free_ring ( intelxl, &intelxl->rx ); + intelxl_free_ring ( intelxl, &intelxl->rx.ring ); /* Free transmit descriptor ring */ - intelxl_free_ring ( intelxl, &intelxl->tx ); + intelxl_free_ring ( intelxl, &intelxl->tx.ring ); - /* Discard any unused receive buffers */ - intelxl_empty_rx ( intelxl ); + /* Flush unused buffers */ + intelxl_flush ( intelxl ); } /** Network device operations */ @@ -596,16 +598,17 @@ static int intelxlvf_probe ( struct pci_device *pci ) { pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( intelxl, 0, sizeof ( *intelxl ) ); + intelxl->dma = &pci->dma; intelxl->intr = INTELXLVF_VFINT_DYN_CTL0; intelxl_init_admin ( &intelxl->command, INTELXLVF_ADMIN, &intelxlvf_admin_command_offsets ); intelxl_init_admin ( &intelxl->event, INTELXLVF_ADMIN, &intelxlvf_admin_event_offsets ); - intelxlvf_init_ring ( &intelxl->tx, INTELXL_TX_NUM_DESC, - sizeof ( intelxl->tx.desc.tx[0] ), + intelxlvf_init_ring ( &intelxl->tx.ring, INTELXL_TX_NUM_DESC, + sizeof ( intelxl->tx.ring.desc.tx[0] ), INTELXLVF_QTX_TAIL ); - intelxlvf_init_ring ( &intelxl->rx, INTELXL_RX_NUM_DESC, - sizeof ( intelxl->rx.desc.rx[0] ), + intelxlvf_init_ring ( &intelxl->rx.ring, INTELXL_RX_NUM_DESC, + sizeof ( intelxl->rx.ring.desc.rx[0] ), INTELXLVF_QRX_TAIL ); /* Fix up PCI device */ -- cgit v1.2.3-55-g7522 From 9e280aecb774ef71e65f41845fdf6cdde1f0b7a2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 24 Nov 2020 17:46:39 +0000 Subject: [intel] Configure DMA mask as 64-bit Signed-off-by: Michael Brown --- src/drivers/net/intel.c | 5 ++++- src/drivers/net/intelx.c | 5 ++++- src/drivers/net/intelxvf.c | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c index 2963d9dc8..408101bad 100644 --- a/src/drivers/net/intel.c +++ b/src/drivers/net/intel.c @@ -983,7 +983,6 @@ static int intel_probe ( struct pci_device *pci ) { pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( intel, 0, sizeof ( *intel ) ); - intel->dma = &pci->dma; intel->port = PCI_FUNC ( pci->busdevfn ); intel->flags = pci->id->driver_data; intel_init_ring ( &intel->tx.ring, INTEL_NUM_TX_DESC, INTEL_TD, @@ -1001,6 +1000,10 @@ static int intel_probe ( struct pci_device *pci ) { goto err_ioremap; } + /* Configure DMA */ + intel->dma = &pci->dma; + dma_set_mask_64bit ( intel->dma ); + /* Reset the NIC */ if ( ( rc = intel_reset ( intel ) ) != 0 ) goto err_reset; diff --git a/src/drivers/net/intelx.c b/src/drivers/net/intelx.c index 3fa68bb3c..364ec76c5 100644 --- a/src/drivers/net/intelx.c +++ b/src/drivers/net/intelx.c @@ -394,7 +394,6 @@ static int intelx_probe ( struct pci_device *pci ) { pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( intel, 0, sizeof ( *intel ) ); - intel->dma = &pci->dma; intel->port = PCI_FUNC ( pci->busdevfn ); intel_init_ring ( &intel->tx.ring, INTEL_NUM_TX_DESC, INTELX_TD, intel_describe_tx ); @@ -411,6 +410,10 @@ static int intelx_probe ( struct pci_device *pci ) { goto err_ioremap; } + /* Configure DMA */ + intel->dma = &pci->dma; + dma_set_mask_64bit ( intel->dma ); + /* Reset the NIC */ if ( ( rc = intelx_reset ( intel ) ) != 0 ) goto err_reset; diff --git a/src/drivers/net/intelxvf.c b/src/drivers/net/intelxvf.c index 4941fc57b..a650979ef 100644 --- a/src/drivers/net/intelxvf.c +++ b/src/drivers/net/intelxvf.c @@ -446,7 +446,6 @@ static int intelxvf_probe ( struct pci_device *pci ) { pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( intel, 0, sizeof ( *intel ) ); - intel->dma = &pci->dma; intel_init_mbox ( &intel->mbox, INTELXVF_MBCTRL, INTELXVF_MBMEM ); intel_init_ring ( &intel->tx.ring, INTEL_NUM_TX_DESC, INTELXVF_TD(0), intel_describe_tx_adv ); @@ -463,6 +462,10 @@ static int intelxvf_probe ( struct pci_device *pci ) { goto err_ioremap; } + /* Configure DMA */ + intel->dma = &pci->dma; + dma_set_mask_64bit ( intel->dma ); + /* Reset the function */ intelxvf_reset ( intel ); -- cgit v1.2.3-55-g7522 From 24ef743778fb47958441d8891e5104135ac4c168 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 24 Nov 2020 17:47:42 +0000 Subject: [intelxl] Configure DMA mask as 64-bit Signed-off-by: Michael Brown --- src/drivers/net/intelxl.c | 5 ++++- src/drivers/net/intelxlvf.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c index 578d6ff02..14a5858f3 100644 --- a/src/drivers/net/intelxl.c +++ b/src/drivers/net/intelxl.c @@ -1718,7 +1718,6 @@ static int intelxl_probe ( struct pci_device *pci ) { pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( intelxl, 0, sizeof ( *intelxl ) ); - intelxl->dma = &pci->dma; intelxl->intr = INTELXL_PFINT_DYN_CTL0; intelxl_init_admin ( &intelxl->command, INTELXL_ADMIN_CMD, &intelxl_admin_offsets ); @@ -1741,6 +1740,10 @@ static int intelxl_probe ( struct pci_device *pci ) { goto err_ioremap; } + /* Configure DMA */ + intelxl->dma = &pci->dma; + dma_set_mask_64bit ( intelxl->dma ); + /* Reset the NIC */ if ( ( rc = intelxl_reset ( intelxl ) ) != 0 ) goto err_reset; diff --git a/src/drivers/net/intelxlvf.c b/src/drivers/net/intelxlvf.c index dc2e3bf4e..61ac5e5c0 100644 --- a/src/drivers/net/intelxlvf.c +++ b/src/drivers/net/intelxlvf.c @@ -598,7 +598,6 @@ static int intelxlvf_probe ( struct pci_device *pci ) { pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( intelxl, 0, sizeof ( *intelxl ) ); - intelxl->dma = &pci->dma; intelxl->intr = INTELXLVF_VFINT_DYN_CTL0; intelxl_init_admin ( &intelxl->command, INTELXLVF_ADMIN, &intelxlvf_admin_command_offsets ); @@ -621,6 +620,10 @@ static int intelxlvf_probe ( struct pci_device *pci ) { goto err_ioremap; } + /* Configure DMA */ + intelxl->dma = &pci->dma; + dma_set_mask_64bit ( intelxl->dma ); + /* Locate PCI Express capability */ intelxl->exp = pci_find_capability ( pci, PCI_CAP_ID_EXP ); if ( ! intelxl->exp ) { -- cgit v1.2.3-55-g7522 From cf12a41703a8b2292e5d2d7528c2733c37869681 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 25 Nov 2020 15:52:00 +0000 Subject: [dma] Modify DMA API to simplify calculation of medial addresses Redefine the value stored within a DMA mapping to be the offset between physical addresses and DMA addresses within the mapped region. Provide a dma() wrapper function to calculate the DMA address for any pointer within a mapped region, thereby simplifying the use cases when a device needs to be given addresses other than the region start address. On a platform using the "flat" DMA implementation the DMA offset for any mapped region is always zero, with the result that dma_map() can be optimised away completely and dma() reduces to a straightforward call to virt_to_phys(). Signed-off-by: Michael Brown --- src/core/dma.c | 2 ++ src/drivers/net/intel.c | 10 ++---- src/drivers/net/intelxl.c | 33 ++++++-------------- src/drivers/net/intelxlvf.c | 6 ++-- src/drivers/net/realtek.c | 27 +++++++++-------- src/include/ipxe/dma.h | 74 +++++++++++++++++++++++++++++++++++++++------ src/interface/efi/efi_pci.c | 6 ++-- 7 files changed, 100 insertions(+), 58 deletions(-) (limited to 'src/drivers') diff --git a/src/core/dma.c b/src/core/dma.c index 9fc0c5453..3bf6957b9 100644 --- a/src/core/dma.c +++ b/src/core/dma.c @@ -46,6 +46,7 @@ PROVIDE_DMAAPI_INLINE ( flat, dma_unmap ); PROVIDE_DMAAPI_INLINE ( flat, dma_alloc ); PROVIDE_DMAAPI_INLINE ( flat, dma_free ); PROVIDE_DMAAPI_INLINE ( flat, dma_set_mask ); +PROVIDE_DMAAPI_INLINE ( flat, dma_phys ); /****************************************************************************** * @@ -138,6 +139,7 @@ PROVIDE_DMAAPI ( op, dma_unmap, dma_op_unmap ); PROVIDE_DMAAPI ( op, dma_alloc, dma_op_alloc ); PROVIDE_DMAAPI ( op, dma_free, dma_op_free ); PROVIDE_DMAAPI ( op, dma_set_mask, dma_op_set_mask ); +PROVIDE_DMAAPI_INLINE ( op, dma_phys ); /****************************************************************************** * diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c index 408101bad..5c6dc2143 100644 --- a/src/drivers/net/intel.c +++ b/src/drivers/net/intel.c @@ -513,7 +513,7 @@ int intel_create_ring ( struct intel_nic *intel, struct intel_ring *ring ) { memset ( ring->desc, 0, ring->len ); /* Program ring address */ - address = ring->map.addr; + address = dma ( &ring->map, ring->desc ); writel ( ( address & 0xffffffffUL ), ( intel->regs + ring->reg + INTEL_xDBAL ) ); if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) { @@ -571,7 +571,6 @@ void intel_refill_rx ( struct intel_nic *intel ) { struct dma_mapping *map; unsigned int rx_idx; unsigned int rx_tail; - physaddr_t address; unsigned int refilled = 0; /* Refill ring */ @@ -596,8 +595,7 @@ void intel_refill_rx ( struct intel_nic *intel ) { intel->rx.ring.prod++; /* Populate receive descriptor */ - address = map->addr; - intel->rx.ring.describe ( rx, address, 0 ); + intel->rx.ring.describe ( rx, dma ( map, iobuf->data ), 0 ); DBGC2 ( intel, "INTEL %p RX %d is [%lx,%lx)\n", intel, rx_idx, virt_to_phys ( iobuf->data ), @@ -762,7 +760,6 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct dma_mapping *map; unsigned int tx_idx; unsigned int tx_tail; - physaddr_t address; size_t len; int rc; @@ -783,9 +780,8 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { intel->tx.ring.prod++; /* Populate transmit descriptor */ - address = map->addr; len = iob_len ( iobuf ); - intel->tx.ring.describe ( tx, address, len ); + intel->tx.ring.describe ( tx, dma ( map, iobuf->data ), len ); wmb(); /* Notify card that there are packets ready to transmit */ diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c index 14a5858f3..0808c784a 100644 --- a/src/drivers/net/intelxl.c +++ b/src/drivers/net/intelxl.c @@ -152,7 +152,8 @@ int intelxl_msix_enable ( struct intelxl_nic *intelxl, } /* Configure interrupt zero to write to dummy location */ - pci_msix_map ( &intelxl->msix.cap, 0, intelxl->msix.map.addr, 0 ); + pci_msix_map ( &intelxl->msix.cap, 0, + dma ( &intelxl->msix.map, &intelxl->msix.msg ), 0 ); /* Enable dummy interrupt zero */ pci_msix_unmask ( &intelxl->msix.cap, 0 ); @@ -230,22 +231,6 @@ static int intelxl_alloc_admin ( struct intelxl_nic *intelxl, return 0; } -/** - * Get DMA address for admin descriptor or buffer entry - * - * @v admin Admin queue - * @v addr Virtual address - * @ret addr DMA address - */ -static physaddr_t intelxl_admin_address ( struct intelxl_admin *admin, - void *addr ) { - size_t offset; - - /* Calculate offset within mapped area */ - offset = ( addr - ( ( void * ) admin->buf ) ); - return ( admin->map.addr + offset ); -} - /** * Enable admin queue * @@ -270,7 +255,7 @@ static void intelxl_enable_admin ( struct intelxl_nic *intelxl, admin->index = 0; /* Program queue address */ - address = intelxl_admin_address ( admin, admin->desc ); + address = dma ( &admin->map, admin->desc ); writel ( ( address & 0xffffffffUL ), admin_regs + regs->bal ); if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) { writel ( ( ( ( uint64_t ) address ) >> 32 ), @@ -365,7 +350,7 @@ static void intelxl_admin_event_init ( struct intelxl_nic *intelxl, /* Initialise descriptor */ evt = &admin->desc[ index % INTELXL_ADMIN_NUM_DESC ]; buf = &admin->buf[ index % INTELXL_ADMIN_NUM_DESC ]; - address = intelxl_admin_address ( admin, buf ); + address = dma ( &admin->map, buf ); evt->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ); evt->len = cpu_to_le16 ( sizeof ( *buf ) ); evt->params.buffer.high = cpu_to_le32 ( address >> 32 ); @@ -410,7 +395,7 @@ int intelxl_admin_command ( struct intelxl_nic *intelxl ) { /* Populate data buffer address if applicable */ if ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ) ) { - address = intelxl_admin_address ( admin, buf ); + address = dma ( &admin->map, buf ); cmd->params.buffer.high = cpu_to_le32 ( address >> 32 ); cmd->params.buffer.low = cpu_to_le32 ( address & 0xffffffffUL ); } @@ -1267,6 +1252,7 @@ static int intelxl_disable_ring ( struct intelxl_nic *intelxl, */ static int intelxl_create_ring ( struct intelxl_nic *intelxl, struct intelxl_ring *ring ) { + physaddr_t address; int rc; /* Allocate descriptor ring */ @@ -1274,7 +1260,8 @@ static int intelxl_create_ring ( struct intelxl_nic *intelxl, goto err_alloc; /* Program queue context */ - if ( ( rc = ring->context ( intelxl, ring->map.addr ) ) != 0 ) + address = dma ( &ring->map, ring->desc.raw ); + if ( ( rc = ring->context ( intelxl, address ) ) != 0 ) goto err_context; /* Enable ring */ @@ -1346,7 +1333,7 @@ static void intelxl_refill_rx ( struct intelxl_nic *intelxl ) { intelxl->rx.ring.prod++; /* Populate receive descriptor */ - rx->address = cpu_to_le64 ( map->addr ); + rx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); rx->flags = 0; DBGC2 ( intelxl, "INTELXL %p RX %d is [%08lx,%08lx)\n", @@ -1537,7 +1524,7 @@ int intelxl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { /* Populate transmit descriptor */ len = iob_len ( iobuf ); - tx->address = cpu_to_le64 ( map->addr ); + tx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); tx->len = cpu_to_le32 ( INTELXL_TX_DATA_LEN ( len ) ); tx->flags = cpu_to_le32 ( INTELXL_TX_DATA_DTYP | INTELXL_TX_DATA_EOP | INTELXL_TX_DATA_RS | INTELXL_TX_DATA_JFDI ); diff --git a/src/drivers/net/intelxlvf.c b/src/drivers/net/intelxlvf.c index 61ac5e5c0..f944b4daa 100644 --- a/src/drivers/net/intelxlvf.c +++ b/src/drivers/net/intelxlvf.c @@ -380,12 +380,14 @@ static int intelxlvf_admin_configure ( struct net_device *netdev ) { buf->cfg.count = cpu_to_le16 ( 1 ); buf->cfg.tx.vsi = cpu_to_le16 ( intelxl->vsi ); buf->cfg.tx.count = cpu_to_le16 ( INTELXL_TX_NUM_DESC ); - buf->cfg.tx.base = cpu_to_le64 ( intelxl->tx.ring.map.addr ); + buf->cfg.tx.base = cpu_to_le64 ( dma ( &intelxl->tx.ring.map, + intelxl->tx.ring.desc.raw ) ); buf->cfg.rx.vsi = cpu_to_le16 ( intelxl->vsi ); buf->cfg.rx.count = cpu_to_le32 ( INTELXL_RX_NUM_DESC ); buf->cfg.rx.len = cpu_to_le32 ( intelxl->mfs ); buf->cfg.rx.mfs = cpu_to_le32 ( intelxl->mfs ); - buf->cfg.rx.base = cpu_to_le64 ( intelxl->rx.ring.map.addr ); + buf->cfg.rx.base = cpu_to_le64 ( dma ( &intelxl->rx.ring.map, + intelxl->rx.ring.desc.raw ) ); /* Issue command */ if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 ) diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index 0f3038d36..bca52266f 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -506,6 +506,7 @@ static void realtek_check_link ( struct net_device *netdev ) { * @ret rc Return status code */ static int realtek_create_buffer ( struct realtek_nic *rtl ) { + struct realtek_rx_buffer *rxbuf = &rtl->rxbuf; size_t len = ( RTL_RXBUF_LEN + RTL_RXBUF_PAD ); /* Do nothing unless in legacy mode */ @@ -513,17 +514,16 @@ static int realtek_create_buffer ( struct realtek_nic *rtl ) { return 0; /* Allocate buffer */ - rtl->rxbuf.data = dma_alloc ( rtl->dma, len, RTL_RXBUF_ALIGN, - &rtl->rxbuf.map ); - if ( ! rtl->rxbuf.data ) + rxbuf->data = dma_alloc ( rtl->dma, len, RTL_RXBUF_ALIGN, &rxbuf->map ); + if ( ! rxbuf->data ) return -ENOMEM; /* Program buffer address */ - writel ( rtl->rxbuf.map.addr, rtl->regs + RTL_RBSTART ); + writel ( dma ( &rxbuf->map, rxbuf->data ), rtl->regs + RTL_RBSTART ); DBGC ( rtl, "REALTEK %p receive buffer is at [%08lx,%08lx,%08lx)\n", - rtl, virt_to_phys ( rtl->rxbuf.data ), - ( virt_to_phys ( rtl->rxbuf.data ) + RTL_RXBUF_LEN ), - ( virt_to_phys ( rtl->rxbuf.data ) + len ) ); + rtl, virt_to_phys ( rxbuf->data ), + ( virt_to_phys ( rxbuf->data ) + RTL_RXBUF_LEN ), + ( virt_to_phys ( rxbuf->data ) + len ) ); return 0; } @@ -534,6 +534,7 @@ static int realtek_create_buffer ( struct realtek_nic *rtl ) { * @v rtl Realtek device */ static void realtek_destroy_buffer ( struct realtek_nic *rtl ) { + struct realtek_rx_buffer *rxbuf = &rtl->rxbuf; size_t len = ( RTL_RXBUF_LEN + RTL_RXBUF_PAD ); /* Do nothing unless in legacy mode */ @@ -544,9 +545,9 @@ static void realtek_destroy_buffer ( struct realtek_nic *rtl ) { writel ( 0, rtl->regs + RTL_RBSTART ); /* Free buffer */ - dma_free ( rtl->dma, rtl->rxbuf.data, len, &rtl->rxbuf.map ); - rtl->rxbuf.data = NULL; - rtl->rxbuf.offset = 0; + dma_free ( rtl->dma, rxbuf->data, len, &rxbuf->map ); + rxbuf->data = NULL; + rxbuf->offset = 0; } /** @@ -574,7 +575,7 @@ static int realtek_create_ring ( struct realtek_nic *rtl, memset ( ring->desc, 0, ring->len ); /* Program ring address */ - address = ring->map.addr; + address = dma ( &ring->map, ring->desc ); writel ( ( ( ( uint64_t ) address ) >> 32 ), rtl->regs + ring->reg + 4 ); writel ( ( address & 0xffffffffUL ), rtl->regs + ring->reg ); @@ -648,7 +649,7 @@ static void realtek_refill_rx ( struct realtek_nic *rtl ) { rtl->rx.ring.prod++; /* Populate receive descriptor */ - rx->address = cpu_to_le64 ( map->addr ); + rx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); rx->length = cpu_to_le16 ( RTL_RX_MAX_LEN ); wmb(); rx->flags = ( cpu_to_le16 ( RTL_DESC_OWN ) | @@ -797,7 +798,7 @@ static int realtek_transmit ( struct net_device *netdev, /* Map I/O buffer */ if ( ( rc = dma_map_tx_iob ( rtl->dma, iobuf, map ) ) != 0 ) return rc; - address = map->addr; + address = dma ( map, iobuf->data ); /* Update producer index */ rtl->tx.ring.prod++; diff --git a/src/include/ipxe/dma.h b/src/include/ipxe/dma.h index 878e03f11..0577493c7 100644 --- a/src/include/ipxe/dma.h +++ b/src/include/ipxe/dma.h @@ -30,8 +30,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** A DMA mapping */ struct dma_mapping { - /** Device-side address */ - physaddr_t addr; + /** Address offset + * + * This is the value that must be added to a physical address + * within the mapping in order to produce the corresponding + * device-side DMA address. + */ + physaddr_t offset; /** Platform mapping token */ void *token; }; @@ -148,12 +153,10 @@ struct dma_operations { * @ret rc Return status code */ static inline __always_inline int -DMAAPI_INLINE ( flat, dma_map ) ( struct dma_device *dma, physaddr_t addr, +DMAAPI_INLINE ( flat, dma_map ) ( struct dma_device *dma, + physaddr_t addr __unused, size_t len __unused, int flags __unused, - struct dma_mapping *map ) { - - /* Use physical address as device address */ - map->addr = addr; + struct dma_mapping *map __unused ) { /* Increment mapping count (for debugging) */ if ( DBG_LOG ) @@ -187,13 +190,13 @@ DMAAPI_INLINE ( flat, dma_unmap ) ( struct dma_device *dma, * @ret addr Buffer address, or NULL on error */ static inline __always_inline void * -DMAAPI_INLINE ( flat, dma_alloc ) ( struct dma_device *dma, size_t len, - size_t align, struct dma_mapping *map ) { +DMAAPI_INLINE ( flat, dma_alloc ) ( struct dma_device *dma, + size_t len, size_t align, + struct dma_mapping *map __unused ) { void *addr; /* Allocate buffer */ addr = malloc_phys ( len, align ); - map->addr = virt_to_phys ( addr ); /* Increment allocation count (for debugging) */ if ( DBG_LOG && addr ) @@ -236,6 +239,35 @@ DMAAPI_INLINE ( flat, dma_set_mask ) ( struct dma_device *dma __unused, /* Nothing to do */ } +/** + * Get DMA address from physical address + * + * @v map DMA mapping + * @v addr Physical address within the mapped region + * @ret addr Device-side DMA address + */ +static inline __always_inline physaddr_t +DMAAPI_INLINE ( flat, dma_phys ) ( struct dma_mapping *map __unused, + physaddr_t addr ) { + + /* Use physical address as device address */ + return addr; +} + +/** + * Get DMA address from physical address + * + * @v map DMA mapping + * @v addr Physical address within the mapped region + * @ret addr Device-side DMA address + */ +static inline __always_inline physaddr_t +DMAAPI_INLINE ( op, dma_phys ) ( struct dma_mapping *map, physaddr_t addr ) { + + /* Adjust physical address using mapping offset */ + return ( addr + map->offset ); +} + /** * Map buffer for DMA * @@ -288,6 +320,28 @@ void dma_free ( struct dma_device *dma, void *addr, size_t len, */ void dma_set_mask ( struct dma_device *dma, physaddr_t mask ); +/** + * Get DMA address from physical address + * + * @v map DMA mapping + * @v addr Physical address within the mapped region + * @ret addr Device-side DMA address + */ +physaddr_t dma_phys ( struct dma_mapping *map, physaddr_t addr ); + +/** + * Get DMA address from virtual address + * + * @v map DMA mapping + * @v addr Virtual address within the mapped region + * @ret addr Device-side DMA address + */ +static inline __always_inline physaddr_t dma ( struct dma_mapping *map, + void *addr ) { + + return dma_phys ( map, virt_to_phys ( addr ) ); +} + /** * Initialise DMA device * diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index 6c6ac5c77..e33a8980d 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -335,7 +335,7 @@ static int efipci_dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, int rc; /* Sanity check */ - assert ( map->addr == 0 ); + assert ( map->offset == 0 ); assert ( map->token == NULL ); /* Determine operation */ @@ -374,7 +374,7 @@ static int efipci_dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, } /* Populate mapping */ - map->addr = bus; + map->offset = ( bus - addr ); map->token = mapping; /* Increment mapping count (for debugging) */ @@ -408,7 +408,7 @@ static void efipci_dma_unmap ( struct dma_device *dma, pci_io->Unmap ( pci_io, map->token ); /* Clear mapping */ - map->addr = 0; + map->offset = 0; map->token = NULL; /* Decrement mapping count (for debugging) */ -- cgit v1.2.3-55-g7522 From 70e6e83243b77a3771756106871d6f945062a44b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 27 Nov 2020 11:27:22 +0000 Subject: [dma] Record DMA device as part of DMA mapping if needed Allow for dma_unmap() to be called by code other than the DMA device driver itself. Signed-off-by: Michael Brown --- src/core/dma.c | 52 +++++++++---------- src/drivers/net/intel.c | 18 +++---- src/drivers/net/intelxl.c | 40 +++++++-------- src/drivers/net/realtek.c | 23 +++++---- src/include/ipxe/dma.h | 121 +++++++++++++++++++++++++------------------- src/interface/efi/efi_pci.c | 25 ++++----- 6 files changed, 150 insertions(+), 129 deletions(-) (limited to 'src/drivers') diff --git a/src/core/dma.c b/src/core/dma.c index 3bf6957b9..561aec1e1 100644 --- a/src/core/dma.c +++ b/src/core/dma.c @@ -59,66 +59,65 @@ PROVIDE_DMAAPI_INLINE ( flat, dma_phys ); * Map buffer for DMA * * @v dma DMA device + * @v map DMA mapping to fill in * @v addr Buffer address * @v len Length of buffer * @v flags Mapping flags - * @v map DMA mapping to fill in * @ret rc Return status code */ -static int dma_op_map ( struct dma_device *dma, physaddr_t addr, size_t len, - int flags, struct dma_mapping *map ) { +static int dma_op_map ( struct dma_device *dma, struct dma_mapping *map, + physaddr_t addr, size_t len, int flags ) { struct dma_operations *op = dma->op; if ( ! op ) return -ENODEV; - return op->map ( dma, addr, len, flags, map ); + return op->map ( dma, map, addr, len, flags ); } /** * Unmap buffer * - * @v dma DMA device * @v map DMA mapping */ -static void dma_op_unmap ( struct dma_device *dma, struct dma_mapping *map ) { - struct dma_operations *op = dma->op; +static void dma_op_unmap ( struct dma_mapping *map ) { + struct dma_device *dma = map->dma; - assert ( op != NULL ); - op->unmap ( dma, map ); + assert ( dma != NULL ); + assert ( dma->op != NULL ); + dma->op->unmap ( dma, map ); } /** * Allocate and map DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping to fill in * @v len Length of buffer * @v align Physical alignment - * @v map DMA mapping to fill in * @ret addr Buffer address, or NULL on error */ -static void * dma_op_alloc ( struct dma_device *dma, size_t len, size_t align, - struct dma_mapping *map ) { +static void * dma_op_alloc ( struct dma_device *dma, struct dma_mapping *map, + size_t len, size_t align ) { struct dma_operations *op = dma->op; if ( ! op ) return NULL; - return op->alloc ( dma, len, align, map ); + return op->alloc ( dma, map, len, align ); } /** * Unmap and free DMA-coherent buffer * - * @v dma DMA device + * @v map DMA mapping * @v addr Buffer address * @v len Length of buffer - * @v map DMA mapping */ -static void dma_op_free ( struct dma_device *dma, void *addr, size_t len, - struct dma_mapping *map ) { - struct dma_operations *op = dma->op; +static void dma_op_free ( struct dma_mapping *map, void *addr, size_t len ) { + struct dma_device *dma = map->dma; - assert ( op != NULL ); - op->free ( dma, addr, len, map ); + assert ( dma != NULL ); + assert ( dma->op != NULL ); + dma->op->free ( dma, map, addr, len ); } /** @@ -152,12 +151,13 @@ PROVIDE_DMAAPI_INLINE ( op, dma_phys ); * Allocate and map I/O buffer for receiving data from device * * @v dma DMA device - * @v len Length of I/O buffer * @v map DMA mapping to fill in + * @v len Length of I/O buffer * @ret iobuf I/O buffer, or NULL on error */ -struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, size_t len, - struct dma_mapping *map ) { +struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, + struct dma_mapping *map, + size_t len ) { struct io_buffer *iobuf; int rc; @@ -167,13 +167,13 @@ struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, size_t len, goto err_alloc; /* Map I/O buffer */ - if ( ( rc = dma_map ( dma, virt_to_phys ( iobuf->data ), len, - DMA_RX, map ) ) != 0 ) + if ( ( rc = dma_map ( dma, map, virt_to_phys ( iobuf->data ), + len, DMA_RX ) ) != 0 ) goto err_map; return iobuf; - dma_unmap ( dma, map ); + dma_unmap ( map ); err_map: free_iob ( iobuf ); err_alloc: diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c index 5c6dc2143..93c5fd1f6 100644 --- a/src/drivers/net/intel.c +++ b/src/drivers/net/intel.c @@ -504,8 +504,8 @@ int intel_create_ring ( struct intel_nic *intel, struct intel_ring *ring ) { * prevent any possible page-crossing errors due to hardware * errata. */ - ring->desc = dma_alloc ( intel->dma, ring->len, ring->len, - &ring->map ); + ring->desc = dma_alloc ( intel->dma, &ring->map, ring->len, + ring->len ); if ( ! ring->desc ) return -ENOMEM; @@ -554,7 +554,7 @@ void intel_destroy_ring ( struct intel_nic *intel, struct intel_ring *ring ) { intel_reset_ring ( intel, ring->reg ); /* Free descriptor ring */ - dma_free ( intel->dma, ring->desc, ring->len, &ring->map ); + dma_free ( &ring->map, ring->desc, ring->len ); ring->desc = NULL; ring->prod = 0; ring->cons = 0; @@ -584,7 +584,7 @@ void intel_refill_rx ( struct intel_nic *intel ) { assert ( intel->rx.iobuf[rx_idx] == NULL ); /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( intel->dma, INTEL_RX_MAX_LEN, map ); + iobuf = dma_alloc_rx_iob ( intel->dma, map, INTEL_RX_MAX_LEN ); if ( ! iobuf ) { /* Wait for next refill */ break; @@ -630,7 +630,7 @@ void intel_flush ( struct intel_nic *intel ) { /* Discard unused receive buffers */ for ( i = 0 ; i < INTEL_NUM_RX_DESC ; i++ ) { if ( intel->rx.iobuf[i] ) { - dma_unmap ( intel->dma, &intel->rx.map[i] ); + dma_unmap ( &intel->rx.map[i] ); free_iob ( intel->rx.iobuf[i] ); } intel->rx.iobuf[i] = NULL; @@ -639,7 +639,7 @@ void intel_flush ( struct intel_nic *intel ) { /* Unmap incomplete transmit buffers */ for ( i = intel->tx.ring.cons ; i != intel->tx.ring.prod ; i++ ) { tx_idx = ( i % INTEL_NUM_TX_DESC ); - dma_unmap ( intel->dma, &intel->tx.map[tx_idx] ); + dma_unmap ( &intel->tx.map[tx_idx] ); } } @@ -773,7 +773,7 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { map = &intel->tx.map[tx_idx]; /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( intel->dma, iobuf, map ) ) != 0 ) + if ( ( rc = dma_map_tx_iob ( intel->dma, map, iobuf ) ) != 0 ) return rc; /* Update producer index */ @@ -822,7 +822,7 @@ void intel_poll_tx ( struct net_device *netdev ) { DBGC2 ( intel, "INTEL %p TX %d complete\n", intel, tx_idx ); /* Unmap I/O buffer */ - dma_unmap ( intel->dma, &intel->tx.map[tx_idx] ); + dma_unmap ( &intel->tx.map[tx_idx] ); /* Complete TX descriptor */ netdev_tx_complete_next ( netdev ); @@ -854,7 +854,7 @@ void intel_poll_rx ( struct net_device *netdev ) { return; /* Unmap I/O buffer */ - dma_unmap ( intel->dma, &intel->rx.map[rx_idx] ); + dma_unmap ( &intel->rx.map[rx_idx] ); /* Populate I/O buffer */ iobuf = intel->rx.iobuf[rx_idx]; diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c index 0808c784a..5de432a6a 100644 --- a/src/drivers/net/intelxl.c +++ b/src/drivers/net/intelxl.c @@ -136,9 +136,9 @@ int intelxl_msix_enable ( struct intelxl_nic *intelxl, int rc; /* Map dummy target location */ - if ( ( rc = dma_map ( intelxl->dma, virt_to_phys ( &intelxl->msix.msg ), - sizeof ( intelxl->msix.msg ), DMA_RX, - &intelxl->msix.map ) ) != 0 ) { + if ( ( rc = dma_map ( intelxl->dma, &intelxl->msix.map, + virt_to_phys ( &intelxl->msix.msg ), + sizeof ( intelxl->msix.msg ), DMA_RX ) ) != 0 ) { DBGC ( intelxl, "INTELXL %p could not map MSI-X target: %s\n", intelxl, strerror ( rc ) ); goto err_map; @@ -162,7 +162,7 @@ int intelxl_msix_enable ( struct intelxl_nic *intelxl, pci_msix_disable ( pci, &intelxl->msix.cap ); err_enable: - dma_unmap ( intelxl->dma, &intelxl->msix.map ); + dma_unmap ( &intelxl->msix.map ); err_map: return rc; } @@ -183,7 +183,7 @@ void intelxl_msix_disable ( struct intelxl_nic *intelxl, pci_msix_disable ( pci, &intelxl->msix.cap ); /* Unmap dummy target location */ - dma_unmap ( intelxl->dma, &intelxl->msix.map ); + dma_unmap ( &intelxl->msix.map ); } /****************************************************************************** @@ -215,8 +215,8 @@ static int intelxl_alloc_admin ( struct intelxl_nic *intelxl, size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC ); /* Allocate admin queue */ - admin->buf = dma_alloc ( intelxl->dma, ( buf_len + len ), - INTELXL_ALIGN, &admin->map ); + admin->buf = dma_alloc ( intelxl->dma, &admin->map, ( buf_len + len ), + INTELXL_ALIGN ); if ( ! admin->buf ) return -ENOMEM; admin->desc = ( ( ( void * ) admin->buf ) + buf_len ); @@ -291,13 +291,13 @@ static void intelxl_disable_admin ( struct intelxl_nic *intelxl, * @v intelxl Intel device * @v admin Admin queue */ -static void intelxl_free_admin ( struct intelxl_nic *intelxl, +static void intelxl_free_admin ( struct intelxl_nic *intelxl __unused, struct intelxl_admin *admin ) { size_t buf_len = ( sizeof ( admin->buf[0] ) * INTELXL_ADMIN_NUM_DESC ); size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC ); /* Free queue */ - dma_free ( intelxl->dma, admin->buf, ( buf_len + len ), &admin->map ); + dma_free ( &admin->map, admin->buf, ( buf_len + len ) ); } /** @@ -945,8 +945,8 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl, int rc; /* Allocate descriptor ring */ - ring->desc.raw = dma_alloc ( intelxl->dma, ring->len, INTELXL_ALIGN, - &ring->map ); + ring->desc.raw = dma_alloc ( intelxl->dma, &ring->map, ring->len, + INTELXL_ALIGN ); if ( ! ring->desc.raw ) { rc = -ENOMEM; goto err_alloc; @@ -969,7 +969,7 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl, return 0; - dma_free ( intelxl->dma, ring->desc.raw, ring->len, &ring->map ); + dma_free ( &ring->map, ring->desc.raw, ring->len ); err_alloc: return rc; } @@ -980,11 +980,11 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl, * @v intelxl Intel device * @v ring Descriptor ring */ -void intelxl_free_ring ( struct intelxl_nic *intelxl, +void intelxl_free_ring ( struct intelxl_nic *intelxl __unused, struct intelxl_ring *ring ) { /* Free descriptor ring */ - dma_free ( intelxl->dma, ring->desc.raw, ring->len, &ring->map ); + dma_free ( &ring->map, ring->desc.raw, ring->len ); ring->desc.raw = NULL; } @@ -1322,7 +1322,7 @@ static void intelxl_refill_rx ( struct intelxl_nic *intelxl ) { assert ( intelxl->rx.iobuf[rx_idx] == NULL ); /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( intelxl->dma, intelxl->mfs, map ); + iobuf = dma_alloc_rx_iob ( intelxl->dma, map, intelxl->mfs ); if ( ! iobuf ) { /* Wait for next refill */ break; @@ -1365,7 +1365,7 @@ void intelxl_flush ( struct intelxl_nic *intelxl ) { /* Discard any unused receive buffers */ for ( i = 0 ; i < INTELXL_RX_NUM_DESC ; i++ ) { if ( intelxl->rx.iobuf[i] ) { - dma_unmap ( intelxl->dma, &intelxl->rx.map[i] ); + dma_unmap ( &intelxl->rx.map[i] ); free_iob ( intelxl->rx.iobuf[i] ); } intelxl->rx.iobuf[i] = NULL; @@ -1374,7 +1374,7 @@ void intelxl_flush ( struct intelxl_nic *intelxl ) { /* Unmap incomplete transmit buffers */ for ( i = intelxl->tx.ring.cons ; i != intelxl->tx.ring.prod ; i++ ) { tx_idx = ( i % INTELXL_TX_NUM_DESC ); - dma_unmap ( intelxl->dma, &intelxl->tx.map[tx_idx] ); + dma_unmap ( &intelxl->tx.map[tx_idx] ); } } @@ -1516,7 +1516,7 @@ int intelxl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { map = &intelxl->tx.map[tx_idx]; /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( intelxl->dma, iobuf, map ) ) != 0 ) + if ( ( rc = dma_map_tx_iob ( intelxl->dma, map, iobuf ) ) != 0 ) return rc; /* Update producer index */ @@ -1564,7 +1564,7 @@ static void intelxl_poll_tx ( struct net_device *netdev ) { intelxl, tx_idx ); /* Unmap I/O buffer */ - dma_unmap ( intelxl->dma, &intelxl->tx.map[tx_idx] ); + dma_unmap ( &intelxl->tx.map[tx_idx] ); /* Complete TX descriptor */ netdev_tx_complete_next ( netdev ); @@ -1597,7 +1597,7 @@ static void intelxl_poll_rx ( struct net_device *netdev ) { return; /* Unmap I/O buffer */ - dma_unmap ( intelxl->dma, &intelxl->rx.map[rx_idx] ); + dma_unmap ( &intelxl->rx.map[rx_idx] ); /* Populate I/O buffer */ iobuf = intelxl->rx.iobuf[rx_idx]; diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index bca52266f..47d435f72 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -514,7 +514,8 @@ static int realtek_create_buffer ( struct realtek_nic *rtl ) { return 0; /* Allocate buffer */ - rxbuf->data = dma_alloc ( rtl->dma, len, RTL_RXBUF_ALIGN, &rxbuf->map ); + rxbuf->data = dma_alloc ( rtl->dma, &rxbuf->map, len, + RTL_RXBUF_ALIGN ); if ( ! rxbuf->data ) return -ENOMEM; @@ -545,7 +546,7 @@ static void realtek_destroy_buffer ( struct realtek_nic *rtl ) { writel ( 0, rtl->regs + RTL_RBSTART ); /* Free buffer */ - dma_free ( rtl->dma, rxbuf->data, len, &rxbuf->map ); + dma_free ( &rxbuf->map, rxbuf->data, len ); rxbuf->data = NULL; rxbuf->offset = 0; } @@ -566,8 +567,8 @@ static int realtek_create_ring ( struct realtek_nic *rtl, return 0; /* Allocate descriptor ring */ - ring->desc = dma_alloc ( rtl->dma, ring->len, RTL_RING_ALIGN, - &ring->map ); + ring->desc = dma_alloc ( rtl->dma, &ring->map, ring->len, + RTL_RING_ALIGN ); if ( ! ring->desc ) return -ENOMEM; @@ -608,7 +609,7 @@ static void realtek_destroy_ring ( struct realtek_nic *rtl, writel ( 0, rtl->regs + ring->reg + 4 ); /* Free descriptor ring */ - dma_free ( rtl->dma, ring->desc, ring->len, &ring->map ); + dma_free ( &ring->map, ring->desc, ring->len ); ring->desc = NULL; } @@ -638,7 +639,7 @@ static void realtek_refill_rx ( struct realtek_nic *rtl ) { assert ( rtl->rx.iobuf[rx_idx] == NULL ); /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( rtl->dma, RTL_RX_MAX_LEN, map ); + iobuf = dma_alloc_rx_iob ( rtl->dma, map, RTL_RX_MAX_LEN ); if ( ! iobuf ) { /* Wait for next refill */ return; @@ -748,7 +749,7 @@ static void realtek_close ( struct net_device *netdev ) { /* Discard any unused receive buffers */ for ( i = 0 ; i < RTL_NUM_RX_DESC ; i++ ) { if ( rtl->rx.iobuf[i] ) { - dma_unmap ( rtl->dma, &rtl->rx.map[i] ); + dma_unmap ( &rtl->rx.map[i] ); free_iob ( rtl->rx.iobuf[i] ); } rtl->rx.iobuf[i] = NULL; @@ -756,7 +757,7 @@ static void realtek_close ( struct net_device *netdev ) { /* Unmap any incomplete transmit buffers */ for ( i = rtl->tx.ring.cons ; i != rtl->tx.ring.prod ; i++ ) - dma_unmap ( rtl->dma, &rtl->tx.map[ i % RTL_NUM_TX_DESC ] ); + dma_unmap ( &rtl->tx.map[ i % RTL_NUM_TX_DESC ] ); /* Destroy transmit descriptor ring */ realtek_destroy_ring ( rtl, &rtl->tx.ring ); @@ -796,7 +797,7 @@ static int realtek_transmit ( struct net_device *netdev, iob_pad ( iobuf, ETH_ZLEN ); /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( rtl->dma, iobuf, map ) ) != 0 ) + if ( ( rc = dma_map_tx_iob ( rtl->dma, map, iobuf ) ) != 0 ) return rc; address = dma ( map, iobuf->data ); @@ -870,7 +871,7 @@ static void realtek_poll_tx ( struct net_device *netdev ) { DBGC2 ( rtl, "REALTEK %p TX %d complete\n", rtl, tx_idx ); /* Unmap I/O buffer */ - dma_unmap ( rtl->dma, &rtl->tx.map[tx_idx] ); + dma_unmap ( &rtl->tx.map[tx_idx] ); /* Complete TX descriptor */ rtl->tx.ring.cons++; @@ -964,7 +965,7 @@ static void realtek_poll_rx ( struct net_device *netdev ) { return; /* Unmap buffer */ - dma_unmap ( rtl->dma, &rtl->rx.map[rx_idx] ); + dma_unmap ( &rtl->rx.map[rx_idx] ); /* Populate I/O buffer */ iobuf = rtl->rx.iobuf[rx_idx]; diff --git a/src/include/ipxe/dma.h b/src/include/ipxe/dma.h index 0577493c7..842c9d6ef 100644 --- a/src/include/ipxe/dma.h +++ b/src/include/ipxe/dma.h @@ -37,6 +37,8 @@ struct dma_mapping { * device-side DMA address. */ physaddr_t offset; + /** DMA device (if unmapping is required) */ + struct dma_device *dma; /** Platform mapping token */ void *token; }; @@ -59,14 +61,14 @@ struct dma_operations { * Map buffer for DMA * * @v dma DMA device + * @v map DMA mapping to fill in * @v addr Buffer address * @v len Length of buffer * @v flags Mapping flags - * @v map DMA mapping to fill in * @ret rc Return status code */ - int ( * map ) ( struct dma_device *dma, physaddr_t addr, size_t len, - int flags, struct dma_mapping *map ); + int ( * map ) ( struct dma_device *dma, struct dma_mapping *map, + physaddr_t addr, size_t len, int flags ); /** * Unmap buffer * @@ -78,23 +80,23 @@ struct dma_operations { * Allocate and map DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping to fill in * @v len Length of buffer * @v align Physical alignment - * @v map DMA mapping to fill in * @ret addr Buffer address, or NULL on error */ - void * ( * alloc ) ( struct dma_device *dma, size_t len, size_t align, - struct dma_mapping *map ); + void * ( * alloc ) ( struct dma_device *dma, struct dma_mapping *map, + size_t len, size_t align ); /** * Unmap and free DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping * @v addr Buffer address * @v len Length of buffer - * @v map DMA mapping */ - void ( * free ) ( struct dma_device *dma, void *addr, size_t len, - struct dma_mapping *map ); + void ( * free ) ( struct dma_device *dma, struct dma_mapping *map, + void *addr, size_t len ); /** * Set addressable space mask * @@ -146,21 +148,23 @@ struct dma_operations { * Map buffer for DMA * * @v dma DMA device + * @v map DMA mapping to fill in * @v addr Buffer address * @v len Length of buffer * @v flags Mapping flags - * @v map DMA mapping to fill in * @ret rc Return status code */ static inline __always_inline int DMAAPI_INLINE ( flat, dma_map ) ( struct dma_device *dma, + struct dma_mapping *map, physaddr_t addr __unused, - size_t len __unused, int flags __unused, - struct dma_mapping *map __unused ) { + size_t len __unused, int flags __unused ) { /* Increment mapping count (for debugging) */ - if ( DBG_LOG ) + if ( DBG_LOG ) { + map->dma = dma; dma->mapped++; + } return 0; } @@ -168,39 +172,42 @@ DMAAPI_INLINE ( flat, dma_map ) ( struct dma_device *dma, /** * Unmap buffer * - * @v dma DMA device * @v map DMA mapping */ static inline __always_inline void -DMAAPI_INLINE ( flat, dma_unmap ) ( struct dma_device *dma, - struct dma_mapping *map __unused ) { +DMAAPI_INLINE ( flat, dma_unmap ) ( struct dma_mapping *map ) { /* Decrement mapping count (for debugging) */ - if ( DBG_LOG ) - dma->mapped--; + if ( DBG_LOG ) { + assert ( map->dma != NULL ); + map->dma->mapped--; + map->dma = NULL; + } } /** * Allocate and map DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping to fill in * @v len Length of buffer * @v align Physical alignment - * @v map DMA mapping to fill in * @ret addr Buffer address, or NULL on error */ static inline __always_inline void * DMAAPI_INLINE ( flat, dma_alloc ) ( struct dma_device *dma, - size_t len, size_t align, - struct dma_mapping *map __unused ) { + struct dma_mapping *map, + size_t len, size_t align ) { void *addr; /* Allocate buffer */ addr = malloc_phys ( len, align ); - /* Increment allocation count (for debugging) */ - if ( DBG_LOG && addr ) - dma->allocated++; + /* Increment mapping count (for debugging) */ + if ( DBG_LOG && addr ) { + map->dma = dma; + dma->mapped++; + } return addr; } @@ -208,22 +215,23 @@ DMAAPI_INLINE ( flat, dma_alloc ) ( struct dma_device *dma, /** * Unmap and free DMA-coherent buffer * - * @v dma DMA device + * @v map DMA mapping * @v addr Buffer address * @v len Length of buffer - * @v map DMA mapping */ static inline __always_inline void -DMAAPI_INLINE ( flat, dma_free ) ( struct dma_device *dma, - void *addr, size_t len, - struct dma_mapping *map __unused ) { +DMAAPI_INLINE ( flat, dma_free ) ( struct dma_mapping *map, + void *addr, size_t len ) { /* Free buffer */ free_phys ( addr, len ); - /* Decrement allocation count (for debugging) */ - if ( DBG_LOG ) - dma->allocated--; + /* Decrement mapping count (for debugging) */ + if ( DBG_LOG ) { + assert ( map->dma != NULL ); + map->dma->mapped--; + map->dma = NULL; + } } /** @@ -272,45 +280,42 @@ DMAAPI_INLINE ( op, dma_phys ) ( struct dma_mapping *map, physaddr_t addr ) { * Map buffer for DMA * * @v dma DMA device + * @v map DMA mapping to fill in * @v addr Buffer address * @v len Length of buffer * @v flags Mapping flags - * @v map DMA mapping to fill in * @ret rc Return status code */ -int dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, - int flags, struct dma_mapping *map ); +int dma_map ( struct dma_device *dma, struct dma_mapping *map, + physaddr_t addr, size_t len, int flags ); /** * Unmap buffer * - * @v dma DMA device * @v map DMA mapping */ -void dma_unmap ( struct dma_device *dma, struct dma_mapping *map ); +void dma_unmap ( struct dma_mapping *map ); /** * Allocate and map DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping to fill in * @v len Length of buffer * @v align Physical alignment - * @v map DMA mapping to fill in * @ret addr Buffer address, or NULL on error */ -void * dma_alloc ( struct dma_device *dma, size_t len, size_t align, - struct dma_mapping *map ); +void * dma_alloc ( struct dma_device *dma, struct dma_mapping *map, + size_t len, size_t align ); /** * Unmap and free DMA-coherent buffer * - * @v dma DMA device + * @v map DMA mapping * @v addr Buffer address * @v len Length of buffer - * @v map DMA mapping */ -void dma_free ( struct dma_device *dma, void *addr, size_t len, - struct dma_mapping *map ); +void dma_free ( struct dma_mapping *map, void *addr, size_t len ); /** * Set addressable space mask @@ -339,9 +344,22 @@ physaddr_t dma_phys ( struct dma_mapping *map, physaddr_t addr ); static inline __always_inline physaddr_t dma ( struct dma_mapping *map, void *addr ) { + /* Get DMA address from corresponding physical address */ return dma_phys ( map, virt_to_phys ( addr ) ); } +/** + * Check if DMA unmapping is required + * + * @v map DMA mapping + * @v unmap Unmapping is required + */ +static inline __always_inline int dma_mapped ( struct dma_mapping *map ) { + + /* Unmapping is required if a DMA device was recorded */ + return ( map->dma != NULL ); +} + /** * Initialise DMA device * @@ -371,20 +389,21 @@ dma_set_mask_64bit ( struct dma_device *dma ) { * Map I/O buffer for transmitting data to device * * @v dma DMA device - * @v iobuf I/O buffer * @v map DMA mapping to fill in + * @v iobuf I/O buffer * @ret rc Return status code */ static inline __always_inline int -dma_map_tx_iob ( struct dma_device *dma, struct io_buffer *iobuf, - struct dma_mapping *map ) { +dma_map_tx_iob ( struct dma_device *dma, struct dma_mapping *map, + struct io_buffer *iobuf ) { /* Map I/O buffer */ - return dma_map ( dma, virt_to_phys ( iobuf->data ), iob_len ( iobuf ), - DMA_TX, map ); + return dma_map ( dma, map, virt_to_phys ( iobuf->data ), + iob_len ( iobuf ), DMA_TX ); } -extern struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, size_t len, - struct dma_mapping *map ); +extern struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, + struct dma_mapping *map, + size_t len ); #endif /* _IPXE_DMA_H */ diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index e33a8980d..7687ffb43 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -315,14 +315,14 @@ PROVIDE_PCIAPI ( efi, pci_ioremap, efipci_ioremap ); * Map buffer for DMA * * @v dma DMA device + * @v map DMA mapping to fill in * @v addr Buffer address * @v len Length of buffer * @v flags Mapping flags - * @v map DMA mapping to fill in * @ret rc Return status code */ -static int efipci_dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, - int flags, struct dma_mapping *map ) { +static int efipci_dma_map ( struct dma_device *dma, struct dma_mapping *map, + physaddr_t addr, size_t len, int flags ) { struct efi_pci_device *efipci = container_of ( dma, struct efi_pci_device, pci.dma ); struct pci_device *pci = &efipci->pci; @@ -374,6 +374,7 @@ static int efipci_dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, } /* Populate mapping */ + map->dma = dma; map->offset = ( bus - addr ); map->token = mapping; @@ -420,14 +421,14 @@ static void efipci_dma_unmap ( struct dma_device *dma, * Allocate and map DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping to fill in * @v len Length of buffer * @v align Physical alignment - * @v map DMA mapping to fill in * @ret addr Buffer address, or NULL on error */ -static void * efipci_dma_alloc ( struct dma_device *dma, size_t len, - size_t align __unused, - struct dma_mapping *map ) { +static void * efipci_dma_alloc ( struct dma_device *dma, + struct dma_mapping *map, + size_t len, size_t align __unused ) { struct efi_pci_device *efipci = container_of ( dma, struct efi_pci_device, pci.dma ); struct pci_device *pci = &efipci->pci; @@ -451,8 +452,8 @@ static void * efipci_dma_alloc ( struct dma_device *dma, size_t len, } /* Map buffer */ - if ( ( rc = efipci_dma_map ( dma, virt_to_phys ( addr ), len, DMA_BI, - map ) ) != 0 ) + if ( ( rc = efipci_dma_map ( dma, map, virt_to_phys ( addr ), + len, DMA_BI ) ) != 0 ) goto err_map; /* Increment allocation count (for debugging) */ @@ -472,12 +473,12 @@ static void * efipci_dma_alloc ( struct dma_device *dma, size_t len, * Unmap and free DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping * @v addr Buffer address * @v len Length of buffer - * @v map DMA mapping */ -static void efipci_dma_free ( struct dma_device *dma, void *addr, size_t len, - struct dma_mapping *map ) { +static void efipci_dma_free ( struct dma_device *dma, struct dma_mapping *map, + void *addr, size_t len ) { struct efi_pci_device *efipci = container_of ( dma, struct efi_pci_device, pci.dma ); EFI_PCI_IO_PROTOCOL *pci_io = efipci->io; -- cgit v1.2.3-55-g7522 From 8d337ecdae3c6d555ea57996bc2280debd984a9c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 26 Nov 2020 12:25:02 +0000 Subject: [dma] Move I/O buffer DMA operations to iobuf.h Include a potential DMA mapping within the definition of an I/O buffer, and move all I/O buffer DMA mapping functions from dma.h to iobuf.h. This avoids the need for drivers to maintain a separate list of DMA mappings for each I/O buffer that they may handle. Network device drivers typically do not keep track of transmit I/O buffers, since the network device core already maintains a transmit queue. Drivers will typically call netdev_tx_complete_next() to complete a transmission without first obtaining the relevant I/O buffer pointer (and will rely on the network device core automatically cancelling any pending transmissions when the device is closed). To allow this driver design approach to be retained, update the netdev_tx_complete() family of functions to automatically perform the DMA unmapping operation if required. For symmetry, also update the netdev_rx() family of functions to behave the same way. As a further convenience for drivers, allow the network device core to automatically perform DMA mapping on the transmit datapath before calling the driver's transmit() method. This avoids the need to introduce a mapping error handling code path into the typically error-free transmit methods. With these changes, the modifications required to update a typical network device driver to use the new DMA API are fairly minimal: - Allocate and free descriptor rings and similar coherent structures using dma_alloc()/dma_free() rather than malloc_phys()/free_phys() - Allocate and free receive buffers using alloc_rx_iob()/free_rx_iob() rather than alloc_iob()/free_iob() - Calculate DMA addresses using dma() or iob_dma() rather than virt_to_bus() - Set a 64-bit DMA mask if needed using dma_set_mask_64bit() and thereafter eliminate checks on DMA address ranges - Either record the DMA device in netdev->dma, or call iob_map_tx() as part of the transmit() method - Ensure that debug messages use virt_to_phys() when displaying "hardware" addresses Signed-off-by: Michael Brown --- src/core/dma.c | 41 ------------- src/core/iobuf.c | 45 +++++++++++++++ src/drivers/net/intel.c | 120 ++++++++++++++------------------------ src/drivers/net/intel.h | 46 +++++---------- src/drivers/net/intelx.c | 21 +++---- src/drivers/net/intelxl.c | 134 ++++++++++++++++--------------------------- src/drivers/net/intelxl.h | 30 +++------- src/drivers/net/intelxlvf.c | 33 +++++------ src/drivers/net/intelxvf.c | 21 +++---- src/drivers/net/realtek.c | 101 ++++++++++++++------------------ src/drivers/net/realtek.h | 24 ++------ src/include/ipxe/dma.h | 22 ------- src/include/ipxe/iobuf.h | 55 ++++++++++++++++++ src/include/ipxe/netdevice.h | 6 ++ src/interface/efi/efi_pci.c | 2 + src/net/netdevice.c | 32 +++++++++++ 16 files changed, 342 insertions(+), 391 deletions(-) (limited to 'src/drivers') diff --git a/src/core/dma.c b/src/core/dma.c index 561aec1e1..e5fa3f323 100644 --- a/src/core/dma.c +++ b/src/core/dma.c @@ -25,7 +25,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -#include #include /** @file @@ -139,43 +138,3 @@ PROVIDE_DMAAPI ( op, dma_alloc, dma_op_alloc ); PROVIDE_DMAAPI ( op, dma_free, dma_op_free ); PROVIDE_DMAAPI ( op, dma_set_mask, dma_op_set_mask ); PROVIDE_DMAAPI_INLINE ( op, dma_phys ); - -/****************************************************************************** - * - * Utility functions - * - ****************************************************************************** - */ - -/** - * Allocate and map I/O buffer for receiving data from device - * - * @v dma DMA device - * @v map DMA mapping to fill in - * @v len Length of I/O buffer - * @ret iobuf I/O buffer, or NULL on error - */ -struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, - struct dma_mapping *map, - size_t len ) { - struct io_buffer *iobuf; - int rc; - - /* Allocate I/O buffer */ - iobuf = alloc_iob ( len ); - if ( ! iobuf ) - goto err_alloc; - - /* Map I/O buffer */ - if ( ( rc = dma_map ( dma, map, virt_to_phys ( iobuf->data ), - len, DMA_RX ) ) != 0 ) - goto err_map; - - return iobuf; - - dma_unmap ( map ); - err_map: - free_iob ( iobuf ); - err_alloc: - return NULL; -} diff --git a/src/core/iobuf.c b/src/core/iobuf.c index 941bb3446..c9970bc76 100644 --- a/src/core/iobuf.c +++ b/src/core/iobuf.c @@ -110,6 +110,7 @@ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { } /* Populate descriptor */ + memset ( &iobuf->map, 0, sizeof ( iobuf->map ) ); iobuf->head = iobuf->data = iobuf->tail = data; iobuf->end = ( data + len ); @@ -153,6 +154,7 @@ void free_iob ( struct io_buffer *iobuf ) { assert ( iobuf->head <= iobuf->data ); assert ( iobuf->data <= iobuf->tail ); assert ( iobuf->tail <= iobuf->end ); + assert ( ! dma_mapped ( &iobuf->map ) ); /* Free buffer */ len = ( iobuf->end - iobuf->head ); @@ -169,6 +171,49 @@ void free_iob ( struct io_buffer *iobuf ) { } } +/** + * Allocate and map I/O buffer for receive DMA + * + * @v len Length of I/O buffer + * @v dma DMA device + * @ret iobuf I/O buffer, or NULL on error + */ +struct io_buffer * alloc_rx_iob ( size_t len, struct dma_device *dma ) { + struct io_buffer *iobuf; + int rc; + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( len ); + if ( ! iobuf ) + goto err_alloc; + + /* Map I/O buffer */ + if ( ( rc = iob_map_rx ( iobuf, dma ) ) != 0 ) + goto err_map; + + return iobuf; + + iob_unmap ( iobuf ); + err_map: + free_iob ( iobuf ); + err_alloc: + return NULL; +} + +/** + * Unmap and free I/O buffer for receive DMA + * + * @v iobuf I/O buffer + */ +void free_rx_iob ( struct io_buffer *iobuf ) { + + /* Unmap I/O buffer */ + iob_unmap ( iobuf ); + + /* Free I/O buffer */ + free_iob ( iobuf ); +} + /** * Ensure I/O buffer has sufficient headroom * diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c index 93c5fd1f6..83492961f 100644 --- a/src/drivers/net/intel.c +++ b/src/drivers/net/intel.c @@ -568,34 +568,30 @@ void intel_destroy_ring ( struct intel_nic *intel, struct intel_ring *ring ) { void intel_refill_rx ( struct intel_nic *intel ) { struct intel_descriptor *rx; struct io_buffer *iobuf; - struct dma_mapping *map; unsigned int rx_idx; unsigned int rx_tail; unsigned int refilled = 0; /* Refill ring */ - while ( ( intel->rx.ring.prod - - intel->rx.ring.cons ) < INTEL_RX_FILL ) { - - /* Get next receive descriptor */ - rx_idx = ( intel->rx.ring.prod % INTEL_NUM_RX_DESC ); - rx = &intel->rx.ring.desc[rx_idx]; - map = &intel->rx.map[rx_idx]; - assert ( intel->rx.iobuf[rx_idx] == NULL ); + while ( ( intel->rx.prod - intel->rx.cons ) < INTEL_RX_FILL ) { /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( intel->dma, map, INTEL_RX_MAX_LEN ); + iobuf = alloc_rx_iob ( INTEL_RX_MAX_LEN, intel->dma ); if ( ! iobuf ) { /* Wait for next refill */ break; } - intel->rx.iobuf[rx_idx] = iobuf; - /* Update producer index */ - intel->rx.ring.prod++; + /* Get next receive descriptor */ + rx_idx = ( intel->rx.prod++ % INTEL_NUM_RX_DESC ); + rx = &intel->rx.desc[rx_idx]; /* Populate receive descriptor */ - intel->rx.ring.describe ( rx, dma ( map, iobuf->data ), 0 ); + intel->rx.describe ( rx, iob_dma ( iobuf ), 0 ); + + /* Record I/O buffer */ + assert ( intel->rx_iobuf[rx_idx] == NULL ); + intel->rx_iobuf[rx_idx] = iobuf; DBGC2 ( intel, "INTEL %p RX %d is [%lx,%lx)\n", intel, rx_idx, virt_to_phys ( iobuf->data ), @@ -606,40 +602,27 @@ void intel_refill_rx ( struct intel_nic *intel ) { /* Push descriptors to card, if applicable */ if ( refilled ) { wmb(); - rx_tail = ( intel->rx.ring.prod % INTEL_NUM_RX_DESC ); + rx_tail = ( intel->rx.prod % INTEL_NUM_RX_DESC ); profile_start ( &intel_vm_refill_profiler ); - writel ( rx_tail, - intel->regs + intel->rx.ring.reg + INTEL_xDT ); + writel ( rx_tail, intel->regs + intel->rx.reg + INTEL_xDT ); profile_stop ( &intel_vm_refill_profiler ); profile_exclude ( &intel_vm_refill_profiler ); } } /** - * Flush unused I/O buffers + * Discard unused receive I/O buffers * * @v intel Intel device - * - * Discard any unused receive I/O buffers and unmap any incomplete - * transmit I/O buffers. */ -void intel_flush ( struct intel_nic *intel ) { +void intel_empty_rx ( struct intel_nic *intel ) { unsigned int i; - unsigned int tx_idx; /* Discard unused receive buffers */ for ( i = 0 ; i < INTEL_NUM_RX_DESC ; i++ ) { - if ( intel->rx.iobuf[i] ) { - dma_unmap ( &intel->rx.map[i] ); - free_iob ( intel->rx.iobuf[i] ); - } - intel->rx.iobuf[i] = NULL; - } - - /* Unmap incomplete transmit buffers */ - for ( i = intel->tx.ring.cons ; i != intel->tx.ring.prod ; i++ ) { - tx_idx = ( i % INTEL_NUM_TX_DESC ); - dma_unmap ( &intel->tx.map[tx_idx] ); + if ( intel->rx_iobuf[i] ) + free_rx_iob ( intel->rx_iobuf[i] ); + intel->rx_iobuf[i] = NULL; } } @@ -670,11 +653,11 @@ static int intel_open ( struct net_device *netdev ) { } /* Create transmit descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->tx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 ) goto err_create_tx; /* Create receive descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->rx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 ) goto err_create_rx; /* Program MAC address */ @@ -713,9 +696,9 @@ static int intel_open ( struct net_device *netdev ) { return 0; - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); err_create_rx: - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); err_create_tx: return rc; } @@ -735,13 +718,13 @@ static void intel_close ( struct net_device *netdev ) { writel ( 0, intel->regs + INTEL_TCTL ); /* Destroy receive descriptor ring */ - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); - /* Flush unused buffers */ - intel_flush ( intel ); + /* Discard any unused receive buffers */ + intel_empty_rx ( intel ); /* Destroy transmit descriptor ring */ - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); /* Reset the NIC, to flush the transmit and receive FIFOs */ intel_reset ( intel ); @@ -757,37 +740,27 @@ static void intel_close ( struct net_device *netdev ) { int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct intel_nic *intel = netdev->priv; struct intel_descriptor *tx; - struct dma_mapping *map; unsigned int tx_idx; unsigned int tx_tail; size_t len; - int rc; /* Get next transmit descriptor */ - if ( ( intel->tx.ring.prod - intel->tx.ring.cons ) >= INTEL_TX_FILL ) { + if ( ( intel->tx.prod - intel->tx.cons ) >= INTEL_TX_FILL ) { DBGC ( intel, "INTEL %p out of transmit descriptors\n", intel ); return -ENOBUFS; } - tx_idx = ( intel->tx.ring.prod % INTEL_NUM_TX_DESC ); - tx = &intel->tx.ring.desc[tx_idx]; - map = &intel->tx.map[tx_idx]; - - /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( intel->dma, map, iobuf ) ) != 0 ) - return rc; - - /* Update producer index */ - intel->tx.ring.prod++; + tx_idx = ( intel->tx.prod++ % INTEL_NUM_TX_DESC ); + tx_tail = ( intel->tx.prod % INTEL_NUM_TX_DESC ); + tx = &intel->tx.desc[tx_idx]; /* Populate transmit descriptor */ len = iob_len ( iobuf ); - intel->tx.ring.describe ( tx, dma ( map, iobuf->data ), len ); + intel->tx.describe ( tx, iob_dma ( iobuf ), len ); wmb(); /* Notify card that there are packets ready to transmit */ profile_start ( &intel_vm_tx_profiler ); - tx_tail = ( intel->tx.ring.prod % INTEL_NUM_TX_DESC ); - writel ( tx_tail, intel->regs + intel->tx.ring.reg + INTEL_xDT ); + writel ( tx_tail, intel->regs + intel->tx.reg + INTEL_xDT ); profile_stop ( &intel_vm_tx_profiler ); profile_exclude ( &intel_vm_tx_profiler ); @@ -809,11 +782,11 @@ void intel_poll_tx ( struct net_device *netdev ) { unsigned int tx_idx; /* Check for completed packets */ - while ( intel->tx.ring.cons != intel->tx.ring.prod ) { + while ( intel->tx.cons != intel->tx.prod ) { /* Get next transmit descriptor */ - tx_idx = ( intel->tx.ring.cons % INTEL_NUM_TX_DESC ); - tx = &intel->tx.ring.desc[tx_idx]; + tx_idx = ( intel->tx.cons % INTEL_NUM_TX_DESC ); + tx = &intel->tx.desc[tx_idx]; /* Stop if descriptor is still in use */ if ( ! ( tx->status & cpu_to_le32 ( INTEL_DESC_STATUS_DD ) ) ) @@ -821,12 +794,9 @@ void intel_poll_tx ( struct net_device *netdev ) { DBGC2 ( intel, "INTEL %p TX %d complete\n", intel, tx_idx ); - /* Unmap I/O buffer */ - dma_unmap ( &intel->tx.map[tx_idx] ); - /* Complete TX descriptor */ netdev_tx_complete_next ( netdev ); - intel->tx.ring.cons++; + intel->tx.cons++; } } @@ -843,22 +813,19 @@ void intel_poll_rx ( struct net_device *netdev ) { size_t len; /* Check for received packets */ - while ( intel->rx.ring.cons != intel->rx.ring.prod ) { + while ( intel->rx.cons != intel->rx.prod ) { /* Get next receive descriptor */ - rx_idx = ( intel->rx.ring.cons % INTEL_NUM_RX_DESC ); - rx = &intel->rx.ring.desc[rx_idx]; + rx_idx = ( intel->rx.cons % INTEL_NUM_RX_DESC ); + rx = &intel->rx.desc[rx_idx]; /* Stop if descriptor is still in use */ if ( ! ( rx->status & cpu_to_le32 ( INTEL_DESC_STATUS_DD ) ) ) return; - /* Unmap I/O buffer */ - dma_unmap ( &intel->rx.map[rx_idx] ); - /* Populate I/O buffer */ - iobuf = intel->rx.iobuf[rx_idx]; - intel->rx.iobuf[rx_idx] = NULL; + iobuf = intel->rx_iobuf[rx_idx]; + intel->rx_iobuf[rx_idx] = NULL; len = le16_to_cpu ( rx->length ); iob_put ( iobuf, len ); @@ -873,7 +840,7 @@ void intel_poll_rx ( struct net_device *netdev ) { intel, rx_idx, len ); netdev_rx ( netdev, iobuf ); } - intel->rx.ring.cons++; + intel->rx.cons++; } } @@ -981,9 +948,9 @@ static int intel_probe ( struct pci_device *pci ) { memset ( intel, 0, sizeof ( *intel ) ); intel->port = PCI_FUNC ( pci->busdevfn ); intel->flags = pci->id->driver_data; - intel_init_ring ( &intel->tx.ring, INTEL_NUM_TX_DESC, INTEL_TD, + intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTEL_TD, intel_describe_tx ); - intel_init_ring ( &intel->rx.ring, INTEL_NUM_RX_DESC, INTEL_RD, + intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTEL_RD, intel_describe_rx ); /* Fix up PCI device */ @@ -999,6 +966,7 @@ static int intel_probe ( struct pci_device *pci ) { /* Configure DMA */ intel->dma = &pci->dma; dma_set_mask_64bit ( intel->dma ); + netdev->dma = intel->dma; /* Reset the NIC */ if ( ( rc = intel_reset ( intel ) ) != 0 ) diff --git a/src/drivers/net/intel.h b/src/drivers/net/intel.h index 731b5f225..4f51a80f6 100644 --- a/src/drivers/net/intel.h +++ b/src/drivers/net/intel.h @@ -276,24 +276,6 @@ intel_init_mbox ( struct intel_mailbox *mbox, unsigned int ctrl, mbox->mem = mem; } -/** Transmit ring */ -struct intel_tx_ring { - /** Descriptor ring */ - struct intel_ring ring; - /** DMA mappings */ - struct dma_mapping map[INTEL_NUM_TX_DESC]; -}; - -/** Receive ring */ -struct intel_rx_ring { - /** Descriptor ring */ - struct intel_ring ring; - /** I/O buffers */ - struct io_buffer *iobuf[INTEL_NUM_RX_DESC]; - /** DMA mappings */ - struct dma_mapping map[INTEL_NUM_RX_DESC]; -}; - /** An Intel network card */ struct intel_nic { /** Registers */ @@ -317,10 +299,12 @@ struct intel_nic { /** Mailbox */ struct intel_mailbox mbox; - /** Transmit ring */ - struct intel_tx_ring tx; - /** Receive ring */ - struct intel_rx_ring rx; + /** Transmit descriptor ring */ + struct intel_ring tx; + /** Receive descriptor ring */ + struct intel_ring rx; + /** Receive I/O buffers */ + struct io_buffer *rx_iobuf[INTEL_NUM_RX_DESC]; }; /** Driver flags */ @@ -349,14 +333,14 @@ static inline void intel_diag ( struct intel_nic *intel ) { DBGC ( intel, "INTEL %p TX %04x(%02x)/%04x(%02x) " "RX %04x(%02x)/%04x(%02x)\n", intel, - ( intel->tx.ring.cons & 0xffff ), - readl ( intel->regs + intel->tx.ring.reg + INTEL_xDH ), - ( intel->tx.ring.prod & 0xffff ), - readl ( intel->regs + intel->tx.ring.reg + INTEL_xDT ), - ( intel->rx.ring.cons & 0xffff ), - readl ( intel->regs + intel->rx.ring.reg + INTEL_xDH ), - ( intel->rx.ring.prod & 0xffff ), - readl ( intel->regs + intel->rx.ring.reg + INTEL_xDT ) ); + ( intel->tx.cons & 0xffff ), + readl ( intel->regs + intel->tx.reg + INTEL_xDH ), + ( intel->tx.prod & 0xffff ), + readl ( intel->regs + intel->tx.reg + INTEL_xDT ), + ( intel->rx.cons & 0xffff ), + readl ( intel->regs + intel->rx.reg + INTEL_xDH ), + ( intel->rx.prod & 0xffff ), + readl ( intel->regs + intel->rx.reg + INTEL_xDT ) ); } extern void intel_describe_tx ( struct intel_descriptor *tx, @@ -371,7 +355,7 @@ extern int intel_create_ring ( struct intel_nic *intel, extern void intel_destroy_ring ( struct intel_nic *intel, struct intel_ring *ring ); extern void intel_refill_rx ( struct intel_nic *intel ); -extern void intel_flush ( struct intel_nic *intel ); +extern void intel_empty_rx ( struct intel_nic *intel ); extern int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ); extern void intel_poll_tx ( struct net_device *netdev ); diff --git a/src/drivers/net/intelx.c b/src/drivers/net/intelx.c index 364ec76c5..ccf6b0648 100644 --- a/src/drivers/net/intelx.c +++ b/src/drivers/net/intelx.c @@ -185,11 +185,11 @@ static int intelx_open ( struct net_device *netdev ) { int rc; /* Create transmit descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->tx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 ) goto err_create_tx; /* Create receive descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->rx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 ) goto err_create_rx; /* Program MAC address */ @@ -263,9 +263,9 @@ static int intelx_open ( struct net_device *netdev ) { return 0; - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); err_create_rx: - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); err_create_tx: return rc; } @@ -291,13 +291,13 @@ static void intelx_close ( struct net_device *netdev ) { writel ( dmatxctl, intel->regs + INTELX_DMATXCTL ); /* Destroy receive descriptor ring */ - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); - /* Flush unused buffers */ - intel_flush ( intel ); + /* Discard any unused receive buffers */ + intel_empty_rx ( intel ); /* Destroy transmit descriptor ring */ - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); /* Reset the NIC, to flush the transmit and receive FIFOs */ intelx_reset ( intel ); @@ -395,9 +395,9 @@ static int intelx_probe ( struct pci_device *pci ) { netdev->dev = &pci->dev; memset ( intel, 0, sizeof ( *intel ) ); intel->port = PCI_FUNC ( pci->busdevfn ); - intel_init_ring ( &intel->tx.ring, INTEL_NUM_TX_DESC, INTELX_TD, + intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTELX_TD, intel_describe_tx ); - intel_init_ring ( &intel->rx.ring, INTEL_NUM_RX_DESC, INTELX_RD, + intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTELX_RD, intel_describe_rx ); /* Fix up PCI device */ @@ -413,6 +413,7 @@ static int intelx_probe ( struct pci_device *pci ) { /* Configure DMA */ intel->dma = &pci->dma; dma_set_mask_64bit ( intel->dma ); + netdev->dma = intel->dma; /* Reset the NIC */ if ( ( rc = intelx_reset ( intel ) ) != 0 ) diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c index 5de432a6a..ac9e37c5a 100644 --- a/src/drivers/net/intelxl.c +++ b/src/drivers/net/intelxl.c @@ -1306,36 +1306,32 @@ static void intelxl_destroy_ring ( struct intelxl_nic *intelxl, static void intelxl_refill_rx ( struct intelxl_nic *intelxl ) { struct intelxl_rx_data_descriptor *rx; struct io_buffer *iobuf; - struct dma_mapping *map; unsigned int rx_idx; unsigned int rx_tail; unsigned int refilled = 0; /* Refill ring */ - while ( ( intelxl->rx.ring.prod - - intelxl->rx.ring.cons ) < INTELXL_RX_FILL ) { - - /* Get next receive descriptor */ - rx_idx = ( intelxl->rx.ring.prod % INTELXL_RX_NUM_DESC ); - rx = &intelxl->rx.ring.desc.rx[rx_idx].data; - map = &intelxl->rx.map[rx_idx]; - assert ( intelxl->rx.iobuf[rx_idx] == NULL ); + while ( ( intelxl->rx.prod - intelxl->rx.cons ) < INTELXL_RX_FILL ) { /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( intelxl->dma, map, intelxl->mfs ); + iobuf = alloc_rx_iob ( intelxl->mfs, intelxl->dma ); if ( ! iobuf ) { /* Wait for next refill */ break; } - intelxl->rx.iobuf[rx_idx] = iobuf; - /* Update producer index */ - intelxl->rx.ring.prod++; + /* Get next receive descriptor */ + rx_idx = ( intelxl->rx.prod++ % INTELXL_RX_NUM_DESC ); + rx = &intelxl->rx.desc.rx[rx_idx].data; /* Populate receive descriptor */ - rx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); + rx->address = cpu_to_le64 ( iob_dma ( iobuf ) ); rx->flags = 0; + /* Record I/O buffer */ + assert ( intelxl->rx_iobuf[rx_idx] == NULL ); + intelxl->rx_iobuf[rx_idx] = iobuf; + DBGC2 ( intelxl, "INTELXL %p RX %d is [%08lx,%08lx)\n", intelxl, rx_idx, virt_to_phys ( iobuf->data ), ( virt_to_phys ( iobuf->data ) + intelxl->mfs ) ); @@ -1345,36 +1341,24 @@ static void intelxl_refill_rx ( struct intelxl_nic *intelxl ) { /* Push descriptors to card, if applicable */ if ( refilled ) { wmb(); - rx_tail = ( intelxl->rx.ring.prod % INTELXL_RX_NUM_DESC ); - writel ( rx_tail, ( intelxl->regs + intelxl->rx.ring.tail ) ); + rx_tail = ( intelxl->rx.prod % INTELXL_RX_NUM_DESC ); + writel ( rx_tail, ( intelxl->regs + intelxl->rx.tail ) ); } } /** - * Flush unused I/O buffers + * Discard unused receive I/O buffers * * @v intelxl Intel device - * - * Discard any unused receive I/O buffers and unmap any incomplete - * transmit I/O buffers. */ -void intelxl_flush ( struct intelxl_nic *intelxl ) { +void intelxl_empty_rx ( struct intelxl_nic *intelxl ) { unsigned int i; - unsigned int tx_idx; /* Discard any unused receive buffers */ for ( i = 0 ; i < INTELXL_RX_NUM_DESC ; i++ ) { - if ( intelxl->rx.iobuf[i] ) { - dma_unmap ( &intelxl->rx.map[i] ); - free_iob ( intelxl->rx.iobuf[i] ); - } - intelxl->rx.iobuf[i] = NULL; - } - - /* Unmap incomplete transmit buffers */ - for ( i = intelxl->tx.ring.cons ; i != intelxl->tx.ring.prod ; i++ ) { - tx_idx = ( i % INTELXL_TX_NUM_DESC ); - dma_unmap ( &intelxl->tx.map[tx_idx] ); + if ( intelxl->rx_iobuf[i] ) + free_rx_iob ( intelxl->rx_iobuf[i] ); + intelxl->rx_iobuf[i] = NULL; } } @@ -1415,7 +1399,7 @@ static int intelxl_open ( struct net_device *netdev ) { /* Associate transmit queue to PF */ writel ( ( INTELXL_QXX_CTL_PFVF_Q_PF | INTELXL_QXX_CTL_PFVF_PF_INDX ( intelxl->pf ) ), - ( intelxl->regs + intelxl->tx.ring.reg + INTELXL_QXX_CTL ) ); + ( intelxl->regs + intelxl->tx.reg + INTELXL_QXX_CTL ) ); /* Clear transmit pre queue disable */ queue = ( intelxl->base + intelxl->queue ); @@ -1427,11 +1411,11 @@ static int intelxl_open ( struct net_device *netdev ) { writel ( 0, ( intelxl->regs + INTELXL_QTX_HEAD ( intelxl->queue ) ) ); /* Create receive descriptor ring */ - if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->rx.ring ) ) != 0 ) + if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->rx ) ) != 0 ) goto err_create_rx; /* Create transmit descriptor ring */ - if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->tx.ring ) ) != 0 ) + if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->tx ) ) != 0 ) goto err_create_tx; /* Fill receive ring */ @@ -1449,9 +1433,9 @@ static int intelxl_open ( struct net_device *netdev ) { INTELXL_GLLAN_TXPRE_QDIS_QINDX ( queue ) ), ( intelxl->regs + INTELXL_GLLAN_TXPRE_QDIS ( queue ) ) ); udelay ( INTELXL_QUEUE_PRE_DISABLE_DELAY_US ); - intelxl_destroy_ring ( intelxl, &intelxl->tx.ring ); + intelxl_destroy_ring ( intelxl, &intelxl->tx ); err_create_tx: - intelxl_destroy_ring ( intelxl, &intelxl->rx.ring ); + intelxl_destroy_ring ( intelxl, &intelxl->rx ); err_create_rx: return rc; } @@ -1479,13 +1463,13 @@ static void intelxl_close ( struct net_device *netdev ) { udelay ( INTELXL_QUEUE_PRE_DISABLE_DELAY_US ); /* Destroy transmit descriptor ring */ - intelxl_destroy_ring ( intelxl, &intelxl->tx.ring ); + intelxl_destroy_ring ( intelxl, &intelxl->tx ); /* Destroy receive descriptor ring */ - intelxl_destroy_ring ( intelxl, &intelxl->rx.ring ); + intelxl_destroy_ring ( intelxl, &intelxl->rx ); - /* Flush unused buffers */ - intelxl_flush ( intelxl ); + /* Discard any unused receive buffers */ + intelxl_empty_rx ( intelxl ); } /** @@ -1498,41 +1482,30 @@ static void intelxl_close ( struct net_device *netdev ) { int intelxl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct intelxl_nic *intelxl = netdev->priv; struct intelxl_tx_data_descriptor *tx; - struct dma_mapping *map; unsigned int tx_idx; unsigned int tx_tail; size_t len; - int rc; /* Get next transmit descriptor */ - if ( ( intelxl->tx.ring.prod - - intelxl->tx.ring.cons ) >= INTELXL_TX_FILL ) { + if ( ( intelxl->tx.prod - intelxl->tx.cons ) >= INTELXL_TX_FILL ) { DBGC ( intelxl, "INTELXL %p out of transmit descriptors\n", intelxl ); return -ENOBUFS; } - tx_idx = ( intelxl->tx.ring.prod % INTELXL_TX_NUM_DESC ); - tx = &intelxl->tx.ring.desc.tx[tx_idx].data; - map = &intelxl->tx.map[tx_idx]; - - /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( intelxl->dma, map, iobuf ) ) != 0 ) - return rc; - - /* Update producer index */ - intelxl->tx.ring.prod++; + tx_idx = ( intelxl->tx.prod++ % INTELXL_TX_NUM_DESC ); + tx_tail = ( intelxl->tx.prod % INTELXL_TX_NUM_DESC ); + tx = &intelxl->tx.desc.tx[tx_idx].data; /* Populate transmit descriptor */ len = iob_len ( iobuf ); - tx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); + tx->address = cpu_to_le64 ( iob_dma ( iobuf ) ); tx->len = cpu_to_le32 ( INTELXL_TX_DATA_LEN ( len ) ); tx->flags = cpu_to_le32 ( INTELXL_TX_DATA_DTYP | INTELXL_TX_DATA_EOP | INTELXL_TX_DATA_RS | INTELXL_TX_DATA_JFDI ); wmb(); /* Notify card that there are packets ready to transmit */ - tx_tail = ( intelxl->tx.ring.prod % INTELXL_TX_NUM_DESC ); - writel ( tx_tail, ( intelxl->regs + intelxl->tx.ring.tail ) ); + writel ( tx_tail, ( intelxl->regs + intelxl->tx.tail ) ); DBGC2 ( intelxl, "INTELXL %p TX %d is [%08lx,%08lx)\n", intelxl, tx_idx, virt_to_phys ( iobuf->data ), @@ -1551,11 +1524,11 @@ static void intelxl_poll_tx ( struct net_device *netdev ) { unsigned int tx_idx; /* Check for completed packets */ - while ( intelxl->tx.ring.cons != intelxl->tx.ring.prod ) { + while ( intelxl->tx.cons != intelxl->tx.prod ) { /* Get next transmit descriptor */ - tx_idx = ( intelxl->tx.ring.cons % INTELXL_TX_NUM_DESC ); - tx_wb = &intelxl->tx.ring.desc.tx[tx_idx].wb; + tx_idx = ( intelxl->tx.cons % INTELXL_TX_NUM_DESC ); + tx_wb = &intelxl->tx.desc.tx[tx_idx].wb; /* Stop if descriptor is still in use */ if ( ! ( tx_wb->flags & INTELXL_TX_WB_FL_DD ) ) @@ -1563,12 +1536,9 @@ static void intelxl_poll_tx ( struct net_device *netdev ) { DBGC2 ( intelxl, "INTELXL %p TX %d complete\n", intelxl, tx_idx ); - /* Unmap I/O buffer */ - dma_unmap ( &intelxl->tx.map[tx_idx] ); - /* Complete TX descriptor */ netdev_tx_complete_next ( netdev ); - intelxl->tx.ring.cons++; + intelxl->tx.cons++; } } @@ -1586,22 +1556,19 @@ static void intelxl_poll_rx ( struct net_device *netdev ) { size_t len; /* Check for received packets */ - while ( intelxl->rx.ring.cons != intelxl->rx.ring.prod ) { + while ( intelxl->rx.cons != intelxl->rx.prod ) { /* Get next receive descriptor */ - rx_idx = ( intelxl->rx.ring.cons % INTELXL_RX_NUM_DESC ); - rx_wb = &intelxl->rx.ring.desc.rx[rx_idx].wb; + rx_idx = ( intelxl->rx.cons % INTELXL_RX_NUM_DESC ); + rx_wb = &intelxl->rx.desc.rx[rx_idx].wb; /* Stop if descriptor is still in use */ if ( ! ( rx_wb->flags & cpu_to_le32 ( INTELXL_RX_WB_FL_DD ) ) ) return; - /* Unmap I/O buffer */ - dma_unmap ( &intelxl->rx.map[rx_idx] ); - /* Populate I/O buffer */ - iobuf = intelxl->rx.iobuf[rx_idx]; - intelxl->rx.iobuf[rx_idx] = NULL; + iobuf = intelxl->rx_iobuf[rx_idx]; + intelxl->rx_iobuf[rx_idx] = NULL; len = INTELXL_RX_WB_LEN ( le32_to_cpu ( rx_wb->len ) ); iob_put ( iobuf, len ); @@ -1623,7 +1590,7 @@ static void intelxl_poll_rx ( struct net_device *netdev ) { "%zd)\n", intelxl, rx_idx, len ); vlan_netdev_rx ( netdev, tag, iobuf ); } - intelxl->rx.ring.cons++; + intelxl->rx.cons++; } } @@ -1710,11 +1677,11 @@ static int intelxl_probe ( struct pci_device *pci ) { &intelxl_admin_offsets ); intelxl_init_admin ( &intelxl->event, INTELXL_ADMIN_EVT, &intelxl_admin_offsets ); - intelxl_init_ring ( &intelxl->tx.ring, INTELXL_TX_NUM_DESC, - sizeof ( intelxl->tx.ring.desc.tx[0] ), + intelxl_init_ring ( &intelxl->tx, INTELXL_TX_NUM_DESC, + sizeof ( intelxl->tx.desc.tx[0] ), intelxl_context_tx ); - intelxl_init_ring ( &intelxl->rx.ring, INTELXL_RX_NUM_DESC, - sizeof ( intelxl->rx.ring.desc.rx[0] ), + intelxl_init_ring ( &intelxl->rx, INTELXL_RX_NUM_DESC, + sizeof ( intelxl->rx.desc.rx[0] ), intelxl_context_rx ); /* Fix up PCI device */ @@ -1730,6 +1697,7 @@ static int intelxl_probe ( struct pci_device *pci ) { /* Configure DMA */ intelxl->dma = &pci->dma; dma_set_mask_64bit ( intelxl->dma ); + netdev->dma = intelxl->dma; /* Reset the NIC */ if ( ( rc = intelxl_reset ( intelxl ) ) != 0 ) @@ -1775,10 +1743,10 @@ static int intelxl_probe ( struct pci_device *pci ) { goto err_admin_promisc; /* Configure queue register addresses */ - intelxl->tx.ring.reg = INTELXL_QTX ( intelxl->queue ); - intelxl->tx.ring.tail = ( intelxl->tx.ring.reg + INTELXL_QXX_TAIL ); - intelxl->rx.ring.reg = INTELXL_QRX ( intelxl->queue ); - intelxl->rx.ring.tail = ( intelxl->rx.ring.reg + INTELXL_QXX_TAIL ); + intelxl->tx.reg = INTELXL_QTX ( intelxl->queue ); + intelxl->tx.tail = ( intelxl->tx.reg + INTELXL_QXX_TAIL ); + intelxl->rx.reg = INTELXL_QRX ( intelxl->queue ); + intelxl->rx.tail = ( intelxl->rx.reg + INTELXL_QXX_TAIL ); /* Configure interrupt causes */ writel ( ( INTELXL_QINT_TQCTL_NEXTQ_INDX_NONE | diff --git a/src/drivers/net/intelxl.h b/src/drivers/net/intelxl.h index cffc0da96..a4a776d28 100644 --- a/src/drivers/net/intelxl.h +++ b/src/drivers/net/intelxl.h @@ -1030,24 +1030,6 @@ union intelxl_receive_address { uint8_t raw[ETH_ALEN]; }; -/** Transmit ring */ -struct intelxl_tx_ring { - /** Descriptor ring */ - struct intelxl_ring ring; - /** DMA mappings */ - struct dma_mapping map[INTELXL_TX_NUM_DESC]; -}; - -/** Receive ring */ -struct intelxl_rx_ring { - /** Descriptor ring */ - struct intelxl_ring ring; - /** I/O buffers */ - struct io_buffer *iobuf[INTELXL_RX_NUM_DESC]; - /** DMA mappings */ - struct dma_mapping map[INTELXL_RX_NUM_DESC]; -}; - /** MSI-X interrupt */ struct intelxl_msix { /** PCI capability */ @@ -1098,10 +1080,12 @@ struct intelxl_nic { /** Current VF event data buffer */ union intelxl_admin_buffer vbuf; - /** Transmit ring */ - struct intelxl_tx_ring tx; - /** Receive ring */ - struct intelxl_rx_ring rx; + /** Transmit descriptor ring */ + struct intelxl_ring tx; + /** Receive descriptor ring */ + struct intelxl_ring rx; + /** Receive I/O buffers */ + struct io_buffer *rx_iobuf[INTELXL_RX_NUM_DESC]; }; extern int intelxl_msix_enable ( struct intelxl_nic *intelxl, @@ -1121,7 +1105,7 @@ extern int intelxl_alloc_ring ( struct intelxl_nic *intelxl, struct intelxl_ring *ring ); extern void intelxl_free_ring ( struct intelxl_nic *intelxl, struct intelxl_ring *ring ); -extern void intelxl_flush ( struct intelxl_nic *intelxl ); +extern void intelxl_empty_rx ( struct intelxl_nic *intelxl ); extern int intelxl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ); extern void intelxl_poll ( struct net_device *netdev ); diff --git a/src/drivers/net/intelxlvf.c b/src/drivers/net/intelxlvf.c index f944b4daa..752de7815 100644 --- a/src/drivers/net/intelxlvf.c +++ b/src/drivers/net/intelxlvf.c @@ -380,14 +380,14 @@ static int intelxlvf_admin_configure ( struct net_device *netdev ) { buf->cfg.count = cpu_to_le16 ( 1 ); buf->cfg.tx.vsi = cpu_to_le16 ( intelxl->vsi ); buf->cfg.tx.count = cpu_to_le16 ( INTELXL_TX_NUM_DESC ); - buf->cfg.tx.base = cpu_to_le64 ( dma ( &intelxl->tx.ring.map, - intelxl->tx.ring.desc.raw ) ); + buf->cfg.tx.base = cpu_to_le64 ( dma ( &intelxl->tx.map, + intelxl->tx.desc.raw ) ); buf->cfg.rx.vsi = cpu_to_le16 ( intelxl->vsi ); buf->cfg.rx.count = cpu_to_le32 ( INTELXL_RX_NUM_DESC ); buf->cfg.rx.len = cpu_to_le32 ( intelxl->mfs ); buf->cfg.rx.mfs = cpu_to_le32 ( intelxl->mfs ); - buf->cfg.rx.base = cpu_to_le64 ( dma ( &intelxl->rx.ring.map, - intelxl->rx.ring.desc.raw ) ); + buf->cfg.rx.base = cpu_to_le64 ( dma ( &intelxl->rx.map, + intelxl->rx.desc.raw ) ); /* Issue command */ if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 ) @@ -501,11 +501,11 @@ static int intelxlvf_open ( struct net_device *netdev ) { INTELXL_ALIGN - 1 ) & ~( INTELXL_ALIGN - 1 ) ); /* Allocate transmit descriptor ring */ - if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->tx.ring ) ) != 0 ) + if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->tx ) ) != 0 ) goto err_alloc_tx; /* Allocate receive descriptor ring */ - if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->rx.ring ) ) != 0 ) + if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->rx ) ) != 0 ) goto err_alloc_rx; /* Configure queues */ @@ -531,9 +531,9 @@ static int intelxlvf_open ( struct net_device *netdev ) { err_enable: err_irq_map: err_configure: - intelxl_free_ring ( intelxl, &intelxl->rx.ring ); + intelxl_free_ring ( intelxl, &intelxl->rx ); err_alloc_rx: - intelxl_free_ring ( intelxl, &intelxl->tx.ring ); + intelxl_free_ring ( intelxl, &intelxl->tx ); err_alloc_tx: return rc; } @@ -554,13 +554,13 @@ static void intelxlvf_close ( struct net_device *netdev ) { } /* Free receive descriptor ring */ - intelxl_free_ring ( intelxl, &intelxl->rx.ring ); + intelxl_free_ring ( intelxl, &intelxl->rx ); /* Free transmit descriptor ring */ - intelxl_free_ring ( intelxl, &intelxl->tx.ring ); + intelxl_free_ring ( intelxl, &intelxl->tx ); - /* Flush unused buffers */ - intelxl_flush ( intelxl ); + /* Discard any unused receive buffers */ + intelxl_empty_rx ( intelxl ); } /** Network device operations */ @@ -605,11 +605,11 @@ static int intelxlvf_probe ( struct pci_device *pci ) { &intelxlvf_admin_command_offsets ); intelxl_init_admin ( &intelxl->event, INTELXLVF_ADMIN, &intelxlvf_admin_event_offsets ); - intelxlvf_init_ring ( &intelxl->tx.ring, INTELXL_TX_NUM_DESC, - sizeof ( intelxl->tx.ring.desc.tx[0] ), + intelxlvf_init_ring ( &intelxl->tx, INTELXL_TX_NUM_DESC, + sizeof ( intelxl->tx.desc.tx[0] ), INTELXLVF_QTX_TAIL ); - intelxlvf_init_ring ( &intelxl->rx.ring, INTELXL_RX_NUM_DESC, - sizeof ( intelxl->rx.ring.desc.rx[0] ), + intelxlvf_init_ring ( &intelxl->rx, INTELXL_RX_NUM_DESC, + sizeof ( intelxl->rx.desc.rx[0] ), INTELXLVF_QRX_TAIL ); /* Fix up PCI device */ @@ -625,6 +625,7 @@ static int intelxlvf_probe ( struct pci_device *pci ) { /* Configure DMA */ intelxl->dma = &pci->dma; dma_set_mask_64bit ( intelxl->dma ); + netdev->dma = intelxl->dma; /* Locate PCI Express capability */ intelxl->exp = pci_find_capability ( pci, PCI_CAP_ID_EXP ); diff --git a/src/drivers/net/intelxvf.c b/src/drivers/net/intelxvf.c index a650979ef..f0ba091d5 100644 --- a/src/drivers/net/intelxvf.c +++ b/src/drivers/net/intelxvf.c @@ -276,11 +276,11 @@ static int intelxvf_open ( struct net_device *netdev ) { } /* Create transmit descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->tx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 ) goto err_create_tx; /* Create receive descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->rx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 ) goto err_create_rx; /* Allocate interrupt vectors */ @@ -317,9 +317,9 @@ static int intelxvf_open ( struct net_device *netdev ) { return 0; - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); err_create_rx: - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); err_create_tx: err_mbox_set_mtu: err_mbox_set_mac: @@ -337,13 +337,13 @@ static void intelxvf_close ( struct net_device *netdev ) { struct intel_nic *intel = netdev->priv; /* Destroy receive descriptor ring */ - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); - /* Flush unused buffers */ - intel_flush ( intel ); + /* Discard any unused receive buffers */ + intel_empty_rx ( intel ); /* Destroy transmit descriptor ring */ - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); /* Reset the function */ intelxvf_reset ( intel ); @@ -447,9 +447,9 @@ static int intelxvf_probe ( struct pci_device *pci ) { netdev->dev = &pci->dev; memset ( intel, 0, sizeof ( *intel ) ); intel_init_mbox ( &intel->mbox, INTELXVF_MBCTRL, INTELXVF_MBMEM ); - intel_init_ring ( &intel->tx.ring, INTEL_NUM_TX_DESC, INTELXVF_TD(0), + intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTELXVF_TD(0), intel_describe_tx_adv ); - intel_init_ring ( &intel->rx.ring, INTEL_NUM_RX_DESC, INTELXVF_RD(0), + intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTELXVF_RD(0), intel_describe_rx ); /* Fix up PCI device */ @@ -465,6 +465,7 @@ static int intelxvf_probe ( struct pci_device *pci ) { /* Configure DMA */ intel->dma = &pci->dma; dma_set_mask_64bit ( intel->dma ); + netdev->dma = intel->dma; /* Reset the function */ intelxvf_reset ( intel ); diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index 47d435f72..0af3416d5 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -621,7 +621,6 @@ static void realtek_destroy_ring ( struct realtek_nic *rtl, static void realtek_refill_rx ( struct realtek_nic *rtl ) { struct realtek_descriptor *rx; struct io_buffer *iobuf; - struct dma_mapping *map; unsigned int rx_idx; int is_last; @@ -629,34 +628,32 @@ static void realtek_refill_rx ( struct realtek_nic *rtl ) { if ( rtl->legacy ) return; - while ( ( rtl->rx.ring.prod - rtl->rx.ring.cons ) < RTL_NUM_RX_DESC ) { - - /* Get next receive descriptor */ - rx_idx = ( rtl->rx.ring.prod % RTL_NUM_RX_DESC ); - is_last = ( rx_idx == ( RTL_NUM_RX_DESC - 1 ) ); - rx = &rtl->rx.ring.desc[rx_idx]; - map = &rtl->rx.map[rx_idx]; - assert ( rtl->rx.iobuf[rx_idx] == NULL ); + while ( ( rtl->rx.prod - rtl->rx.cons ) < RTL_NUM_RX_DESC ) { /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( rtl->dma, map, RTL_RX_MAX_LEN ); + iobuf = alloc_rx_iob ( RTL_RX_MAX_LEN, rtl->dma ); if ( ! iobuf ) { /* Wait for next refill */ return; } - rtl->rx.iobuf[rx_idx] = iobuf; - /* Update producer index */ - rtl->rx.ring.prod++; + /* Get next receive descriptor */ + rx_idx = ( rtl->rx.prod++ % RTL_NUM_RX_DESC ); + is_last = ( rx_idx == ( RTL_NUM_RX_DESC - 1 ) ); + rx = &rtl->rx.desc[rx_idx]; /* Populate receive descriptor */ - rx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); + rx->address = cpu_to_le64 ( iob_dma ( iobuf ) ); rx->length = cpu_to_le16 ( RTL_RX_MAX_LEN ); wmb(); rx->flags = ( cpu_to_le16 ( RTL_DESC_OWN ) | ( is_last ? cpu_to_le16 ( RTL_DESC_EOR ) : 0 ) ); wmb(); + /* Record I/O buffer */ + assert ( rtl->rx_iobuf[rx_idx] == NULL ); + rtl->rx_iobuf[rx_idx] = iobuf; + DBGC2 ( rtl, "REALTEK %p RX %d is [%lx,%lx)\n", rtl, rx_idx, virt_to_phys ( iobuf->data ), ( virt_to_phys ( iobuf->data ) + RTL_RX_MAX_LEN ) ); @@ -676,11 +673,11 @@ static int realtek_open ( struct net_device *netdev ) { int rc; /* Create transmit descriptor ring */ - if ( ( rc = realtek_create_ring ( rtl, &rtl->tx.ring ) ) != 0 ) + if ( ( rc = realtek_create_ring ( rtl, &rtl->tx ) ) != 0 ) goto err_create_tx; /* Create receive descriptor ring */ - if ( ( rc = realtek_create_ring ( rtl, &rtl->rx.ring ) ) != 0 ) + if ( ( rc = realtek_create_ring ( rtl, &rtl->rx ) ) != 0 ) goto err_create_rx; /* Create receive buffer */ @@ -721,9 +718,9 @@ static int realtek_open ( struct net_device *netdev ) { realtek_destroy_buffer ( rtl ); err_create_buffer: - realtek_destroy_ring ( rtl, &rtl->rx.ring ); + realtek_destroy_ring ( rtl, &rtl->rx ); err_create_rx: - realtek_destroy_ring ( rtl, &rtl->tx.ring ); + realtek_destroy_ring ( rtl, &rtl->tx ); err_create_tx: return rc; } @@ -744,23 +741,17 @@ static void realtek_close ( struct net_device *netdev ) { realtek_destroy_buffer ( rtl ); /* Destroy receive descriptor ring */ - realtek_destroy_ring ( rtl, &rtl->rx.ring ); + realtek_destroy_ring ( rtl, &rtl->rx ); /* Discard any unused receive buffers */ for ( i = 0 ; i < RTL_NUM_RX_DESC ; i++ ) { - if ( rtl->rx.iobuf[i] ) { - dma_unmap ( &rtl->rx.map[i] ); - free_iob ( rtl->rx.iobuf[i] ); - } - rtl->rx.iobuf[i] = NULL; + if ( rtl->rx_iobuf[i] ) + free_rx_iob ( rtl->rx_iobuf[i] ); + rtl->rx_iobuf[i] = NULL; } - /* Unmap any incomplete transmit buffers */ - for ( i = rtl->tx.ring.cons ; i != rtl->tx.ring.prod ; i++ ) - dma_unmap ( &rtl->tx.map[ i % RTL_NUM_TX_DESC ] ); - /* Destroy transmit descriptor ring */ - realtek_destroy_ring ( rtl, &rtl->tx.ring ); + realtek_destroy_ring ( rtl, &rtl->tx ); /* Reset legacy transmit descriptor index, if applicable */ if ( rtl->legacy ) @@ -778,37 +769,33 @@ static int realtek_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct realtek_nic *rtl = netdev->priv; struct realtek_descriptor *tx; - struct dma_mapping *map; unsigned int tx_idx; - physaddr_t address; int is_last; int rc; /* Get next transmit descriptor */ - if ( ( rtl->tx.ring.prod - rtl->tx.ring.cons ) >= RTL_NUM_TX_DESC ) { + if ( ( rtl->tx.prod - rtl->tx.cons ) >= RTL_NUM_TX_DESC ) { netdev_tx_defer ( netdev, iobuf ); return 0; } - tx_idx = ( rtl->tx.ring.prod % RTL_NUM_TX_DESC ); - map = &rtl->tx.map[tx_idx]; + tx_idx = ( rtl->tx.prod % RTL_NUM_TX_DESC ); /* Pad and align packet, if needed */ if ( rtl->legacy ) iob_pad ( iobuf, ETH_ZLEN ); /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( rtl->dma, map, iobuf ) ) != 0 ) + if ( ( rc = iob_map_tx ( iobuf, rtl->dma ) ) != 0 ) return rc; - address = dma ( map, iobuf->data ); /* Update producer index */ - rtl->tx.ring.prod++; + rtl->tx.prod++; /* Transmit packet */ if ( rtl->legacy ) { /* Add to transmit ring */ - writel ( address, rtl->regs + RTL_TSAD ( tx_idx ) ); + writel ( iob_dma ( iobuf ), rtl->regs + RTL_TSAD ( tx_idx ) ); writel ( ( RTL_TSD_ERTXTH_DEFAULT | iob_len ( iobuf ) ), rtl->regs + RTL_TSD ( tx_idx ) ); @@ -816,8 +803,8 @@ static int realtek_transmit ( struct net_device *netdev, /* Populate transmit descriptor */ is_last = ( tx_idx == ( RTL_NUM_TX_DESC - 1 ) ); - tx = &rtl->tx.ring.desc[tx_idx]; - tx->address = cpu_to_le64 ( address ); + tx = &rtl->tx.desc[tx_idx]; + tx->address = cpu_to_le64 ( iob_dma ( iobuf ) ); tx->length = cpu_to_le16 ( iob_len ( iobuf ) ); wmb(); tx->flags = ( cpu_to_le16 ( RTL_DESC_OWN | RTL_DESC_FS | @@ -847,10 +834,10 @@ static void realtek_poll_tx ( struct net_device *netdev ) { unsigned int tx_idx; /* Check for completed packets */ - while ( rtl->tx.ring.cons != rtl->tx.ring.prod ) { + while ( rtl->tx.cons != rtl->tx.prod ) { /* Get next transmit descriptor */ - tx_idx = ( rtl->tx.ring.cons % RTL_NUM_TX_DESC ); + tx_idx = ( rtl->tx.cons % RTL_NUM_TX_DESC ); /* Stop if descriptor is still in use */ if ( rtl->legacy ) { @@ -863,18 +850,15 @@ static void realtek_poll_tx ( struct net_device *netdev ) { } else { /* Check ownership bit in descriptor */ - tx = &rtl->tx.ring.desc[tx_idx]; + tx = &rtl->tx.desc[tx_idx]; if ( tx->flags & cpu_to_le16 ( RTL_DESC_OWN ) ) return; } DBGC2 ( rtl, "REALTEK %p TX %d complete\n", rtl, tx_idx ); - /* Unmap I/O buffer */ - dma_unmap ( &rtl->tx.map[tx_idx] ); - /* Complete TX descriptor */ - rtl->tx.ring.cons++; + rtl->tx.cons++; netdev_tx_complete_next ( netdev ); } } @@ -954,22 +938,19 @@ static void realtek_poll_rx ( struct net_device *netdev ) { } /* Check for received packets */ - while ( rtl->rx.ring.cons != rtl->rx.ring.prod ) { + while ( rtl->rx.cons != rtl->rx.prod ) { /* Get next receive descriptor */ - rx_idx = ( rtl->rx.ring.cons % RTL_NUM_RX_DESC ); - rx = &rtl->rx.ring.desc[rx_idx]; + rx_idx = ( rtl->rx.cons % RTL_NUM_RX_DESC ); + rx = &rtl->rx.desc[rx_idx]; /* Stop if descriptor is still in use */ if ( rx->flags & cpu_to_le16 ( RTL_DESC_OWN ) ) return; - /* Unmap buffer */ - dma_unmap ( &rtl->rx.map[rx_idx] ); - /* Populate I/O buffer */ - iobuf = rtl->rx.iobuf[rx_idx]; - rtl->rx.iobuf[rx_idx] = NULL; + iobuf = rtl->rx_iobuf[rx_idx]; + rtl->rx_iobuf[rx_idx] = NULL; len = ( le16_to_cpu ( rx->length ) & RTL_DESC_SIZE_MASK ); iob_put ( iobuf, ( len - 4 /* strip CRC */ ) ); @@ -984,7 +965,7 @@ static void realtek_poll_rx ( struct net_device *netdev ) { "%zd)\n", rtl, rx_idx, len ); netdev_rx ( netdev, iobuf ); } - rtl->rx.ring.cons++; + rtl->rx.cons++; } } @@ -1128,9 +1109,8 @@ static int realtek_probe ( struct pci_device *pci ) { pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( rtl, 0, sizeof ( *rtl ) ); - rtl->dma = &pci->dma; - realtek_init_ring ( &rtl->tx.ring, RTL_NUM_TX_DESC, RTL_TNPDS ); - realtek_init_ring ( &rtl->rx.ring, RTL_NUM_RX_DESC, RTL_RDSAR ); + realtek_init_ring ( &rtl->tx, RTL_NUM_TX_DESC, RTL_TNPDS ); + realtek_init_ring ( &rtl->rx, RTL_NUM_RX_DESC, RTL_RDSAR ); /* Fix up PCI device */ adjust_pci_device ( pci ); @@ -1142,6 +1122,9 @@ static int realtek_probe ( struct pci_device *pci ) { goto err_ioremap; } + /* Configure DMA */ + rtl->dma = &pci->dma; + /* Reset the NIC */ if ( ( rc = realtek_reset ( rtl ) ) != 0 ) goto err_reset; diff --git a/src/drivers/net/realtek.h b/src/drivers/net/realtek.h index c7cb7e422..d4642fd76 100644 --- a/src/drivers/net/realtek.h +++ b/src/drivers/net/realtek.h @@ -274,24 +274,6 @@ realtek_init_ring ( struct realtek_ring *ring, unsigned int count, ring->reg = reg; } -/** Transmit ring */ -struct realtek_tx_ring { - /** Descriptor ring */ - struct realtek_ring ring; - /** DMA mappings */ - struct dma_mapping map[RTL_NUM_TX_DESC]; -}; - -/** Receive ring */ -struct realtek_rx_ring { - /** Descriptor ring */ - struct realtek_ring ring; - /** I/O buffers */ - struct io_buffer *iobuf[RTL_NUM_RX_DESC]; - /** DMA mappings */ - struct dma_mapping map[RTL_NUM_RX_DESC]; -}; - /** Receive buffer (legacy mode *) */ struct realtek_rx_buffer { /** Buffer */ @@ -327,9 +309,11 @@ struct realtek_nic { unsigned int tppoll; /** Transmit descriptor ring */ - struct realtek_tx_ring tx; + struct realtek_ring tx; /** Receive descriptor ring */ - struct realtek_rx_ring rx; + struct realtek_ring rx; + /** Receive I/O buffers */ + struct io_buffer *rx_iobuf[RTL_NUM_RX_DESC]; /** Receive buffer (legacy mode) */ struct realtek_rx_buffer rxbuf; }; diff --git a/src/include/ipxe/dma.h b/src/include/ipxe/dma.h index 842c9d6ef..b3fa24e47 100644 --- a/src/include/ipxe/dma.h +++ b/src/include/ipxe/dma.h @@ -12,7 +12,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include @@ -385,25 +384,4 @@ dma_set_mask_64bit ( struct dma_device *dma ) { dma_set_mask ( dma, ~( ( physaddr_t ) 0 ) ); } -/** - * Map I/O buffer for transmitting data to device - * - * @v dma DMA device - * @v map DMA mapping to fill in - * @v iobuf I/O buffer - * @ret rc Return status code - */ -static inline __always_inline int -dma_map_tx_iob ( struct dma_device *dma, struct dma_mapping *map, - struct io_buffer *iobuf ) { - - /* Map I/O buffer */ - return dma_map ( dma, map, virt_to_phys ( iobuf->data ), - iob_len ( iobuf ), DMA_TX ); -} - -extern struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, - struct dma_mapping *map, - size_t len ); - #endif /* _IPXE_DMA_H */ diff --git a/src/include/ipxe/iobuf.h b/src/include/ipxe/iobuf.h index b40ade350..630a7753c 100644 --- a/src/include/ipxe/iobuf.h +++ b/src/include/ipxe/iobuf.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include /** * Minimum I/O buffer length @@ -38,6 +39,9 @@ struct io_buffer { */ struct list_head list; + /** DMA mapping */ + struct dma_mapping map; + /** Start of the buffer */ void *head; /** Start of data */ @@ -210,10 +214,61 @@ static inline void iob_populate ( struct io_buffer *iobuf, (iobuf) = NULL; \ __iobuf; } ) +/** + * Map I/O buffer for transmit DMA + * + * @v iobuf I/O buffer + * @v dma DMA device + * @ret rc Return status code + */ +static inline __always_inline int iob_map_tx ( struct io_buffer *iobuf, + struct dma_device *dma ) { + return dma_map ( dma, &iobuf->map, virt_to_phys ( iobuf->data ), + iob_len ( iobuf ), DMA_TX ); +} + +/** + * Map empty I/O buffer for receive DMA + * + * @v iobuf I/O buffer + * @v dma DMA device + * @ret rc Return status code + */ +static inline __always_inline int iob_map_rx ( struct io_buffer *iobuf, + struct dma_device *dma ) { + assert ( iob_len ( iobuf ) == 0 ); + return dma_map ( dma, &iobuf->map, virt_to_phys ( iobuf->data ), + iob_tailroom ( iobuf ), DMA_RX ); +} + +/** + * Get I/O buffer DMA address + * + * @v iobuf I/O buffer + * @ret addr DMA address + */ +static inline __always_inline physaddr_t iob_dma ( struct io_buffer *iobuf ) { + return dma ( &iobuf->map, iobuf->data ); +} + +/** + * Unmap I/O buffer for DMA + * + * @v iobuf I/O buffer + * @v dma DMA device + * @ret rc Return status code + */ +static inline __always_inline void iob_unmap ( struct io_buffer *iobuf ) { + dma_unmap ( &iobuf->map ); +} + extern struct io_buffer * __malloc alloc_iob_raw ( size_t len, size_t align, size_t offset ); extern struct io_buffer * __malloc alloc_iob ( size_t len ); extern void free_iob ( struct io_buffer *iobuf ); +extern struct io_buffer * __malloc alloc_rx_iob ( size_t len, + struct dma_device *dma ); +extern void free_rx_iob ( struct io_buffer *iobuf ); extern void iob_pad ( struct io_buffer *iobuf, size_t min_len ); extern int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len ); extern struct io_buffer * iob_concatenate ( struct list_head *list ); diff --git a/src/include/ipxe/netdevice.h b/src/include/ipxe/netdevice.h index d498ab697..b9c651c71 100644 --- a/src/include/ipxe/netdevice.h +++ b/src/include/ipxe/netdevice.h @@ -246,6 +246,10 @@ struct net_device_operations { * * This method is guaranteed to be called only when the device * is open. + * + * If the network device has an associated DMA device, then + * the I/O buffer will be automatically mapped for transmit + * DMA. */ int ( * transmit ) ( struct net_device *netdev, struct io_buffer *iobuf ); @@ -358,6 +362,8 @@ struct net_device { char name[NETDEV_NAME_LEN]; /** Underlying hardware device */ struct device *dev; + /** DMA device */ + struct dma_device *dma; /** Network device operations */ struct net_device_operations *op; diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index 7687ffb43..8c30c9514 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -335,6 +335,7 @@ static int efipci_dma_map ( struct dma_device *dma, struct dma_mapping *map, int rc; /* Sanity check */ + assert ( map->dma == NULL ); assert ( map->offset == 0 ); assert ( map->token == NULL ); @@ -409,6 +410,7 @@ static void efipci_dma_unmap ( struct dma_device *dma, pci_io->Unmap ( pci_io, map->token ); /* Clear mapping */ + map->dma = NULL; map->offset = 0; map->token = NULL; diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 3b02e64bd..f3feca26b 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -307,6 +307,12 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) { if ( ( rc = inject_fault ( NETDEV_DISCARD_RATE ) ) != 0 ) goto err; + /* Map for DMA, if required */ + if ( netdev->dma && ( ! dma_mapped ( &iobuf->map ) ) ) { + if ( ( rc = iob_map_tx ( iobuf, netdev->dma ) ) != 0 ) + goto err; + } + /* Transmit packet */ if ( ( rc = netdev->op->transmit ( netdev, iobuf ) ) != 0 ) goto err; @@ -340,6 +346,9 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) { * Failure to do this will cause the retransmitted packet to be * immediately redeferred (which will result in out-of-order * transmissions and other nastiness). + * + * I/O buffers that have been mapped for DMA will remain mapped while + * present in the deferred transmit queue. */ void netdev_tx_defer ( struct net_device *netdev, struct io_buffer *iobuf ) { @@ -365,6 +374,9 @@ void netdev_tx_defer ( struct net_device *netdev, struct io_buffer *iobuf ) { * * The packet is discarded and a TX error is recorded. This function * takes ownership of the I/O buffer. + * + * The I/O buffer will be automatically unmapped for DMA, if + * applicable. */ void netdev_tx_err ( struct net_device *netdev, struct io_buffer *iobuf, int rc ) { @@ -379,6 +391,10 @@ void netdev_tx_err ( struct net_device *netdev, netdev->name, iobuf, strerror ( rc ) ); } + /* Unmap I/O buffer, if required */ + if ( dma_mapped ( &iobuf->map ) ) + iob_unmap ( iobuf ); + /* Discard packet */ free_iob ( iobuf ); } @@ -466,6 +482,9 @@ static void netdev_tx_flush ( struct net_device *netdev ) { * * The packet is added to the network device's RX queue. This * function takes ownership of the I/O buffer. + * + * The I/O buffer will be automatically unmapped for DMA, if + * applicable. */ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { int rc; @@ -479,6 +498,10 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { return; } + /* Unmap I/O buffer, if required */ + if ( dma_mapped ( &iobuf->map ) ) + iob_unmap ( iobuf ); + /* Enqueue packet */ list_add_tail ( &iobuf->list, &netdev->rx_queue ); @@ -497,6 +520,9 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { * takes ownership of the I/O buffer. @c iobuf may be NULL if, for * example, the net device wishes to report an error due to being * unable to allocate an I/O buffer. + * + * The I/O buffer will be automatically unmapped for DMA, if + * applicable. */ void netdev_rx_err ( struct net_device *netdev, struct io_buffer *iobuf, int rc ) { @@ -504,6 +530,10 @@ void netdev_rx_err ( struct net_device *netdev, DBGC ( netdev, "NETDEV %s failed to receive %p: %s\n", netdev->name, iobuf, strerror ( rc ) ); + /* Unmap I/O buffer, if required */ + if ( iobuf && dma_mapped ( &iobuf->map ) ) + iob_unmap ( iobuf ); + /* Discard packet */ free_iob ( iobuf ); @@ -1178,6 +1208,8 @@ static unsigned int net_discard ( void ) { /* Discard first deferred packet */ list_del ( &iobuf->list ); + if ( dma_mapped ( &iobuf->map ) ) + iob_unmap ( iobuf ); free_iob ( iobuf ); /* Report discard */ -- cgit v1.2.3-55-g7522 From 13a6d172964667646b1b3ad382470aca141c2d42 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 25 Nov 2020 11:24:41 +0000 Subject: [xhci] Update driver to use DMA API Signed-off-by: Michael Brown --- src/drivers/usb/xhci.c | 223 +++++++++++++++++++++++++++++------------------ src/drivers/usb/xhci.h | 43 +++++++-- src/include/ipxe/iobuf.h | 22 ++++- 3 files changed, 193 insertions(+), 95 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index 7f55a90f2..7bc2e356e 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -31,7 +31,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include #include @@ -294,9 +293,9 @@ static void xhci_init ( struct xhci_device *xhci, void *regs ) { /* Read structural parameters 2 */ hcsparams2 = readl ( xhci->cap + XHCI_CAP_HCSPARAMS2 ); - xhci->scratchpads = XHCI_HCSPARAMS2_SCRATCHPADS ( hcsparams2 ); + xhci->scratch.count = XHCI_HCSPARAMS2_SCRATCHPADS ( hcsparams2 ); DBGC2 ( xhci, "XHCI %s needs %d scratchpads\n", - xhci->name, xhci->scratchpads ); + xhci->name, xhci->scratch.count ); /* Read capability parameters 1 */ hccparams1 = readl ( xhci->cap + XHCI_CAP_HCCPARAMS1 ); @@ -918,27 +917,29 @@ static int xhci_dcbaa_alloc ( struct xhci_device *xhci ) { * align on its own size (rounded up to a power of two and * with a minimum of 64 bytes). */ - len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa[0] ) ); - xhci->dcbaa = malloc_phys ( len, xhci_align ( len ) ); - if ( ! xhci->dcbaa ) { + len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa.context[0] ) ); + xhci->dcbaa.context = dma_alloc ( xhci->dma, &xhci->dcbaa.map, len, + xhci_align ( len ) ); + if ( ! xhci->dcbaa.context ) { DBGC ( xhci, "XHCI %s could not allocate DCBAA\n", xhci->name ); rc = -ENOMEM; goto err_alloc; } - memset ( xhci->dcbaa, 0, len ); + memset ( xhci->dcbaa.context, 0, len ); /* Program DCBAA pointer */ - dcbaap = virt_to_phys ( xhci->dcbaa ); + dcbaap = dma ( &xhci->dcbaa.map, xhci->dcbaa.context ); if ( ( rc = xhci_writeq ( xhci, dcbaap, xhci->op + XHCI_OP_DCBAAP ) ) != 0 ) goto err_writeq; - DBGC2 ( xhci, "XHCI %s DCBAA at [%08lx,%08lx)\n", - xhci->name, dcbaap, ( dcbaap + len ) ); + DBGC2 ( xhci, "XHCI %s DCBAA at [%08lx,%08lx)\n", xhci->name, + virt_to_phys ( xhci->dcbaa.context ), + ( virt_to_phys ( xhci->dcbaa.context ) + len ) ); return 0; err_writeq: - free_phys ( xhci->dcbaa, len ); + dma_free ( &xhci->dcbaa.map, xhci->dcbaa.context, len ); err_alloc: return rc; } @@ -954,14 +955,14 @@ static void xhci_dcbaa_free ( struct xhci_device *xhci ) { /* Sanity check */ for ( i = 0 ; i <= xhci->slots ; i++ ) - assert ( xhci->dcbaa[i] == 0 ); + assert ( xhci->dcbaa.context[i] == 0 ); /* Clear DCBAA pointer */ xhci_writeq ( xhci, 0, xhci->op + XHCI_OP_DCBAAP ); /* Free DCBAA */ - len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa[0] ) ); - free_phys ( xhci->dcbaa, len ); + len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa.context[0] ) ); + dma_free ( &xhci->dcbaa.map, xhci->dcbaa.context, len ); } /****************************************************************************** @@ -978,32 +979,34 @@ static void xhci_dcbaa_free ( struct xhci_device *xhci ) { * @ret rc Return status code */ static int xhci_scratchpad_alloc ( struct xhci_device *xhci ) { + struct xhci_scratchpad *scratch = &xhci->scratch; + size_t buffer_len; size_t array_len; - size_t len; - physaddr_t phys; + physaddr_t addr; unsigned int i; int rc; /* Do nothing if no scratchpad buffers are used */ - if ( ! xhci->scratchpads ) + if ( ! scratch->count ) return 0; - /* Allocate scratchpads */ - len = ( xhci->scratchpads * xhci->pagesize ); - xhci->scratchpad = umalloc ( len ); - if ( ! xhci->scratchpad ) { + /* Allocate scratchpad buffers */ + buffer_len = ( scratch->count * xhci->pagesize ); + scratch->buffer = dma_umalloc ( xhci->dma, &scratch->buffer_map, + buffer_len, xhci->pagesize ); + if ( ! scratch->buffer ) { DBGC ( xhci, "XHCI %s could not allocate scratchpad buffers\n", xhci->name ); rc = -ENOMEM; goto err_alloc; } - memset_user ( xhci->scratchpad, 0, 0, len ); + memset_user ( scratch->buffer, 0, 0, buffer_len ); /* Allocate scratchpad array */ - array_len = ( xhci->scratchpads * sizeof ( xhci->scratchpad_array[0] )); - xhci->scratchpad_array = - malloc_phys ( array_len, xhci_align ( array_len ) ); - if ( ! xhci->scratchpad_array ) { + array_len = ( scratch->count * sizeof ( scratch->array[0] ) ); + scratch->array = dma_alloc ( xhci->dma, &scratch->array_map, + array_len, xhci_align ( array_len ) ); + if ( ! scratch->array ) { DBGC ( xhci, "XHCI %s could not allocate scratchpad buffer " "array\n", xhci->name ); rc = -ENOMEM; @@ -1011,25 +1014,28 @@ static int xhci_scratchpad_alloc ( struct xhci_device *xhci ) { } /* Populate scratchpad array */ - for ( i = 0 ; i < xhci->scratchpads ; i++ ) { - phys = user_to_phys ( xhci->scratchpad, ( i * xhci->pagesize )); - xhci->scratchpad_array[i] = phys; + addr = dma_phys ( &scratch->buffer_map, + user_to_phys ( scratch->buffer, 0 ) ); + for ( i = 0 ; i < scratch->count ; i++ ) { + scratch->array[i] = cpu_to_le64 ( addr ); + addr += xhci->pagesize; } /* Set scratchpad array pointer */ - assert ( xhci->dcbaa != NULL ); - xhci->dcbaa[0] = cpu_to_le64 ( virt_to_phys ( xhci->scratchpad_array )); + assert ( xhci->dcbaa.context != NULL ); + xhci->dcbaa.context[0] = cpu_to_le64 ( dma ( &scratch->array_map, + scratch->array ) ); DBGC2 ( xhci, "XHCI %s scratchpad [%08lx,%08lx) array [%08lx,%08lx)\n", - xhci->name, user_to_phys ( xhci->scratchpad, 0 ), - user_to_phys ( xhci->scratchpad, len ), - virt_to_phys ( xhci->scratchpad_array ), - ( virt_to_phys ( xhci->scratchpad_array ) + array_len ) ); + xhci->name, user_to_phys ( scratch->buffer, 0 ), + user_to_phys ( scratch->buffer, buffer_len ), + virt_to_phys ( scratch->array ), + ( virt_to_phys ( scratch->array ) + array_len ) ); return 0; - free_phys ( xhci->scratchpad_array, array_len ); + dma_free ( &scratch->array_map, scratch->array, array_len ); err_alloc_array: - ufree ( xhci->scratchpad ); + dma_ufree ( &scratch->buffer_map, scratch->buffer, buffer_len ); err_alloc: return rc; } @@ -1040,22 +1046,25 @@ static int xhci_scratchpad_alloc ( struct xhci_device *xhci ) { * @v xhci xHCI device */ static void xhci_scratchpad_free ( struct xhci_device *xhci ) { + struct xhci_scratchpad *scratch = &xhci->scratch; size_t array_len; + size_t buffer_len; /* Do nothing if no scratchpad buffers are used */ - if ( ! xhci->scratchpads ) + if ( ! scratch->count ) return; /* Clear scratchpad array pointer */ - assert ( xhci->dcbaa != NULL ); - xhci->dcbaa[0] = 0; + assert ( xhci->dcbaa.context != NULL ); + xhci->dcbaa.context[0] = 0; /* Free scratchpad array */ - array_len = ( xhci->scratchpads * sizeof ( xhci->scratchpad_array[0] )); - free_phys ( xhci->scratchpad_array, array_len ); + array_len = ( scratch->count * sizeof ( scratch->array[0] ) ); + dma_free ( &scratch->array_map, scratch->array, array_len ); - /* Free scratchpads */ - ufree ( xhci->scratchpad ); + /* Free scratchpad buffers */ + buffer_len = ( scratch->count * xhci->pagesize ); + dma_ufree ( &scratch->buffer_map, scratch->buffer, buffer_len ); } /****************************************************************************** @@ -1202,7 +1211,8 @@ static int xhci_ring_alloc ( struct xhci_device *xhci, } /* Allocate TRBs */ - ring->trb = malloc_phys ( ring->len, xhci_align ( ring->len ) ); + ring->trb = dma_alloc ( xhci->dma, &ring->map, ring->len, + xhci_align ( ring->len ) ); if ( ! ring->trb ) { rc = -ENOMEM; goto err_alloc_trb; @@ -1211,14 +1221,14 @@ static int xhci_ring_alloc ( struct xhci_device *xhci, /* Initialise Link TRB */ link = &ring->trb[count].link; - link->next = cpu_to_le64 ( virt_to_phys ( ring->trb ) ); + link->next = cpu_to_le64 ( dma ( &ring->map, ring->trb ) ); link->flags = XHCI_TRB_TC; link->type = XHCI_TRB_LINK; ring->link = link; return 0; - free_phys ( ring->trb, ring->len ); + dma_free ( &ring->map, ring->trb, ring->len ); err_alloc_trb: free ( ring->iobuf ); err_alloc_iobuf: @@ -1256,7 +1266,7 @@ static void xhci_ring_free ( struct xhci_trb_ring *ring ) { assert ( ring->iobuf[i] == NULL ); /* Free TRBs */ - free_phys ( ring->trb, ring->len ); + dma_free ( &ring->map, ring->trb, ring->len ); /* Free I/O buffers */ free ( ring->iobuf ); @@ -1422,13 +1432,14 @@ static int xhci_command_alloc ( struct xhci_device *xhci ) { goto err_ring_alloc; /* Program command ring control register */ - crp = virt_to_phys ( xhci->command.trb ); + crp = dma ( &xhci->command.map, xhci->command.trb ); if ( ( rc = xhci_writeq ( xhci, ( crp | XHCI_CRCR_RCS ), xhci->op + XHCI_OP_CRCR ) ) != 0 ) goto err_writeq; - DBGC2 ( xhci, "XHCI %s CRCR at [%08lx,%08lx)\n", - xhci->name, crp, ( crp + xhci->command.len ) ); + DBGC2 ( xhci, "XHCI %s CRCR at [%08lx,%08lx)\n", xhci->name, + virt_to_phys ( xhci->command.trb ), + ( virt_to_phys ( xhci->command.trb ) + xhci->command.len ) ); return 0; err_writeq: @@ -1469,7 +1480,8 @@ static int xhci_event_alloc ( struct xhci_device *xhci ) { /* Allocate event ring */ count = ( 1 << XHCI_EVENT_TRBS_LOG2 ); len = ( count * sizeof ( event->trb[0] ) ); - event->trb = malloc_phys ( len, xhci_align ( len ) ); + event->trb = dma_alloc ( xhci->dma, &event->trb_map, len, + xhci_align ( len ) ); if ( ! event->trb ) { rc = -ENOMEM; goto err_alloc_trb; @@ -1477,22 +1489,25 @@ static int xhci_event_alloc ( struct xhci_device *xhci ) { memset ( event->trb, 0, len ); /* Allocate event ring segment table */ - event->segment = malloc_phys ( sizeof ( event->segment[0] ), - xhci_align ( sizeof(event->segment[0]))); + event->segment = dma_alloc ( xhci->dma, &event->segment_map, + sizeof ( event->segment[0] ), + xhci_align ( sizeof (event->segment[0]))); if ( ! event->segment ) { rc = -ENOMEM; goto err_alloc_segment; } memset ( event->segment, 0, sizeof ( event->segment[0] ) ); - event->segment[0].base = cpu_to_le64 ( virt_to_phys ( event->trb ) ); + event->segment[0].base = cpu_to_le64 ( dma ( &event->trb_map, + event->trb ) ); event->segment[0].count = cpu_to_le32 ( count ); /* Program event ring registers */ writel ( 1, xhci->run + XHCI_RUN_ERSTSZ ( 0 ) ); - if ( ( rc = xhci_writeq ( xhci, virt_to_phys ( event->trb ), + if ( ( rc = xhci_writeq ( xhci, dma ( &event->trb_map, event->trb ), xhci->run + XHCI_RUN_ERDP ( 0 ) ) ) != 0 ) goto err_writeq_erdp; - if ( ( rc = xhci_writeq ( xhci, virt_to_phys ( event->segment ), + if ( ( rc = xhci_writeq ( xhci, + dma ( &event->segment_map, event->segment ), xhci->run + XHCI_RUN_ERSTBA ( 0 ) ) ) != 0 ) goto err_writeq_erstba; @@ -1501,16 +1516,17 @@ static int xhci_event_alloc ( struct xhci_device *xhci ) { ( virt_to_phys ( event->trb ) + len ), virt_to_phys ( event->segment ), ( virt_to_phys ( event->segment ) + - sizeof (event->segment[0] ) ) ); + sizeof ( event->segment[0] ) ) ); return 0; xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERSTBA ( 0 ) ); err_writeq_erstba: xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERDP ( 0 ) ); err_writeq_erdp: - free_phys ( event->trb, len ); + dma_free ( &event->segment_map, event->segment, + sizeof ( event->segment[0] ) ); err_alloc_segment: - free_phys ( event->segment, sizeof ( event->segment[0] ) ); + dma_free ( &event->trb_map, event->trb, len ); err_alloc_trb: return rc; } @@ -1531,12 +1547,13 @@ static void xhci_event_free ( struct xhci_device *xhci ) { xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERDP ( 0 ) ); /* Free event ring segment table */ - free_phys ( event->segment, sizeof ( event->segment[0] ) ); + dma_free ( &event->segment_map, event->segment, + sizeof ( event->segment[0] ) ); /* Free event ring */ count = ( 1 << XHCI_EVENT_TRBS_LOG2 ); len = ( count * sizeof ( event->trb[0] ) ); - free_phys ( event->trb, len ); + dma_free ( &event->trb_map, event->trb, len ); } /** @@ -1577,6 +1594,9 @@ static void xhci_transfer ( struct xhci_device *xhci, iobuf = xhci_dequeue_multi ( &endpoint->ring ); assert ( iobuf != NULL ); + /* Unmap I/O buffer */ + iob_unmap ( iobuf ); + /* Check for errors */ if ( ! ( ( trb->code == XHCI_CMPLT_SUCCESS ) || ( trb->code == XHCI_CMPLT_SHORT ) ) ) { @@ -1745,7 +1765,7 @@ static void xhci_event_poll ( struct xhci_device *xhci ) { /* Update dequeue pointer if applicable */ if ( consumed ) { - xhci_writeq ( xhci, virt_to_phys ( trb ), + xhci_writeq ( xhci, dma ( &event->trb_map, trb ), xhci->run + XHCI_RUN_ERDP ( 0 ) ); profile_stop ( &xhci_event_profiler ); } @@ -1774,7 +1794,7 @@ static void xhci_abort ( struct xhci_device *xhci ) { /* Reset the command ring control register */ xhci_ring_reset ( &xhci->command ); - crp = virt_to_phys ( xhci->command.trb ); + crp = dma ( &xhci->command.map, xhci->command.trb ); xhci_writeq ( xhci, ( crp | XHCI_CRCR_RCS ), xhci->op + XHCI_OP_CRCR ); } @@ -1942,13 +1962,15 @@ static int xhci_context ( struct xhci_device *xhci, struct xhci_slot *slot, void *input ) ) { union xhci_trb trb; struct xhci_trb_context *context = &trb.context; + struct dma_mapping map; size_t len; void *input; int rc; /* Allocate an input context */ + memset ( &map, 0, sizeof ( map ) ); len = xhci_input_context_offset ( xhci, XHCI_CTX_END ); - input = malloc_phys ( len, xhci_align ( len ) ); + input = dma_alloc ( xhci->dma, &map, len, xhci_align ( len ) ); if ( ! input ) { rc = -ENOMEM; goto err_alloc; @@ -1961,7 +1983,7 @@ static int xhci_context ( struct xhci_device *xhci, struct xhci_slot *slot, /* Construct command */ memset ( context, 0, sizeof ( *context ) ); context->type = type; - context->input = cpu_to_le64 ( virt_to_phys ( input ) ); + context->input = cpu_to_le64 ( dma ( &map, input ) ); context->slot = slot->id; /* Issue command and wait for completion */ @@ -1969,7 +1991,7 @@ static int xhci_context ( struct xhci_device *xhci, struct xhci_slot *slot, goto err_command; err_command: - free_phys ( input, len ); + dma_free ( &map, input, len ); err_alloc: return rc; } @@ -1986,6 +2008,7 @@ static void xhci_address_device_input ( struct xhci_device *xhci, struct xhci_slot *slot, struct xhci_endpoint *endpoint, void *input ) { + struct xhci_trb_ring *ring = &endpoint->ring; struct xhci_control_context *control_ctx; struct xhci_slot_context *slot_ctx; struct xhci_endpoint_context *ep_ctx; @@ -2011,7 +2034,7 @@ static void xhci_address_device_input ( struct xhci_device *xhci, ep_ctx->type = XHCI_EP_TYPE_CONTROL; ep_ctx->burst = endpoint->ep->burst; ep_ctx->mtu = cpu_to_le16 ( endpoint->ep->mtu ); - ep_ctx->dequeue = cpu_to_le64 ( virt_to_phys ( endpoint->ring.trb ) | + ep_ctx->dequeue = cpu_to_le64 ( dma ( &ring->map, ring->trb ) | XHCI_EP_DCS ); ep_ctx->trb_len = cpu_to_le16 ( XHCI_EP0_TRB_LEN ); } @@ -2057,6 +2080,7 @@ static void xhci_configure_endpoint_input ( struct xhci_device *xhci, struct xhci_slot *slot, struct xhci_endpoint *endpoint, void *input ) { + struct xhci_trb_ring *ring = &endpoint->ring; struct xhci_control_context *control_ctx; struct xhci_slot_context *slot_ctx; struct xhci_endpoint_context *ep_ctx; @@ -2079,7 +2103,7 @@ static void xhci_configure_endpoint_input ( struct xhci_device *xhci, ep_ctx->type = endpoint->type; ep_ctx->burst = endpoint->ep->burst; ep_ctx->mtu = cpu_to_le16 ( endpoint->ep->mtu ); - ep_ctx->dequeue = cpu_to_le64 ( virt_to_phys ( endpoint->ring.trb ) | + ep_ctx->dequeue = cpu_to_le64 ( dma ( &ring->map, ring->trb ) | XHCI_EP_DCS ); ep_ctx->trb_len = cpu_to_le16 ( endpoint->ep->mtu ); /* best guess */ } @@ -2297,6 +2321,7 @@ xhci_set_tr_dequeue_pointer ( struct xhci_device *xhci, unsigned int mask; unsigned int index; unsigned int dcs; + physaddr_t addr; int rc; /* Construct command */ @@ -2305,8 +2330,8 @@ xhci_set_tr_dequeue_pointer ( struct xhci_device *xhci, mask = ring->mask; dcs = ( ( ~( cons >> ring->shift ) ) & XHCI_EP_DCS ); index = ( cons & mask ); - dequeue->dequeue = - cpu_to_le64 ( virt_to_phys ( &ring->trb[index] ) | dcs ); + addr = dma ( &ring->map, &ring->trb[index] ); + dequeue->dequeue = cpu_to_le64 ( addr | dcs ); dequeue->slot = slot->id; dequeue->endpoint = endpoint->ctx; dequeue->type = XHCI_TRB_SET_TR_DEQUEUE_POINTER; @@ -2425,6 +2450,7 @@ static void xhci_endpoint_close ( struct usb_endpoint *ep ) { /* Cancel any incomplete transfers */ while ( xhci_ring_fill ( &endpoint->ring ) ) { iobuf = xhci_dequeue_multi ( &endpoint->ring ); + iob_unmap ( iobuf ); usb_complete_err ( ep, iobuf, -ECANCELED ); } @@ -2491,6 +2517,7 @@ static int xhci_endpoint_mtu ( struct usb_endpoint *ep ) { static int xhci_endpoint_message ( struct usb_endpoint *ep, struct io_buffer *iobuf ) { struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep ); + struct xhci_device *xhci = endpoint->xhci; struct usb_setup_packet *packet; unsigned int input; size_t len; @@ -2520,10 +2547,15 @@ static int xhci_endpoint_message ( struct usb_endpoint *ep, if ( len ) setup->direction = ( input ? XHCI_SETUP_IN : XHCI_SETUP_OUT ); + /* Map I/O buffer */ + if ( ( rc = iob_map ( iobuf, xhci->dma, len, + ( input ? DMA_RX : DMA_TX ) ) ) != 0 ) + goto err_map; + /* Construct data stage TRB, if applicable */ if ( len ) { data = &(trb++)->data; - data->data = cpu_to_le64 ( virt_to_phys ( iobuf->data ) ); + data->data = cpu_to_le64 ( iob_dma ( iobuf ) ); data->len = cpu_to_le32 ( len ); data->type = XHCI_TRB_DATA; data->direction = ( input ? XHCI_DATA_IN : XHCI_DATA_OUT ); @@ -2539,13 +2571,18 @@ static int xhci_endpoint_message ( struct usb_endpoint *ep, /* Enqueue TRBs */ if ( ( rc = xhci_enqueue_multi ( &endpoint->ring, iobuf, trbs, ( trb - trbs ) ) ) != 0 ) - return rc; + goto err_enqueue; /* Ring the doorbell */ xhci_doorbell ( &endpoint->ring ); profile_stop ( &xhci_message_profiler ); return 0; + + err_enqueue: + iob_unmap ( iobuf ); + err_map: + return rc; } /** @@ -2579,12 +2616,13 @@ static unsigned int xhci_endpoint_count ( size_t len, int zlp ) { static int xhci_endpoint_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf, int zlp ) { struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep ); - void *data = iobuf->data; + struct xhci_device *xhci = endpoint->xhci; size_t len = iob_len ( iobuf ); unsigned int count = xhci_endpoint_count ( len, zlp ); union xhci_trb trbs[count]; union xhci_trb *trb = trbs; struct xhci_trb_normal *normal; + physaddr_t data; unsigned int i; size_t trb_len; int rc; @@ -2592,6 +2630,13 @@ static int xhci_endpoint_stream ( struct usb_endpoint *ep, /* Profile stream transfers */ profile_start ( &xhci_stream_profiler ); + /* Map I/O buffer */ + if ( ( rc = iob_map ( iobuf, xhci->dma, len, + ( ( ep->address & USB_DIR_IN ) ? + DMA_RX : DMA_TX ) ) ) != 0 ) + goto err_map; + data = iob_dma ( iobuf ); + /* Construct normal TRBs */ memset ( &trbs, 0, sizeof ( trbs ) ); for ( i = 0 ; i < count ; i ++ ) { @@ -2603,7 +2648,7 @@ static int xhci_endpoint_stream ( struct usb_endpoint *ep, /* Construct normal TRB */ normal = &trb->normal; - normal->data = cpu_to_le64 ( virt_to_phys ( data ) ); + normal->data = cpu_to_le64 ( data ); normal->len = cpu_to_le32 ( trb_len ); normal->type = XHCI_TRB_NORMAL; normal->flags = XHCI_TRB_CH; @@ -2624,13 +2669,18 @@ static int xhci_endpoint_stream ( struct usb_endpoint *ep, /* Enqueue TRBs */ if ( ( rc = xhci_enqueue_multi ( &endpoint->ring, iobuf, trbs, count ) ) != 0 ) - return rc; + goto err_enqueue; /* Ring the doorbell */ xhci_doorbell ( &endpoint->ring ); profile_stop ( &xhci_stream_profiler ); return 0; + + err_enqueue: + iob_unmap ( iobuf ); + err_map: + return rc; } /****************************************************************************** @@ -2693,7 +2743,8 @@ static int xhci_device_open ( struct usb_device *usb ) { /* Allocate a device context */ len = xhci_device_context_offset ( xhci, XHCI_CTX_END ); - slot->context = malloc_phys ( len, xhci_align ( len ) ); + slot->context = dma_alloc ( xhci->dma, &slot->map, len, + xhci_align ( len ) ); if ( ! slot->context ) { rc = -ENOMEM; goto err_alloc_context; @@ -2701,16 +2752,17 @@ static int xhci_device_open ( struct usb_device *usb ) { memset ( slot->context, 0, len ); /* Set device context base address */ - assert ( xhci->dcbaa[id] == 0 ); - xhci->dcbaa[id] = cpu_to_le64 ( virt_to_phys ( slot->context ) ); + assert ( xhci->dcbaa.context[id] == 0 ); + xhci->dcbaa.context[id] = cpu_to_le64 ( dma ( &slot->map, + slot->context ) ); DBGC2 ( xhci, "XHCI %s slot %d device context [%08lx,%08lx) for %s\n", xhci->name, slot->id, virt_to_phys ( slot->context ), ( virt_to_phys ( slot->context ) + len ), usb->name ); return 0; - xhci->dcbaa[id] = 0; - free_phys ( slot->context, len ); + xhci->dcbaa.context[id] = 0; + dma_free ( &slot->map, slot->context, len ); err_alloc_context: xhci->slot[id] = NULL; free ( slot ); @@ -2750,8 +2802,8 @@ static void xhci_device_close ( struct usb_device *usb ) { /* Free slot */ if ( slot->context ) { - free_phys ( slot->context, len ); - xhci->dcbaa[id] = 0; + dma_free ( &slot->map, slot->context, len ); + xhci->dcbaa.context[id] = 0; } xhci->slot[id] = NULL; free ( slot ); @@ -3270,6 +3322,11 @@ static int xhci_probe ( struct pci_device *pci ) { /* Initialise xHCI device */ xhci_init ( xhci, xhci->regs ); + /* Configure DMA device */ + xhci->dma = &pci->dma; + if ( xhci->addr64 ) + dma_set_mask_64bit ( xhci->dma ); + /* Initialise USB legacy support and claim ownership */ xhci_legacy_init ( xhci ); xhci_legacy_claim ( xhci ); diff --git a/src/drivers/usb/xhci.h b/src/drivers/usb/xhci.h index e996363ea..6e02d70e0 100644 --- a/src/drivers/usb/xhci.h +++ b/src/drivers/usb/xhci.h @@ -854,6 +854,8 @@ struct xhci_trb_ring { union xhci_trb *trb; /** Length of transfer request blocks */ size_t len; + /** DMA mapping */ + struct dma_mapping map; /** Link TRB (if applicable) */ struct xhci_trb_link *link; @@ -869,8 +871,12 @@ struct xhci_event_ring { unsigned int cons; /** Event ring segment table */ struct xhci_event_ring_segment *segment; + /** Event ring segment table DMA mapping */ + struct dma_mapping segment_map; /** Transfer request blocks */ union xhci_trb *trb; + /** Transfer request blocks DMA mapping */ + struct dma_mapping trb_map; }; /** @@ -1035,10 +1041,34 @@ struct xhci_pch { /** Invalid protocol speed ID values quirk */ #define XHCI_BAD_PSIV 0x0002 +/** Device context base address array */ +struct xhci_dcbaa { + /** Context base addresses */ + uint64_t *context; + /** DMA mapping */ + struct dma_mapping map; +}; + +/** Scratchpad buffer */ +struct xhci_scratchpad { + /** Number of page-sized scratchpad buffers */ + unsigned int count; + /** Scratchpad buffer area */ + userptr_t buffer; + /** Buffer DMA mapping */ + struct dma_mapping buffer_map; + /** Scratchpad array */ + uint64_t *array; + /** Array DMA mapping */ + struct dma_mapping array_map; +}; + /** An xHCI device */ struct xhci_device { /** Registers */ void *regs; + /** DMA device */ + struct dma_device *dma; /** Name */ const char *name; /** Quirks */ @@ -1060,9 +1090,6 @@ struct xhci_device { /** Number of ports */ unsigned int ports; - /** Number of page-sized scratchpad buffers */ - unsigned int scratchpads; - /** 64-bit addressing capability */ int addr64; /** Context size shift */ @@ -1077,12 +1104,10 @@ struct xhci_device { unsigned int legacy; /** Device context base address array */ - uint64_t *dcbaa; + struct xhci_dcbaa dcbaa; - /** Scratchpad buffer area */ - userptr_t scratchpad; - /** Scratchpad buffer array */ - uint64_t *scratchpad_array; + /** Scratchpad buffer */ + struct xhci_scratchpad scratch; /** Command ring */ struct xhci_trb_ring command; @@ -1111,6 +1136,8 @@ struct xhci_slot { unsigned int id; /** Slot context */ struct xhci_slot_context *context; + /** DMA mapping */ + struct dma_mapping map; /** Route string */ unsigned int route; /** Root hub port number */ diff --git a/src/include/ipxe/iobuf.h b/src/include/ipxe/iobuf.h index 630a7753c..3e079c064 100644 --- a/src/include/ipxe/iobuf.h +++ b/src/include/ipxe/iobuf.h @@ -214,6 +214,22 @@ static inline void iob_populate ( struct io_buffer *iobuf, (iobuf) = NULL; \ __iobuf; } ) +/** + * Map I/O buffer for DMA + * + * @v iobuf I/O buffer + * @v dma DMA device + * @v len Length to map + * @v flags Mapping flags + * @ret rc Return status code + */ +static inline __always_inline int iob_map ( struct io_buffer *iobuf, + struct dma_device *dma, + size_t len, int flags ) { + return dma_map ( dma, &iobuf->map, virt_to_phys ( iobuf->data ), + len, flags ); +} + /** * Map I/O buffer for transmit DMA * @@ -223,8 +239,7 @@ static inline void iob_populate ( struct io_buffer *iobuf, */ static inline __always_inline int iob_map_tx ( struct io_buffer *iobuf, struct dma_device *dma ) { - return dma_map ( dma, &iobuf->map, virt_to_phys ( iobuf->data ), - iob_len ( iobuf ), DMA_TX ); + return iob_map ( iobuf, dma, iob_len ( iobuf ), DMA_TX ); } /** @@ -237,8 +252,7 @@ static inline __always_inline int iob_map_tx ( struct io_buffer *iobuf, static inline __always_inline int iob_map_rx ( struct io_buffer *iobuf, struct dma_device *dma ) { assert ( iob_len ( iobuf ) == 0 ); - return dma_map ( dma, &iobuf->map, virt_to_phys ( iobuf->data ), - iob_tailroom ( iobuf ), DMA_RX ); + return iob_map ( iobuf, dma, iob_tailroom ( iobuf ), DMA_RX ); } /** -- cgit v1.2.3-55-g7522 From f47a45ea2d4ff0f7b725e0c069948c81ef8b67a1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 16 Dec 2020 13:29:06 +0000 Subject: [iphone] Add iPhone tethering driver USB tethering via an iPhone is unreasonably complicated due to the requirement to perform a pairing operation that involves establishing a TLS session over a completely unrelated USB function that speaks a protocol that is almost, but not quite, entirely unlike TCP. Signed-off-by: Michael Brown --- src/drivers/net/iphone.c | 2268 ++++++++++++++++++++++++++++++++++++++++++++ src/drivers/net/iphone.h | 291 ++++++ src/include/ipxe/errfile.h | 1 + 3 files changed, 2560 insertions(+) create mode 100644 src/drivers/net/iphone.c create mode 100644 src/drivers/net/iphone.h (limited to 'src/drivers') diff --git a/src/drivers/net/iphone.c b/src/drivers/net/iphone.c new file mode 100644 index 000000000..7d0eb4b64 --- /dev/null +++ b/src/drivers/net/iphone.c @@ -0,0 +1,2268 @@ +/* + * Copyright (C) 2020 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iphone.h" + +/** @file + * + * iPhone USB Ethernet driver + * + */ + +/* Disambiguate the various error causes */ +#define EPIPE_NO_MUX __einfo_error ( EINFO_EPIPE_NO_MUX ) +#define EINFO_EPIPE_NO_MUX \ + __einfo_uniqify ( EINFO_EPIPE, 0x01, \ + "No USB multiplexer" ) +#define EINPROGRESS_PAIRING __einfo_error ( EINFO_EINPROGRESS_PAIRING ) +#define EINFO_EINPROGRESS_PAIRING \ + __einfo_uniqify ( EINFO_EINPROGRESS, 0x01, \ + "Pairing in progress" ) +#define ENOTCONN_DISABLED __einfo_error ( EINFO_ENOTCONN_DISABLED ) +#define EINFO_ENOTCONN_DISABLED \ + __einfo_uniqify ( EINFO_ENOTCONN, IPHONE_LINK_DISABLED, \ + "Personal Hotspot disabled" ) +#define ENOTCONN_STATUS( status ) \ + EUNIQ ( EINFO_ENOTCONN, ( (status) & 0x1f ), \ + ENOTCONN_DISABLED ) + +static int ipair_create ( struct interface *xfer, unsigned int flags ); + +/** Bulk IN completion profiler */ +static struct profiler iphone_in_profiler __profiler = + { .name = "iphone.in" }; + +/** Bulk OUT profiler */ +static struct profiler iphone_out_profiler __profiler = + { .name = "iphone.out" }; + +/** List of USB multiplexers */ +static LIST_HEAD ( imuxes ); + +/** List of iPhone network devices */ +static LIST_HEAD ( iphones ); + +/****************************************************************************** + * + * iPhone pairing certificates + * + ****************************************************************************** + */ + +/** iPhone root certificate fingerprint */ +static uint8_t icert_root_fingerprint[SHA256_DIGEST_SIZE]; + +/** Root of trust for iPhone certificates */ +static struct x509_root icert_root = { + .refcnt = REF_INIT ( ref_no_free ), + .digest = &sha256_algorithm, + .count = 1, + .fingerprints = icert_root_fingerprint, +}; + +/** Single zero byte used in constructed certificates */ +static const uint8_t icert_nul[] = { 0x00 }; + +/** "RSA algorithm" identifier used in constructed certificates */ +static const uint8_t icert_rsa[] = { + /* algorithm */ + ASN1_SHORT ( ASN1_SEQUENCE, + ASN1_SHORT ( ASN1_OID, ASN1_OID_RSAENCRYPTION ), + ASN1_NULL, 0x00 ) +}; + +/** "SHA-256 with RSA algorithm" identifier used in constructed certificates */ +static const uint8_t icert_sha256_rsa[] = { + ASN1_SHORT ( ASN1_SEQUENCE, + ASN1_SHORT ( ASN1_OID, ASN1_OID_SHA256WITHRSAENCRYPTION ), + ASN1_NULL, 0x00 ), +}; + +/** Extensions used in constructed root certificate */ +static const uint8_t icert_root_exts_data[] = { + /* extensions */ + ASN1_SHORT ( ASN1_EXPLICIT_TAG ( 3 ), ASN1_SHORT ( ASN1_SEQUENCE, + /* basicConstraints */ + ASN1_SHORT ( ASN1_SEQUENCE, + /* extnID */ + ASN1_SHORT ( ASN1_OID, ASN1_OID_BASICCONSTRAINTS ), + /* critical */ + ASN1_SHORT ( ASN1_BOOLEAN, 0xff ), + /* extnValue */ + ASN1_SHORT ( ASN1_OCTET_STRING, + ASN1_SHORT ( ASN1_SEQUENCE, + ASN1_SHORT ( ASN1_BOOLEAN, + 0xff ) ) ) ) ) ) +}; + +/** Extensions used in constructed root certificate */ +static struct asn1_cursor icert_root_exts = + ASN1_CURSOR ( icert_root_exts_data ); + +/** Extensions used in constructed leaf certificates */ +static const uint8_t icert_leaf_exts_data[] = { + /* extensions */ + ASN1_SHORT ( ASN1_EXPLICIT_TAG ( 3 ), ASN1_SHORT ( ASN1_SEQUENCE, + /* basicConstraints */ + ASN1_SHORT ( ASN1_SEQUENCE, + /* extnID */ + ASN1_SHORT ( ASN1_OID, ASN1_OID_BASICCONSTRAINTS ), + /* critical */ + ASN1_SHORT ( ASN1_BOOLEAN, 0xff ), + /* extnValue */ + ASN1_SHORT ( ASN1_OCTET_STRING, + ASN1_SHORT ( ASN1_SEQUENCE, + ASN1_SHORT ( ASN1_BOOLEAN, + 0x00 ) ) ) ), + /* keyUsage */ + ASN1_SHORT ( ASN1_SEQUENCE, + /* extnID */ + ASN1_SHORT ( ASN1_OID, ASN1_OID_KEYUSAGE ), + /* critical */ + ASN1_SHORT ( ASN1_BOOLEAN, 0xff ), + /* extnValue */ + ASN1_SHORT ( ASN1_OCTET_STRING, + ASN1_SHORT ( ASN1_BIT_STRING, 0x07, + ( X509_DIGITAL_SIGNATURE | + X509_KEY_ENCIPHERMENT ), + 0x00 ) ) ) ) ) +}; + +/** Extensions used in constructed leaf certificates */ +static struct asn1_cursor icert_leaf_exts = + ASN1_CURSOR ( icert_leaf_exts_data ); + +/** "TBSCertificate" prefix in constructed certificates */ +static const uint8_t icert_tbs_prefix[] = { + /* version */ + ASN1_SHORT ( ASN1_EXPLICIT_TAG ( 0 ), ASN1_SHORT ( ASN1_INTEGER, 2 ) ), + /* serialNumber */ + ASN1_SHORT ( ASN1_INTEGER, 0 ), + /* signature */ + ASN1_SHORT ( ASN1_SEQUENCE, + ASN1_SHORT ( ASN1_OID, ASN1_OID_SHA256WITHRSAENCRYPTION ), + ASN1_NULL, 0x00 ) +}; + +/** Validity period in constructed certificates */ +static const uint8_t icert_validity[] = { + /* validity */ + ASN1_SHORT ( ASN1_SEQUENCE, + /* notBefore */ + ASN1_SHORT ( ASN1_GENERALIZED_TIME, + '1', '9', '7', '8', '1', '2', '1', '0', + '2', '2', '0', '0', '0', '0', 'Z' ), + /* notAfter */ + ASN1_SHORT ( ASN1_GENERALIZED_TIME, + '2', '9', '9', '9', '0', '1', '0', '1', + '0', '0', '0', '0', '0', '0', 'Z' ) ) +}; + +/** "Root" subject name */ +static const uint8_t icert_name_root_data[] = { + ASN1_SHORT ( ASN1_SEQUENCE, ASN1_SHORT ( ASN1_SET, + ASN1_SHORT ( ASN1_SEQUENCE, + ASN1_SHORT ( ASN1_OID, ASN1_OID_COMMON_NAME ), + ASN1_SHORT ( ASN1_UTF8_STRING, 'R', 'o', 'o', 't' ) ) ) ) +}; + +/** "Root" subject name */ +static struct asn1_cursor icert_name_root = + ASN1_CURSOR ( icert_name_root_data ); + +/** "iPXE" subject name */ +static const uint8_t icert_name_ipxe_data[] = { + ASN1_SHORT ( ASN1_SEQUENCE, ASN1_SHORT ( ASN1_SET, + ASN1_SHORT ( ASN1_SEQUENCE, + ASN1_SHORT ( ASN1_OID, ASN1_OID_COMMON_NAME ), + ASN1_SHORT ( ASN1_UTF8_STRING, 'i', 'P', 'X', 'E' ) ) ) ) +}; + +/** "iPXE" subject name */ +static struct asn1_cursor icert_name_ipxe = + ASN1_CURSOR ( icert_name_ipxe_data ); + +/** "iPhone" subject name */ +static const uint8_t icert_name_iphone_data[] = { + ASN1_SHORT ( ASN1_SEQUENCE, ASN1_SHORT ( ASN1_SET, + ASN1_SHORT ( ASN1_SEQUENCE, + ASN1_SHORT ( ASN1_OID, ASN1_OID_COMMON_NAME ), + ASN1_SHORT ( ASN1_UTF8_STRING, + 'i', 'P', 'h', 'o', 'n', 'e' ) ) ) ) +}; + +/** "iPhone" subject name */ +static struct asn1_cursor icert_name_iphone = + ASN1_CURSOR ( icert_name_iphone_data ); + +/** Public key(s) used for pairing */ +static const uint8_t icert_public_a[] __unused = { + 0x02, 0x81, 0x81, 0x00, 0xc9, 0xc0, 0xdd, 0xa6, 0xd5, 0xf9, 0x05, 0x3e, + 0x1d, 0xcb, 0x67, 0x08, 0xa8, 0x50, 0x27, 0x63, 0x95, 0x87, 0x42, 0x7e, + 0xfb, 0xff, 0x55, 0x55, 0xb8, 0xc0, 0x6f, 0x13, 0xcb, 0xf7, 0xc5, 0x1b, + 0xda, 0x44, 0x3c, 0xbc, 0x1a, 0xe1, 0x15, 0x1e, 0xab, 0x56, 0x74, 0x02, + 0x8b, 0xb3, 0xcd, 0x42, 0x56, 0xcd, 0x9c, 0xc3, 0x15, 0xe2, 0x33, 0x97, + 0x6d, 0x77, 0xdd, 0x20, 0x3a, 0x74, 0xb1, 0x4c, 0xee, 0xeb, 0xe8, 0xaa, + 0x20, 0x71, 0x5a, 0xa2, 0x5b, 0xf8, 0x1a, 0xcb, 0xd2, 0x7b, 0x96, 0xb6, + 0x42, 0xb4, 0x7c, 0x7a, 0x13, 0xec, 0x55, 0xd3, 0x36, 0x8b, 0xe3, 0x17, + 0xc5, 0xc4, 0xcc, 0xe0, 0x27, 0x8c, 0xed, 0xa1, 0x4c, 0x8a, 0x50, 0x4a, + 0x1c, 0xc4, 0x58, 0xf6, 0xcd, 0xcc, 0xc3, 0x5f, 0xe6, 0x3c, 0xff, 0x97, + 0x51, 0xed, 0xf5, 0xaa, 0x89, 0xcc, 0x3f, 0x63, 0x67, 0x46, 0x9f, 0xbf, + 0x02, 0x03, 0x01, 0x00, 0x01 +}; +static const uint8_t icert_public_b[] __unused = { + 0x02, 0x81, 0x81, 0x00, 0xcd, 0x96, 0x81, 0x78, 0xbb, 0x2e, 0x64, 0xda, + 0xd3, 0x7e, 0xd7, 0x3a, 0xac, 0x3f, 0x00, 0xe5, 0x41, 0x65, 0x56, 0xac, + 0x2d, 0x77, 0xc0, 0x1a, 0xad, 0x32, 0xca, 0x0c, 0x72, 0xae, 0xdb, 0x57, + 0xc1, 0xc7, 0x79, 0xef, 0xc6, 0x71, 0x9f, 0xad, 0x82, 0x14, 0x94, 0x4b, + 0xf9, 0xd8, 0x78, 0xf1, 0xca, 0x99, 0xf5, 0x71, 0x07, 0x88, 0xd7, 0x55, + 0xc7, 0xcb, 0x36, 0x5d, 0xdb, 0x84, 0x46, 0xac, 0x05, 0xea, 0xf1, 0xe1, + 0xbe, 0x91, 0x50, 0x85, 0x1e, 0x64, 0xab, 0x02, 0x82, 0xab, 0xba, 0x42, + 0x06, 0x5a, 0xe3, 0xc3, 0x25, 0xd0, 0x95, 0x04, 0x54, 0xb4, 0x44, 0x40, + 0x5a, 0x42, 0x06, 0x04, 0x7d, 0x3b, 0x9e, 0xaf, 0x2e, 0xe9, 0xc8, 0xad, + 0x46, 0x3a, 0xff, 0xe2, 0x39, 0xc8, 0x48, 0x0a, 0x49, 0xaa, 0xfe, 0x1f, + 0x6c, 0x91, 0x5d, 0x1d, 0xd6, 0xb0, 0x04, 0xd1, 0x6c, 0xb2, 0x43, 0xaf, + 0x02, 0x03, 0x01, 0x00, 0x01 +}; + +/** + * "Private" key(s) used for pairing + * + * Yes, this publicly visible "private" key completely obviates any + * nominal security provided by the pairing process. Looked at + * another way, this modifies the iPhone to behave like every other + * USB tethering device: if the cable is physically connected and + * tethering is enabled then the device will Just Work. + * + * Unlike Android, the iPhone seems to have no meaningful permissions + * model: any device that is trusted to use the phone for tethering + * seems to also be trusted to use the iPhone for any other purpose + * (e.g. accessing files, reading messages, etc). Apple should + * probably fix this at some point, e.g. via defining extended key + * usages in the root and host certificates. + */ +static const uint8_t icert_private_a[] __unused = { + 0x02, 0x81, 0x80, 0x1d, 0x60, 0xb7, 0x25, 0xdf, 0x0c, 0x76, 0xc5, 0xf7, + 0xc2, 0xb1, 0x8b, 0x22, 0x2f, 0x21, 0xbd, 0x2f, 0x7d, 0xd5, 0xa1, 0xf6, + 0x01, 0xd5, 0x24, 0x39, 0x55, 0xd4, 0x16, 0xd6, 0xe1, 0x8a, 0x53, 0x26, + 0xf2, 0x3e, 0xc1, 0xc9, 0x4c, 0x33, 0x2e, 0x17, 0x16, 0xec, 0xa7, 0x9e, + 0x3e, 0x1d, 0x4a, 0x66, 0xa7, 0x64, 0x07, 0x48, 0x3d, 0x7a, 0xf3, 0xb6, + 0xdd, 0xf8, 0x56, 0x04, 0x0d, 0x0f, 0xef, 0xf8, 0xbd, 0xbc, 0x73, 0xe2, + 0xc2, 0xae, 0x1b, 0x87, 0x90, 0x18, 0x2a, 0x68, 0xff, 0xae, 0x49, 0xdf, + 0x7c, 0xff, 0xe8, 0x44, 0xa8, 0x3e, 0x4e, 0x4f, 0xf5, 0xfa, 0x51, 0x96, + 0xb8, 0x08, 0xf3, 0x18, 0xd6, 0x52, 0xdf, 0x3a, 0x8a, 0xed, 0xda, 0xcd, + 0xb4, 0x06, 0x99, 0x41, 0xcb, 0x23, 0x17, 0xaf, 0xc3, 0x3e, 0xfe, 0xdf, + 0x97, 0xf3, 0xd6, 0x18, 0x7e, 0x03, 0xaf, 0x62, 0xb2, 0xc8, 0xc9 +}; +static const uint8_t icert_private_b[] __unused = { + 0x02, 0x81, 0x80, 0x45, 0xbd, 0xc0, 0xbe, 0x0c, 0x01, 0x79, 0x05, 0x22, + 0xa9, 0xec, 0xa9, 0x62, 0xb5, 0x1c, 0xc0, 0xa8, 0xa6, 0x8f, 0xf8, 0x68, + 0x94, 0x2e, 0xfe, 0xdd, 0xb2, 0x55, 0x08, 0x53, 0xff, 0x2d, 0x39, 0x5f, + 0xeb, 0x23, 0x5a, 0x4b, 0x9f, 0x4f, 0xe3, 0xb4, 0x34, 0xf6, 0xf9, 0xaf, + 0x0f, 0xd8, 0x37, 0x6d, 0xdb, 0x3c, 0x7f, 0xd3, 0x66, 0x80, 0x66, 0x01, + 0x18, 0xd6, 0xa0, 0x90, 0x4f, 0x17, 0x09, 0xb8, 0x68, 0x44, 0xf0, 0xde, + 0x16, 0x4a, 0x8a, 0x0d, 0xa7, 0x5f, 0xb5, 0x4c, 0x53, 0xcc, 0x21, 0xdd, + 0x4f, 0x05, 0x64, 0xa5, 0xc5, 0xac, 0x2c, 0xd8, 0x0a, 0x7b, 0xf5, 0xa4, + 0x63, 0x32, 0xb0, 0x2c, 0xf8, 0xef, 0x8c, 0xf8, 0x2c, 0xba, 0x1c, 0x2c, + 0xc7, 0x0a, 0xf3, 0xe9, 0x8f, 0xfb, 0x0a, 0x61, 0x1b, 0x3a, 0xdd, 0x9f, + 0x74, 0x7d, 0xb3, 0x42, 0x59, 0x52, 0x07, 0x59, 0x8e, 0xb7, 0x41 +}; + +/** Key pair selection + * + * This exists only to allow for testing of the process for handling a + * failed TLS negotiation. + */ +#define icert_key_suffix a +#define icert_key_variable( prefix ) _C2 ( prefix, icert_key_suffix ) +#define icert_public icert_key_variable ( icert_public_ ) +#define icert_private icert_key_variable ( icert_private_ ) + +/** PEM certificate prefix */ +static const char icert_begin[] = "-----BEGIN CERTIFICATE-----\n"; + +/** PEM certificate suffix */ +static const char icert_end[] = "\n-----END CERTIFICATE-----\n"; + +/** + * Free pairing certificates + * + * @v icert Pairing certificates + */ +static void icert_free ( struct icert *icert ) { + + privkey_put ( icert->key ); + x509_put ( icert->root ); + x509_put ( icert->host ); + x509_put ( icert->device ); + memset ( icert, 0, sizeof ( *icert ) ); +} + +/** + * Construct certificate + * + * @v icert Pairing certificates + * @v subject Subject name + * @v issuer Issuer name + * @v private Private key + * @v public Public key + * @v exts Certificate extensions + * @v cert Certificate to fill in + * @ret rc Return status code + * + * On success, the caller is responsible for eventually calling + * x509_put() on the allocated encoded certificate. + */ +static int icert_cert ( struct icert *icert, struct asn1_cursor *subject, + struct asn1_cursor *issuer, struct asn1_cursor *private, + struct asn1_cursor *public, struct asn1_cursor *exts, + struct x509_certificate **cert ) { + struct digest_algorithm *digest = &sha256_algorithm; + struct pubkey_algorithm *pubkey = &rsa_algorithm; + struct asn1_builder spki = { NULL, 0 }; + struct asn1_builder tbs = { NULL, 0 }; + struct asn1_builder raw = { NULL, 0 }; + uint8_t digest_ctx[SHA256_CTX_SIZE]; + uint8_t digest_out[SHA256_DIGEST_SIZE]; + uint8_t pubkey_ctx[RSA_CTX_SIZE]; + int len; + int rc; + + /* Initialise "private" key */ + if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, private->data, + private->len ) ) != 0 ) { + DBGC ( icert, "ICERT %p could not initialise private key: " + "%s\n", icert, strerror ( rc ) ); + goto err_pubkey_init; + } + + /* Construct subjectPublicKeyInfo */ + if ( ( rc = ( asn1_prepend_raw ( &spki, public->data, public->len ), + asn1_prepend_raw ( &spki, icert_nul, + sizeof ( icert_nul ) ), + asn1_wrap ( &spki, ASN1_BIT_STRING ), + asn1_prepend_raw ( &spki, icert_rsa, + sizeof ( icert_rsa ) ), + asn1_wrap ( &spki, ASN1_SEQUENCE ) ) ) != 0 ) { + DBGC ( icert, "ICERT %p could not build subjectPublicKeyInfo: " + "%s\n", icert, strerror ( rc ) ); + goto err_spki; + } + + /* Construct tbsCertificate */ + if ( ( rc = ( asn1_prepend_raw ( &tbs, exts->data, exts->len ), + asn1_prepend_raw ( &tbs, spki.data, spki.len ), + asn1_prepend_raw ( &tbs, subject->data, subject->len ), + asn1_prepend_raw ( &tbs, icert_validity, + sizeof ( icert_validity ) ), + asn1_prepend_raw ( &tbs, issuer->data, issuer->len ), + asn1_prepend_raw ( &tbs, icert_tbs_prefix, + sizeof ( icert_tbs_prefix ) ), + asn1_wrap ( &tbs, ASN1_SEQUENCE ) ) ) != 0 ) { + DBGC ( icert, "ICERT %p could not build tbsCertificate: %s\n", + icert, strerror ( rc ) ); + goto err_tbs; + } + + /* Calculate certificate digest */ + digest_init ( digest, digest_ctx ); + digest_update ( digest, digest_ctx, tbs.data, tbs.len ); + digest_final ( digest, digest_ctx, digest_out ); + + /* Construct signature */ + if ( ( rc = asn1_grow ( &raw, pubkey_max_len ( pubkey, + pubkey_ctx ) ) ) != 0 ) { + DBGC ( icert, "ICERT %p could not build signature: %s\n", + icert, strerror ( rc ) ); + goto err_grow; + } + if ( ( len = pubkey_sign ( pubkey, pubkey_ctx, digest, digest_out, + raw.data ) ) < 0 ) { + rc = len; + DBGC ( icert, "ICERT %p could not sign: %s\n", + icert, strerror ( rc ) ); + goto err_pubkey_sign; + } + assert ( ( ( size_t ) len ) == raw.len ); + + /* Construct raw certificate data */ + if ( ( rc = ( asn1_prepend_raw ( &raw, icert_nul, + sizeof ( icert_nul ) ), + asn1_wrap ( &raw, ASN1_BIT_STRING ), + asn1_prepend_raw ( &raw, icert_sha256_rsa, + sizeof ( icert_sha256_rsa ) ), + asn1_prepend_raw ( &raw, tbs.data, tbs.len ), + asn1_wrap ( &raw, ASN1_SEQUENCE ) ) ) != 0 ) { + DBGC ( icert, "ICERT %p could not build certificate: %s\n", + icert, strerror ( rc ) ); + goto err_raw; + } + + /* Parse certificate */ + if ( ( rc = x509_certificate ( raw.data, raw.len, cert ) ) != 0 ) { + DBGC ( icert, "ICERT %p invalid certificate: %s\n", + icert, strerror ( rc ) ); + DBGC_HDA ( icert, 0, raw.data, raw.len ); + goto err_x509; + } + + err_x509: + err_raw: + err_pubkey_sign: + free ( raw.data ); + err_grow: + free ( tbs.data ); + err_tbs: + free ( spki.data ); + err_spki: + pubkey_final ( pubkey, pubkey_ctx ); + err_pubkey_init: + return rc; +} + +/** + * Construct certificates + * + * @v icert Certificate set + * @v pubkey Device public key + * @ret rc Return status code + */ +static int icert_certs ( struct icert *icert, struct asn1_cursor *key ) { + struct digest_algorithm *digest = icert_root.digest; + struct asn1_builder public = { NULL, 0 }; + struct asn1_builder *private; + int rc; + + /* Free any existing key and certificates */ + icert_free ( icert ); + + /* Allocate "private" key */ + icert->key = zalloc ( sizeof ( *icert->key ) ); + if ( ! icert->key ) { + rc = -ENOMEM; + goto error; + } + privkey_init ( icert->key ); + private = &icert->key->builder; + + /* Construct our "private" key */ + if ( ( rc = ( asn1_prepend_raw ( private, icert_private, + sizeof ( icert_private ) ), + asn1_prepend_raw ( private, icert_public, + sizeof ( icert_public ) ), + asn1_prepend ( private, ASN1_INTEGER, icert_nul, + sizeof ( icert_nul ) ), + asn1_wrap ( private, ASN1_SEQUENCE ) ) ) != 0 ) { + DBGC ( icert, "ICERT %p could not build private key: %s\n", + icert, strerror ( rc ) ); + goto error; + } + + /* Construct our own public key */ + if ( ( rc = ( asn1_prepend_raw ( &public, icert_public, + sizeof ( icert_public ) ), + asn1_wrap ( &public, ASN1_SEQUENCE ) ) ) != 0 ) { + DBGC ( icert, "ICERT %p could not build public key: %s\n", + icert, strerror ( rc ) ); + goto error; + } + + /* Construct root certificate */ + if ( ( rc = icert_cert ( icert, &icert_name_root, &icert_name_root, + asn1_built ( private ), asn1_built ( &public ), + &icert_root_exts, &icert->root ) ) != 0 ) + goto error; + + /* Construct host certificate */ + if ( ( rc = icert_cert ( icert, &icert_name_ipxe, &icert_name_root, + asn1_built ( private ), asn1_built ( &public ), + &icert_leaf_exts, &icert->host ) ) != 0 ) + goto error; + + /* Construct device certificate */ + if ( ( rc = icert_cert ( icert, &icert_name_iphone, &icert_name_root, + asn1_built ( private ), key, + &icert_leaf_exts, &icert->device ) ) != 0 ) + goto error; + + /* Construct root of trust */ + assert ( digest->digestsize == sizeof ( icert_root_fingerprint ) ); + x509_fingerprint ( icert->root, digest, icert_root_fingerprint ); + + /* Free constructed keys */ + free ( public.data ); + return 0; + + error: + icert_free ( icert ); + free ( public.data ); + return rc; +} + +/** + * Construct doubly base64-encoded certificate + * + * @v icert Pairing certificates + * @v cert X.509 certificate + * @v encenc Doubly base64-encoded certificate to construct + * @ret rc Return status code + * + * On success, the caller is responsible for eventually calling free() + * on the allocated doubly encoded encoded certificate. + */ +static int icert_encode ( struct icert *icert, struct x509_certificate *cert, + char **encenc ) { + size_t encencoded_len; + size_t encoded_len; + size_t pem_len; + char *pem; + int rc; + + /* Sanity check */ + assert ( cert != NULL ); + + /* Create PEM */ + encoded_len = ( base64_encoded_len ( cert->raw.len ) + 1 /* NUL */ ); + pem_len = ( ( sizeof ( icert_begin ) - 1 /* NUL */ ) + + ( encoded_len - 1 /* NUL */ ) + + ( sizeof ( icert_end ) - 1 /* NUL */ ) + + 1 /* NUL */ ); + pem = malloc ( pem_len ); + if ( ! pem ) { + rc = -ENOMEM; + goto err_alloc_pem; + } + strcpy ( pem, icert_begin ); + base64_encode ( cert->raw.data, cert->raw.len, + ( pem + sizeof ( icert_begin ) - 1 /* NUL */ ), + encoded_len ); + strcpy ( ( pem + + ( sizeof ( icert_begin ) - 1 /* NUL */ ) + + ( encoded_len - 1 /* NUL */ ) ), icert_end ); + DBGC2 ( icert, "ICERT %p \"%s\" certificate:\n%s", + icert, x509_name ( cert ), pem ); + + /* Base64-encode the PEM (sic) */ + encencoded_len = ( base64_encoded_len ( pem_len - 1 /* NUL */ ) + + 1 /* NUL */ ); + *encenc = malloc ( encencoded_len ); + if ( ! *encenc ) { + rc = -ENOMEM; + goto err_alloc_encenc; + } + base64_encode ( pem, ( pem_len - 1 /* NUL */ ), *encenc, + encencoded_len ); + + /* Success */ + rc = 0; + + err_alloc_encenc: + free ( pem ); + err_alloc_pem: + return rc; +} + +/****************************************************************************** + * + * iPhone USB multiplexer + * + ****************************************************************************** + * + * The iPhone USB multiplexer speaks a protocol that is almost, but + * not quite, entirely unlike TCP. + * + */ + +/** + * Transmit message + * + * @v imux USB multiplexer + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int imux_tx ( struct imux *imux, struct io_buffer *iobuf ) { + struct imux_header *hdr = iobuf->data; + size_t len = iob_len ( iobuf ); + int rc; + + /* Populate header */ + assert ( len >= sizeof ( *hdr ) ); + hdr->len = htonl ( len ); + hdr->in_seq = htons ( imux->in_seq ); + hdr->out_seq = htons ( imux->out_seq ); + DBGCP ( imux, "IMUX %p transmitting:\n", imux ); + DBGCP_HDA ( imux, 0, hdr, len ); + + /* Transmit message */ + if ( ( rc = usb_stream ( &imux->usbnet.out, iobuf, 1 ) ) != 0 ) + goto err; + + /* Increment sequence number */ + imux->out_seq++; + + return 0; + + err: + free_iob ( iobuf ); + return rc; +} + +/** + * Transmit version message + * + * @v imux USB multiplexer + * @ret rc Return status code + */ +static int imux_tx_version ( struct imux *imux ) { + struct io_buffer *iobuf; + struct imux_header_version *vers; + int rc; + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( sizeof ( *vers ) ); + if ( ! iobuf ) + return -ENOMEM; + vers = iob_put ( iobuf, sizeof ( *vers ) ); + + /* Construct version message */ + memset ( vers, 0, sizeof ( *vers ) ); + vers->hdr.protocol = htonl ( IMUX_VERSION ); + + /* Transmit message */ + if ( ( rc = imux_tx ( imux, iob_disown ( iobuf ) ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Transmit pseudo-TCP message + * + * @v imux USB multiplexer + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int imux_tx_tcp ( struct imux *imux, struct io_buffer *iobuf ) { + struct imux_header_tcp *tcp = iobuf->data; + size_t len = iob_len ( iobuf ); + int rc; + + /* Populate TCP header */ + assert ( len >= sizeof ( *tcp ) ); + tcp->hdr.protocol = htonl ( IMUX_TCP ); + tcp->tcp.src = htons ( imux->port ); + tcp->tcp.dest = htons ( IMUX_PORT_LOCKDOWND ); + tcp->tcp.seq = htonl ( imux->tcp_seq ); + tcp->tcp.ack = htonl ( imux->tcp_ack ); + tcp->tcp.hlen = ( ( sizeof ( tcp->tcp ) / 4 ) << 4 ); + tcp->tcp.win = htons ( IMUX_WINDOW ); + + /* Transmit message */ + if ( ( rc = imux_tx ( imux, iob_disown ( iobuf ) ) ) != 0 ) + return rc; + + /* Update TCP sequence */ + imux->tcp_seq += ( len - sizeof ( *tcp ) ); + + return 0; +} + +/** + * Transmit pseudo-TCP SYN + * + * @v imux USB multiplexer + * @ret rc Return status code + */ +static int imux_tx_syn ( struct imux *imux ) { + struct io_buffer *iobuf; + struct imux_header_tcp *syn; + int rc; + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( sizeof ( *syn ) ); + if ( ! iobuf ) + return -ENOMEM; + syn = iob_put ( iobuf, sizeof ( *syn ) ); + + /* Construct TCP SYN message */ + memset ( syn, 0, sizeof ( *syn ) ); + syn->tcp.flags = TCP_SYN; + + /* Transmit message */ + if ( ( rc = imux_tx_tcp ( imux, iob_disown ( iobuf ) ) ) != 0 ) + return rc; + + /* Increment TCP sequence to compensate for SYN */ + imux->tcp_seq++; + + return 0; +} + +/** + * Open pairing client + * + * @v imux USB multiplexer + * @ret rc Return status code + */ +static int imux_start_pair ( struct imux *imux ) { + int rc; + + /* Disconnect any existing pairing client */ + intf_restart ( &imux->tcp, -EPIPE ); + + /* Create pairing client */ + if ( ( rc = ipair_create ( &imux->tcp, imux->flags ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Receive version message + * + * @v imux USB multiplexer + */ +static void imux_rx_version ( struct imux *imux ) { + + /* Reset output sequence */ + imux->out_seq = 0; + + /* Send TCP SYN */ + imux->action = imux_tx_syn; +} + +/** + * Receive log message + * + * @v imux USB multiplexer + * @v hdr Message header + * @v len Length of message + */ +static void imux_rx_log ( struct imux *imux, struct imux_header *hdr, + size_t len ) { + struct imux_header_log *log = + container_of ( hdr, struct imux_header_log, hdr ); + unsigned int level; + size_t msg_len; + char *tmp; + + /* Sanity check */ + if ( len < sizeof ( *log ) ) { + DBGC ( imux, "IMUX %p malformed log message:\n", imux ); + DBGC_HDA ( imux, 0, log, len ); + return; + } + + /* First byte is the log level, followed by a printable + * message with no NUL terminator. Extract the log level, + * then shuffle the message down within the buffer and append + * a NUL terminator. + */ + msg_len = ( len - sizeof ( *hdr ) ); + level = log->level; + tmp = ( ( void * ) &log->level ); + memmove ( tmp, &log->msg, msg_len ); + tmp[msg_len] = '\0'; + + /* Print log message */ + DBGC ( imux, "IMUX %p <%d>: %s\n", imux, level, tmp ); +} + +/** + * Receive pseudo-TCP SYN+ACK + * + * @v imux USB multiplexer + */ +static void imux_rx_syn ( struct imux *imux ) { + + /* Increment TCP acknowledgement to compensate for SYN */ + imux->tcp_ack++; + + /* Start pairing client */ + imux->action = imux_start_pair; +} + +/** + * Receive pseudo-TCP message + * + * @v imux USB multiplexer + * @v iobuf I/O buffer + */ +static void imux_rx_tcp ( struct imux *imux, struct io_buffer *iobuf ) { + struct imux_header_tcp *tcp = iobuf->data; + size_t len = iob_len ( iobuf ); + int rc; + + /* Sanity check */ + if ( len < sizeof ( *tcp ) ) { + DBGC ( imux, "IMUX %p malformed TCP message:\n", imux ); + DBGC_HDA ( imux, 0, tcp, len ); + goto error; + } + + /* Ignore unexpected packets */ + if ( tcp->tcp.dest != htons ( imux->port ) ) { + DBGC ( imux, "IMUX %p ignoring unexpected TCP port %d:\n", + imux, ntohs ( tcp->tcp.dest ) ); + DBGC_HDA ( imux, 0, tcp, len ); + goto error; + } + + /* Ignore resets */ + if ( tcp->tcp.flags & TCP_RST ) { + DBGC ( imux, "IMUX %p ignoring TCP RST\n", imux ); + DBGC2_HDA ( imux, 0, tcp, len ); + goto error; + } + + /* Record ACK number */ + imux->tcp_ack = ( ntohl ( tcp->tcp.seq ) + len - sizeof ( *tcp ) ); + + /* Handle received message */ + if ( tcp->tcp.flags & TCP_SYN ) { + + /* Received SYN+ACK */ + imux_rx_syn ( imux ); + + } else { + + /* Strip header */ + iob_pull ( iobuf, sizeof ( *tcp ) ); + + /* Deliver via socket */ + if ( ( rc = xfer_deliver_iob ( &imux->tcp, + iob_disown ( iobuf ) ) ) != 0 ) + goto error; + } + + error: + free_iob ( iobuf ); +} + +/** + * Complete bulk IN transfer + * + * @v ep USB endpoint + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void imux_in_complete ( struct usb_endpoint *ep, + struct io_buffer *iobuf, int rc ) { + struct imux *imux = container_of ( ep, struct imux, usbnet.in ); + struct imux_header *hdr = iobuf->data; + size_t len = iob_len ( iobuf ); + + /* Ignore packets cancelled when the endpoint closes */ + if ( ! ep->open ) + goto drop; + + /* Report USB errors */ + if ( rc != 0 ) { + DBGC ( imux, "IMUX %p bulk IN failed: %s\n", + imux, strerror ( rc ) ); + goto drop; + } + + /* Sanity check */ + if ( len < sizeof ( *hdr ) ) { + DBGC ( imux, "IMUX %p malformed message:\n", imux ); + DBGC_HDA ( imux, 0, hdr, len ); + goto drop; + } + + /* Record input sequence */ + imux->in_seq = ntohs ( hdr->in_seq ); + + /* Handle according to protocol */ + DBGCP ( imux, "IMUX %p received:\n", imux ); + DBGCP_HDA ( imux, 0, hdr, len ); + switch ( hdr->protocol ) { + case htonl ( IMUX_VERSION ): + imux_rx_version ( imux ); + break; + case htonl ( IMUX_LOG ): + imux_rx_log ( imux, hdr, len ); + break; + case htonl ( IMUX_TCP ): + imux_rx_tcp ( imux, iob_disown ( iobuf ) ); + break; + default: + DBGC ( imux, "IMUX %p unknown message type %d:\n", + imux, ntohl ( hdr->protocol ) ); + DBGC_HDA ( imux, 0, hdr, len ); + break; + } + + drop: + free_iob ( iobuf ); +} + +/** Bulk IN endpoint operations */ +static struct usb_endpoint_driver_operations imux_in_operations = { + .complete = imux_in_complete, +}; + +/** + * Complete bulk OUT transfer + * + * @v ep USB endpoint + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void imux_out_complete ( struct usb_endpoint *ep, + struct io_buffer *iobuf, int rc ) { + struct imux *imux = container_of ( ep, struct imux, usbnet.out ); + + /* Report USB errors */ + if ( rc != 0 ) { + DBGC ( imux, "IMUX %p bulk OUT failed: %s\n", + imux, strerror ( rc ) ); + goto error; + } + + error: + free_iob ( iobuf ); +} + +/** Bulk OUT endpoint operations */ +static struct usb_endpoint_driver_operations imux_out_operations = { + .complete = imux_out_complete, +}; + +/** + * Shut down USB multiplexer + * + * @v imux USB multiplexer + */ +static void imux_shutdown ( struct imux *imux ) { + + /* Shut down interfaces */ + intf_shutdown ( &imux->tcp, -ECANCELED ); + + /* Close USB network device, if open */ + if ( process_running ( &imux->process ) ) { + process_del ( &imux->process ); + usbnet_close ( &imux->usbnet ); + } +} + +/** + * Close USB multiplexer + * + * @v imux USB multiplexer + * @v rc Reason for close + */ +static void imux_close ( struct imux *imux, int rc ) { + struct iphone *iphone; + + /* Restart interfaces */ + intf_restart ( &imux->tcp, rc ); + + /* Record pairing status */ + imux->rc = rc; + + /* Trigger link check on any associated iPhones */ + list_for_each_entry ( iphone, &iphones, list ) { + if ( iphone->usb == imux->usb ) + start_timer_nodelay ( &iphone->timer ); + } + + /* Retry pairing on any error */ + if ( rc != 0 ) { + + /* Increment port number */ + imux->port++; + + /* Request pairing on any retry attempt */ + imux->flags = IPAIR_REQUEST; + + /* Send new pseudo-TCP SYN */ + imux->action = imux_tx_syn; + + DBGC ( imux, "IMUX %p retrying pairing: %s\n", + imux, strerror ( rc ) ); + return; + } + + /* Shut down multiplexer on pairing success */ + imux_shutdown ( imux ); +} + +/** + * Allocate I/O buffer for pseudo-TCP socket + * + * @v imux USB multiplexer + * @v len I/O buffer payload length + * @ret iobuf I/O buffer + */ +static struct io_buffer * imux_alloc_iob ( struct imux *imux __unused, + size_t len ) { + struct imux_header_tcp *tcp; + struct io_buffer *iobuf; + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( sizeof ( *tcp ) + len ); + if ( ! iobuf ) + return NULL; + + /* Reserve space for pseudo-TCP message header */ + iob_reserve ( iobuf, sizeof ( *tcp ) ); + + return iobuf; +} + +/** + * Transmit packet via pseudo-TCP socket + * + * @v imux USB multiplexer + * @v iobuf I/O buffer + * @v meta Data transfer metadata + * @ret rc Return status code + */ +static int imux_deliver ( struct imux *imux, struct io_buffer *iobuf, + struct xfer_metadata *meta __unused ) { + struct imux_header_tcp *tcp; + + /* Prepend pseudo-TCP header */ + tcp = iob_push ( iobuf, sizeof ( *tcp ) ); + memset ( tcp, 0, sizeof ( *tcp ) ); + tcp->tcp.flags = TCP_ACK; + + /* Transmit pseudo-TCP packet */ + return imux_tx_tcp ( imux, iob_disown ( iobuf ) ); +} + +/** Pseudo-TCP socket interface operations */ +static struct interface_operation imux_tcp_operations[] = { + INTF_OP ( xfer_deliver, struct imux *, imux_deliver ), + INTF_OP ( xfer_alloc_iob, struct imux *, imux_alloc_iob ), + INTF_OP ( intf_close, struct imux *, imux_close ), +}; + +/** Pseudo-TCP socket interface descriptor */ +static struct interface_descriptor imux_tcp_desc = + INTF_DESC ( struct imux, tcp, imux_tcp_operations ); + +/** + * Multiplexer process + * + * @v imux USB multiplexer + */ +static void imux_step ( struct imux *imux ) { + int rc; + + /* Poll USB bus */ + usb_poll ( imux->bus ); + + /* Do nothing more if multiplexer has been closed */ + if ( ! process_running ( &imux->process ) ) + return; + + /* Refill endpoints */ + if ( ( rc = usbnet_refill ( &imux->usbnet ) ) != 0 ) { + /* Wait for next poll */ + return; + } + + /* Perform pending action, if any */ + if ( imux->action ) { + if ( ( rc = imux->action ( imux ) ) != 0 ) + imux_close ( imux, rc ); + imux->action = NULL; + } +} + +/** Multiplexer process descriptor */ +static struct process_descriptor imux_process_desc = + PROC_DESC ( struct imux, process, imux_step ); + +/** + * Probe device + * + * @v func USB function + * @v config Configuration descriptor + * @ret rc Return status code + */ +static int imux_probe ( struct usb_function *func, + struct usb_configuration_descriptor *config ) { + struct usb_device *usb = func->usb; + struct imux *imux; + int rc; + + /* Allocate and initialise structure */ + imux = zalloc ( sizeof ( *imux ) ); + if ( ! imux ) { + rc = -ENOMEM; + goto err_alloc; + } + ref_init ( &imux->refcnt, NULL ); + imux->usb = usb; + imux->bus = usb->port->hub->bus; + usbnet_init ( &imux->usbnet, func, NULL, &imux_in_operations, + &imux_out_operations ); + usb_refill_init ( &imux->usbnet.in, 0, IMUX_IN_MTU, IMUX_IN_MAX_FILL ); + process_init ( &imux->process, &imux_process_desc, &imux->refcnt ); + imux->action = imux_tx_version; + imux->port = IMUX_PORT_LOCAL; + intf_init ( &imux->tcp, &imux_tcp_desc, &imux->refcnt ); + imux->rc = -EINPROGRESS_PAIRING; + + /* Describe USB network device */ + if ( ( rc = usbnet_describe ( &imux->usbnet, config ) ) != 0 ) { + DBGC ( imux, "IMUX %p could not describe: %s\n", + imux, strerror ( rc ) ); + goto err_describe; + } + + /* Open USB network device */ + if ( ( rc = usbnet_open ( &imux->usbnet ) ) != 0 ) { + DBGC ( imux, "IMUX %p could not open: %s\n", + imux, strerror ( rc ) ); + goto err_open; + } + + /* Start polling process */ + process_add ( &imux->process ); + + /* Add to list of multiplexers */ + list_add ( &imux->list, &imuxes ); + + usb_func_set_drvdata ( func, imux ); + return 0; + + list_del ( &imux->list ); + imux_shutdown ( imux ); + err_open: + err_describe: + ref_put ( &imux->refcnt ); + err_alloc: + return rc; +} + +/** + * Remove device + * + * @v func USB function + */ +static void imux_remove ( struct usb_function *func ) { + struct imux *imux = usb_func_get_drvdata ( func ); + + list_del ( &imux->list ); + imux_shutdown ( imux ); + ref_put ( &imux->refcnt ); +} + +/** USB multiplexer device IDs */ +static struct usb_device_id imux_ids[] = { + { + .name = "imux", + .vendor = 0x05ac, + .product = USB_ANY_ID, + }, +}; + +/** USB multiplexer driver */ +struct usb_driver imux_driver __usb_driver = { + .ids = imux_ids, + .id_count = ( sizeof ( imux_ids ) / sizeof ( imux_ids[0] ) ), + .class = USB_CLASS_ID ( 0xff, 0xfe, 0x02 ), + .score = USB_SCORE_NORMAL, + .probe = imux_probe, + .remove = imux_remove, +}; + +/****************************************************************************** + * + * iPhone pairing client + * + ****************************************************************************** + */ + +/** Common prefix for all pairing messages */ +static const char ipair_prefix[] = + "\n" + "\n" + "\n" + "\n" + "Label\n" + "iPXE\n" + "Request\n"; + +/** Common suffix for all pairing messages */ +static const char ipair_suffix[] = + "\n" + "\n"; + +/** Arbitrary system BUID used for pairing */ +static const char ipair_system_buid[] = "E4DB92D2-248A-469A-AC34-92045D07E695"; + +/** Arbitrary host ID used for pairing */ +static const char ipair_host_id[] = "93CEBC27-8457-4804-9108-F42549DF6143"; + +static int ipair_tx_pubkey ( struct ipair *ipair ); +static int ipair_rx_pubkey ( struct ipair *ipair, char *msg ); +static int ipair_tx_pair ( struct ipair *ipair ); +static int ipair_rx_pair ( struct ipair *ipair, char *msg ); +static int ipair_tx_session ( struct ipair *ipair ); +static int ipair_rx_session ( struct ipair *ipair, char *msg ); + +/** + * Free pairing client + * + * @v refcnt Reference counter + */ +static void ipair_free ( struct refcnt *refcnt ) { + struct ipair *ipair = container_of ( refcnt, struct ipair, refcnt ); + + icert_free ( &ipair->icert ); + free ( ipair ); +} + +/** + * Shut down pairing client + * + * @v ipair Pairing client + * @v rc Reason for close + */ +static void ipair_close ( struct ipair *ipair, int rc ) { + + /* Shut down interfaces */ + intf_shutdown ( &ipair->xfer, rc ); + + /* Stop timer */ + stop_timer ( &ipair->timer ); +} + +/** + * Transmit XML message + * + * @v ipair Pairing client + * @v fmt Format string + * @v ... Arguments + * @ret rc Return status code + */ +static int __attribute__ (( format ( printf, 2, 3 ) )) +ipair_tx ( struct ipair *ipair, const char *fmt, ... ) { + struct io_buffer *iobuf; + struct ipair_header *hdr; + va_list args; + size_t len; + char *msg; + int rc; + + /* Calculate length of formatted string */ + va_start ( args, fmt ); + len = ( vsnprintf ( NULL, 0, fmt, args ) + 1 /* NUL */ ); + va_end ( args ); + + /* Allocate I/O buffer */ + iobuf = xfer_alloc_iob ( &ipair->xfer, ( sizeof ( *hdr ) + len ) ); + if ( ! iobuf ) + return -ENOMEM; + hdr = iob_put ( iobuf, sizeof ( *hdr ) ); + + /* Construct XML message */ + memset ( hdr, 0, sizeof ( *hdr ) ); + hdr->len = htonl ( len ); + msg = iob_put ( iobuf, len ); + vsnprintf ( msg, len, fmt, args ); + DBGC2 ( ipair, "IPAIR %p transmitting:\n%s\n", ipair, msg ); + + /* Transmit message */ + if ( ( rc = xfer_deliver_iob ( &ipair->xfer, + iob_disown ( iobuf ) ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Receive XML message payload + * + * @v ipair Pairing client + * @v msg Message payload + * @v len Length of message + * @ret rc Return status code + */ +static int ipair_rx ( struct ipair *ipair, char *msg, size_t len ) { + int ( * rx ) ( struct ipair *ipair, char *msg ); + int rc; + + /* Ignore empty messages */ + if ( ! len ) + return 0; + + /* Sanity check */ + if ( ( msg[ len - 1 ] != '\0' ) && ( msg[ len - 1 ] != '\n' ) ) { + DBGC ( ipair, "IPAIR %p malformed XML:\n", ipair ); + DBGC_HDA ( ipair, 0, msg, len ); + return -EPROTO; + } + + /* Add NUL terminator (potentially overwriting final newline) */ + msg[ len - 1 ] = '\0'; + DBGC2 ( ipair, "IPAIR %p received:\n%s\n\n", ipair, msg ); + + /* Handle according to current state */ + rx = ipair->rx; + if ( ! rx ) { + DBGC ( ipair, "IPAIR %p unexpected XML:\n%s\n", ipair, msg ); + return -EPROTO; + } + ipair->rx = NULL; + if ( ( rc = rx ( ipair, msg ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Locate XML tag + * + * @v ipair Pairing client + * @v msg XML message + * @v tag Tag name + * @ret start Start of tag content + * @ret end End of tag content + * @ret rc Return status code + */ +static int ipair_tag ( struct ipair *ipair, const char *msg, const char *tag, + char **start, char **end ) { + char buf[ 2 /* "" */ + 1 /* NUL */ ]; + + /* Locate opening tag */ + sprintf ( buf, "<%s>", tag ); + *start = strstr ( msg, buf ); + if ( ! *start ) + return -ENOENT; + *start += strlen ( buf ); + + /* Locate closing tag */ + sprintf ( buf, "", tag ); + *end = strstr ( *start, buf ); + if ( ! *end ) { + DBGC ( ipair, "IPAIR %p missing closing tag %s in:\n%s\n", + ipair, buf, msg ); + return -ENOENT; + } + + return 0; +} + +/** + * Locate XML property list dictionary value + * + * @v ipair Pairing client + * @v msg XML message + * @v key Key name + * @v type Key type + * @ret start Start of value content + * @ret end End of value content + * @ret rc Return status code + */ +static int ipair_key ( struct ipair *ipair, const char *msg, const char *key, + const char *type, char **start, char **end ) { + int rc; + + /* Iterate over keys */ + while ( 1 ) { + + /* Locate key */ + if ( ( rc = ipair_tag ( ipair, msg, "key", start, + end ) ) != 0 ) + return rc; + msg = *end; + + /* Check key name */ + if ( memcmp ( *start, key, ( *end - *start ) ) != 0 ) + continue; + + /* Locate value */ + return ipair_tag ( ipair, msg, type, start, end ); + } +} + +/** + * Transmit DevicePublicKey message + * + * @v ipair Pairing client + * @ret rc Return status code + */ +static int ipair_tx_pubkey ( struct ipair *ipair ) { + int rc; + + /* Transmit message */ + if ( ( rc = ipair_tx ( ipair, + "%s" + "GetValue\n" + "Key\n" + "DevicePublicKey\n" + "%s", + ipair_prefix, ipair_suffix ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Receive DevicePublicKey message + * + * @v ipair Pairing client + * @v msg XML message + * @ret rc Return status code + */ +static int ipair_rx_pubkey ( struct ipair *ipair, char *msg ) { + struct asn1_cursor *key; + char *data; + char *end; + char *decoded; + size_t max_len; + int len; + int next; + int rc; + + /* Locate "Value" value */ + if ( ( rc = ipair_key ( ipair, msg, "Value", "data", &data, + &end ) ) != 0 ) { + DBGC ( ipair, "IPAIR %p unexpected public key message:\n%s\n", + ipair, msg ); + goto err_tag; + } + *end = '\0'; + + /* Decode outer layer of Base64 */ + max_len = base64_decoded_max_len ( data ); + decoded = malloc ( max_len ); + if ( ! decoded ) { + rc = -ENOMEM; + goto err_alloc; + } + len = base64_decode ( data, decoded, max_len ); + if ( len < 0 ) { + rc = len; + DBGC ( ipair, "IPAIR %p invalid outer public key:\n%s\n", + ipair, data ); + goto err_decode; + } + + /* Decode inner layer of Base64 */ + next = pem_asn1 ( virt_to_user ( decoded ), len, 0, &key ); + if ( next < 0 ) { + rc = next; + DBGC ( ipair, "IPAIR %p invalid inner public key:\n%s\n", + ipair, decoded ); + goto err_asn1; + } + DBGC ( ipair, "IPAIR %p received public key\n", ipair ); + DBGC2_HDA ( ipair, 0, key->data, key->len ); + + /* Construct certificates */ + if ( ( rc = icert_certs ( &ipair->icert, key ) ) != 0 ) + goto err_certs; + + /* Send session request or pair request as applicable */ + if ( ipair->flags & IPAIR_REQUEST ) { + ipair->tx = ipair_tx_pair; + ipair->rx = ipair_rx_pair; + } else { + ipair->tx = ipair_tx_session; + ipair->rx = ipair_rx_session; + } + start_timer_nodelay ( &ipair->timer ); + + /* Free key */ + free ( key ); + + /* Free intermediate Base64 */ + free ( decoded ); + + return 0; + + err_certs: + free ( key ); + err_asn1: + err_decode: + free ( decoded ); + err_alloc: + err_tag: + return rc; +} + +/** + * Transmit Pair message + * + * @v ipair Pairing client + * @ret rc Return status code + */ +static int ipair_tx_pair ( struct ipair *ipair ) { + char *root; + char *host; + char *device; + int rc; + + /* Construct doubly encoded certificates */ + if ( ( rc = icert_encode ( &ipair->icert, ipair->icert.root, + &root ) ) != 0 ) + goto err_root; + if ( ( rc = icert_encode ( &ipair->icert, ipair->icert.host, + &host ) ) != 0 ) + goto err_host; + if ( ( rc = icert_encode ( &ipair->icert, ipair->icert.device, + &device ) ) != 0 ) + goto err_device; + + /* Transmit message */ + if ( ( rc = ipair_tx ( ipair, + "%s" + "Pair\n" + "PairRecord\n" + "\n" + "RootCertificate\n" + "%s\n" + "HostCertificate\n" + "%s\n" + "DeviceCertificate\n" + "%s\n" + "SystemBUID\n" + "%s\n" + "HostID\n" + "%s\n" + "\n" + "ProtocolVersion\n" + "2\n" + "PairingOptions\n" + "\n" + "ExtendedPairingErrors\n" + "\n" + "\n" + "%s", + ipair_prefix, root, host, device, + ipair_system_buid, ipair_host_id, + ipair_suffix + ) ) != 0 ) + goto err_tx; + + err_tx: + free ( device ); + err_device: + free ( host ); + err_host: + free ( root ); + err_root: + return rc; +} + +/** + * Receive Pair message error + * + * @v ipair Pairing client + * @v error Pairing error + * @ret rc Return status code + */ +static int ipair_rx_pair_error ( struct ipair *ipair, char *error ) { + + /* Check for actual errors */ + if ( strcmp ( error, "PairingDialogResponsePending" ) != 0 ) { + DBGC ( ipair, "IPAIR %p pairing error \"%s\"\n", ipair, error ); + return -EPERM; + } + + /* Retransmit pairing request */ + ipair->tx = ipair_tx_pair; + ipair->rx = ipair_rx_pair; + start_timer_fixed ( &ipair->timer, IPAIR_RETRY_DELAY ); + + DBGC ( ipair, "IPAIR %p waiting for pairing dialog\n", ipair ); + return 0; +} + +/** + * Receive Pair message + * + * @v ipair Pairing client + * @v msg XML message + * @ret rc Return status code + */ +static int ipair_rx_pair ( struct ipair *ipair, char *msg ) { + char *error; + char *escrow; + char *end; + int rc; + + /* Check for pairing errors */ + if ( ( rc = ipair_key ( ipair, msg, "Error", "string", &error, + &end ) ) == 0 ) { + *end = '\0'; + return ipair_rx_pair_error ( ipair, error ); + } + + /* Get EscrowBag */ + if ( ( rc = ipair_key ( ipair, msg, "EscrowBag", "data", &escrow, + &end ) ) != 0 ) { + DBGC ( ipair, "IPAIR %p unexpected pairing response:\n%s\n", + ipair, msg ); + return rc; + } + DBGC ( ipair, "IPAIR %p pairing successful\n", ipair ); + + /* Send session request */ + ipair->tx = ipair_tx_session; + ipair->rx = ipair_rx_session; + start_timer_nodelay ( &ipair->timer ); + + return 0; +} + +/** + * Transmit StartSession message + * + * @v ipair Pairing client + * @ret rc Return status code + */ +static int ipair_tx_session ( struct ipair *ipair ) { + int rc; + + /* Transmit message */ + if ( ( rc = ipair_tx ( ipair, + "%s" + "StartSession\n" + "SystemBUID\n" + "%s\n" + "HostID\n" + "%s\n" + "%s", + ipair_prefix, ipair_system_buid, + ipair_host_id, ipair_suffix + ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Receive StartSession message error + * + * @v ipair Pairing client + * @v error Pairing error + * @ret rc Return status code + */ +static int ipair_rx_session_error ( struct ipair *ipair, char *error ) { + + /* Check for actual errors */ + if ( strcmp ( error, "InvalidHostID" ) != 0 ) { + DBGC ( ipair, "IPAIR %p session error \"%s\"\n", ipair, error ); + return -EPERM; + } + + /* Transmit pairing request */ + ipair->tx = ipair_tx_pair; + ipair->rx = ipair_rx_pair; + start_timer_nodelay ( &ipair->timer ); + + DBGC ( ipair, "IPAIR %p unknown host: requesting pairing\n", ipair ); + return 0; +} + +/** + * Receive StartSession message + * + * @v ipair Pairing client + * @v msg XML message + * @ret rc Return status code + */ +static int ipair_rx_session ( struct ipair *ipair, char *msg ) { + char *error; + char *session; + char *end; + int rc; + + /* Check for session errors */ + if ( ( rc = ipair_key ( ipair, msg, "Error", "string", &error, + &end ) ) == 0 ) { + *end = '\0'; + return ipair_rx_session_error ( ipair, error ); + } + + /* Check for session ID */ + if ( ( rc = ipair_key ( ipair, msg, "SessionID", "string", &session, + &end ) ) != 0 ) { + DBGC ( ipair, "IPAIR %p unexpected session response:\n%s\n", + ipair, msg ); + return rc; + } + *end = '\0'; + DBGC ( ipair, "IPAIR %p starting session \"%s\"\n", ipair, session ); + + /* Start TLS */ + if ( ( rc = add_tls ( &ipair->xfer, "iPhone", &icert_root, + ipair->icert.key ) ) != 0 ) { + DBGC ( ipair, "IPAIR %p could not start TLS: %s\n", + ipair, strerror ( rc ) ); + return rc; + } + + /* Record that TLS has been started */ + ipair->flags |= IPAIR_TLS; + + return 0; +} + +/** + * Handle window change notification + * + * @v ipair Pairing client + */ +static void ipair_window_changed ( struct ipair *ipair ) { + + /* Report pairing as complete once TLS session has been established */ + if ( ( ipair->flags & IPAIR_TLS ) && xfer_window ( &ipair->xfer ) ) { + + /* Sanity checks */ + assert ( x509_is_valid ( ipair->icert.root, &icert_root ) ); + assert ( x509_is_valid ( ipair->icert.device, &icert_root ) ); + assert ( ! x509_is_valid ( ipair->icert.root, NULL ) ); + assert ( ! x509_is_valid ( ipair->icert.host, NULL ) ); + assert ( ! x509_is_valid ( ipair->icert.device, NULL ) ); + + /* Report pairing as complete */ + DBGC ( ipair, "IPAIR %p established TLS session\n", ipair ); + ipair_close ( ipair, 0 ); + return; + } +} + +/** + * Handle received data + * + * @v ipair Pairing client + * @v iobuf I/O buffer + * @v meta Data transfer metadata + * @ret rc Return status code + */ +static int ipair_deliver ( struct ipair *ipair, struct io_buffer *iobuf, + struct xfer_metadata *meta __unused ) { + struct ipair_header *hdr; + int rc; + + /* Strip header (which may appear in a separate packet) */ + if ( ( ! ( ipair->flags & IPAIR_RX_LEN ) ) && + ( iob_len ( iobuf ) >= sizeof ( *hdr ) ) ) { + iob_pull ( iobuf, sizeof ( *hdr ) ); + ipair->flags |= IPAIR_RX_LEN; + } + + /* Clear received header flag if we have a message */ + if ( iob_len ( iobuf ) ) + ipair->flags &= ~IPAIR_RX_LEN; + + /* Receive message */ + if ( ( rc = ipair_rx ( ipair, iobuf->data, iob_len ( iobuf ) ) ) != 0 ) + goto error; + + /* Free I/O buffer */ + free_iob ( iobuf ); + + return 0; + + error: + ipair_close ( ipair, rc ); + free_iob ( iobuf ); + return rc; +} + +/** + * Pairing transmission timer + * + * @v timer Retransmission timer + * @v over Failure indicator + */ +static void ipair_expired ( struct retry_timer *timer, int over __unused ) { + struct ipair *ipair = container_of ( timer, struct ipair, timer ); + int ( * tx ) ( struct ipair *ipair ); + int rc; + + /* Sanity check */ + tx = ipair->tx; + assert ( tx != NULL ); + + /* Clear pending transmission */ + ipair->tx = NULL; + + /* Transmit data, if applicable */ + if ( ( rc = tx ( ipair ) ) != 0 ) + ipair_close ( ipair, rc ); +} + +/** Pairing client interface operations */ +static struct interface_operation ipair_xfer_operations[] = { + INTF_OP ( xfer_deliver, struct ipair *, ipair_deliver ), + INTF_OP ( xfer_window_changed, struct ipair *, ipair_window_changed ), + INTF_OP ( intf_close, struct ipair *, ipair_close ), +}; + +/** Pairing client interface descriptor */ +static struct interface_descriptor ipair_xfer_desc = + INTF_DESC ( struct ipair, xfer, ipair_xfer_operations ); + +/** + * Create a pairing client + * + * @v xfer Data transfer interface + * @v flags Initial state flags + * @ret rc Return status code + */ +static int ipair_create ( struct interface *xfer, unsigned int flags ) { + struct ipair *ipair; + int rc; + + /* Allocate and initialise structure */ + ipair = zalloc ( sizeof ( *ipair ) ); + if ( ! ipair ) { + rc = -ENOMEM; + goto err_alloc; + } + ref_init ( &ipair->refcnt, ipair_free ); + intf_init ( &ipair->xfer, &ipair_xfer_desc, &ipair->refcnt ); + timer_init ( &ipair->timer, ipair_expired, &ipair->refcnt ); + ipair->tx = ipair_tx_pubkey; + ipair->rx = ipair_rx_pubkey; + ipair->flags = flags; + + /* Schedule initial transmission */ + start_timer_nodelay ( &ipair->timer ); + + /* Attach to parent interface, mortalise self, and return */ + intf_plug_plug ( &ipair->xfer, xfer ); + ref_put ( &ipair->refcnt ); + return 0; + + ref_put ( &ipair->refcnt ); + err_alloc: + return rc; +} + +/****************************************************************************** + * + * iPhone USB networking + * + ****************************************************************************** + */ + +/** + * Complete bulk IN transfer + * + * @v ep USB endpoint + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void iphone_in_complete ( struct usb_endpoint *ep, + struct io_buffer *iobuf, int rc ) { + struct iphone *iphone = container_of ( ep, struct iphone, usbnet.in ); + struct net_device *netdev = iphone->netdev; + + /* Profile receive completions */ + profile_start ( &iphone_in_profiler ); + + /* Ignore packets cancelled when the endpoint closes */ + if ( ! ep->open ) + goto ignore; + + /* Record USB errors against the network device */ + if ( rc != 0 ) { + DBGC ( iphone, "IPHONE %p bulk IN failed: %s\n", + iphone, strerror ( rc ) ); + goto error; + } + + /* Strip padding */ + if ( iob_len ( iobuf ) < IPHONE_IN_PAD ) { + DBGC ( iphone, "IPHONE %p malformed bulk IN:\n", iphone ); + DBGC_HDA ( iphone, 0, iobuf->data, iob_len ( iobuf ) ); + rc = -EINVAL; + goto error; + } + iob_pull ( iobuf, IPHONE_IN_PAD ); + + /* Hand off to network stack */ + netdev_rx ( netdev, iob_disown ( iobuf ) ); + + profile_stop ( &iphone_in_profiler ); + return; + + error: + netdev_rx_err ( netdev, iob_disown ( iobuf ), rc ); + ignore: + free_iob ( iobuf ); +} + +/** Bulk IN endpoint operations */ +static struct usb_endpoint_driver_operations iphone_in_operations = { + .complete = iphone_in_complete, +}; + +/** + * Transmit packet + * + * @v iphone iPhone device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int iphone_out_transmit ( struct iphone *iphone, + struct io_buffer *iobuf ) { + int rc; + + /* Profile transmissions */ + profile_start ( &iphone_out_profiler ); + + /* Enqueue I/O buffer */ + if ( ( rc = usb_stream ( &iphone->usbnet.out, iobuf, 1 ) ) != 0 ) + return rc; + + profile_stop ( &iphone_out_profiler ); + return 0; +} + +/** + * Complete bulk OUT transfer + * + * @v ep USB endpoint + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void iphone_out_complete ( struct usb_endpoint *ep, + struct io_buffer *iobuf, int rc ) { + struct iphone *iphone = container_of ( ep, struct iphone, usbnet.out ); + struct net_device *netdev = iphone->netdev; + + /* Report TX completion */ + netdev_tx_complete_err ( netdev, iobuf, rc ); +} + +/** Bulk OUT endpoint operations */ +static struct usb_endpoint_driver_operations iphone_out_operations = { + .complete = iphone_out_complete, +}; + +/** + * Check pairing status + * + * @v iphone iPhone device + * @ret rc Return status code + */ +static int iphone_check_pair ( struct iphone *iphone ) { + struct imux *imux; + + /* Find corresponding USB multiplexer */ + list_for_each_entry ( imux, &imuxes, list ) { + if ( imux->usb == iphone->usb ) + return imux->rc; + } + + return -EPIPE_NO_MUX; +} + +/** + * Check link status + * + * @v netdev Network device + */ +static void iphone_check_link ( struct net_device *netdev ) { + struct iphone *iphone = netdev->priv; + struct usb_device *usb = iphone->usb; + uint8_t status; + int rc; + + /* Check pairing status */ + if ( ( rc = iphone_check_pair ( iphone ) ) != 0 ) + goto err_pair; + + /* Get link status */ + if ( ( rc = usb_control ( usb, IPHONE_GET_LINK, 0, 0, &status, + sizeof ( status ) ) ) != 0 ) { + DBGC ( iphone, "IPHONE %p could not get link status: %s\n", + iphone, strerror ( rc ) ); + goto err_control; + } + + /* Check link status */ + if ( status != IPHONE_LINK_UP ) { + rc = -ENOTCONN_STATUS ( status ); + goto err_status; + } + + /* Success */ + rc = 0; + + err_status: + err_control: + err_pair: + /* Report link status. Since we have to check the link + * periodically (due to an absence of an interrupt endpoint), + * do this only if the link status has actually changed. + */ + if ( rc != netdev->link_rc ) { + if ( rc == 0 ) { + DBGC ( iphone, "IPHONE %p link up\n", iphone ); + } else { + DBGC ( iphone, "IPHONE %p link down: %s\n", + iphone, strerror ( rc ) ); + } + netdev_link_err ( netdev, rc ); + } +} + +/** + * Periodically update link status + * + * @v timer Link status timer + * @v over Failure indicator + */ +static void iphone_expired ( struct retry_timer *timer, int over __unused ) { + struct iphone *iphone = container_of ( timer, struct iphone, timer ); + struct net_device *netdev = iphone->netdev; + + /* Check link status */ + iphone_check_link ( netdev ); + + /* Restart timer, if device is open */ + if ( netdev_is_open ( netdev ) ) + start_timer_fixed ( timer, IPHONE_LINK_CHECK_INTERVAL ); +} + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int iphone_open ( struct net_device *netdev ) { + struct iphone *iphone = netdev->priv; + int rc; + + /* Open USB network device */ + if ( ( rc = usbnet_open ( &iphone->usbnet ) ) != 0 ) { + DBGC ( iphone, "IPHONE %p could not open: %s\n", + iphone, strerror ( rc ) ); + goto err_open; + } + + /* Start the link status check timer */ + start_timer_nodelay ( &iphone->timer ); + + return 0; + + usbnet_close ( &iphone->usbnet ); + err_open: + return rc; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void iphone_close ( struct net_device *netdev ) { + struct iphone *iphone = netdev->priv; + + /* Stop the link status check timer */ + stop_timer ( &iphone->timer ); + + /* Close USB network device */ + usbnet_close ( &iphone->usbnet ); +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int iphone_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct iphone *iphone = netdev->priv; + int rc; + + /* Transmit packet */ + if ( ( rc = iphone_out_transmit ( iphone, iobuf ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Poll for completed and received packets + * + * @v netdev Network device + */ +static void iphone_poll ( struct net_device *netdev ) { + struct iphone *iphone = netdev->priv; + int rc; + + /* Poll USB bus */ + usb_poll ( iphone->bus ); + + /* Refill endpoints */ + if ( ( rc = usbnet_refill ( &iphone->usbnet ) ) != 0 ) + netdev_rx_err ( netdev, NULL, rc ); +} + +/** iPhone network device operations */ +static struct net_device_operations iphone_operations = { + .open = iphone_open, + .close = iphone_close, + .transmit = iphone_transmit, + .poll = iphone_poll, +}; + +/** + * Probe device + * + * @v func USB function + * @v config Configuration descriptor + * @ret rc Return status code + */ +static int iphone_probe ( struct usb_function *func, + struct usb_configuration_descriptor *config ) { + struct usb_device *usb = func->usb; + struct net_device *netdev; + struct iphone *iphone; + int rc; + + /* Allocate and initialise structure */ + netdev = alloc_etherdev ( sizeof ( *iphone ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &iphone_operations ); + netdev->dev = &func->dev; + iphone = netdev->priv; + memset ( iphone, 0, sizeof ( *iphone ) ); + iphone->usb = usb; + iphone->bus = usb->port->hub->bus; + iphone->netdev = netdev; + usbnet_init ( &iphone->usbnet, func, NULL, &iphone_in_operations, + &iphone_out_operations ); + usb_refill_init ( &iphone->usbnet.in, 0, IPHONE_IN_MTU, + IPHONE_IN_MAX_FILL ); + timer_init ( &iphone->timer, iphone_expired, &netdev->refcnt ); + DBGC ( iphone, "IPHONE %p on %s\n", iphone, func->name ); + + /* Describe USB network device */ + if ( ( rc = usbnet_describe ( &iphone->usbnet, config ) ) != 0 ) { + DBGC ( iphone, "IPHONE %p could not describe: %s\n", + iphone, strerror ( rc ) ); + goto err_describe; + } + + /* Fetch MAC address */ + if ( ( rc = usb_control ( usb, IPHONE_GET_MAC, 0, 0, netdev->hw_addr, + ETH_ALEN ) ) != 0 ) { + DBGC ( iphone, "IPHONE %p could not fetch MAC address: %s\n", + iphone, strerror ( rc ) ); + goto err_fetch_mac; + } + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register; + + /* Set initial link status */ + iphone_check_link ( netdev ); + + /* Add to list of iPhone network devices */ + list_add ( &iphone->list, &iphones ); + + usb_func_set_drvdata ( func, iphone ); + return 0; + + list_del ( &iphone->list ); + unregister_netdev ( netdev ); + err_register: + err_fetch_mac: + err_describe: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: + return rc; +} + +/** + * Remove device + * + * @v func USB function + */ +static void iphone_remove ( struct usb_function *func ) { + struct iphone *iphone = usb_func_get_drvdata ( func ); + struct net_device *netdev = iphone->netdev; + + list_del ( &iphone->list ); + unregister_netdev ( netdev ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** iPhone device IDs */ +static struct usb_device_id iphone_ids[] = { + { + .name = "iphone", + .vendor = 0x05ac, + .product = USB_ANY_ID, + }, +}; + +/** iPhone driver */ +struct usb_driver iphone_driver __usb_driver = { + .ids = iphone_ids, + .id_count = ( sizeof ( iphone_ids ) / sizeof ( iphone_ids[0] ) ), + .class = USB_CLASS_ID ( 0xff, 0xfd, 0x01 ), + .score = USB_SCORE_NORMAL, + .probe = iphone_probe, + .remove = iphone_remove, +}; + +/* Drag in objects via iphone_driver */ +REQUIRING_SYMBOL ( iphone_driver ); + +/* Drag in RSA-with-SHA256 OID prefixes */ +REQUIRE_OBJECT ( rsa_sha256 ); diff --git a/src/drivers/net/iphone.h b/src/drivers/net/iphone.h new file mode 100644 index 000000000..2db6da7bd --- /dev/null +++ b/src/drivers/net/iphone.h @@ -0,0 +1,291 @@ +#ifndef _IPHONE_H +#define _IPHONE_H + +/** @file + * + * iPhone USB Ethernet driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * + * iPhone pairing certificates + * + ****************************************************************************** + */ + +/** An iPhone pairing certificate set */ +struct icert { + /** "Private" key */ + struct private_key *key; + /** Root certificate */ + struct x509_certificate *root; + /** Host certificate */ + struct x509_certificate *host; + /** Device certificate */ + struct x509_certificate *device; +}; + +/****************************************************************************** + * + * iPhone USB multiplexer + * + ****************************************************************************** + */ + +/** An iPhone USB multiplexed packet header */ +struct imux_header { + /** Protocol */ + uint32_t protocol; + /** Length (including this header) */ + uint32_t len; + /** Reserved */ + uint32_t reserved; + /** Output sequence number */ + uint16_t out_seq; + /** Input sequence number */ + uint16_t in_seq; +} __attribute__ (( packed )); + +/** iPhone USB multiplexer protocols */ +enum imux_protocol { + /** Version number */ + IMUX_VERSION = 0, + /** Log message */ + IMUX_LOG = 1, + /** TCP packet */ + IMUX_TCP = IP_TCP, +}; + +/** An iPhone USB multiplexed version message header */ +struct imux_header_version { + /** Multiplexed packet header */ + struct imux_header hdr; + /** Reserved */ + uint32_t reserved; +} __attribute__ (( packed )); + +/** An iPhone USB multiplexed log message header */ +struct imux_header_log { + /** Multiplexed packet header */ + struct imux_header hdr; + /** Log level */ + uint8_t level; + /** Message */ + char msg[0]; +} __attribute__ (( packed )); + +/** An iPhone USB multiplexed pseudo-TCP message header */ +struct imux_header_tcp { + /** Multiplexed packet header */ + struct imux_header hdr; + /** Pseudo-TCP header */ + struct tcp_header tcp; +} __attribute__ (( packed )); + +/** Local port number + * + * This is a policy decision. + */ +#define IMUX_PORT_LOCAL 0x18ae + +/** Lockdown daemon port number */ +#define IMUX_PORT_LOCKDOWND 62078 + +/** Advertised TCP window + * + * This is a policy decision. + */ +#define IMUX_WINDOW 0x0200 + +/** An iPhone USB multiplexer */ +struct imux { + /** Reference counter */ + struct refcnt refcnt; + /** USB device */ + struct usb_device *usb; + /** USB bus */ + struct usb_bus *bus; + /** USB network device */ + struct usbnet_device usbnet; + /** List of USB multiplexers */ + struct list_head list; + + /** Polling process */ + struct process process; + /** Pending action + * + * @v imux USB multiplexer + * @ret rc Return status code + */ + int ( * action ) ( struct imux *imux ); + + /** Input sequence */ + uint16_t in_seq; + /** Output sequence */ + uint16_t out_seq; + /** Pseudo-TCP sequence number */ + uint32_t tcp_seq; + /** Pseudo-TCP acknowledgement number */ + uint32_t tcp_ack; + /** Pseudo-TCP local port number */ + uint16_t port; + + /** Pseudo-TCP lockdown socket interface */ + struct interface tcp; + /** Pairing flags */ + unsigned int flags; + /** Pairing status */ + int rc; +}; + +/** Multiplexer bulk IN maximum fill level + * + * This is a policy decision. + */ +#define IMUX_IN_MAX_FILL 1 + +/** Multiplexer bulk IN buffer size + * + * This is a policy decision. + */ +#define IMUX_IN_MTU 4096 + +/****************************************************************************** + * + * iPhone pairing client + * + ****************************************************************************** + */ + +/** An iPhone USB multiplexed pseudo-TCP XML message header */ +struct ipair_header { + /** Message length */ + uint32_t len; + /** Message */ + char msg[0]; +} __attribute__ (( packed )); + +/** An iPhone pairing client */ +struct ipair { + /** Reference counter */ + struct refcnt refcnt; + /** Data transfer interface */ + struct interface xfer; + + /** Pairing timer */ + struct retry_timer timer; + /** Transmit message + * + * @v ipair Pairing client + * @ret rc Return status code + */ + int ( * tx ) ( struct ipair *ipair ); + /** Receive message + * + * @v ipair Pairing client + * @v msg XML message + * @ret rc Return status code + */ + int ( * rx ) ( struct ipair *ipair, char *msg ); + /** State flags */ + unsigned int flags; + + /** Pairing certificates */ + struct icert icert; +}; + +/** Pairing client state flags */ +enum ipair_flags { + /** Request a new pairing */ + IPAIR_REQUEST = 0x0001, + /** Standalone length has been received */ + IPAIR_RX_LEN = 0x0002, + /** TLS session has been started */ + IPAIR_TLS = 0x0004, +}; + +/** Pairing retry delay + * + * This is a policy decision. + */ +#define IPAIR_RETRY_DELAY ( 1 * TICKS_PER_SEC ) + +/****************************************************************************** + * + * iPhone USB networking + * + ****************************************************************************** + */ + +/** Get MAC address */ +#define IPHONE_GET_MAC \ + ( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \ + USB_REQUEST_TYPE ( 0x00 ) ) + +/** Get link status */ +#define IPHONE_GET_LINK \ + ( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \ + USB_REQUEST_TYPE ( 0x45 ) ) + +/** An iPhone link status */ +enum iphone_link_status { + /** Personal Hotspot is disabled */ + IPHONE_LINK_DISABLED = 0x03, + /** Link up */ + IPHONE_LINK_UP = 0x04, + /** Link not yet determined */ + IPHONE_LINK_UNKNOWN = -1U, +}; + +/** An iPhone network device */ +struct iphone { + /** USB device */ + struct usb_device *usb; + /** USB bus */ + struct usb_bus *bus; + /** Network device */ + struct net_device *netdev; + /** USB network device */ + struct usbnet_device usbnet; + + /** List of iPhone network devices */ + struct list_head list; + /** Link status check timer */ + struct retry_timer timer; +}; + +/** Bulk IN padding */ +#define IPHONE_IN_PAD 2 + +/** Bulk IN buffer size + * + * This is a policy decision. + */ +#define IPHONE_IN_MTU ( ETH_FRAME_LEN + IPHONE_IN_PAD ) + +/** Bulk IN maximum fill level + * + * This is a policy decision. + */ +#define IPHONE_IN_MAX_FILL 8 + +/** Link check interval + * + * This is a policy decision. + */ +#define IPHONE_LINK_CHECK_INTERVAL ( 5 * TICKS_PER_SEC ) + +#endif /* _IPHONE_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 7c98909d1..3437a5217 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -210,6 +210,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_pcimsix ( ERRFILE_DRIVER | 0x00cc0000 ) #define ERRFILE_intelxlvf ( ERRFILE_DRIVER | 0x00cd0000 ) #define ERRFILE_usbblk ( ERRFILE_DRIVER | 0x00ce0000 ) +#define ERRFILE_iphone ( ERRFILE_DRIVER | 0x00cf0000 ) #define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 ) #define ERRFILE_arp ( ERRFILE_NET | 0x00010000 ) -- cgit v1.2.3-55-g7522 From ce841946df7055afc99adfe9be449fe74de7d155 Mon Sep 17 00:00:00 2001 From: Mohammed Taha Date: Mon, 14 Dec 2020 14:48:23 +0000 Subject: [golan] Add new PCI IDs Signed-off-by: Mohammed Signed-off-by: Michael Brown --- src/drivers/infiniband/golan.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/golan.c b/src/drivers/infiniband/golan.c index 9bd810e23..441d3b73f 100755 --- a/src/drivers/infiniband/golan.c +++ b/src/drivers/infiniband/golan.c @@ -2642,7 +2642,10 @@ static struct pci_device_id golan_nics[] = { PCI_ROM ( 0x15b3, 0x1019, "ConnectX-5EX", "ConnectX-5EX HCA driver, DevID 4121", 0 ), PCI_ROM ( 0x15b3, 0x101b, "ConnectX-6", "ConnectX-6 HCA driver, DevID 4123", 0 ), PCI_ROM ( 0x15b3, 0x101d, "ConnectX-6DX", "ConnectX-6DX HCA driver, DevID 4125", 0 ), + PCI_ROM ( 0x15b3, 0x101f, "ConnectX-6Lx", "ConnectX-6LX HCA driver, DevID 4127", 0 ), + PCI_ROM ( 0x15b3, 0x1021, "ConnectX-7", "ConnectX-7 HCA driver, DevID 4129", 0 ), PCI_ROM ( 0x15b3, 0xa2d2, "BlueField", "BlueField integrated ConnectX-5 network controller HCA driver, DevID 41682", 0 ), + PCI_ROM ( 0x15b3, 0xa2d6, "BlueField-2", "BlueField-2 network controller HCA driver, DevID 41686", 0 ), }; struct pci_driver golan_driver __pci_driver = { -- cgit v1.2.3-55-g7522 From da491eaae721d49f2a1ff72a9c2c32119eb0de2c Mon Sep 17 00:00:00 2001 From: Martin Habets Date: Mon, 23 Nov 2020 08:07:13 +0000 Subject: [sfc] Update email addresses Email from solarflare.com will stop working, so update those. Remove email for Shradha Shah, as she is not involved with this any more. Update copyright notices for files touched. Signed-off-by: Michael Brown --- src/drivers/net/sfc/efx_common.c | 5 +++-- src/drivers/net/sfc/efx_hunt.c | 5 +++-- src/drivers/net/sfc/efx_hunt.h | 5 +++-- src/drivers/net/sfc/mcdi.h | 6 ++++-- src/drivers/net/sfc/sfc_hunt.c | 5 +++-- 5 files changed, 16 insertions(+), 10 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/net/sfc/efx_common.c b/src/drivers/net/sfc/efx_common.c index fd465612e..ad572b1da 100644 --- a/src/drivers/net/sfc/efx_common.c +++ b/src/drivers/net/sfc/efx_common.c @@ -2,11 +2,12 @@ * * Driver datapath common code for Solarflare network cards * - * Written by Shradha Shah + * Written by Shradha Shah, maintained by * * Copyright Fen Systems Ltd. 2005 * Copyright Level 5 Networks Inc. 2005 - * Copyright 2006-2017 Solarflare Communications Inc. + * Copyright 2006-2019 Solarflare Communications Inc. + * Copyright 2019-2020 Xilinx Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/drivers/net/sfc/efx_hunt.c b/src/drivers/net/sfc/efx_hunt.c index c846379af..0bce3e45a 100644 --- a/src/drivers/net/sfc/efx_hunt.c +++ b/src/drivers/net/sfc/efx_hunt.c @@ -2,9 +2,10 @@ * * Driver datapath for Solarflare network cards * - * Written by Shradha Shah + * Written by Shradha Shah, maintained by * - * Copyright 2012-2017 Solarflare Communications Inc. + * Copyright 2012-2019 Solarflare Communications Inc. + * Copyright 2019-2020 Xilinx Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/drivers/net/sfc/efx_hunt.h b/src/drivers/net/sfc/efx_hunt.h index b8377bf20..d6bb4659f 100644 --- a/src/drivers/net/sfc/efx_hunt.h +++ b/src/drivers/net/sfc/efx_hunt.h @@ -2,9 +2,10 @@ * * GPL net driver for Solarflare network cards * - * Written by Shradha Shah + * Written by Shradha Shah, maintained by * - * Copyright 2012-2017 Solarflare Communications Inc. + * Copyright 2012-2019 Solarflare Communications Inc. + * Copyright 2019-2020 Xilinx Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/drivers/net/sfc/mcdi.h b/src/drivers/net/sfc/mcdi.h index 19c62021a..2d26cded3 100644 --- a/src/drivers/net/sfc/mcdi.h +++ b/src/drivers/net/sfc/mcdi.h @@ -1,9 +1,11 @@ /**************************************************************************** * Driver for Solarflare network controllers and boards * - * Written by Martin Habets + * Written by Martin Habets , maintained + * by * - * Copyright 2012-2017 Solarflare Communications Inc. + * Copyright 2012-2019 Solarflare Communications Inc. + * Copyright 2019-2020 Xilinx Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/drivers/net/sfc/sfc_hunt.c b/src/drivers/net/sfc/sfc_hunt.c index 3c9a5fe38..a37670ae2 100644 --- a/src/drivers/net/sfc/sfc_hunt.c +++ b/src/drivers/net/sfc/sfc_hunt.c @@ -2,9 +2,10 @@ * * Device driver for Solarflare Communications EF10 devices * - * Written by Shradha Shah + * Written by Shradha Shah, maintained by * - * Copyright 2012-2017 Solarflare Communications Inc. + * Copyright 2012-2019 Solarflare Communications Inc. + * Copyright 2019-2020 Xilinx Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as -- cgit v1.2.3-55-g7522 From 017b345d5a3c9ba8cc10e2ca69b6c986b91e0668 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 3 Jan 2021 19:08:49 +0000 Subject: [xhci] Fail attempts to issue concurrent commands The xHCI driver can handle only a single command TRB in progress at any one time. Immediately fail any attempts to issue concurrent commands (which should not occur in normal operation). Signed-off-by: Michael Brown --- src/drivers/usb/xhci.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/drivers') diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index 7bc2e356e..7c8b2f21c 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -1813,6 +1813,13 @@ static int xhci_command ( struct xhci_device *xhci, union xhci_trb *trb ) { unsigned int i; int rc; + /* Sanity check */ + if ( xhci->pending != NULL ) { + DBGC ( xhci, "XHCI %s command ring busy\n", xhci->name ); + rc = -EBUSY; + goto err_pending; + } + /* Record the pending command */ xhci->pending = trb; @@ -1855,6 +1862,7 @@ static int xhci_command ( struct xhci_device *xhci, union xhci_trb *trb ) { err_enqueue: xhci->pending = NULL; + err_pending: return rc; } -- cgit v1.2.3-55-g7522 From 7ce3b8405002ac58c4c2d24b90a601b1802c1d83 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 3 Jan 2021 19:10:30 +0000 Subject: [xhci] Show meaningful error messages after command failures Ensure that any command failure messages are followed up with an error message indicating what the failed command was attempting to perform. Signed-off-by: Michael Brown --- src/drivers/usb/xhci.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index 7c8b2f21c..550097a81 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -1883,9 +1883,13 @@ static inline int xhci_nop ( struct xhci_device *xhci ) { nop->type = XHCI_TRB_NOP_CMD; /* Issue command and wait for completion */ - if ( ( rc = xhci_command ( xhci, &trb ) ) != 0 ) + if ( ( rc = xhci_command ( xhci, &trb ) ) != 0 ) { + DBGC ( xhci, "XHCI %s NOP failed: %s\n", + xhci->name, strerror ( rc ) ); return rc; + } + DBGC2 ( xhci, "XHCI %s NOP completed successfully\n", xhci->name ); return 0; } @@ -2063,15 +2067,18 @@ static inline int xhci_address_device ( struct xhci_device *xhci, /* Assign device address */ if ( ( rc = xhci_context ( xhci, slot, slot->endpoint[XHCI_CTX_EP0], XHCI_TRB_ADDRESS_DEVICE, - xhci_address_device_input ) ) != 0 ) + xhci_address_device_input ) ) != 0 ) { + DBGC ( xhci, "XHCI %s slot %d could not assign address: %s\n", + xhci->name, slot->id, strerror ( rc ) ); return rc; + } /* Get assigned address */ slot_ctx = ( slot->context + xhci_device_context_offset ( xhci, XHCI_CTX_SLOT ) ); usb->address = slot_ctx->address; - DBGC2 ( xhci, "XHCI %s assigned address %d to %s\n", - xhci->name, usb->address, usb->name ); + DBGC2 ( xhci, "XHCI %s slot %d assigned address %d to %s\n", + xhci->name, slot->id, usb->address, usb->name ); return 0; } @@ -2132,8 +2139,11 @@ static inline int xhci_configure_endpoint ( struct xhci_device *xhci, /* Configure endpoint */ if ( ( rc = xhci_context ( xhci, slot, endpoint, XHCI_TRB_CONFIGURE_ENDPOINT, - xhci_configure_endpoint_input ) ) != 0 ) + xhci_configure_endpoint_input ) ) != 0 ) { + DBGC ( xhci, "XHCI %s slot %d ctx %d could not configure: %s\n", + xhci->name, slot->id, endpoint->ctx, strerror ( rc ) ); return rc; + } DBGC2 ( xhci, "XHCI %s slot %d ctx %d configured\n", xhci->name, slot->id, endpoint->ctx ); @@ -2183,8 +2193,12 @@ static inline int xhci_deconfigure_endpoint ( struct xhci_device *xhci, /* Deconfigure endpoint */ if ( ( rc = xhci_context ( xhci, slot, endpoint, XHCI_TRB_CONFIGURE_ENDPOINT, - xhci_deconfigure_endpoint_input ) ) != 0 ) + xhci_deconfigure_endpoint_input ) ) != 0 ) { + DBGC ( xhci, "XHCI %s slot %d ctx %d could not deconfigure: " + "%s\n", xhci->name, slot->id, endpoint->ctx, + strerror ( rc ) ); return rc; + } DBGC2 ( xhci, "XHCI %s slot %d ctx %d deconfigured\n", xhci->name, slot->id, endpoint->ctx ); @@ -2238,8 +2252,12 @@ static inline int xhci_evaluate_context ( struct xhci_device *xhci, /* Configure endpoint */ if ( ( rc = xhci_context ( xhci, slot, endpoint, XHCI_TRB_EVALUATE_CONTEXT, - xhci_evaluate_context_input ) ) != 0 ) + xhci_evaluate_context_input ) ) != 0 ) { + DBGC ( xhci, "XHCI %s slot %d ctx %d could not (re-)evaluate: " + "%s\n", xhci->name, slot->id, endpoint->ctx, + strerror ( rc ) ); return rc; + } DBGC2 ( xhci, "XHCI %s slot %d ctx %d (re-)evaluated\n", xhci->name, slot->id, endpoint->ctx ); -- cgit v1.2.3-55-g7522 From c42f31bc8ad8ffce57b8662f902a343b1a4d3209 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 4 Jan 2021 09:37:59 +0000 Subject: [xhci] Avoid false positive Coverity warning Signed-off-by: Michael Brown --- src/drivers/usb/xhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/drivers') diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index 550097a81..cc48af033 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -1814,7 +1814,7 @@ static int xhci_command ( struct xhci_device *xhci, union xhci_trb *trb ) { int rc; /* Sanity check */ - if ( xhci->pending != NULL ) { + if ( xhci->pending ) { DBGC ( xhci, "XHCI %s command ring busy\n", xhci->name ); rc = -EBUSY; goto err_pending; -- cgit v1.2.3-55-g7522 From a5fb41873dc1dcce5dcc817bf53a0649c01f8cac Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Wed, 13 Jan 2021 15:58:59 -0500 Subject: [isa] Add missing #include Signed-off-by: Manuel Mendez Modified-by: Michael Brown Signed-off-by: Michael Brown --- src/drivers/bus/isa.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/drivers') diff --git a/src/drivers/bus/isa.c b/src/drivers/bus/isa.c index da0c43c60..6b360a44d 100644 --- a/src/drivers/bus/isa.c +++ b/src/drivers/bus/isa.c @@ -5,6 +5,7 @@ #include #include #include +#include FILE_LICENCE ( GPL2_OR_LATER ); -- cgit v1.2.3-55-g7522 From 8e3826aa10ee5b2d9f85d6177cc061260f3388df Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 15 Jan 2021 20:54:27 +0000 Subject: [build] Inhibit spurious array bounds warning on some versions of gcc Some versions of gcc (observed with gcc 9.3.0 on NixOS Linux) produce a spurious warning about an out-of-bounds array access for the isa_extra_probe_addrs[] array. Work around this compiler bug by redefining the array index as a signed long, which seems to somehow avoid this spurious warning. Debugged-by: Manuel Mendez Signed-off-by: Michael Brown --- src/drivers/bus/isa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/drivers') diff --git a/src/drivers/bus/isa.c b/src/drivers/bus/isa.c index 6b360a44d..94d4ce99b 100644 --- a/src/drivers/bus/isa.c +++ b/src/drivers/bus/isa.c @@ -95,7 +95,7 @@ static void isa_remove ( struct isa_device *isa ) { static int isabus_probe ( struct root_device *rootdev ) { struct isa_device *isa = NULL; struct isa_driver *driver; - int ioidx; + long ioidx; int rc; for_each_table_entry ( driver, ISA_DRIVERS ) { -- cgit v1.2.3-55-g7522 From b9de7e6eda04cecaff6735a60c7fe7f488fdccf1 Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Wed, 27 Jan 2021 00:43:51 +0100 Subject: [infiniband] Require drivers to specify the number of ports Require drivers to report the total number of Infiniband ports. This is necessary to report the correct number of ports on devices with dynamic port types. For example, dual-port Mellanox cards configured for (eth, ib) would be rejected by the subnet manager, because they report using "port 2, out of 1". Signed-off-by: Christian Iversen --- src/drivers/infiniband/arbel.c | 1 + src/drivers/infiniband/flexboot_nodnic.c | 1 + src/drivers/infiniband/golan.c | 1 + src/drivers/infiniband/hermon.c | 1 + src/drivers/infiniband/linda.c | 1 + src/drivers/infiniband/qib7322.c | 1 + src/include/ipxe/infiniband.h | 3 ++- src/net/infiniband.c | 20 -------------------- src/net/infiniband/ib_sma.c | 2 +- 9 files changed, 9 insertions(+), 22 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/arbel.c b/src/drivers/infiniband/arbel.c index fb48487f3..fbef3f8a6 100644 --- a/src/drivers/infiniband/arbel.c +++ b/src/drivers/infiniband/arbel.c @@ -3061,6 +3061,7 @@ static int arbel_probe ( struct pci_device *pci ) { ibdev->op = &arbel_ib_operations; ibdev->dev = &pci->dev; ibdev->port = ( ARBEL_PORT_BASE + i ); + ibdev->ports = ARBEL_NUM_PORTS; ib_set_drvdata ( ibdev, arbel ); } diff --git a/src/drivers/infiniband/flexboot_nodnic.c b/src/drivers/infiniband/flexboot_nodnic.c index 54b858406..c6e19b955 100644 --- a/src/drivers/infiniband/flexboot_nodnic.c +++ b/src/drivers/infiniband/flexboot_nodnic.c @@ -1165,6 +1165,7 @@ flexboot_nodnic_allocate_infiniband_devices( struct flexboot_nodnic *flexboot_no ibdev->op = &flexboot_nodnic_ib_operations; ibdev->dev = &pci->dev; ibdev->port = ( FLEXBOOT_NODNIC_PORT_BASE + i); + ibdev->ports = device_priv->device_cap.num_ports; ib_set_drvdata(ibdev, flexboot_nodnic_priv); } return status; diff --git a/src/drivers/infiniband/golan.c b/src/drivers/infiniband/golan.c index 441d3b73f..2f1ab2357 100755 --- a/src/drivers/infiniband/golan.c +++ b/src/drivers/infiniband/golan.c @@ -2386,6 +2386,7 @@ static int golan_probe_normal ( struct pci_device *pci ) { ibdev->op = &golan_ib_operations; ibdev->dev = &pci->dev; ibdev->port = (GOLAN_PORT_BASE + i); + ibdev->ports = golan->caps.num_ports; ib_set_drvdata( ibdev, golan ); } diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index fdf2d9dd8..7537d83c2 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -3829,6 +3829,7 @@ static int hermon_probe ( struct pci_device *pci ) { ibdev->op = &hermon_ib_operations; ibdev->dev = &pci->dev; ibdev->port = ( HERMON_PORT_BASE + i ); + ibdev->ports = hermon->cap.num_ports; ib_set_drvdata ( ibdev, hermon ); } diff --git a/src/drivers/infiniband/linda.c b/src/drivers/infiniband/linda.c index b275268a2..8c5912660 100644 --- a/src/drivers/infiniband/linda.c +++ b/src/drivers/infiniband/linda.c @@ -2330,6 +2330,7 @@ static int linda_probe ( struct pci_device *pci ) { ibdev->op = &linda_ib_operations; ibdev->dev = &pci->dev; ibdev->port = 1; + ibdev->ports = 1; /* Fix up PCI device */ adjust_pci_device ( pci ); diff --git a/src/drivers/infiniband/qib7322.c b/src/drivers/infiniband/qib7322.c index e3250147d..a4b51db05 100644 --- a/src/drivers/infiniband/qib7322.c +++ b/src/drivers/infiniband/qib7322.c @@ -2348,6 +2348,7 @@ static int qib7322_probe ( struct pci_device *pci ) { ibdev->dev = &pci->dev; ibdev->op = &qib7322_ib_operations; ibdev->port = ( QIB7322_PORT_BASE + i ); + ibdev->ports = QIB7322_MAX_PORTS; ibdev->link_width_enabled = ibdev->link_width_supported = IB_LINK_WIDTH_4X; /* 1x does not work */ ibdev->link_speed_enabled = ibdev->link_speed_supported = diff --git a/src/include/ipxe/infiniband.h b/src/include/ipxe/infiniband.h index 6f4951f17..379bc109e 100644 --- a/src/include/ipxe/infiniband.h +++ b/src/include/ipxe/infiniband.h @@ -416,6 +416,8 @@ struct ib_device { struct ib_device_operations *op; /** Port number */ unsigned int port; + /** Total ports on device */ + unsigned int ports; /** Port open request counter */ unsigned int open_count; @@ -538,7 +540,6 @@ extern int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp, union ib_gid *gid ); extern void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp, union ib_gid *gid ); -extern int ib_count_ports ( struct ib_device *ibdev ); extern int ib_set_port_info ( struct ib_device *ibdev, union ib_mad *mad ); extern int ib_set_pkey_table ( struct ib_device *ibdev, union ib_mad *mad ); extern struct ib_device * alloc_ibdev ( size_t priv_size ); diff --git a/src/net/infiniband.c b/src/net/infiniband.c index 3b79a660c..e19e121c1 100644 --- a/src/net/infiniband.c +++ b/src/net/infiniband.c @@ -813,26 +813,6 @@ void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp, *************************************************************************** */ -/** - * Count Infiniband HCA ports - * - * @v ibdev Infiniband device - * @ret num_ports Number of ports - */ -int ib_count_ports ( struct ib_device *ibdev ) { - struct ib_device *tmp; - int num_ports = 0; - - /* Search for IB devices with the same physical device to - * identify port count. - */ - for_each_ibdev ( tmp ) { - if ( tmp->dev == ibdev->dev ) - num_ports++; - } - return num_ports; -} - /** * Set port information * diff --git a/src/net/infiniband/ib_sma.c b/src/net/infiniband/ib_sma.c index 24ec9f4e0..b553e66b1 100644 --- a/src/net/infiniband/ib_sma.c +++ b/src/net/infiniband/ib_sma.c @@ -63,7 +63,7 @@ static void ib_sma_node_info ( struct ib_device *ibdev, node_info->base_version = IB_MGMT_BASE_VERSION; node_info->class_version = IB_SMP_CLASS_VERSION; node_info->node_type = IB_NODE_TYPE_HCA; - node_info->num_ports = ib_count_ports ( ibdev ); + node_info->num_ports = ibdev->ports; memcpy ( &node_info->sys_guid, &ibdev->node_guid, sizeof ( node_info->sys_guid ) ); memcpy ( &node_info->node_guid, &ibdev->node_guid, -- cgit v1.2.3-55-g7522 From 414c842f06038e1979e4fcb5bc7b718e7dad6ca4 Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Mon, 4 May 2020 15:45:11 +0200 Subject: [hermon] Clean up whitespace in MT25408_PRM.h header Signed-off-by: Christian Iversen --- src/drivers/infiniband/MT25408_PRM.h | 264 +++++++++++++++++------------------ 1 file changed, 132 insertions(+), 132 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/MT25408_PRM.h b/src/drivers/infiniband/MT25408_PRM.h index cc248daf9..f8c19ce72 100644 --- a/src/drivers/infiniband/MT25408_PRM.h +++ b/src/drivers/infiniband/MT25408_PRM.h @@ -47,7 +47,7 @@ struct hermonprm_ud_address_vector_st { /* Little Endian */ pseudo_bit_t reserved1[0x00008]; /* -------------- */ pseudo_bit_t hop_limit[0x00008]; /* IPv6 hop limit */ - pseudo_bit_t max_stat_rate[0x00004];/* Maximum static rate control. + pseudo_bit_t max_stat_rate[0x00004];/* Maximum static rate control. 0 - 4X injection rate 1 - 1X injection rate other - reserved @@ -72,7 +72,7 @@ struct hermonprm_ud_address_vector_st { /* Little Endian */ /* -------------- */ pseudo_bit_t rgid_31_0[0x00020]; /* Remote GID[31:0] if G bit is set. Must be set to 0x2 if G bit is cleared. */ /* -------------- */ -}; +}; /* Send doorbell */ @@ -87,7 +87,7 @@ struct hermonprm_send_doorbell_st { /* Little Endian */ pseudo_bit_t reserved1[0x00002]; pseudo_bit_t qpn[0x00018]; /* QP number this doorbell is rung on */ /* -------------- */ -}; +}; /* Send wqe segment data inline */ @@ -101,7 +101,7 @@ struct hermonprm_wqe_segment_data_inline_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved2[0x00040]; /* -------------- */ -}; +}; /* Send wqe segment data ptr */ @@ -115,7 +115,7 @@ struct hermonprm_wqe_segment_data_ptr_st { /* Little Endian */ /* -------------- */ pseudo_bit_t local_address_l[0x00020]; /* -------------- */ -}; +}; /* Send wqe segment rd */ @@ -127,7 +127,7 @@ struct hermonprm_local_invalidate_segment_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved2[0x000a0]; /* -------------- */ -}; +}; /* Fast_Registration_Segment ####michal - doesn't match PRM (fields were added, see below) new table size in bytes - 0x30 */ @@ -157,7 +157,7 @@ struct hermonprm_fast_registration_segment_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reg_len_l[0x00020]; /* Region Length[31:0] */ /* -------------- */ -}; +}; /* Send wqe segment atomic */ @@ -170,7 +170,7 @@ struct hermonprm_wqe_segment_atomic_st { /* Little Endian */ /* -------------- */ pseudo_bit_t compare_l[0x00020]; /* -------------- */ -}; +}; /* Send wqe segment remote address */ @@ -183,7 +183,7 @@ struct hermonprm_wqe_segment_remote_address_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved0[0x00020]; /* -------------- */ -}; +}; /* end wqe segment bind */ @@ -213,7 +213,7 @@ struct hermonprm_wqe_segment_bind_st { /* Little Endian */ /* -------------- */ pseudo_bit_t length_l[0x00020]; /* -------------- */ -}; +}; /* Send wqe segment ud */ @@ -227,7 +227,7 @@ struct hermonprm_wqe_segment_ud_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x00040]; /* -------------- */ -}; +}; /* Send wqe segment rd */ @@ -239,7 +239,7 @@ struct hermonprm_wqe_segment_rd_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x00040]; /* -------------- */ -}; +}; /* Send wqe segment ctrl */ @@ -263,7 +263,7 @@ struct hermonprm_wqe_segment_ctrl_send_st { /* Little Endian */ /* -------------- */ pseudo_bit_t immediate[0x00020]; /* If the OpCode encodes an operation with Immediate (RDMA-write/SEND), This field will hold the Immediate data to be sent. If the OpCode encodes send and invalidate operations, this field holds the Invalidation key to be inserted into the packet; otherwise, this field is reserved. */ /* -------------- */ -}; +}; /* Address Path # ###michal - match to PRM */ @@ -280,19 +280,19 @@ struct hermonprm_address_path_st { /* Little Endian */ pseudo_bit_t reserved1[0x00008]; /* -------------- */ pseudo_bit_t hop_limit[0x00008]; /* IPv6 hop limit */ - pseudo_bit_t max_stat_rate[0x00004];/* Maximum static rate control. - 0 - 100% injection rate + pseudo_bit_t max_stat_rate[0x00004];/* Maximum static rate control. + 0 - 100% injection rate 1 - 25% injection rate 2 - 12.5% injection rate 3 - 50% injection rate - 7: 2.5 Gb/s. - 8: 10 Gb/s. - 9: 30 Gb/s. - 10: 5 Gb/s. + 7: 2.5 Gb/s. + 8: 10 Gb/s. + 9: 30 Gb/s. + 10: 5 Gb/s. 11: 20 Gb/s. - 12: 40 Gb/s. - 13: 60 Gb/s. - 14: 80 Gb/s. + 12: 40 Gb/s. + 13: 60 Gb/s. + 14: 80 Gb/s. 15: 120 Gb/s. */ pseudo_bit_t reserved2[0x00004]; pseudo_bit_t mgid_index[0x00007]; /* Index to port GID table */ @@ -328,7 +328,7 @@ struct hermonprm_address_path_st { /* Little Endian */ /* -------------- */ pseudo_bit_t dmac_31_0[0x00020]; /* -------------- */ -}; +}; /* HCA Command Register (HCR) #### michal - match PRM */ @@ -359,7 +359,7 @@ struct hermonprm_hca_command_register_st { /* Little Endian */ pseudo_bit_t status[0x00008]; /* Command execution status report. Valid only if command interface in under SW ownership (Go bit is cleared) 0 - command completed without error. If different than zero, command execution completed with error. Syndrom encoding is depended on command executed and is defined for each command */ /* -------------- */ -}; +}; /* CQ Doorbell */ @@ -373,14 +373,14 @@ struct hermonprm_cq_cmd_doorbell_st { /* Little Endian */ Other - Reserved */ pseudo_bit_t reserved0[0x00001]; pseudo_bit_t cmd_sn[0x00002]; /* Command Sequence Number - This field should be incremented upon receiving completion notification of the respective CQ. - This transition is done by ringing Request notification for next Solicited, Request notification for next Solicited or Unsolicited + This transition is done by ringing Request notification for next Solicited, Request notification for next Solicited or Unsolicited completion or Request notification for multiple completions doorbells after receiving completion notification. This field is initialized to Zero */ pseudo_bit_t reserved1[0x00002]; /* -------------- */ pseudo_bit_t cq_param[0x00020]; /* parameter to be used by CQ command */ /* -------------- */ -}; +}; /* RD-send doorbell */ @@ -394,7 +394,7 @@ struct hermonprm_rd_send_doorbell_st { /* Little Endian */ /* -------------- */ struct hermonprm_send_doorbell_st send_doorbell;/* Send Parameters */ /* -------------- */ -}; +}; /* Multicast Group Member QP #### michal - match PRM */ @@ -404,7 +404,7 @@ struct hermonprm_mgmqp_st { /* Little Endian */ pseudo_bit_t blck_lb[0x00001]; /* Block self-loopback messages arriving to this qp */ pseudo_bit_t qi[0x00001]; /* Qi: QPN_i is valid */ /* -------------- */ -}; +}; /* vsd */ @@ -521,7 +521,7 @@ struct hermonprm_vsd_st { /* Little Endian */ /* -------------- */ pseudo_bit_t vsd_dw55[0x00020]; /* -------------- */ -}; +}; /* UAR Parameters */ @@ -535,7 +535,7 @@ struct hermonprm_uar_params_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved2[0x000a0]; /* -------------- */ -}; +}; /* Translation and Protection Tables Parameters */ @@ -552,7 +552,7 @@ struct hermonprm_tptparams_st { /* Little Endian */ /* -------------- */ pseudo_bit_t log_dmpt_sz[0x00006]; /* Log (base 2) of the number of region/windows entries in the dMPT table. */ pseudo_bit_t reserved0[0x00002]; - pseudo_bit_t pfto[0x00005]; /* Page Fault RNR Timeout - + pseudo_bit_t pfto[0x00005]; /* Page Fault RNR Timeout - The field returned in RNR Naks generated when a page fault is detected. It has no effect when on-demand-paging is not used. */ pseudo_bit_t reserved1[0x00013]; @@ -575,7 +575,7 @@ struct hermonprm_tptparams_st { /* Little Endian */ Entry size is 64 bytes. Table must be aligned to its size. */ /* -------------- */ -}; +}; /* Multicast Support Parameters #### michal - match PRM */ @@ -584,14 +584,14 @@ struct hermonprm_multicastparam_st { /* Little Endian */ The base address must be aligned to the entry size. Address may be set to 0xFFFFFFFF if multicast is not supported. */ /* -------------- */ - pseudo_bit_t mc_base_addr_l[0x00020];/* Base Address of the Multicast Table [31:0]. + pseudo_bit_t mc_base_addr_l[0x00020];/* Base Address of the Multicast Table [31:0]. The base address must be aligned to the entry size. Address may be set to 0xFFFFFFFF if multicast is not supported. */ /* -------------- */ pseudo_bit_t reserved0[0x00040]; /* -------------- */ pseudo_bit_t log_mc_table_entry_sz[0x00005];/* Log2 of the Size of multicast group member (MGM) entry. - Must be greater than 5 (to allow CTRL and GID sections). + Must be greater than 5 (to allow CTRL and GID sections). That implies the number of QPs per MC table entry. */ pseudo_bit_t reserved1[0x0000b]; pseudo_bit_t reserved2[0x00010]; @@ -611,7 +611,7 @@ struct hermonprm_multicastparam_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved6[0x00020]; /* -------------- */ -}; +}; /* QPC/EEC/CQC/EQC/RDB Parameters #### michal - doesn't match PRM (field name are differs. see below) */ @@ -679,12 +679,12 @@ struct hermonprm_qpcbaseaddr_st { /* Little Endian */ /* -------------- */ pseudo_bit_t log_num_rd[0x00003]; /* Log (base 2) of the maximum number of RdmaRdC entries per QP. This denotes the maximum number of outstanding reads/atomics as a responder. */ pseudo_bit_t reserved7[0x00002]; - pseudo_bit_t rdmardc_base_addr_l[0x0001b];/* rdmardc_base_addr_l: Base address of table that holds remote read and remote atomic requests [31:0]. + pseudo_bit_t rdmardc_base_addr_l[0x0001b];/* rdmardc_base_addr_l: Base address of table that holds remote read and remote atomic requests [31:0]. Table must be aligned to RDB entry size (32 bytes). */ /* -------------- */ pseudo_bit_t reserved8[0x00040]; /* -------------- */ -}; +}; /* Header_Log_Register */ @@ -693,7 +693,7 @@ struct hermonprm_header_log_register_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved0[0x00060]; /* -------------- */ -}; +}; /* Performance Monitors */ @@ -725,7 +725,7 @@ struct hermonprm_performance_monitors_st { /* Little Endian */ /* -------------- */ pseudo_bit_t event_counter2[0x00020];/* Read/write event counter, counting events specified by EvCntl and EvCnt2 fields repsectively. When the event counter reaches is maximum value of 0xFFFFFF, the next event will cause it to roll over to zero, set F1 or F2 bit respectively and generate interrupt by I1 I2 bit respectively. */ /* -------------- */ -}; +}; /* MLX WQE segment format */ @@ -751,7 +751,7 @@ struct hermonprm_wqe_segment_ctrl_mlx_st { /* Little Endian */ pseudo_bit_t reserved5[0x00010]; pseudo_bit_t rlid[0x00010]; /* Destination LID (must match given headers) */ /* -------------- */ -}; +}; /* Send WQE segment format */ @@ -780,7 +780,7 @@ struct hermonprm_send_wqe_segment_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x00200]; /* -------------- */ -}; +}; /* QP and EE Context Entry */ @@ -833,7 +833,7 @@ struct hermonprm_queue_pair_ee_context_entry_st { /* Little Endian */ 0x3 - 1024 0x4 - 2048 other - reserved - + Should be configured to 0x4 for UD and MLX QPs. */ /* -------------- */ pseudo_bit_t usr_page[0x00018]; /* UAR number to ring doorbells for this QP (aliased to doorbell and Blue Flame pages) */ @@ -883,7 +883,7 @@ struct hermonprm_queue_pair_ee_context_entry_st { /* Little Endian */ pseudo_bit_t reserved24[0x00008]; /* -------------- */ pseudo_bit_t reserved25[0x00004]; - pseudo_bit_t ric[0x00001]; /* Invalid Credits. + pseudo_bit_t ric[0x00001]; /* Invalid Credits. 1 - place "Invalid Credits" to ACKs sent from this queue. 0 - ACKs report the actual number of end to end credits on the connection. Not valid (reserved) in EE context. @@ -895,12 +895,12 @@ struct hermonprm_queue_pair_ee_context_entry_st { /* Little Endian */ pseudo_bit_t rwe[0x00001]; /* If set - RDMA - write enabled on receive queue. Not valid (reserved) in EE context. */ pseudo_bit_t rre[0x00001]; /* If set - RDMA - read enabled on receive queue. Not valid (reserved) in EE context. */ pseudo_bit_t reserved28[0x00005]; - pseudo_bit_t rra_max[0x00003]; /* Maximum number of outstanding RDMA-read/Atomic operations allowed on receive queue is 2^RRA_Max. + pseudo_bit_t rra_max[0x00003]; /* Maximum number of outstanding RDMA-read/Atomic operations allowed on receive queue is 2^RRA_Max. Must be 0 for EE context. */ pseudo_bit_t physical_function[0x00008]; /* -------------- */ pseudo_bit_t next_rcv_psn[0x00018]; /* Next (expected) PSN on receive */ - pseudo_bit_t min_rnr_nak[0x00005]; /* Minimum RNR NAK timer value (TTTTT field encoding according to the IB spec Vol1 9.7.5.2.8). + pseudo_bit_t min_rnr_nak[0x00005]; /* Minimum RNR NAK timer value (TTTTT field encoding according to the IB spec Vol1 9.7.5.2.8). Not valid (reserved) in EE context. */ pseudo_bit_t reserved30[0x00003]; /* -------------- */ @@ -919,7 +919,7 @@ struct hermonprm_queue_pair_ee_context_entry_st { /* Little Endian */ On send datagrams, if Q_Key[31] specified in the WQE is set, then this Q_Key will be transmitted in the outgoing message. Not valid (reserved) in EE context. */ /* -------------- */ - pseudo_bit_t srqn[0x00018]; /* SRQN - Shared Receive Queue Number - specifies the SRQ number from which the QP dequeues receive descriptors. + pseudo_bit_t srqn[0x00018]; /* SRQN - Shared Receive Queue Number - specifies the SRQ number from which the QP dequeues receive descriptors. SRQN is valid only if SRQ bit is set. Not valid (reserved) in EE context. */ pseudo_bit_t srq[0x00001]; /* SRQ - Shared Receive Queue. If this bit is set, then the QP is associated with a SRQ. Not valid (reserved) in EE context. */ pseudo_bit_t reserved34[0x00007]; @@ -983,7 +983,7 @@ struct hermonprm_queue_pair_ee_context_entry_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved48[0x000c0]; /* -------------- */ -}; +}; /* */ @@ -993,21 +993,21 @@ struct hermonprm_mcg_qp_dw_st { /* Little Endian */ pseudo_bit_t blck_lb[0x00001]; pseudo_bit_t reserved1[0x00001]; /* -------------- */ -}; +}; /* Clear Interrupt [63:0] #### michal - match to PRM */ struct hermonprm_clr_int_st { /* Little Endian */ pseudo_bit_t clr_int_h[0x00020]; /* Clear Interrupt [63:32] - Write transactions to this register will clear (de-assert) the virtual interrupt output pins of InfiniHost-III-EX. The value to be written in this register is obtained by executing QUERY_ADAPTER command on command interface after system boot. + Write transactions to this register will clear (de-assert) the virtual interrupt output pins of InfiniHost-III-EX. The value to be written in this register is obtained by executing QUERY_ADAPTER command on command interface after system boot. This register is write-only. Reading from this register will cause undefined result */ /* -------------- */ pseudo_bit_t clr_int_l[0x00020]; /* Clear Interrupt [31:0] - Write transactions to this register will clear (de-assert) the virtual interrupt output pins of InfiniHost-III-EX. The value to be written in this register is obtained by executing QUERY_ADAPTER command on command interface after system boot. + Write transactions to this register will clear (de-assert) the virtual interrupt output pins of InfiniHost-III-EX. The value to be written in this register is obtained by executing QUERY_ADAPTER command on command interface after system boot. This register is write-only. Reading from this register will cause undefined result */ /* -------------- */ -}; +}; /* EQ Set CI DBs Table */ @@ -1268,7 +1268,7 @@ struct hermonprm_eq_set_ci_table_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved63[0x00020]; /* -------------- */ -}; +}; /* InfiniHost-III-EX Configuration Registers #### michal - match to PRM */ @@ -1279,7 +1279,7 @@ struct hermonprm_configuration_registers_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x3fcb20]; /* -------------- */ -}; +}; /* QP_DB_Record ### michal = gdror fixed */ @@ -1287,7 +1287,7 @@ struct hermonprm_qp_db_record_st { /* Little Endian */ pseudo_bit_t receive_wqe_counter[0x00010];/* Modulo-64K counter of WQEs posted to the QP since its creation. Should be initialized to zero. */ pseudo_bit_t reserved0[0x00010]; /* -------------- */ -}; +}; /* CQ_ARM_DB_Record */ @@ -1303,7 +1303,7 @@ struct hermonprm_cq_arm_db_record_st { /* Little Endian */ pseudo_bit_t res[0x00003]; /* Must be 0x2 */ pseudo_bit_t cq_number[0x00018]; /* CQ number */ /* -------------- */ -}; +}; /* CQ_CI_DB_Record */ @@ -1314,7 +1314,7 @@ struct hermonprm_cq_ci_db_record_st { /* Little Endian */ pseudo_bit_t res[0x00003]; /* Must be 0x1 */ pseudo_bit_t cq_number[0x00018]; /* CQ number */ /* -------------- */ -}; +}; /* Virtual_Physical_Mapping */ @@ -1330,7 +1330,7 @@ struct hermonprm_virtual_physical_mapping_st { /* Little Endian */ pseudo_bit_t reserved1[0x00006]; pseudo_bit_t pa_l[0x00014]; /* Physical Address[31:12] */ /* -------------- */ -}; +}; /* MOD_STAT_CFG #### michal - gdror fix */ @@ -1518,7 +1518,7 @@ struct hermonprm_srq_context_st { /* Little Endian */ pseudo_bit_t reserved10[0x00002]; pseudo_bit_t db_record_addr_l[0x0001e];/* SRQ DB Record physical address [31:2] */ /* -------------- */ -}; +}; /* PBL */ @@ -1539,7 +1539,7 @@ struct hermonprm_pbl_st { /* Little Endian */ /* -------------- */ pseudo_bit_t mtt_3_l[0x00020]; /* Fourth MTT[31:0] */ /* -------------- */ -}; +}; /* Performance Counters #### michal - gdror fixed */ @@ -1554,7 +1554,7 @@ struct hermonprm_performance_counters_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved4[0x00620]; /* -------------- */ -}; +}; /* Transport and CI Error Counters */ @@ -1575,10 +1575,10 @@ struct hermonprm_transport_and_ci_error_counters_st { /* Little Endian */ /* -------------- */ pseudo_bit_t sq_num_lpe[0x00020]; /* Requester - number of local protection errors */ /* -------------- */ - pseudo_bit_t rq_num_wrfe[0x00020]; /* Responder - number of CQEs with error. + pseudo_bit_t rq_num_wrfe[0x00020]; /* Responder - number of CQEs with error. Incremented each time a CQE with error is generated */ /* -------------- */ - pseudo_bit_t sq_num_wrfe[0x00020]; /* Requester - number of CQEs with error. + pseudo_bit_t sq_num_wrfe[0x00020]; /* Requester - number of CQEs with error. Incremented each time a CQE with error is generated */ /* -------------- */ pseudo_bit_t reserved0[0x00020]; @@ -1698,7 +1698,7 @@ struct hermonprm_transport_and_ci_error_counters_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved12[0x002a0]; /* -------------- */ -}; +}; /* Event_data Field - HCR Completion Event #### michal - match PRM */ @@ -1717,7 +1717,7 @@ struct hermonprm_hcr_completion_event_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved3[0x00020]; /* -------------- */ -}; +}; /* Completion with Error CQE #### michal - gdror fixed */ @@ -1732,7 +1732,7 @@ struct hermonprm_completion_with_error_st { /* Little Endian */ 0x02 - Local QP Operation Error 0x03 - Local EE Context Operation Error 0x04 - Local Protection Error - 0x05 - Work Request Flushed Error + 0x05 - Work Request Flushed Error 0x06 - Memory Window Bind Error 0x10 - Bad Response Error 0x11 - Local Access Error @@ -1752,7 +1752,7 @@ struct hermonprm_completion_with_error_st { /* Little Endian */ pseudo_bit_t wqe_counter[0x00010]; /* -------------- */ pseudo_bit_t opcode[0x00005]; /* The opcode of WQE completion is reported for. - + The following values are reported in case of completion with error: 0xFE - For completion with error on Receive Queues 0xFF - For completion with error on Send Queues */ @@ -1761,7 +1761,7 @@ struct hermonprm_completion_with_error_st { /* Little Endian */ pseudo_bit_t owner[0x00001]; /* HW Flips this bit for every CQ warp around. Initialized to Zero. */ pseudo_bit_t reserved3[0x00018]; /* -------------- */ -}; +}; /* Resize CQ Input Mailbox */ @@ -1790,7 +1790,7 @@ struct hermonprm_resize_cq_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved10[0x00100]; /* -------------- */ -}; +}; /* MAD_IFC Input Modifier */ @@ -1802,14 +1802,14 @@ struct hermonprm_mad_ifc_input_modifier_st { /* Little Endian */ pseudo_bit_t rlid[0x00010]; /* Remote (source) LID from the received MAD. This field is required for trap generation upon MKey/BKey validation. */ /* -------------- */ -}; +}; /* MAD_IFC Input Mailbox ###michal -gdror fixed */ struct hermonprm_mad_ifc_st { /* Little Endian */ pseudo_bit_t request_mad_packet[64][0x00020];/* Request MAD Packet (256bytes) */ /* -------------- */ - pseudo_bit_t my_qpn[0x00018]; /* Destination QP number from the received MAD. + pseudo_bit_t my_qpn[0x00018]; /* Destination QP number from the received MAD. This field is reserved if Mad_extended_info indication in the input modifier is clear. */ pseudo_bit_t reserved0[0x00008]; /* -------------- */ @@ -1822,25 +1822,25 @@ struct hermonprm_mad_ifc_st { /* Little Endian */ pseudo_bit_t reserved3[0x00010]; pseudo_bit_t ml_path[0x00007]; /* My (destination) LID path bits from the received MAD. This field is reserved if Mad_extended_info indication in the input modifier is clear. */ - pseudo_bit_t g[0x00001]; /* If set, the GRH field in valid. + pseudo_bit_t g[0x00001]; /* If set, the GRH field in valid. This field is reserved if Mad_extended_info indication in the input modifier is clear. */ pseudo_bit_t reserved4[0x00004]; pseudo_bit_t sl[0x00004]; /* Service Level of the received MAD. This field is reserved if Mad_extended_info indication in the input modifier is clear. */ /* -------------- */ - pseudo_bit_t pkey_indx[0x00010]; /* Index in PKey table that matches PKey of the received MAD. + pseudo_bit_t pkey_indx[0x00010]; /* Index in PKey table that matches PKey of the received MAD. This field is reserved if Mad_extended_info indication in the input modifier is clear. */ pseudo_bit_t reserved5[0x00010]; /* -------------- */ pseudo_bit_t reserved6[0x00160]; /* -------------- */ - pseudo_bit_t grh[10][0x00020]; /* The GRH field of the MAD packet that was scattered to the first 40 bytes pointed to by the scatter list. - Valid if Mad_extended_info bit (in the input modifier) and g bit are set. + pseudo_bit_t grh[10][0x00020]; /* The GRH field of the MAD packet that was scattered to the first 40 bytes pointed to by the scatter list. + Valid if Mad_extended_info bit (in the input modifier) and g bit are set. Otherwise this field is reserved. */ /* -------------- */ pseudo_bit_t reserved7[0x004c0]; /* -------------- */ -}; +}; /* Query Debug Message #### michal - gdror fixed */ @@ -1899,7 +1899,7 @@ struct hermonprm_query_debug_msg_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved4[0x003c0]; /* -------------- */ -}; +}; /* User Access Region */ @@ -1914,7 +1914,7 @@ struct hermonprm_uar_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x03ec0]; /* -------------- */ -}; +}; /* Receive doorbell */ @@ -1928,7 +1928,7 @@ struct hermonprm_receive_doorbell_st { /* Little Endian */ pseudo_bit_t reserved3[0x00002]; pseudo_bit_t qpn[0x00018]; /* QP number or SRQ number this doorbell is rung on */ /* -------------- */ -}; +}; /* SET_IB Parameters */ @@ -1949,7 +1949,7 @@ struct hermonprm_set_ib_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved2[0x00180]; /* -------------- */ -}; +}; /* Multicast Group Member #### michal - gdror fixed */ @@ -1989,7 +1989,7 @@ struct hermonprm_mgm_entry_st { /* Little Endian */ /* -------------- */ struct hermonprm_mgmqp_st mgmqp_7; /* Multicast Group Member QP */ /* -------------- */ -}; +}; /* INIT_PORT Parameters #### michal - match PRM */ @@ -2041,7 +2041,7 @@ struct hermonprm_init_port_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved5[0x006c0]; /* -------------- */ -}; +}; /* Query Device Capablities #### michal - gdror fixed */ @@ -2267,7 +2267,7 @@ struct hermonprm_query_dev_cap_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved46[0x002c0]; /* -------------- */ -}; +}; /* QUERY_ADAPTER Parameters Block #### michal - gdror fixed */ @@ -2281,7 +2281,7 @@ struct hermonprm_query_adapter_st { /* Little Endian */ /* -------------- */ struct hermonprm_vsd_st vsd; /* ###michal- this field was replaced by 2 fields : vsd .1664; vsd(continued/psid .128; */ /* -------------- */ -}; +}; /* QUERY_FW Parameters Block #### michal - doesn't match PRM */ @@ -2298,7 +2298,7 @@ struct hermonprm_query_fw_st { /* Little Endian */ pseudo_bit_t log_max_outstanding_cmd[0x00008];/* Log2 of the maximum number of commands the HCR can support simultaneously */ pseudo_bit_t reserved1[0x00017]; pseudo_bit_t dt[0x00001]; /* Debug Trace Support - 0 - Debug trace is not supported + 0 - Debug trace is not supported 1 - Debug trace is supported */ /* -------------- */ pseudo_bit_t reserved2[0x00001]; @@ -2346,7 +2346,7 @@ struct hermonprm_query_fw_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved8[0x00600]; /* -------------- */ -}; +}; /* Memory Access Parameters for UD Address Vector Table */ @@ -2358,7 +2358,7 @@ struct hermonprm_udavtable_memory_parameters_st { /* Little Endian */ pseudo_bit_t xlation_en[0x00001]; /* When cleared, address is physical address and no translation will be done. When set, address is virtual. */ pseudo_bit_t reserved1[0x00002]; /* -------------- */ -}; +}; /* INIT_HCA & QUERY_HCA Parameters Block ####michal-doesn't match PRM (see differs below) new size in bytes:0x300 */ @@ -2407,7 +2407,7 @@ struct hermonprm_init_hca_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved10[0x00600]; /* -------------- */ -}; +}; /* Event Queue Context Table Entry #### michal - gdror fixed */ @@ -2454,19 +2454,19 @@ struct hermonprm_eqc_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved12[0x00040]; /* -------------- */ - pseudo_bit_t consumer_counter[0x00018];/* Consumer counter. The counter is incremented for each EQE polled from the EQ. - Must be 0x0 in EQ initialization. + pseudo_bit_t consumer_counter[0x00018];/* Consumer counter. The counter is incremented for each EQE polled from the EQ. + Must be 0x0 in EQ initialization. Maintained by HW (valid for the QUERY_EQ command only). */ pseudo_bit_t reserved13[0x00008]; /* -------------- */ - pseudo_bit_t producer_counter[0x00018];/* Producer Coutner. The counter is incremented for each EQE that is written by the HW to the EQ. + pseudo_bit_t producer_counter[0x00018];/* Producer Coutner. The counter is incremented for each EQE that is written by the HW to the EQ. EQ overrun is reported if Producer_counter + 1 equals to Consumer_counter and a EQE needs to be added. Maintained by HW (valid for the QUERY_EQ command only) */ pseudo_bit_t reserved14[0x00008]; /* -------------- */ pseudo_bit_t reserved15[0x00080]; /* -------------- */ -}; +}; /* Memory Translation Table (MTT) Entry #### michal - match to PRM */ @@ -2477,7 +2477,7 @@ struct hermonprm_mtt_st { /* Little Endian */ pseudo_bit_t reserved0[0x00002]; pseudo_bit_t ptag_l[0x0001d]; /* Low-order bits of Physical tag. The size of the field depends on the page size of the region. Maximum PTAG size is 52 bits. */ /* -------------- */ -}; +}; /* Memory Protection Table (MPT) Entry ### doesn't match PRM (new fields were added). new size in bytes : 0x54 */ @@ -2547,7 +2547,7 @@ struct hermonprm_mpt_st { /* Little Endian */ pseudo_bit_t mtt_fbo[0x00015]; /* First byte offset in the zero-based region - the first byte within the first block/page start address refers to. When mtt_rep is being used, fbo points within the replicated block (i.e. block-size x 2^mtt_rep) */ pseudo_bit_t reserved10[0x0000b]; /* -------------- */ -}; +}; /* Completion Queue Context Table Entry #### michal - match PRM */ @@ -2559,7 +2559,7 @@ struct hermonprm_completion_queue_context_st { /* Little Endian */ 0x6 - ARMED SOLICITED (Request Solicited Notification) 0xA - FIRED other - reserved - + Must be 0x0 in CQ initialization. Valid for the QUERY_CQ and HW2SW_CQ commands only. */ pseudo_bit_t reserved1[0x00005]; @@ -2605,7 +2605,7 @@ struct hermonprm_completion_queue_context_st { /* Little Endian */ pseudo_bit_t reserved11[0x00008]; /* -------------- */ pseudo_bit_t solicit_producer_indx[0x00018];/* Maintained by HW. - Valid for QUERY_CQ and HW2SW_CQ commands only. + Valid for QUERY_CQ and HW2SW_CQ commands only. */ pseudo_bit_t reserved12[0x00008]; /* -------------- */ @@ -2627,7 +2627,7 @@ struct hermonprm_completion_queue_context_st { /* Little Endian */ pseudo_bit_t reserved17[0x00003]; pseudo_bit_t db_record_addr_l[0x0001d];/* CQ DB Record physical address [31:3] */ /* -------------- */ -}; +}; /* GPIO_event_data #### michal - gdror fixed */ @@ -2640,7 +2640,7 @@ struct hermonprm_gpio_event_data_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x00020]; /* -------------- */ -}; +}; /* Event_data Field - QP/EE Events #### michal - doesn't match PRM */ @@ -2657,7 +2657,7 @@ struct hermonprm_qp_ee_event_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved4[0x00060]; /* -------------- */ -}; +}; /* InfiniHost-III-EX Type0 Configuration Header ####michal - doesn't match PRM (new fields added, see below) */ @@ -2803,19 +2803,19 @@ struct hermonprm_mt25208_type0_st { /* Little Endian */ /* -------------- */ pseudo_bit_t uncorrectable_error_status_register[0x00020];/* 0 Training Error Status 4 Data Link Protocol Error Status - 12 Poisoned TLP Status - 13 Flow Control Protocol Error Status - 14 Completion Timeout Status - 15 Completer Abort Status - 16 Unexpected Completion Status - 17 Receiver Overflow Status - 18 Malformed TLP Status - 19 ECRC Error Status + 12 Poisoned TLP Status + 13 Flow Control Protocol Error Status + 14 Completion Timeout Status + 15 Completer Abort Status + 16 Unexpected Completion Status + 17 Receiver Overflow Status + 18 Malformed TLP Status + 19 ECRC Error Status 20 Unsupported Request Error Status */ /* -------------- */ pseudo_bit_t uncorrectable_error_mask_register[0x00020];/* 0 Training Error Mask 4 Data Link Protocol Error Mask - 12 Poisoned TLP Mask + 12 Poisoned TLP Mask 13 Flow Control Protocol Error Mask 14 Completion Timeout Mask 15 Completer Abort Mask @@ -2855,7 +2855,7 @@ struct hermonprm_mt25208_type0_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved13[0x006a0]; /* -------------- */ -}; +}; /* Event Data Field - Performance Monitor */ @@ -2873,7 +2873,7 @@ struct hermonprm_performance_monitor_event_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x00040]; /* -------------- */ -}; +}; /* Event_data Field - Page Faults */ @@ -2897,7 +2897,7 @@ struct hermonprm_page_fault_event_data_st { /* Little Endian */ /* -------------- */ pseudo_bit_t prefetch_len[0x00020]; /* Indicates how many subsequent pages in the same memory region/window will be accessed by the following transaction after this page fault is resolved. measured in bytes. SW can use this information in order to page-in the subsequent pages if they are not present. */ /* -------------- */ -}; +}; /* WQE segments format */ @@ -2914,7 +2914,7 @@ struct hermonprm_wqe_segment_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved2[0x00080]; /* -------------- */ -}; +}; /* Event_data Field - Port State Change #### michal - match PRM */ @@ -2927,7 +2927,7 @@ struct hermonprm_port_state_change_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved3[0x00060]; /* -------------- */ -}; +}; /* Event_data Field - Completion Queue Error #### michal - match PRM */ @@ -2944,7 +2944,7 @@ struct hermonprm_completion_queue_error_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved3[0x00060]; /* -------------- */ -}; +}; /* Event_data Field - Completion Event #### michal - match PRM */ @@ -2954,12 +2954,12 @@ struct hermonprm_completion_event_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x000a0]; /* -------------- */ -}; +}; /* Event Queue Entry #### michal - match to PRM */ struct hermonprm_event_queue_entry_st { /* Little Endian */ - pseudo_bit_t event_sub_type[0x00008];/* Event Sub Type. + pseudo_bit_t event_sub_type[0x00008];/* Event Sub Type. Defined for events which have sub types, zero elsewhere. */ pseudo_bit_t reserved0[0x00008]; pseudo_bit_t event_type[0x00008]; /* Event Type */ @@ -2968,12 +2968,12 @@ struct hermonprm_event_queue_entry_st { /* Little Endian */ pseudo_bit_t event_data[6][0x00020];/* Delivers auxilary data to handle event. */ /* -------------- */ pseudo_bit_t reserved2[0x00007]; - pseudo_bit_t owner[0x00001]; /* Owner of the entry - 0 SW + pseudo_bit_t owner[0x00001]; /* Owner of the entry + 0 SW 1 HW */ pseudo_bit_t reserved3[0x00018]; /* -------------- */ -}; +}; /* QP/EE State Transitions Command Parameters ###michal - doesn't match PRM (field name changed) */ @@ -2986,7 +2986,7 @@ struct hermonprm_qp_ee_state_transitions_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x00800]; /* -------------- */ -}; +}; /* Completion Queue Entry Format #### michal - fixed by gdror */ @@ -3010,7 +3010,7 @@ struct hermonprm_completion_queue_entry_st { /* Little Endian */ For IPoIB (UD) and RawEth CQEs this field contains the RSS hash function value. Otherwise, this field is reserved. */ /* -------------- */ - pseudo_bit_t srq_rqpn[0x00018]; /* For Responder UD QPs, Remote (source) QP number. + pseudo_bit_t srq_rqpn[0x00018]; /* For Responder UD QPs, Remote (source) QP number. For Responder SRC QPs, SRQ number. Otherwise, this field is reserved. */ pseudo_bit_t ml_path_mac_index[0x00007];/* For responder UD over IB CQE: These are the lower LMC bits of the DLID in an incoming UD packet, higher bits of this field, that are not part of the LMC bits are zeroed by HW. Invalid if incoming message DLID is the permissive LID or incoming message is multicast. @@ -3028,17 +3028,17 @@ struct hermonprm_completion_queue_entry_st { /* Little Endian */ For responder UD over Ethernet and RawEth - it is VLAN-header[15:12] Otherwise, this field is reserved. */ /* -------------- */ - pseudo_bit_t smac31_0_rawether_ipoib_status[0x00020];/* For responder UD over Ethernet - source MAC[31:0] of the packet. - For responder RawEth and UD over IB - RawEth-IPoIB status {3 reserved, ipok,udp,tcp,ipv4opt,ipv6,ipv4vf,ipv4,rht(6),ipv6extmask(6),reserved(2),l2am,reserved(2),bfcs,reserved(2),enc} + pseudo_bit_t smac31_0_rawether_ipoib_status[0x00020];/* For responder UD over Ethernet - source MAC[31:0] of the packet. + For responder RawEth and UD over IB - RawEth-IPoIB status {3 reserved, ipok,udp,tcp,ipv4opt,ipv6,ipv4vf,ipv4,rht(6),ipv6extmask(6),reserved(2),l2am,reserved(2),bfcs,reserved(2),enc} Otherwise, this field is reserved. */ /* -------------- */ - pseudo_bit_t byte_cnt[0x00020]; /* Byte count of data transferred. Applicable for RDMA-read, Atomic and all receive operations. completions. + pseudo_bit_t byte_cnt[0x00020]; /* Byte count of data transferred. Applicable for RDMA-read, Atomic and all receive operations. completions. For Receive Queue that is subject for headers. separation, byte_cnt[31:24] specify number of bytes scattered to the first scatter entry (headers. length). Byte_cnt[23:0] specify total byte count received (including headers). */ /* -------------- */ pseudo_bit_t checksum[0x00010]; /* Valid for RawEth and IPoIB only. */ pseudo_bit_t wqe_counter[0x00010]; /* -------------- */ - pseudo_bit_t opcode[0x00005]; /* Send completions - same encoding as WQE. + pseudo_bit_t opcode[0x00005]; /* Send completions - same encoding as WQE. Error coding is 0x1F Receive: 0x0 - RDMA-Write with Immediate @@ -3052,14 +3052,14 @@ struct hermonprm_completion_queue_entry_st { /* Little Endian */ pseudo_bit_t reserved1[0x00010]; pseudo_bit_t reserved2[0x00008]; /* -------------- */ -}; +}; /* */ struct hermonprm_mcg_qps_st { /* Little Endian */ struct hermonprm_mcg_qp_dw_st dw[128]; /* -------------- */ -}; +}; /* */ @@ -3084,7 +3084,7 @@ struct hermonprm_mcg_hdr_st { /* Little Endian */ /* -------------- */ pseudo_bit_t gid0[0x00020]; /* -------------- */ -}; +}; /* */ @@ -3096,7 +3096,7 @@ struct hermonprm_sched_queue_context_st { /* Little Endian */ pseudo_bit_t reserved0[0x00006]; pseudo_bit_t weight[0x00010]; /* Weight of this SchQ */ /* -------------- */ -}; +}; /* */ @@ -3117,7 +3117,7 @@ struct hermonprm_ecc_detect_event_data_st { /* Little Endian */ pseudo_bit_t err_ra[0x00010]; pseudo_bit_t err_ca[0x00010]; /* -------------- */ -}; +}; /* Event_data Field - ECC Detection Event */ @@ -3142,14 +3142,14 @@ struct hermonprm_scrubbing_event_st { /* Little Endian */ pseudo_bit_t err_ra[0x00010]; /* Error row address */ pseudo_bit_t err_ca[0x00010]; /* Error column address */ /* -------------- */ -}; +}; /* */ struct hermonprm_eq_cmd_doorbell_st { /* Little Endian */ pseudo_bit_t reserved0[0x00020]; /* -------------- */ -}; +}; /* 0 */ @@ -3400,5 +3400,5 @@ struct hermonprm_hermon_prm_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved64[0xffcfc0]; /* -------------- */ -}; +}; #endif /* H_prefix_hermonprm_bits_fixnames_MT25408_PRM_csp_H */ -- cgit v1.2.3-55-g7522 From 36a892a7c719aed3fd00fc838140b8d24bbb708a Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Mon, 4 May 2020 16:15:13 +0200 Subject: [arbel] Clean up whitespace in MT25218_PRM.h header Signed-off-by: Christian Iversen --- src/drivers/infiniband/MT25218_PRM.h | 176 +++++++++++++++++------------------ 1 file changed, 88 insertions(+), 88 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/MT25218_PRM.h b/src/drivers/infiniband/MT25218_PRM.h index 4011bd0ba..c4dc3316b 100644 --- a/src/drivers/infiniband/MT25218_PRM.h +++ b/src/drivers/infiniband/MT25218_PRM.h @@ -73,7 +73,7 @@ struct arbelprm_ud_address_vector_st { /* Little Endian */ /* -------------- */ pseudo_bit_t rgid_31_0[0x00020]; /* Remote GID[31:0] if G bit is set. Must be set to 0x2 if G bit is cleared. */ /* -------------- */ -}; +}; /* Send doorbell */ @@ -88,7 +88,7 @@ struct arbelprm_send_doorbell_st { /* Little Endian */ pseudo_bit_t reserved1[0x00002]; pseudo_bit_t qpn[0x00018]; /* QP number this doorbell is rung on */ /* -------------- */ -}; +}; /* ACCESS_LAM_inject_errors_input_modifier */ @@ -102,7 +102,7 @@ struct arbelprm_access_lam_inject_errors_input_modifier_st { /* Little Endian */ pseudo_bit_t index0[0x00007]; pseudo_bit_t q0[0x00001]; /* -------------- */ -}; +}; /* ACCESS_LAM_inject_errors_input_parameter */ @@ -114,7 +114,7 @@ struct arbelprm_access_lam_inject_errors_input_parameter_st { /* Little Endian * pseudo_bit_t ra[0x00010]; /* Row Address */ pseudo_bit_t ca[0x00010]; /* Column Address */ /* -------------- */ -}; +}; /* */ @@ -127,7 +127,7 @@ struct arbelprm_recv_wqe_segment_next_st { /* Little Endian */ */ pseudo_bit_t reserved1[0x0001a]; /* -------------- */ -}; +}; /* Send wqe segment data inline */ @@ -141,7 +141,7 @@ struct arbelprm_wqe_segment_data_inline_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved2[0x00040]; /* -------------- */ -}; +}; /* Send wqe segment data ptr */ @@ -155,7 +155,7 @@ struct arbelprm_wqe_segment_data_ptr_st { /* Little Endian */ /* -------------- */ pseudo_bit_t local_address_l[0x00020]; /* -------------- */ -}; +}; /* Send wqe segment rd */ @@ -167,7 +167,7 @@ struct arbelprm_local_invalidate_segment_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved2[0x000a0]; /* -------------- */ -}; +}; /* Fast_Registration_Segment */ @@ -197,7 +197,7 @@ struct arbelprm_fast_registration_segment_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reg_len_l[0x00020]; /* Region Length[31:0] */ /* -------------- */ -}; +}; /* Send wqe segment atomic */ @@ -210,7 +210,7 @@ struct arbelprm_wqe_segment_atomic_st { /* Little Endian */ /* -------------- */ pseudo_bit_t compare_l[0x00020]; /* -------------- */ -}; +}; /* Send wqe segment remote address */ @@ -223,7 +223,7 @@ struct arbelprm_wqe_segment_remote_address_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved0[0x00020]; /* -------------- */ -}; +}; /* end wqe segment bind */ @@ -253,7 +253,7 @@ struct arbelprm_wqe_segment_bind_st { /* Little Endian */ /* -------------- */ pseudo_bit_t length_l[0x00020]; /* -------------- */ -}; +}; /* Send wqe segment ud */ @@ -267,7 +267,7 @@ struct arbelprm_wqe_segment_ud_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x00040]; /* -------------- */ -}; +}; /* Send wqe segment rd */ @@ -279,7 +279,7 @@ struct arbelprm_wqe_segment_rd_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x00040]; /* -------------- */ -}; +}; /* Send wqe segment ctrl */ @@ -296,7 +296,7 @@ struct arbelprm_wqe_segment_ctrl_send_st { /* Little Endian */ /* -------------- */ pseudo_bit_t immediate[0x00020]; /* If the OpCode encodes an operation with Immediate (RDMA-write/SEND), This field will hold the Immediate data to be sent. If the OpCode encodes send and invalidate operations, this field holds the Invalidation key to be inserted into the packet; otherwise, this field is reserved. */ /* -------------- */ -}; +}; /* Send wqe segment next */ @@ -338,7 +338,7 @@ struct arbelprm_wqe_segment_next_st { /* Little Endian */ pseudo_bit_t always1[0x00001]; pseudo_bit_t reserved1[0x00018]; /* -------------- */ -}; +}; /* Address Path */ @@ -384,7 +384,7 @@ struct arbelprm_address_path_st { /* Little Endian */ /* -------------- */ pseudo_bit_t rgid_31_0[0x00020]; /* Remote GID[31:0] */ /* -------------- */ -}; +}; /* HCA Command Register (HCR) */ @@ -414,7 +414,7 @@ struct arbelprm_hca_command_register_st { /* Little Endian */ pseudo_bit_t status[0x00008]; /* Command execution status report. Valid only if command interface in under SW ownership (Go bit is cleared) 0 - command completed without error. If different than zero, command execution completed with error. Syndrom encoding is depended on command executed and is defined for each command */ /* -------------- */ -}; +}; /* CQ Doorbell */ @@ -435,7 +435,7 @@ struct arbelprm_cq_cmd_doorbell_st { /* Little Endian */ /* -------------- */ pseudo_bit_t cq_param[0x00020]; /* parameter to be used by CQ command */ /* -------------- */ -}; +}; /* RD-send doorbell */ @@ -449,7 +449,7 @@ struct arbelprm_rd_send_doorbell_st { /* Little Endian */ /* -------------- */ struct arbelprm_send_doorbell_st send_doorbell;/* Send Parameters */ /* -------------- */ -}; +}; /* Multicast Group Member QP */ @@ -458,7 +458,7 @@ struct arbelprm_mgmqp_st { /* Little Endian */ pseudo_bit_t reserved0[0x00007]; pseudo_bit_t qi[0x00001]; /* Qi: QPN_i is valid */ /* -------------- */ -}; +}; /* vsd */ @@ -575,7 +575,7 @@ struct arbelprm_vsd_st { /* Little Endian */ /* -------------- */ pseudo_bit_t vsd_dw55[0x00020]; /* -------------- */ -}; +}; /* ACCESS_LAM_inject_errors */ @@ -586,7 +586,7 @@ struct arbelprm_access_lam_inject_errors_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved0[0x00020]; /* -------------- */ -}; +}; /* Logical DIMM Information */ @@ -626,7 +626,7 @@ struct arbelprm_dimminfo_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved4[0x00040]; /* -------------- */ -}; +}; /* UAR Parameters */ @@ -661,7 +661,7 @@ struct arbelprm_uar_params_st { /* Little Endian */ Number of entries in table is 2^log_max_uars. Table must be aligned to its size. */ /* -------------- */ -}; +}; /* Translation and Protection Tables Parameters */ @@ -695,7 +695,7 @@ struct arbelprm_tptparams_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved3[0x00040]; /* -------------- */ -}; +}; /* Multicast Support Parameters */ @@ -729,7 +729,7 @@ struct arbelprm_multicastparam_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved5[0x00020]; /* -------------- */ -}; +}; /* QPC/EEC/CQC/EQC/RDB Parameters */ @@ -821,7 +821,7 @@ struct arbelprm_qpcbaseaddr_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved10[0x00040]; /* -------------- */ -}; +}; /* Header_Log_Register */ @@ -830,7 +830,7 @@ struct arbelprm_header_log_register_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved0[0x00060]; /* -------------- */ -}; +}; /* Performance Monitors */ @@ -862,7 +862,7 @@ struct arbelprm_performance_monitors_st { /* Little Endian */ /* -------------- */ pseudo_bit_t event_counter2[0x00020];/* Read/write event counter, counting events specified by EvCntl and EvCnt2 fields repsectively. When the event counter reaches is maximum value of 0xFFFFFF, the next event will cause it to roll over to zero, set F1 or F2 bit respectively and generate interrupt by I1 I2 bit respectively. */ /* -------------- */ -}; +}; /* Receive segment format */ @@ -876,7 +876,7 @@ struct arbelprm_wqe_segment_ctrl_recv_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved4[0x00020]; /* -------------- */ -}; +}; /* MLX WQE segment format */ @@ -895,7 +895,7 @@ struct arbelprm_wqe_segment_ctrl_mlx_st { /* Little Endian */ pseudo_bit_t vcrc[0x00010]; /* Packet's VCRC (if not 0 - otherwise computed by HW) */ pseudo_bit_t rlid[0x00010]; /* Destination LID (must match given headers) */ /* -------------- */ -}; +}; /* Send WQE segment format */ @@ -926,7 +926,7 @@ struct arbelprm_send_wqe_segment_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x00200]; /* -------------- */ -}; +}; /* QP and EE Context Entry */ @@ -1118,7 +1118,7 @@ struct arbelprm_queue_pair_ee_context_entry_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved33[0x00040]; /* -------------- */ -}; +}; /* Clear Interrupt [63:0] */ @@ -1132,7 +1132,7 @@ struct arbelprm_clr_int_st { /* Little Endian */ Write transactions to this register will clear (de-assert) the virtual interrupt output pins of InfiniHost-III-EX. The value to be written in this register is obtained by executing QUERY_ADAPTER command on command interface after system boot. This register is write-only. Reading from this register will cause undefined result */ /* -------------- */ -}; +}; /* EQ_Arm_DB_Region */ @@ -1143,7 +1143,7 @@ struct arbelprm_eq_arm_db_region_st { /* Little Endian */ pseudo_bit_t eq_x_arm_l[0x00020]; /* EQ[31:0] X state. This register is used to Arm EQs when setting the appropriate bits. */ /* -------------- */ -}; +}; /* EQ Set CI DBs Table */ @@ -1404,7 +1404,7 @@ struct arbelprm_eq_set_ci_table_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved63[0x00020]; /* -------------- */ -}; +}; /* InfiniHost-III-EX Configuration Registers */ @@ -1415,7 +1415,7 @@ struct arbelprm_configuration_registers_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x3fcb20]; /* -------------- */ -}; +}; /* QP_DB_Record */ @@ -1429,7 +1429,7 @@ struct arbelprm_qp_db_record_st { /* Little Endian */ 0x5 for SRQ */ pseudo_bit_t qp_number[0x00018]; /* QP number */ /* -------------- */ -}; +}; /* CQ_ARM_DB_Record */ @@ -1445,7 +1445,7 @@ struct arbelprm_cq_arm_db_record_st { /* Little Endian */ pseudo_bit_t res[0x00003]; /* Must be 0x2 */ pseudo_bit_t cq_number[0x00018]; /* CQ number */ /* -------------- */ -}; +}; /* CQ_CI_DB_Record */ @@ -1456,7 +1456,7 @@ struct arbelprm_cq_ci_db_record_st { /* Little Endian */ pseudo_bit_t res[0x00003]; /* Must be 0x1 */ pseudo_bit_t cq_number[0x00018]; /* CQ number */ /* -------------- */ -}; +}; /* Virtual_Physical_Mapping */ @@ -1472,7 +1472,7 @@ struct arbelprm_virtual_physical_mapping_st { /* Little Endian */ pseudo_bit_t reserved1[0x00006]; pseudo_bit_t pa_l[0x00014]; /* Physical Address[31:12] */ /* -------------- */ -}; +}; /* MOD_STAT_CFG */ @@ -1485,7 +1485,7 @@ struct arbelprm_mod_stat_cfg_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved2[0x007e0]; /* -------------- */ -}; +}; /* SRQ Context */ @@ -1528,7 +1528,7 @@ struct arbelprm_srq_context_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved4[0x00060]; /* -------------- */ -}; +}; /* PBL */ @@ -1549,7 +1549,7 @@ struct arbelprm_pbl_st { /* Little Endian */ /* -------------- */ pseudo_bit_t mtt_3_l[0x00020]; /* Fourth MTT[31:0] */ /* -------------- */ -}; +}; /* Performance Counters */ @@ -1580,7 +1580,7 @@ struct arbelprm_performance_counters_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved3[0x00620]; /* -------------- */ -}; +}; /* Transport and CI Error Counters */ @@ -1724,7 +1724,7 @@ struct arbelprm_transport_and_ci_error_counters_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved12[0x002a0]; /* -------------- */ -}; +}; /* Event_data Field - HCR Completion Event */ @@ -1743,7 +1743,7 @@ struct arbelprm_hcr_completion_event_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved3[0x00020]; /* -------------- */ -}; +}; /* Completion with Error CQE */ @@ -1791,7 +1791,7 @@ struct arbelprm_completion_with_error_st { /* Little Endian */ 0xFE - For completion with error on Receive Queues 0xFF - For completion with error on Send Queues */ /* -------------- */ -}; +}; /* Resize CQ Input Mailbox */ @@ -1814,7 +1814,7 @@ struct arbelprm_resize_cq_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved4[0x00100]; /* -------------- */ -}; +}; /* MAD_IFC Input Modifier */ @@ -1826,7 +1826,7 @@ struct arbelprm_mad_ifc_input_modifier_st { /* Little Endian */ pseudo_bit_t rlid[0x00010]; /* Remote (source) LID from the received MAD. This field is required for trap generation upon MKey/BKey validation. */ /* -------------- */ -}; +}; /* MAD_IFC Input Mailbox */ @@ -1863,7 +1863,7 @@ struct arbelprm_mad_ifc_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved5[0x004c0]; /* -------------- */ -}; +}; /* Query Debug Message */ @@ -1924,7 +1924,7 @@ struct arbelprm_query_debug_msg_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved3[0x00400]; /* -------------- */ -}; +}; /* User Access Region */ @@ -1939,7 +1939,7 @@ struct arbelprm_uar_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x03ec0]; /* -------------- */ -}; +}; /* Receive doorbell */ @@ -1953,7 +1953,7 @@ struct arbelprm_receive_doorbell_st { /* Little Endian */ pseudo_bit_t reserved3[0x00002]; pseudo_bit_t qpn[0x00018]; /* QP number or SRQ number this doorbell is rung on */ /* -------------- */ -}; +}; /* SET_IB Parameters */ @@ -1974,7 +1974,7 @@ struct arbelprm_set_ib_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved2[0x00180]; /* -------------- */ -}; +}; /* Multicast Group Member */ @@ -2014,7 +2014,7 @@ struct arbelprm_mgm_entry_st { /* Little Endian */ /* -------------- */ struct arbelprm_mgmqp_st mgmqp_7; /* Multicast Group Member QP */ /* -------------- */ -}; +}; /* INIT_IB Parameters */ @@ -2068,7 +2068,7 @@ struct arbelprm_init_ib_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved5[0x006c0]; /* -------------- */ -}; +}; /* Query Device Limitations */ @@ -2285,7 +2285,7 @@ struct arbelprm_query_dev_lim_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved41[0x002c0]; /* -------------- */ -}; +}; /* QUERY_ADAPTER Parameters Block */ @@ -2299,7 +2299,7 @@ struct arbelprm_query_adapter_st { /* Little Endian */ /* -------------- */ struct arbelprm_vsd_st vsd; /* -------------- */ -}; +}; /* QUERY_FW Parameters Block */ @@ -2375,7 +2375,7 @@ struct arbelprm_query_fw_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved6[0x004c0]; /* -------------- */ -}; +}; /* ACCESS_LAM */ @@ -2384,7 +2384,7 @@ struct arbelprm_access_lam_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved0[0x00080]; /* -------------- */ -}; +}; /* ENABLE_LAM Parameters Block */ @@ -2418,7 +2418,7 @@ struct arbelprm_enable_lam_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved2[0x00400]; /* -------------- */ -}; +}; /* Memory Access Parameters for UD Address Vector Table */ @@ -2430,7 +2430,7 @@ struct arbelprm_udavtable_memory_parameters_st { /* Little Endian */ pseudo_bit_t xlation_en[0x00001]; /* When cleared, address is physical address and no translation will be done. When set, address is virtual. */ pseudo_bit_t reserved1[0x00002]; /* -------------- */ -}; +}; /* INIT_HCA & QUERY_HCA Parameters Block */ @@ -2495,7 +2495,7 @@ struct arbelprm_init_hca_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved11[0x00600]; /* -------------- */ -}; +}; /* Event Queue Context Table Entry */ @@ -2555,7 +2555,7 @@ struct arbelprm_eqc_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved9[0x00080]; /* -------------- */ -}; +}; /* Memory Translation Table (MTT) Entry */ @@ -2566,7 +2566,7 @@ struct arbelprm_mtt_st { /* Little Endian */ pseudo_bit_t reserved0[0x0000b]; pseudo_bit_t ptag_l[0x00014]; /* Low-order bits of Physical tag. The size of the field depends on the page size of the region. Maximum PTAG size is 52 bits. */ /* -------------- */ -}; +}; /* Memory Protection Table (MPT) Entry */ @@ -2641,7 +2641,7 @@ struct arbelprm_mpt_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved8[0x00040]; /* -------------- */ -}; +}; /* Completion Queue Context Table Entry */ @@ -2719,7 +2719,7 @@ struct arbelprm_completion_queue_context_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved8[0x00020]; /* -------------- */ -}; +}; /* GPIO_event_data */ @@ -2732,7 +2732,7 @@ struct arbelprm_gpio_event_data_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x00020]; /* -------------- */ -}; +}; /* Event_data Field - QP/EE Events */ @@ -2749,7 +2749,7 @@ struct arbelprm_qp_ee_event_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved4[0x00060]; /* -------------- */ -}; +}; /* InfiniHost-III-EX Type0 Configuration Header */ @@ -2947,7 +2947,7 @@ struct arbelprm_mt25208_type0_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved13[0x006a0]; /* -------------- */ -}; +}; /* Event Data Field - Performance Monitor */ @@ -2965,7 +2965,7 @@ struct arbelprm_performance_monitor_event_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x00040]; /* -------------- */ -}; +}; /* Event_data Field - Page Faults */ @@ -2989,7 +2989,7 @@ struct arbelprm_page_fault_event_data_st { /* Little Endian */ /* -------------- */ pseudo_bit_t prefetch_len[0x00020]; /* Indicates how many subsequent pages in the same memory region/window will be accessed by the following transaction after this page fault is resolved. measured in bytes. SW can use this information in order to page-in the subsequent pages if they are not present. */ /* -------------- */ -}; +}; /* WQE segments format */ @@ -3006,7 +3006,7 @@ struct arbelprm_wqe_segment_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved2[0x00080]; /* -------------- */ -}; +}; /* Event_data Field - Port State Change */ @@ -3019,7 +3019,7 @@ struct arbelprm_port_state_change_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved3[0x00060]; /* -------------- */ -}; +}; /* Event_data Field - Completion Queue Error */ @@ -3036,7 +3036,7 @@ struct arbelprm_completion_queue_error_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved3[0x00060]; /* -------------- */ -}; +}; /* Event_data Field - Completion Event */ @@ -3046,7 +3046,7 @@ struct arbelprm_completion_event_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x000a0]; /* -------------- */ -}; +}; /* Event Queue Entry */ @@ -3065,7 +3065,7 @@ struct arbelprm_event_queue_entry_st { /* Little Endian */ 1 HW */ pseudo_bit_t reserved3[0x00018]; /* -------------- */ -}; +}; /* QP/EE State Transitions Command Parameters */ @@ -3078,7 +3078,7 @@ struct arbelprm_qp_ee_state_transitions_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved1[0x009c0]; /* -------------- */ -}; +}; /* Completion Queue Entry Format */ @@ -3131,7 +3131,7 @@ struct arbelprm_completion_queue_entry_st { /* Little Endian */ 0xFE - For completion with error on Receive Queues 0xFF - For completion with error on Send Queues */ /* -------------- */ -}; +}; /* */ @@ -3152,7 +3152,7 @@ struct arbelprm_ecc_detect_event_data_st { /* Little Endian */ pseudo_bit_t err_ra[0x00010]; pseudo_bit_t err_ca[0x00010]; /* -------------- */ -}; +}; /* Event_data Field - ECC Detection Event */ @@ -3177,7 +3177,7 @@ struct arbelprm_scrubbing_event_st { /* Little Endian */ pseudo_bit_t err_ra[0x00010]; /* Error row address */ pseudo_bit_t err_ca[0x00010]; /* Error column address */ /* -------------- */ -}; +}; /* Miscellaneous Counters */ @@ -3186,28 +3186,28 @@ struct arbelprm_misc_counters_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved0[0x007e0]; /* -------------- */ -}; +}; /* LAM_EN Output Parameter */ struct arbelprm_lam_en_out_param_st { /* Little Endian */ pseudo_bit_t reserved0[0x00040]; /* -------------- */ -}; +}; /* Extended_Completion_Queue_Entry */ struct arbelprm_extended_completion_queue_entry_st { /* Little Endian */ pseudo_bit_t reserved0[0x00020]; /* -------------- */ -}; +}; /* */ struct arbelprm_eq_cmd_doorbell_st { /* Little Endian */ pseudo_bit_t reserved0[0x00020]; /* -------------- */ -}; +}; /* 0 */ @@ -3456,5 +3456,5 @@ struct arbelprm_arbel_prm_st { /* Little Endian */ /* -------------- */ pseudo_bit_t reserved59[0xffcfc0]; /* -------------- */ -}; +}; #endif /* H_prefix_arbelprm_bits_fixnames_MT25218_PRM_csp_H */ -- cgit v1.2.3-55-g7522 From 0e788c8edabc0a6a31db180bfad7308804b2d731 Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Mon, 4 May 2020 21:45:29 +0200 Subject: [golan] Backport typo fix in nodnic_prm.h: s/HERMON/NODNIC/ Signed-off-by: Christian Iversen --- src/drivers/infiniband/nodnic_prm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/nodnic_prm.h b/src/drivers/infiniband/nodnic_prm.h index 5e0fa9890..a962c821c 100644 --- a/src/drivers/infiniband/nodnic_prm.h +++ b/src/drivers/infiniband/nodnic_prm.h @@ -38,10 +38,10 @@ struct nodnic_wqe_segment_data_ptr_st { /* Little Endian */ struct MLX_DECLARE_STRUCT ( nodnic_wqe_segment_data_ptr ); -#define HERMON_MAX_SCATTER 1 +#define NODNIC_MAX_SCATTER 1 struct nodnic_recv_wqe { - struct nodnic_wqe_segment_data_ptr data[HERMON_MAX_SCATTER]; + struct nodnic_wqe_segment_data_ptr data[NODNIC_MAX_SCATTER]; } __attribute__ (( packed )); #endif /* SRC_DRIVERS_INFINIBAND_MLX_NODNIC_INCLUDE_PRM_NODNIC_PRM_H_ */ -- cgit v1.2.3-55-g7522 From a2893dc18a58007106a50fc7b01e6af8663e340d Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Sat, 23 Jan 2021 13:26:24 +0100 Subject: [hermon] Reorganize PCI ROM list and document well-known product names Signed-off-by: Christian Iversen --- src/drivers/infiniband/hermon.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index 7537d83c2..dafddf7da 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -3995,15 +3995,22 @@ static void hermon_bofm_remove ( struct pci_device *pci ) { } static struct pci_device_id hermon_nics[] = { + /* Mellanox ConnectX VPI (ethernet + infiniband) */ PCI_ROM ( 0x15b3, 0x6340, "mt25408", "MT25408 HCA driver", 0 ), PCI_ROM ( 0x15b3, 0x634a, "mt25418", "MT25418 HCA driver", 0 ), + + /* Mellanox ConnectX EN (ethernet only) */ + PCI_ROM ( 0x15b3, 0x6368, "mt25448", "MT25448 HCA driver", 0 ), + PCI_ROM ( 0x15b3, 0x6372, "mt25458", "MT25458 HCA driver", 0 ), + + /* Mellanox ConnectX-2 VPI (ethernet + infiniband) */ PCI_ROM ( 0x15b3, 0x6732, "mt26418", "MT26418 HCA driver", 0 ), PCI_ROM ( 0x15b3, 0x673c, "mt26428", "MT26428 HCA driver", 0 ), PCI_ROM ( 0x15b3, 0x6746, "mt26438", "MT26438 HCA driver", 0 ), PCI_ROM ( 0x15b3, 0x6778, "mt26488", "MT26488 HCA driver", 0 ), - PCI_ROM ( 0x15b3, 0x6368, "mt25448", "MT25448 HCA driver", 0 ), + + /* Mellanox ConnectX-2 EN (ethernet only) */ PCI_ROM ( 0x15b3, 0x6750, "mt26448", "MT26448 HCA driver", 0 ), - PCI_ROM ( 0x15b3, 0x6372, "mt25458", "MT25458 HCA driver", 0 ), PCI_ROM ( 0x15b3, 0x675a, "mt26458", "MT26458 HCA driver", 0 ), PCI_ROM ( 0x15b3, 0x6764, "mt26468", "MT26468 HCA driver", 0 ), PCI_ROM ( 0x15b3, 0x676e, "mt26478", "MT26478 HCA driver", 0 ), -- cgit v1.2.3-55-g7522 From ce45c8dc21e39cb9342537c3d45e2e69a33f996b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 28 Jan 2021 17:29:36 +0000 Subject: [hermon] Show "issuing command" messages only at DBGLVL_EXTRA Originally-implemented-by: Christian Iversen Signed-off-by: Michael Brown --- src/drivers/infiniband/hermon.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index dafddf7da..2e6f489b1 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -175,7 +175,7 @@ static int hermon_cmd ( struct hermon *hermon, unsigned long command, assert ( in_len <= HERMON_MBOX_SIZE ); assert ( out_len <= HERMON_MBOX_SIZE ); - DBGC2 ( hermon, "Hermon %p command %02x in %zx%s out %zx%s\n", + DBGC2 ( hermon, "Hermon %p command %04x in %zx%s out %zx%s\n", hermon, opcode, in_len, ( ( command & HERMON_HCR_IN_MBOX ) ? "(mbox)" : "" ), out_len, ( ( command & HERMON_HCR_OUT_MBOX ) ? "(mbox)" : "" ) ); @@ -214,8 +214,6 @@ static int hermon_cmd ( struct hermon *hermon, unsigned long command, opcode_modifier, op_mod, go, 1, t, hermon->toggle ); - DBGC ( hermon, "Hermon %p issuing command %04x\n", - hermon, opcode ); DBGC2_HDA ( hermon, virt_to_phys ( hermon->config + HERMON_HCR_BASE ), &hcr, sizeof ( hcr ) ); if ( in_len && ( command & HERMON_HCR_IN_MBOX ) ) { @@ -234,8 +232,8 @@ static int hermon_cmd ( struct hermon *hermon, unsigned long command, /* Wait for command completion */ if ( ( rc = hermon_cmd_wait ( hermon, &hcr ) ) != 0 ) { - DBGC ( hermon, "Hermon %p timed out waiting for command:\n", - hermon ); + DBGC ( hermon, "Hermon %p timed out waiting for command " + "%04x:\n", hermon, opcode ); DBGC_HDA ( hermon, virt_to_phys ( hermon->config + HERMON_HCR_BASE ), &hcr, sizeof ( hcr ) ); @@ -245,8 +243,8 @@ static int hermon_cmd ( struct hermon *hermon, unsigned long command, /* Check command status */ status = MLX_GET ( &hcr, status ); if ( status != 0 ) { - DBGC ( hermon, "Hermon %p command failed with status %02x:\n", - hermon, status ); + DBGC ( hermon, "Hermon %p command %04x failed with status " + "%02x:\n", hermon, opcode, status ); DBGC_HDA ( hermon, virt_to_phys ( hermon->config + HERMON_HCR_BASE ), &hcr, sizeof ( hcr ) ); -- cgit v1.2.3-55-g7522 From cd126c41bbec5563c5042902f4aa22a8e92ee76f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 28 Jan 2021 20:52:36 +0000 Subject: [hermon] Add assorted debug error messages Signed-off-by: Michael Brown --- src/drivers/infiniband/hermon.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index 2e6f489b1..efcb2c4c5 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -636,9 +636,9 @@ static int hermon_alloc_mtt ( struct hermon *hermon, mtt_offset = hermon_bitmask_alloc ( hermon->mtt_inuse, HERMON_MAX_MTTS, num_pages ); if ( mtt_offset < 0 ) { - DBGC ( hermon, "Hermon %p could not allocate %d MTT entries\n", - hermon, num_pages ); rc = mtt_offset; + DBGC ( hermon, "Hermon %p could not allocate %d MTT entries: " + "%s\n", hermon, num_pages, strerror ( rc ) ); goto err_mtt_offset; } mtt_base_addr = ( ( hermon->cap.reserved_mtts + mtt_offset ) * @@ -662,8 +662,9 @@ static int hermon_alloc_mtt ( struct hermon *hermon, ptag_l, ( addr >> 3 ) ); if ( ( rc = hermon_cmd_write_mtt ( hermon, &write_mtt ) ) != 0 ) { - DBGC ( hermon, "Hermon %p could not write MTT at %x\n", - hermon, mtt_base_addr ); + DBGC ( hermon, "Hermon %p could not write MTT at %x: " + "%s\n", hermon, mtt_base_addr, + strerror ( rc ) ); goto err_write_mtt; } addr += HERMON_PAGE_SIZE; @@ -857,6 +858,8 @@ static int hermon_create_cq ( struct ib_device *ibdev, /* Allocate control structures */ hermon_cq = zalloc ( sizeof ( *hermon_cq ) ); if ( ! hermon_cq ) { + DBGC ( hermon, "Hermon %p CQN %#lx could not allocate CQ\n", + hermon, cq->cqn ); rc = -ENOMEM; goto err_hermon_cq; } @@ -865,6 +868,8 @@ static int hermon_create_cq ( struct ib_device *ibdev, hermon_cq->doorbell = malloc_phys ( sizeof ( hermon_cq->doorbell[0] ), sizeof ( hermon_cq->doorbell[0] ) ); if ( ! hermon_cq->doorbell ) { + DBGC ( hermon, "Hermon %p CQN %#lx could not allocate " + "doorbell\n", hermon, cq->cqn ); rc = -ENOMEM; goto err_doorbell; } @@ -875,6 +880,8 @@ static int hermon_create_cq ( struct ib_device *ibdev, hermon_cq->cqe = malloc_phys ( hermon_cq->cqe_size, sizeof ( hermon_cq->cqe[0] ) ); if ( ! hermon_cq->cqe ) { + DBGC ( hermon, "Hermon %p CQN %#lx could not allocate CQEs\n", + hermon, cq->cqn ); rc = -ENOMEM; goto err_cqe; } @@ -887,8 +894,11 @@ static int hermon_create_cq ( struct ib_device *ibdev, /* Allocate MTT entries */ if ( ( rc = hermon_alloc_mtt ( hermon, hermon_cq->cqe, hermon_cq->cqe_size, - &hermon_cq->mtt ) ) != 0 ) + &hermon_cq->mtt ) ) != 0 ) { + DBGC ( hermon, "Hermon %p CQN %#lx could not allocate MTTs: " + "%s\n", hermon, cq->cqn, strerror ( rc ) ); goto err_alloc_mtt; + } /* Hand queue over to hardware */ memset ( &cqctx, 0, sizeof ( cqctx ) ); @@ -1120,6 +1130,8 @@ static int hermon_create_qp ( struct ib_device *ibdev, /* Allocate control structures */ hermon_qp = zalloc ( sizeof ( *hermon_qp ) ); if ( ! hermon_qp ) { + DBGC ( hermon, "Hermon %p QPN %#lx could not allocate QP\n", + hermon, qp->qpn ); rc = -ENOMEM; goto err_hermon_qp; } @@ -1129,6 +1141,8 @@ static int hermon_create_qp ( struct ib_device *ibdev, malloc_phys ( sizeof ( hermon_qp->recv.doorbell[0] ), sizeof ( hermon_qp->recv.doorbell[0] ) ); if ( ! hermon_qp->recv.doorbell ) { + DBGC ( hermon, "Hermon %p QPN %#lx could not allocate " + "doorbell\n", hermon, qp->qpn ); rc = -ENOMEM; goto err_recv_doorbell; } @@ -1158,6 +1172,8 @@ static int hermon_create_qp ( struct ib_device *ibdev, hermon_qp->wqe = malloc_phys ( hermon_qp->wqe_size, sizeof ( hermon_qp->send.wqe[0] ) ); if ( ! hermon_qp->wqe ) { + DBGC ( hermon, "Hermon %p QPN %#lx could not allocate WQEs\n", + hermon, qp->qpn ); rc = -ENOMEM; goto err_alloc_wqe; } @@ -1182,6 +1198,8 @@ static int hermon_create_qp ( struct ib_device *ibdev, if ( ( rc = hermon_alloc_mtt ( hermon, hermon_qp->wqe, hermon_qp->wqe_size, &hermon_qp->mtt ) ) != 0 ) { + DBGC ( hermon, "Hermon %p QPN %#lx could not allocate MTTs: " + "%s\n", hermon, qp->qpn, strerror ( rc ) ); goto err_alloc_mtt; } @@ -1888,6 +1906,8 @@ static int hermon_create_eq ( struct hermon *hermon ) { hermon_eq->eqe = malloc_phys ( hermon_eq->eqe_size, sizeof ( hermon_eq->eqe[0] ) ); if ( ! hermon_eq->eqe ) { + DBGC ( hermon, "Hermon %p EQN %#lx could not allocate EQEs\n", + hermon, hermon_eq->eqn ); rc = -ENOMEM; goto err_eqe; } @@ -1900,8 +1920,11 @@ static int hermon_create_eq ( struct hermon *hermon ) { /* Allocate MTT entries */ if ( ( rc = hermon_alloc_mtt ( hermon, hermon_eq->eqe, hermon_eq->eqe_size, - &hermon_eq->mtt ) ) != 0 ) + &hermon_eq->mtt ) ) != 0 ) { + DBGC ( hermon, "Hermon %p EQN %#lx could not allocate MTTs: " + "%s\n", hermon, hermon_eq->eqn, strerror ( rc ) ); goto err_alloc_mtt; + } /* Hand queue over to hardware */ memset ( &eqctx, 0, sizeof ( eqctx ) ); @@ -2200,6 +2223,8 @@ static int hermon_start_firmware ( struct hermon *hermon ) { hermon->firmware_len = fw_len; hermon->firmware_area = umalloc ( hermon->firmware_len ); if ( ! hermon->firmware_area ) { + DBGC ( hermon, "Hermon %p could not allocate firmware " + "area\n", hermon ); rc = -ENOMEM; goto err_alloc_fa; } @@ -2567,6 +2592,8 @@ static int hermon_map_icm ( struct hermon *hermon, hermon->icm_aux_len = icm_aux_len; hermon->icm = umalloc ( hermon->icm_aux_len + hermon->icm_len ); if ( ! hermon->icm ) { + DBGC ( hermon, "Hermon %p could not allocate ICM\n", + hermon ); rc = -ENOMEM; goto err_alloc; } -- cgit v1.2.3-55-g7522 From 7c40227e18d532bff5fe32b1a71c3916b0ce1774 Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Mon, 25 Jan 2021 13:32:04 +0100 Subject: [hermon] Increase command timeout from 2 to 10 seconds Some commands (particularly in relation to device initialization) can occasionally take longer than 2 seconds, and the Mellanox documentation recommends a 10 second timeout. Signed-off-by: Christian Iversen --- src/drivers/infiniband/hermon.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.h b/src/drivers/infiniband/hermon.h index 61e285781..8ac35620c 100644 --- a/src/drivers/infiniband/hermon.h +++ b/src/drivers/infiniband/hermon.h @@ -925,7 +925,7 @@ struct hermon { #define HERMON_HCR_BASE 0x80680 #define HERMON_HCR_REG(x) ( HERMON_HCR_BASE + 4 * (x) ) -#define HERMON_HCR_MAX_WAIT_MS 2000 +#define HERMON_HCR_MAX_WAIT_MS 10000 #define HERMON_MBOX_ALIGN 4096 #define HERMON_MBOX_SIZE 1024 -- cgit v1.2.3-55-g7522 From 7d32225b553274cc6e9c922a272903de18bbd458 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 28 Jan 2021 22:01:43 +0000 Subject: [hermon] Add event queue debug functions Add hermon_dump_eqctx() for dumping the event queue context and hermon_dump_eqes() for dumping any unconsumed event queue entries. Originally-implemented-by: Christian Iversen Signed-off-by: Michael Brown --- src/drivers/infiniband/hermon.c | 78 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 2 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index efcb2c4c5..eb1255ffb 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -1878,6 +1878,79 @@ static void hermon_poll_cq ( struct ib_device *ibdev, *************************************************************************** */ +/** + * Dump event queue context (for debugging only) + * + * @v hermon Hermon device + * @v hermon_eq Event queue + * @ret rc Return status code + */ +static __attribute__ (( unused )) int +hermon_dump_eqctx ( struct hermon *hermon, + struct hermon_event_queue *hermon_eq ) { + struct hermonprm_eqc eqctx; + int rc; + + memset ( &eqctx, 0, sizeof ( eqctx ) ); + if ( ( rc = hermon_cmd_query_eq ( hermon, hermon_eq->eqn, + &eqctx ) ) != 0 ) { + DBGC ( hermon, "Hermon %p EQN %#lx QUERY_EQ failed: %s\n", + hermon, hermon_eq->eqn, strerror ( rc ) ); + return rc; + } + DBGC ( hermon, "Hermon %p EQN %#lx context:\n", + hermon, hermon_eq->eqn ); + DBGC_HDA ( hermon, 0, &eqctx, sizeof ( eqctx ) ); + + return 0; +} + +/** + * Dump unconsumed event queue entries (for debugging only) + * + * @v hermon Hermon device + * @v hermon_eq Event queue + * @ret rc Return status code + */ +static __attribute__ (( unused )) int +hermon_dump_eqes ( struct hermon *hermon, + struct hermon_event_queue *hermon_eq ) { + struct hermonprm_eqc eqctx; + union hermonprm_event_entry *eqe; + unsigned int mask; + unsigned int prod; + unsigned int cons; + unsigned int idx; + int rc; + + memset ( &eqctx, 0, sizeof ( eqctx ) ); + if ( ( rc = hermon_cmd_query_eq ( hermon, hermon_eq->eqn, + &eqctx ) ) != 0 ) { + DBGC ( hermon, "Hermon %p EQN %#lx QUERY_EQ failed: %s\n", + hermon, hermon_eq->eqn, strerror ( rc ) ); + return rc; + } + mask = ( HERMON_NUM_EQES - 1 ); + prod = MLX_GET ( &eqctx, producer_counter ) & mask; + cons = MLX_GET ( &eqctx, consumer_counter ) & mask; + idx = hermon_eq->next_idx; + if ( ( idx & mask ) != ( cons & mask ) ) { + DBGC ( hermon, "Hermon %p EQN %#lx mismatch: SW %#x != HW " + "%#x\n", hermon, hermon_eq->eqn, idx, cons ); + } + for ( ; ( idx & mask ) != ( prod & mask ) ; idx++ ) { + eqe = &hermon_eq->eqe[idx & mask]; + DBGC ( hermon, "Hermon %p EQN %#lx event %#x owner %d type " + "%#02x:%#02x\n", hermon, hermon_eq->eqn, idx, + MLX_GET ( &eqe->generic, owner ), + MLX_GET ( &eqe->generic, event_type ), + MLX_GET ( &eqe->generic, event_sub_type ) ); + DBGC_HDA ( hermon, 0, eqe, sizeof ( *eqe ) ); + } + + return 0; +} + /** * Create event queue * @@ -2084,8 +2157,9 @@ static void hermon_poll_eq ( struct ib_device *ibdev ) { break; default: DBGC ( hermon, "Hermon %p EQN %#lx unrecognised event " - "type %#x:\n", - hermon, hermon_eq->eqn, event_type ); + "type %#02x:%#02x\n", + hermon, hermon_eq->eqn, event_type, + MLX_GET ( &eqe->generic, event_sub_type ) ); DBGC_HDA ( hermon, virt_to_phys ( eqe ), eqe, sizeof ( *eqe ) ); break; -- cgit v1.2.3-55-g7522 From 6cb12ee2b02dac4455bc60aebdcd326436dff743 Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Tue, 26 Jan 2021 22:47:29 +0100 Subject: [hermon] Increase polling rate for command completions Some older versions of the hardware (and/or firmware) do not report an event when an Infiniband link reaches the INIT state. The driver works around this missing event by calling ib_smc_update() on each event queue poll while the link is in the DOWN state. This results in a very large number of commands being issued while any open Infiniband link is in the DOWN state (e.g. unplugged), to the point that the 1ms delay from waiting for each command to complete will noticeably affect responsiveness. Fix by decreasing the command completion polling delay from 1ms to 10us. Signed-off-by: Christian Iversen Modified-by: Michael Brown Signed-off-by: Michael Brown --- src/drivers/infiniband/hermon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index eb1255ffb..e818b4d29 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -137,13 +137,13 @@ static int hermon_cmd_wait ( struct hermon *hermon, struct hermonprm_hca_command_register *hcr ) { unsigned int wait; - for ( wait = HERMON_HCR_MAX_WAIT_MS ; wait ; wait-- ) { + for ( wait = ( 100 * HERMON_HCR_MAX_WAIT_MS ) ; wait ; wait-- ) { hcr->u.dwords[6] = readl ( hermon->config + HERMON_HCR_REG ( 6 ) ); if ( ( MLX_GET ( hcr, go ) == 0 ) && ( MLX_GET ( hcr, t ) == hermon->toggle ) ) return 0; - mdelay ( 1 ); + udelay ( 10 ); } return -EBUSY; } -- cgit v1.2.3-55-g7522 From 699b9f1d1b0338272dc4871ec3348ff3281784a3 Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Tue, 26 Jan 2021 22:56:42 +0100 Subject: [hermon] Use Ethernet MAC as eIPoIB local EMAC The eIPoIB local Ethernet MAC is currently constructed from the port GUID. Given a base GUID/MAC value of N, Mellanox seems to populate: Node GUID: N + 0 Port 1 GUID: N + 1 Port 2 GUID: N + 2 and Port 1 MAC: N + 0 Port 2 MAC: N + 1 This causes a duplicate local MAC address when port 1 is configured as Infiniband and port 2 as Ethernet, since both will derive their MAC address as (N + 1). Fix by using the port's Ethernet MAC as the eIPoIB local EMAC. This is a behavioural change that could potentially break configurations that rely on the local EMAC value, such as a DHCP server relying on the chaddr field for DHCP reservations. Signed-off-by: Christian Iversen Modified-by: Michael Brown Signed-off-by: Michael Brown --- src/drivers/infiniband/hermon.c | 26 +++++++++----------------- src/drivers/infiniband/hermon.h | 11 +++++++++++ 2 files changed, 20 insertions(+), 17 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index e818b4d29..d766ed585 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -3179,6 +3179,9 @@ static int hermon_register_ibdev ( struct hermon *hermon, struct ib_device *ibdev = port->ibdev; int rc; + /* Use Ethernet MAC as eIPoIB local EMAC */ + memcpy ( ibdev->lemac, port->eth_mac.raw, ETH_ALEN ); + /* Initialise parameters using SMC */ ib_smc_init ( ibdev, hermon_mad ); @@ -3495,24 +3498,10 @@ static int hermon_register_netdev ( struct hermon *hermon, struct hermon_port *port ) { struct net_device *netdev = port->netdev; struct ib_device *ibdev = port->ibdev; - struct hermonprm_query_port_cap query_port; - union { - uint8_t bytes[8]; - uint32_t dwords[2]; - } mac; int rc; - /* Retrieve MAC address */ - if ( ( rc = hermon_cmd_query_port ( hermon, ibdev->port, - &query_port ) ) != 0 ) { - DBGC ( hermon, "Hermon %p port %d could not query port: %s\n", - hermon, ibdev->port, strerror ( rc ) ); - goto err_query_port; - } - mac.dwords[0] = htonl ( MLX_GET ( &query_port, mac_47_32 ) ); - mac.dwords[1] = htonl ( MLX_GET ( &query_port, mac_31_0 ) ); - memcpy ( netdev->hw_addr, - &mac.bytes[ sizeof ( mac.bytes ) - ETH_ALEN ], ETH_ALEN ); + /* Set MAC address */ + memcpy ( netdev->hw_addr, port->eth_mac.raw, ETH_ALEN ); /* Register network device */ if ( ( rc = register_netdev ( netdev ) ) != 0 ) { @@ -3536,7 +3525,6 @@ static int hermon_register_netdev ( struct hermon *hermon, err_register_nvo: unregister_netdev ( netdev ); err_register_netdev: - err_query_port: return rc; } @@ -3674,6 +3662,10 @@ static int hermon_set_port_type ( struct hermon *hermon, ( ( ib_supported && eth_supported ) ? " and" : "" ), ( eth_supported ? " Ethernet" : "" ) ); + /* Record Ethernet MAC address */ + port->eth_mac.part.h = htons ( MLX_GET ( &query_port, mac_47_32 ) ); + port->eth_mac.part.l = htonl ( MLX_GET ( &query_port, mac_31_0 ) ); + /* Sense network, if applicable */ if ( ib_supported && eth_supported ) { diff --git a/src/drivers/infiniband/hermon.h b/src/drivers/infiniband/hermon.h index 8ac35620c..381e2e462 100644 --- a/src/drivers/infiniband/hermon.h +++ b/src/drivers/infiniband/hermon.h @@ -822,6 +822,15 @@ struct hermon_port_type { struct hermon_port *port ); }; +/** A Hermon port Ethernet MAC address */ +union hermon_port_mac { + struct { + uint16_t h; + uint32_t l; + } __attribute__ (( packed )) part; + uint8_t raw[ETH_ALEN]; +}; + /** A Hermon port */ struct hermon_port { /** Infiniband device */ @@ -832,6 +841,8 @@ struct hermon_port { struct ib_completion_queue *eth_cq; /** Ethernet queue pair */ struct ib_queue_pair *eth_qp; + /** Ethernet MAC */ + union hermon_port_mac eth_mac; /** Port type */ struct hermon_port_type *type; /** Non-volatile option storage */ -- cgit v1.2.3-55-g7522 From 43d72d0087c4d81354abfff26d6900047f56b0e4 Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Tue, 26 Jan 2021 23:48:44 +0100 Subject: [hermon] Perform clean MPT unmap on device shutdown This change is ported from Flexboot sources. When stopping a Hermon device, perform hermon_unmap_mpt() which runs HERMON_HCR_HW2SW_MPT to bring the Memory Protection Table (MPT) back to software control. Signed-off-by: Christian Iversen Modified-by: Michael Brown Signed-off-by: Michael Brown --- src/drivers/infiniband/hermon.c | 28 ++++++++++++++++++++++++++++ src/drivers/infiniband/hermon.h | 1 + 2 files changed, 29 insertions(+) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index d766ed585..2a9649de2 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -331,6 +331,13 @@ hermon_cmd_sw2hw_mpt ( struct hermon *hermon, unsigned int index, 0, mpt, index, NULL ); } +static inline int +hermon_cmd_hw2sw_mpt ( struct hermon *hermon, unsigned int index ) { + return hermon_cmd ( hermon, + HERMON_HCR_VOID_CMD ( HERMON_HCR_HW2SW_MPT ), + 0, NULL, index, NULL ); +} + static inline int hermon_cmd_write_mtt ( struct hermon *hermon, const struct hermonprm_write_mtt *write_mtt ) { @@ -2807,6 +2814,25 @@ static int hermon_setup_mpt ( struct hermon *hermon ) { return 0; } +/** + * Unmap memory protection table + * + * @v hermon Hermon device + * @ret rc Return status code + */ +static int hermon_unmap_mpt ( struct hermon *hermon ) { + int rc; + + if ( ( rc = hermon_cmd_hw2sw_mpt ( hermon, + hermon->cap.reserved_mrws ) ) != 0 ){ + DBGC ( hermon, "Hermon %p could not unmap MPT: %s\n", + hermon, strerror ( rc ) ); + return rc; + } + + return 0; +} + /** * Configure special queue pairs * @@ -2888,6 +2914,7 @@ static int hermon_start ( struct hermon *hermon, int running ) { err_conf_special_qps: hermon_destroy_eq ( hermon ); err_create_eq: + hermon_unmap_mpt ( hermon ); err_setup_mpt: hermon_cmd_close_hca ( hermon ); err_init_hca: @@ -2905,6 +2932,7 @@ static int hermon_start ( struct hermon *hermon, int running ) { */ static void hermon_stop ( struct hermon *hermon ) { hermon_destroy_eq ( hermon ); + hermon_unmap_mpt ( hermon ); hermon_cmd_close_hca ( hermon ); hermon_unmap_icm ( hermon ); hermon_stop_firmware ( hermon ); diff --git a/src/drivers/infiniband/hermon.h b/src/drivers/infiniband/hermon.h index 381e2e462..61f3b0418 100644 --- a/src/drivers/infiniband/hermon.h +++ b/src/drivers/infiniband/hermon.h @@ -52,6 +52,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define HERMON_HCR_CLOSE_PORT 0x000a #define HERMON_HCR_SET_PORT 0x000c #define HERMON_HCR_SW2HW_MPT 0x000d +#define HERMON_HCR_HW2SW_MPT 0x000f #define HERMON_HCR_WRITE_MTT 0x0011 #define HERMON_HCR_MAP_EQ 0x0012 #define HERMON_HCR_SW2HW_EQ 0x0013 -- cgit v1.2.3-55-g7522 From def46cf344dc9981a0901a1293d4513efafe14d2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 31 Jan 2021 23:29:45 +0000 Subject: [hermon] Limit link poll frequency in DOWN state Some older versions of the hardware (and/or firmware) do not report an event when an Infiniband link reaches the INIT state. The driver works around this missing event by calling ib_smc_update() on each event queue poll while the link is in the DOWN state. Commit 6cb12ee ("[hermon] Increase polling rate for command completions") addressed this by speeding up the time taken to issue each command invoked by ib_smc_update(). Experimentation shows that the impact is still significant: for example, in a situation where an unplugged port is opened, the throughput on the other port can be reduced by over 99%. Fix by throttling the rate at which link polling is attempted. Debugged-by: Christian Iversen Signed-off-by: Michael Brown --- src/drivers/infiniband/hermon.c | 9 ++++++++- src/drivers/infiniband/hermon.h | 9 +++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index 2a9649de2..50ba4f4e8 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -2130,6 +2130,8 @@ static void hermon_poll_eq ( struct ib_device *ibdev ) { struct hermon_event_queue *hermon_eq = &hermon->eq; union hermonprm_event_entry *eqe; union hermonprm_doorbell_register db_reg; + unsigned long now; + unsigned long elapsed; unsigned int eqe_idx_mask; unsigned int event_type; @@ -2138,7 +2140,12 @@ static void hermon_poll_eq ( struct ib_device *ibdev ) { */ if ( ib_is_open ( ibdev ) && ( ibdev->port_state == IB_PORT_STATE_DOWN ) ) { - ib_smc_update ( ibdev, hermon_mad ); + now = currticks(); + elapsed = ( now - hermon->last_poll ); + if ( elapsed >= HERMON_LINK_POLL_INTERVAL ) { + hermon->last_poll = now; + ib_smc_update ( ibdev, hermon_mad ); + } } /* Poll event queue */ diff --git a/src/drivers/infiniband/hermon.h b/src/drivers/infiniband/hermon.h index 61f3b0418..6d7471dfd 100644 --- a/src/drivers/infiniband/hermon.h +++ b/src/drivers/infiniband/hermon.h @@ -894,6 +894,8 @@ struct hermon { /** Event queue */ struct hermon_event_queue eq; + /** Last unsolicited link state poll */ + unsigned long last_poll; /** Unrestricted LKey * * Used to get unrestricted memory access. @@ -930,6 +932,13 @@ struct hermon { /** Memory key prefix */ #define HERMON_MKEY_PREFIX 0x77000000UL +/** Link poll interval + * + * Used when we need to poll for link state (rather than relying upon + * receiving an event). + */ +#define HERMON_LINK_POLL_INTERVAL ( TICKS_PER_SEC / 2 ) + /* * HCA commands * -- cgit v1.2.3-55-g7522 From 79031fee2155a178a9788ca57d55c975607df688 Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Mon, 1 Feb 2021 01:27:08 +0100 Subject: [iscsi] Update link to iBFT reference manual Signed-off-by: Christian Iversen --- src/drivers/block/ibft.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/block/ibft.c b/src/drivers/block/ibft.c index f9918363a..ca5fad9ff 100644 --- a/src/drivers/block/ibft.c +++ b/src/drivers/block/ibft.c @@ -48,11 +48,15 @@ FILE_LICENCE ( BSD2 ); * * iSCSI boot firmware table * - * The information in this file is derived from the document "iSCSI - * Boot Firmware Table (iBFT)" as published by IBM at + * The information in this file is originally derived from the document "iSCSI + * Boot Firmware Table (iBFT)" as published by IBM at: * * ftp://ftp.software.ibm.com/systems/support/system_x_pdf/ibm_iscsi_boot_firmware_table_v1.02.pdf * + * That file is no longer available, but a more recent version is available: + * + * ftp://ftp.software.ibm.com/systems/support/bladecenter/iscsi_boot_firmware_table_v1.03.pdf + * */ /** -- cgit v1.2.3-55-g7522 From 2e3d5909ee7ad35889c3bc55f9119ca5d4615a40 Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Tue, 26 Jan 2021 23:47:01 +0100 Subject: [hermon] Clean up whitespace in hermon.c Signed-off-by: Christian Iversen --- src/drivers/infiniband/hermon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index 50ba4f4e8..45dfd1a94 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -3946,7 +3946,7 @@ static int hermon_probe ( struct pci_device *pci ) { /* Allocate Infiniband devices */ for ( i = 0 ; i < hermon->cap.num_ports ; i++ ) { - ibdev = alloc_ibdev ( 0 ); + ibdev = alloc_ibdev ( 0 ); if ( ! ibdev ) { rc = -ENOMEM; goto err_alloc_ibdev; -- cgit v1.2.3-55-g7522 From e62c3e3513758a523f0222d3fe7fa44d7fe0d4fb Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 1 Feb 2021 01:53:15 +0000 Subject: [hermon] Use reset value suitable for ConnectX-3 The programming documentation states that the reset magic value is "0x00000001 (Big Endian)", and the current code matches this by using the value 0x01000000 for the implicitly little-endian writel(). Inspection of the FlexBoot source code reveals an exciting variety of reset values, some suggestive of confusion around endianness. Experimentation suggests that the value 0x01000001 works reliably across a wide range of hardware. Debugged-by: Christian Iversen Signed-off-by: Michael Brown --- src/drivers/infiniband/hermon.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.h b/src/drivers/infiniband/hermon.h index 6d7471dfd..b4d95d23e 100644 --- a/src/drivers/infiniband/hermon.h +++ b/src/drivers/infiniband/hermon.h @@ -34,7 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /* Device reset */ #define HERMON_RESET_OFFSET 0x0f0010 -#define HERMON_RESET_MAGIC 0x01000000UL +#define HERMON_RESET_MAGIC 0x01000001UL #define HERMON_RESET_WAIT_TIME_MS 1000 /* Work queue entry and completion queue entry opcodes */ -- cgit v1.2.3-55-g7522 From d948ac6c6127c23c77d9e8fd6299ffa588f09f64 Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Wed, 27 Jan 2021 00:03:01 +0100 Subject: [hermon] Adjust Ethernet work queue size Hermon Ethernet work queues have more RX than TX entries, unlike most other drivers. This is possibly the source of some stochastic deadlocks previously experienced with this driver. Update the sizes to be in line with other drivers, and make them slightly larger for better performance. These new queue sizes have been found to work well with ConnectX-3 hardware. Signed-off-by: Christian Iversen Signed-off-by: Michael Brown --- src/drivers/infiniband/hermon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index 45dfd1a94..061ee81c7 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -3274,13 +3274,13 @@ static struct hermon_port_type hermon_port_type_ib = { */ /** Number of Hermon Ethernet send work queue entries */ -#define HERMON_ETH_NUM_SEND_WQES 2 +#define HERMON_ETH_NUM_SEND_WQES 16 /** Number of Hermon Ethernet receive work queue entries */ -#define HERMON_ETH_NUM_RECV_WQES 4 +#define HERMON_ETH_NUM_RECV_WQES 8 /** Number of Hermon Ethernet completion entries */ -#define HERMON_ETH_NUM_CQES 8 +#define HERMON_ETH_NUM_CQES 32 /** * Transmit packet via Hermon Ethernet device -- cgit v1.2.3-55-g7522 From 8b07c88df8ec53a5bd554d940d3b2bd5f0caa27a Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Thu, 28 Jan 2021 21:29:57 +0100 Subject: [hermon] Add support for port management event Inspired by Flexboot, the function hermon_event_port_mgmnt_change() is added to handle the HERMON_EV_PORT_MGMNT_CHANGE event type, which updates the Infiniband subsystem. Signed-off-by: Christian Iversen Modified-by: Michael Brown Signed-off-by: Michael Brown --- src/drivers/infiniband/hermon.c | 29 +++++++++++++++++++++++++++++ src/drivers/infiniband/hermon.h | 10 ++++++++++ 2 files changed, 39 insertions(+) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index 061ee81c7..68ce5d4a0 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -2120,6 +2120,32 @@ static void hermon_event_port_state_change ( struct hermon *hermon, link_up ); } +/** + * Handle port management event + * + * @v hermon Hermon device + * @v eqe Port management change event queue entry + */ +static void hermon_event_port_mgmnt_change ( struct hermon *hermon, + union hermonprm_event_entry *eqe){ + unsigned int port; + + /* Get port */ + port = ( MLX_GET ( &eqe->port_mgmnt_change, port ) - 1 ); + DBGC ( hermon, "Hermon %p port %d management change\n", + hermon, ( port + 1 ) ); + + /* Sanity check */ + if ( port >= hermon->cap.num_ports ) { + DBGC ( hermon, "Hermon %p port %d does not exist!\n", + hermon, ( port + 1 ) ); + return; + } + + /* Update MAD parameters */ + ib_smc_update ( hermon->port[port].ibdev, hermon_mad ); +} + /** * Poll event queue * @@ -2169,6 +2195,9 @@ static void hermon_poll_eq ( struct ib_device *ibdev ) { case HERMON_EV_PORT_STATE_CHANGE: hermon_event_port_state_change ( hermon, eqe ); break; + case HERMON_EV_PORT_MGMNT_CHANGE: + hermon_event_port_mgmnt_change ( hermon, eqe ); + break; default: DBGC ( hermon, "Hermon %p EQN %#lx unrecognised event " "type %#02x:%#02x\n", diff --git a/src/drivers/infiniband/hermon.h b/src/drivers/infiniband/hermon.h index b4d95d23e..fddd7fd41 100644 --- a/src/drivers/infiniband/hermon.h +++ b/src/drivers/infiniband/hermon.h @@ -123,6 +123,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define HERMON_SET_PORT_GID_TABLE 0x0500 #define HERMON_EV_PORT_STATE_CHANGE 0x09 +#define HERMON_EV_PORT_MGMNT_CHANGE 0x1d #define HERMON_SCHED_QP0 0x3f #define HERMON_SCHED_DEFAULT 0x83 @@ -217,6 +218,13 @@ struct hermonprm_port_state_change_event_st { struct hermonprm_port_state_change_st data; } __attribute__ (( packed )); +struct hermonprm_port_mgmnt_change_event_st { + pseudo_bit_t reserved[0x00020]; +/* -------------- */ + pseudo_bit_t port[0x00008]; + pseudo_bit_t reserved0[0x00018]; +} __attribute__ (( packed )); + struct hermonprm_sense_port_st { pseudo_bit_t reserved0[0x00020]; /* -------------- */ @@ -460,6 +468,7 @@ struct MLX_DECLARE_STRUCT ( hermonprm_mod_stat_cfg_input_mod ); struct MLX_DECLARE_STRUCT ( hermonprm_mpt ); struct MLX_DECLARE_STRUCT ( hermonprm_mtt ); struct MLX_DECLARE_STRUCT ( hermonprm_port_state_change_event ); +struct MLX_DECLARE_STRUCT ( hermonprm_port_mgmnt_change_event ); struct MLX_DECLARE_STRUCT ( hermonprm_qp_db_record ); struct MLX_DECLARE_STRUCT ( hermonprm_qp_ee_state_transitions ); struct MLX_DECLARE_STRUCT ( hermonprm_query_dev_cap ); @@ -530,6 +539,7 @@ union hermonprm_completion_entry { union hermonprm_event_entry { struct hermonprm_event_queue_entry generic; struct hermonprm_port_state_change_event port_state_change; + struct hermonprm_port_mgmnt_change_event port_mgmnt_change; } __attribute__ (( packed )); union hermonprm_doorbell_register { -- cgit v1.2.3-55-g7522 From 299c671f57715d5c882eaf0606b1e45ecbd5c73a Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Tue, 26 Jan 2021 22:36:15 +0100 Subject: [hermon] Add a debug notice when initialization is complete Signed-off-by: Christian Iversen Modified-by: Michael Brown Signed-off-by: Michael Brown --- src/drivers/infiniband/hermon.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index 68ce5d4a0..e3b692dc9 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -2945,6 +2945,7 @@ static int hermon_start ( struct hermon *hermon, int running ) { if ( ( rc = hermon_configure_special_qps ( hermon ) ) != 0 ) goto err_conf_special_qps; + DBGC ( hermon, "Hermon %p device started\n", hermon ); return 0; err_conf_special_qps: -- cgit v1.2.3-55-g7522 From 7b2b35981f862ba17765c87f657353f93b5b41d4 Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Wed, 27 Jan 2021 00:06:37 +0100 Subject: [hermon] Throttle debug output when sensing port type When auto-detecting the initial port type, the Hermon driver will spam the debug output without hesitation. Add a short delay in each iteration to fix this. Signed-off-by: Christian Iversen --- src/drivers/infiniband/hermon.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index e3b692dc9..35326ac6e 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -3743,6 +3743,9 @@ static int hermon_set_port_type ( struct hermon *hermon, rc = port_type; return rc; } + + /* Avoid spamming debug output */ + mdelay ( 50 ); } while ( ( port_type == HERMON_PORT_TYPE_UNKNOWN ) && ( ( elapsed = ( currticks() - start ) ) < HERMON_SENSE_PORT_TIMEOUT ) ); -- cgit v1.2.3-55-g7522 From 410566cef7b760b5e59050b38e1eb4e7572f059b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 1 Feb 2021 22:25:52 +0000 Subject: [hermon] Minimise reset time Check for reset completion by waiting for the device to respond to PCI configuration cycles, as documented in the Programmer's Reference Manual. On the original ConnectX HCA, this reduces the time spent on reset from 1000ms down to 1ms. Signed-off-by: Michael Brown --- src/drivers/infiniband/hermon.c | 37 +++++++++++++++++++++++++++++++------ src/drivers/infiniband/hermon.h | 2 +- 2 files changed, 32 insertions(+), 7 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index 35326ac6e..d13a14678 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -2792,22 +2792,45 @@ static void hermon_unmap_icm ( struct hermon *hermon ) { * Reset device * * @v hermon Hermon device + * @ret rc Return status code */ -static void hermon_reset ( struct hermon *hermon ) { +static int hermon_reset ( struct hermon *hermon ) { struct pci_device *pci = hermon->pci; struct pci_config_backup backup; static const uint8_t backup_exclude[] = PCI_CONFIG_BACKUP_EXCLUDE ( 0x58, 0x5c ); + uint16_t vendor; + unsigned int i; + + /* Reset command interface toggle */ + hermon->toggle = 0; /* Perform device reset and preserve PCI configuration */ pci_backup ( pci, &backup, backup_exclude ); writel ( HERMON_RESET_MAGIC, ( hermon->config + HERMON_RESET_OFFSET ) ); - mdelay ( HERMON_RESET_WAIT_TIME_MS ); - pci_restore ( pci, &backup, backup_exclude ); - /* Reset command interface toggle */ - hermon->toggle = 0; + /* Wait until device starts responding to configuration cycles */ + for ( i = 0 ; i < HERMON_RESET_MAX_WAIT_MS ; i++ ) { + + /* Read PCI vendor ID */ + pci_read_config_word ( pci, PCI_VENDOR_ID, &vendor ); + if ( vendor == pci->vendor ) { + + /* Restore PCI configuration */ + pci_restore ( pci, &backup, backup_exclude ); + + DBGC ( hermon, "Hermon %p reset after %dms\n", + hermon, i ); + return 0; + } + + /* Delay */ + mdelay ( 1 ); + } + + DBGC ( hermon, "Hermon %p timed out waiting for reset\n", hermon ); + return -ETIMEDOUT; } /** @@ -3967,7 +3990,8 @@ static int hermon_probe ( struct pci_device *pci ) { HERMON_UAR_NON_EQ_PAGE * HERMON_PAGE_SIZE ); /* Reset device */ - hermon_reset ( hermon ); + if ( ( rc = hermon_reset ( hermon ) ) != 0 ) + goto err_reset; /* Start firmware */ if ( ( rc = hermon_start_firmware ( hermon ) ) != 0 ) @@ -4060,6 +4084,7 @@ static int hermon_probe ( struct pci_device *pci ) { err_get_cap: hermon_stop_firmware ( hermon ); err_start_firmware: + err_reset: iounmap ( hermon->uar ); iounmap ( hermon->config ); hermon_free ( hermon ); diff --git a/src/drivers/infiniband/hermon.h b/src/drivers/infiniband/hermon.h index fddd7fd41..a952bbd81 100644 --- a/src/drivers/infiniband/hermon.h +++ b/src/drivers/infiniband/hermon.h @@ -35,7 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /* Device reset */ #define HERMON_RESET_OFFSET 0x0f0010 #define HERMON_RESET_MAGIC 0x01000001UL -#define HERMON_RESET_WAIT_TIME_MS 1000 +#define HERMON_RESET_MAX_WAIT_MS 1000 /* Work queue entry and completion queue entry opcodes */ #define HERMON_OPCODE_NOP 0x00 -- cgit v1.2.3-55-g7522 From 8747241b3e843ed9771de21d8f2c57c3e67c77c7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 1 Feb 2021 22:57:57 +0000 Subject: [hermon] Make hermon_dump_xxx() functions no-ops on non-debug builds Signed-off-by: Michael Brown --- src/drivers/infiniband/hermon.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index d13a14678..53e514d5b 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -823,6 +823,11 @@ hermon_dump_cqctx ( struct hermon *hermon, struct ib_completion_queue *cq ) { struct hermonprm_completion_queue_context cqctx; int rc; + /* Do nothing unless debugging is enabled */ + if ( ! DBG_LOG ) + return 0; + + /* Dump completion queue context */ memset ( &cqctx, 0, sizeof ( cqctx ) ); if ( ( rc = hermon_cmd_query_cq ( hermon, cq->cqn, &cqctx ) ) != 0 ) { DBGC ( hermon, "Hermon %p CQN %#lx QUERY_CQ failed: %s\n", @@ -1102,6 +1107,11 @@ hermon_dump_qpctx ( struct hermon *hermon, struct ib_queue_pair *qp ) { struct hermonprm_qp_ee_state_transitions qpctx; int rc; + /* Do nothing unless debugging is enabled */ + if ( ! DBG_LOG ) + return 0; + + /* Dump queue pair context */ memset ( &qpctx, 0, sizeof ( qpctx ) ); if ( ( rc = hermon_cmd_query_qp ( hermon, qp->qpn, &qpctx ) ) != 0 ) { DBGC ( hermon, "Hermon %p QPN %#lx QUERY_QP failed: %s\n", @@ -1898,6 +1908,11 @@ hermon_dump_eqctx ( struct hermon *hermon, struct hermonprm_eqc eqctx; int rc; + /* Do nothing unless debugging is enabled */ + if ( ! DBG_LOG ) + return 0; + + /* Dump event queue context */ memset ( &eqctx, 0, sizeof ( eqctx ) ); if ( ( rc = hermon_cmd_query_eq ( hermon, hermon_eq->eqn, &eqctx ) ) != 0 ) { @@ -1930,6 +1945,11 @@ hermon_dump_eqes ( struct hermon *hermon, unsigned int idx; int rc; + /* Do nothing unless debugging is enabled */ + if ( ! DBG_LOG ) + return 0; + + /* Dump event queue entries */ memset ( &eqctx, 0, sizeof ( eqctx ) ); if ( ( rc = hermon_cmd_query_eq ( hermon, hermon_eq->eqn, &eqctx ) ) != 0 ) { -- cgit v1.2.3-55-g7522 From 6f1cb791ee7939c7302c8f815d178e89295b0eda Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 1 Feb 2021 23:06:04 +0000 Subject: [hermon] Avoid parsing length field on completion errors The CQE length field will not be valid for a completion in error. Avoid parsing the length field and just call the completion handler directly. In debug builds, also dump the queue pair context to allow for inspection of the error. Signed-off-by: Michael Brown --- src/drivers/infiniband/hermon.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index 53e514d5b..4d5272f02 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -1104,7 +1104,9 @@ static uint8_t hermon_qp_st[] = { */ static __attribute__ (( unused )) int hermon_dump_qpctx ( struct hermon *hermon, struct ib_queue_pair *qp ) { + struct hermon_queue_pair *hermon_qp = ib_qp_get_drvdata ( qp ); struct hermonprm_qp_ee_state_transitions qpctx; + unsigned int state; int rc; /* Do nothing unless debugging is enabled */ @@ -1118,7 +1120,14 @@ hermon_dump_qpctx ( struct hermon *hermon, struct ib_queue_pair *qp ) { hermon, qp->qpn, strerror ( rc ) ); return rc; } - DBGC ( hermon, "Hermon %p QPN %#lx context:\n", hermon, qp->qpn ); + state = MLX_GET ( &qpctx, qpc_eec_data.state ); + if ( state != hermon_qp->state ) { + DBGC ( hermon, "Hermon %p QPN %#lx state %d unexpected " + "(should be %d)\n", + hermon, qp->qpn, state, hermon_qp->state ); + } + DBGC ( hermon, "Hermon %p QPN %#lx state %d context:\n", + hermon, qp->qpn, state ); DBGC_HDA ( hermon, 0, &qpctx.u.dwords[2], ( sizeof ( qpctx ) - 8 ) ); return 0; @@ -1799,6 +1808,11 @@ static int hermon_complete ( struct ib_device *ibdev, if ( is_send ) { /* Hand off to completion handler */ ib_complete_send ( ibdev, qp, iobuf, rc ); + } else if ( rc != 0 ) { + /* Dump queue state (for debugging) */ + hermon_dump_qpctx ( hermon, qp ); + /* Hand off to completion handler */ + ib_complete_recv ( ibdev, qp, NULL, NULL, iobuf, rc ); } else { /* Set received length */ len = MLX_GET ( &cqe->normal, byte_cnt ); @@ -1841,7 +1855,7 @@ static int hermon_complete ( struct ib_device *ibdev, assert ( len <= iob_tailroom ( iobuf ) ); iob_put ( iobuf, len ); /* Hand off to completion handler */ - ib_complete_recv ( ibdev, qp, &recv_dest, source, iobuf, rc ); + ib_complete_recv ( ibdev, qp, &recv_dest, source, iobuf, 0 ); } return rc; -- cgit v1.2.3-55-g7522 From 1af0fe04f887a5df0ec930cd056023454d6320fe Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Wed, 27 Jan 2021 00:08:18 +0100 Subject: [hermon] Add support for ConnectX-3 based cards After a ton of tedious work, I am pleased to finally introduce full support for ConnectX-3 cards in iPXE! The work has been done by finding all publicly available versions of the Mellanox Flexboot sources, cleaning them up, synthesizing a git history from them, cleaning out non-significant changes, and correlating with the iPXE upstream git history. After this, a proof-of-concept diff was produced, that allowed iPXE to be compiled with rudimentary ConnectX-3 support. This diff was over 10k lines, and contained many changes that were not part of the core driver. Special thanks to Michael Brown for answering my barrage of questions, and helping brainstorm the development along the way. Signed-off-by: Christian Iversen --- src/drivers/infiniband/hermon.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/drivers') diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index 4d5272f02..2afaaf991 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -4232,6 +4232,10 @@ static struct pci_device_id hermon_nics[] = { PCI_ROM ( 0x15b3, 0x675a, "mt26458", "MT26458 HCA driver", 0 ), PCI_ROM ( 0x15b3, 0x6764, "mt26468", "MT26468 HCA driver", 0 ), PCI_ROM ( 0x15b3, 0x676e, "mt26478", "MT26478 HCA driver", 0 ), + + /* Mellanox ConnectX-3 VPI (ethernet + infiniband) */ + PCI_ROM ( 0x15b3, 0x1003, "mt4099", "ConnectX-3 HCA driver", 0 ), + PCI_ROM ( 0x15b3, 0x1007, "mt4103", "ConnectX-3 Pro HCA driver", 0 ), }; struct pci_driver hermon_driver __pci_driver = { -- cgit v1.2.3-55-g7522 From 0049243367e50ccfbc66611716ec3b96b6ab95b5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 13 Feb 2021 18:55:39 +0000 Subject: [ena] Switch to two-phase reset mechanism The Linux and FreeBSD drivers for the (totally undocumented) ENA adapters use a two-phase reset mechanism: first set ENA_CTRL.RESET and wait for this to be reflected in ENA_STAT.RESET, then clear ENA_CTRL.RESET and again wait for it to be reflected in ENA_STAT.RESET. The iPXE driver currently assumes a self-clearing reset mechanism, which appeared to work at the time that the driver was created but seems no longer to function, at least on the t3.nano and t3a.nano instance types found in eu-west-1. Switch to a simplified version of the two-phase reset mechanism as used by Linux and FreeBSD. Signed-off-by: Michael Brown --- src/drivers/net/ena.c | 40 ++++++++++++++++++++++++++++++++-------- src/drivers/net/ena.h | 2 +- 2 files changed, 33 insertions(+), 9 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/net/ena.c b/src/drivers/net/ena.c index 12c161522..85da1c090 100644 --- a/src/drivers/net/ena.c +++ b/src/drivers/net/ena.c @@ -65,35 +65,59 @@ static const char * ena_direction ( unsigned int direction ) { */ /** - * Reset hardware + * Wait for reset operation to be acknowledged * * @v ena ENA device + * @v expected Expected reset state * @ret rc Return status code */ -static int ena_reset ( struct ena_nic *ena ) { +static int ena_reset_wait ( struct ena_nic *ena, uint32_t expected ) { uint32_t stat; unsigned int i; - /* Trigger reset */ - writel ( ENA_CTRL_RESET, ( ena->regs + ENA_CTRL ) ); - /* Wait for reset to complete */ for ( i = 0 ; i < ENA_RESET_MAX_WAIT_MS ; i++ ) { /* Check if device is ready */ stat = readl ( ena->regs + ENA_STAT ); - if ( stat & ENA_STAT_READY ) + if ( ( stat & ENA_STAT_RESET ) == expected ) return 0; /* Delay */ mdelay ( 1 ); } - DBGC ( ena, "ENA %p timed out waiting for reset (status %#08x)\n", - ena, stat ); + DBGC ( ena, "ENA %p timed out waiting for reset status %#08x " + "(got %#08x)\n", ena, expected, stat ); return -ETIMEDOUT; } +/** + * Reset hardware + * + * @v ena ENA device + * @ret rc Return status code + */ +static int ena_reset ( struct ena_nic *ena ) { + int rc; + + /* Trigger reset */ + writel ( ENA_CTRL_RESET, ( ena->regs + ENA_CTRL ) ); + + /* Wait for reset to take effect */ + if ( ( rc = ena_reset_wait ( ena, ENA_STAT_RESET ) ) != 0 ) + return rc; + + /* Clear reset */ + writel ( 0, ( ena->regs + ENA_CTRL ) ); + + /* Wait for reset to clear */ + if ( ( rc = ena_reset_wait ( ena, 0 ) ) != 0 ) + return rc; + + return 0; +} + /****************************************************************************** * * Admin queue diff --git a/src/drivers/net/ena.h b/src/drivers/net/ena.h index 0496fc6bd..676c5b878 100644 --- a/src/drivers/net/ena.h +++ b/src/drivers/net/ena.h @@ -66,7 +66,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** Device status register */ #define ENA_STAT 0x58 -#define ENA_STAT_READY 0x00000001UL /**< Ready */ +#define ENA_STAT_RESET 0x00000008UL /**< Reset in progress */ /** Admin queue entry header */ struct ena_aq_header { -- cgit v1.2.3-55-g7522 From 19d0fab40f07eeea7fe6b9e0d4e8d4b0c2de215f Mon Sep 17 00:00:00 2001 From: Bruce Rogers Date: Tue, 16 Feb 2021 11:29:41 -0700 Subject: [ath5k] Add missing AR5K_EEPROM_READ in ath5k_eeprom_read_turbo_modes The GCC11 compiler pointed out something that apparently no previous compiler noticed: in ath5k_eeprom_pread_turbo_modes, local variable val is used uninitialized. From what I can see, the code is just missing an initial AR5K_EEPROM_READ. Add it right before the switch statement. Signed-off-by: Bruce Rogers Signed-off-by: Michael Brown --- src/drivers/net/ath/ath5k/ath5k_eeprom.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/drivers') diff --git a/src/drivers/net/ath/ath5k/ath5k_eeprom.c b/src/drivers/net/ath/ath5k/ath5k_eeprom.c index 983d206b7..12519bc59 100644 --- a/src/drivers/net/ath/ath5k/ath5k_eeprom.c +++ b/src/drivers/net/ath/ath5k/ath5k_eeprom.c @@ -416,6 +416,7 @@ ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah, if (ee->ee_version < AR5K_EEPROM_VERSION_5_0) return 0; + AR5K_EEPROM_READ(o++, val); switch (mode){ case AR5K_EEPROM_MODE_11A: ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f; -- cgit v1.2.3-55-g7522 From f309d7a7b78eec10621bc71f9401d5b9257f9f39 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 28 Feb 2021 13:45:58 +0000 Subject: [linux] Use host glibc system call wrappers When building as a Linux userspace application, iPXE currently implements its own system calls to the host kernel rather than relying on the host's C library. The output binary is statically linked and has no external dependencies. This matches the general philosophy of other platforms on which iPXE runs, since there are no external libraries available on either BIOS or UEFI bare metal. However, it would be useful for the Linux userspace application to be able to link against host libraries such as libslirp. Modify the build process to perform a two-stage link: first picking out the requested objects in the usual way from blib.a but with relocations left present, then linking again with a helper object to create a standard hosted application. The helper object provides the standard main() entry point and wrappers for the Linux system calls required by the iPXE Linux drivers and interface code. Signed-off-by: Michael Brown --- .github/workflows/build.yml | 4 +- src/Makefile.linux | 39 +++ src/arch/i386/Makefile.linux | 10 +- src/arch/i386/core/linux/linux_syscall.S | 45 --- src/arch/i386/core/linux/linuxprefix.S | 28 -- src/arch/i386/include/bits/linux_api.h | 6 - src/arch/x86/Makefile.linux | 19 +- src/arch/x86/core/linux/linux_api.c | 149 ---------- src/arch/x86/core/linux/linux_strerror.c | 169 ----------- src/arch/x86/include/bits/linux_api_platform.h | 6 - src/arch/x86_64/Makefile.linux | 8 +- src/arch/x86_64/core/linux/linux_syscall.S | 33 --- src/arch/x86_64/core/linux/linuxprefix.S | 25 -- src/arch/x86_64/include/bits/linux_api.h | 6 - src/drivers/linux/af_packet.c | 2 +- src/drivers/linux/tap.c | 2 +- src/hci/linux_args.c | 20 +- src/include/hci/linux_args.h | 31 -- src/include/ipxe/linux_api.h | 86 ++++++ src/include/linux_api.h | 81 ------ src/interface/linux/linux_api.c | 373 +++++++++++++++++++++++++ src/interface/linux/linux_console.c | 2 +- src/interface/linux/linux_entropy.c | 2 +- src/interface/linux/linux_nap.c | 2 +- src/interface/linux/linux_pci.c | 2 +- src/interface/linux/linux_smbios.c | 2 +- src/interface/linux/linux_time.c | 2 +- src/interface/linux/linux_timer.c | 2 +- src/interface/linux/linux_umalloc.c | 2 +- src/interface/linux/linuxprefix.c | 38 +++ 30 files changed, 574 insertions(+), 622 deletions(-) create mode 100644 src/Makefile.linux delete mode 100644 src/arch/i386/core/linux/linux_syscall.S delete mode 100644 src/arch/i386/core/linux/linuxprefix.S delete mode 100644 src/arch/i386/include/bits/linux_api.h delete mode 100644 src/arch/x86/core/linux/linux_api.c delete mode 100644 src/arch/x86/core/linux/linux_strerror.c delete mode 100644 src/arch/x86/include/bits/linux_api_platform.h delete mode 100644 src/arch/x86_64/core/linux/linux_syscall.S delete mode 100644 src/arch/x86_64/core/linux/linuxprefix.S delete mode 100644 src/arch/x86_64/include/bits/linux_api.h delete mode 100644 src/include/hci/linux_args.h create mode 100644 src/include/ipxe/linux_api.h delete mode 100644 src/include/linux_api.h create mode 100644 src/interface/linux/linux_api.c create mode 100644 src/interface/linux/linuxprefix.c (limited to 'src/drivers') diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d890dfb13..6dc577ef1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,9 +14,11 @@ jobs: fetch-depth: 0 - name: Install packages run: | + sudo dpkg --add-architecture i386 sudo apt update sudo apt install -y -o Acquire::Retries=50 \ - mtools syslinux isolinux libc6-dev-i386 valgrind + mtools syslinux isolinux \ + libc6-dev-i386 libc6-dbg:i386 valgrind - name: Build (BIOS) run: | make -j 4 -C src diff --git a/src/Makefile.linux b/src/Makefile.linux new file mode 100644 index 000000000..4a7837916 --- /dev/null +++ b/src/Makefile.linux @@ -0,0 +1,39 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# Prefix all iPXE symbols to avoid collisions with platform libraries +# +SYMBOL_PREFIX = _ipxe__ + +# Enable valgrind +# +CFLAGS += -UNVALGRIND + +# Use a two-stage link +# +LDFLAGS += -r -d + +# Source directories +# +SRCDIRS += drivers/linux +SRCDIRS += interface/linux +NON_AUTO_SRCS += interface/linux/linux_api.c + +# Media types +# +NON_AUTO_MEDIA = linux + +# Compiler flags for building host API wrapper +# +LINUX_CFLAGS += -Os -idirafter include -DSYMBOL_PREFIX=$(SYMBOL_PREFIX) + +# Host API wrapper +# +$(BIN)/linux_api.o : interface/linux/linux_api.c $(MAKEDEPS) + $(QM)$(ECHO) " [BUILD] $@" + $(Q)$(CC) $(LINUX_CFLAGS) $(WORKAROUND_CFLAGS) -o $@ -c $< + +# Rule to generate final binary +# +$(BIN)/%.linux : $(BIN)/%.linux.tmp $(BIN)/linux_api.o + $(QM)$(ECHO) " [FINISH] $@" + $(Q)$(CC) $(LINUX_CFLAGS) $(WORKAROUND_CFLAGS) -o $@ $^ diff --git a/src/arch/i386/Makefile.linux b/src/arch/i386/Makefile.linux index 46328c83b..fe4229e94 100644 --- a/src/arch/i386/Makefile.linux +++ b/src/arch/i386/Makefile.linux @@ -1,6 +1,14 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# Linker script +# LDSCRIPT = arch/i386/scripts/linux.lds -SRCDIRS += arch/i386/core/linux +# Compiler flags for building host API wrapper +# +LINUX_CFLAGS += -m32 +# Include generic Linux Makefile +# MAKEDEPS += arch/x86/Makefile.linux include arch/x86/Makefile.linux diff --git a/src/arch/i386/core/linux/linux_syscall.S b/src/arch/i386/core/linux/linux_syscall.S deleted file mode 100644 index 38a3e74bd..000000000 --- a/src/arch/i386/core/linux/linux_syscall.S +++ /dev/null @@ -1,45 +0,0 @@ - - .section ".data" - .globl linux_errno - -linux_errno: .int 0 - - .section ".text" - .code32 - .globl linux_syscall - .type linux_syscall, @function - -linux_syscall: - /* Save registers */ - pushl %ebx - pushl %esi - pushl %edi - pushl %ebp - - movl 20(%esp), %eax // C arg1 -> syscall number - movl 24(%esp), %ebx // C arg2 -> syscall arg1 - movl 28(%esp), %ecx // C arg3 -> syscall arg2 - movl 32(%esp), %edx // C arg4 -> syscall arg3 - movl 36(%esp), %esi // C arg5 -> syscall arg4 - movl 40(%esp), %edi // C arg6 -> syscall arg5 - movl 44(%esp), %ebp // C arg7 -> syscall arg6 - - int $0x80 - - /* Restore registers */ - popl %ebp - popl %edi - popl %esi - popl %ebx - - cmpl $-4095, %eax - jae 1f - ret - -1: - negl %eax - movl %eax, linux_errno - movl $-1, %eax - ret - - .size linux_syscall, . - linux_syscall diff --git a/src/arch/i386/core/linux/linuxprefix.S b/src/arch/i386/core/linux/linuxprefix.S deleted file mode 100644 index 398d3cb21..000000000 --- a/src/arch/i386/core/linux/linuxprefix.S +++ /dev/null @@ -1,28 +0,0 @@ -#include - - .section ".text" - .code32 - .globl _linux_start - .type _linux_start, @function - -_linux_start: - xorl %ebp, %ebp - - popl %esi // save argc - movl %esp, %edi // save argv - - andl $~15, %esp // 16-byte align the stack - - pushl %edi // argv -> C arg2 - pushl %esi // argc -> C arg1 - - call save_args - - /* Our main doesn't use any arguments */ - call main - - movl %eax, %ebx // rc -> syscall arg1 - movl $__NR_exit, %eax - int $0x80 - - .size _linux_start, . - _linux_start diff --git a/src/arch/i386/include/bits/linux_api.h b/src/arch/i386/include/bits/linux_api.h deleted file mode 100644 index dc6e7416e..000000000 --- a/src/arch/i386/include/bits/linux_api.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _I386_LINUX_API_H -#define _I386_LINUX_API_H - -#define __SYSCALL_mmap __NR_mmap2 - -#endif /* _I386_LINUX_API_H */ diff --git a/src/arch/x86/Makefile.linux b/src/arch/x86/Makefile.linux index 3740cc81a..b60065567 100644 --- a/src/arch/x86/Makefile.linux +++ b/src/arch/x86/Makefile.linux @@ -1,15 +1,10 @@ -MEDIA = linux - -# enable valgrind -CFLAGS += -UNVALGRIND - -SYMBOL_PREFIX = _ipxe__ +# -*- makefile -*- : Force emacs to use Makefile mode +# Include x86 Linux headers +# INCDIRS += arch/x86/include/linux -SRCDIRS += interface/linux -SRCDIRS += drivers/linux -SRCDIRS += arch/x86/core/linux -$(BIN)/%.linux : $(BIN)/%.linux.tmp - $(QM)$(ECHO) " [FINISH] $@" - $(Q)$(CP) $< $@ +# Include generic Linux Makefile +# +MAKEDEPS += Makefile.linux +include Makefile.linux diff --git a/src/arch/x86/core/linux/linux_api.c b/src/arch/x86/core/linux/linux_api.c deleted file mode 100644 index 17b1f3fd4..000000000 --- a/src/arch/x86/core/linux/linux_api.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2010 Piotr Jaroszyński - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -/** @file - * - * Implementation of most of the linux API. - */ - -#include - -#include -#include -#include - -int linux_open ( const char *pathname, int flags ) { - return linux_syscall ( __NR_open, pathname, flags ); -} - -int linux_close ( int fd ) { - return linux_syscall ( __NR_close, fd ); -} - -off_t linux_lseek ( int fd, off_t offset, int whence ) { - return linux_syscall ( __NR_lseek, fd, offset, whence ); -} - -__kernel_ssize_t linux_read ( int fd, void *buf, __kernel_size_t count ) { - return linux_syscall ( __NR_read, fd, buf, count ); -} - -__kernel_ssize_t linux_write ( int fd, const void *buf, - __kernel_size_t count ) { - return linux_syscall ( __NR_write, fd, buf, count ); -} - -int linux_fcntl ( int fd, int cmd, ... ) { - long arg; - va_list list; - - va_start ( list, cmd ); - arg = va_arg ( list, long ); - va_end ( list ); - - return linux_syscall ( __NR_fcntl, fd, cmd, arg ); -} - -int linux_ioctl ( int fd, int request, ... ) { - void *arg; - va_list list; - - va_start ( list, request ); - arg = va_arg ( list, void * ); - va_end ( list ); - - return linux_syscall ( __NR_ioctl, fd, request, arg ); -} - -int linux_poll ( struct pollfd *fds, nfds_t nfds, int timeout ) { - return linux_syscall ( __NR_poll, fds, nfds, timeout ); -} - -int linux_nanosleep ( const struct timespec *req, struct timespec *rem ) { - return linux_syscall ( __NR_nanosleep, req, rem ); -} - -int linux_usleep ( useconds_t usec ) { - struct timespec ts = { - .tv_sec = ( ( long ) ( usec / 1000000 ) ), - .tv_nsec = ( ( long ) ( usec % 1000000 ) * 1000UL ), - }; - - return linux_nanosleep ( &ts, NULL ); -} - -int linux_gettimeofday ( struct timeval *tv, struct timezone *tz ) { - return linux_syscall ( __NR_gettimeofday, tv, tz ); -} - -void * linux_mmap ( void *addr, __kernel_size_t length, int prot, int flags, - int fd, __kernel_off_t offset ) { - return ( void * ) linux_syscall ( __SYSCALL_mmap, addr, length, prot, - flags, fd, offset ); -} - -void * linux_mremap ( void *old_address, __kernel_size_t old_size, - __kernel_size_t new_size, int flags ) { - return ( void * ) linux_syscall ( __NR_mremap, old_address, old_size, - new_size, flags ); -} - -int linux_munmap ( void *addr, __kernel_size_t length ) { - return linux_syscall ( __NR_munmap, addr, length ); -} - -int linux_socket ( int domain, int type_, int protocol ) { -#ifdef __NR_socket - return linux_syscall ( __NR_socket, domain, type_, protocol ); -#else -#ifndef SOCKOP_socket -# define SOCKOP_socket 1 -#endif - unsigned long sc_args[] = { domain, type_, protocol }; - return linux_syscall ( __NR_socketcall, SOCKOP_socket, sc_args ); -#endif -} - -int linux_bind ( int fd, const struct sockaddr *addr, socklen_t addrlen ) { -#ifdef __NR_bind - return linux_syscall ( __NR_bind, fd, addr, addrlen ); -#else -#ifndef SOCKOP_bind -# define SOCKOP_bind 2 -#endif - unsigned long sc_args[] = { fd, (unsigned long)addr, addrlen }; - return linux_syscall ( __NR_socketcall, SOCKOP_bind, sc_args ); -#endif -} - -ssize_t linux_sendto ( int fd, const void *buf, size_t len, int flags, - const struct sockaddr *daddr, socklen_t addrlen ) { -#ifdef __NR_sendto - return linux_syscall ( __NR_sendto, fd, buf, len, flags, - daddr, addrlen ); -#else -#ifndef SOCKOP_sendto -# define SOCKOP_sendto 11 -#endif - unsigned long sc_args[] = { fd, (unsigned long)buf, len, - flags, (unsigned long)daddr, addrlen }; - return linux_syscall ( __NR_socketcall, SOCKOP_sendto, sc_args ); -#endif -} diff --git a/src/arch/x86/core/linux/linux_strerror.c b/src/arch/x86/core/linux/linux_strerror.c deleted file mode 100644 index 24c9b7738..000000000 --- a/src/arch/x86/core/linux/linux_strerror.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2010 Piotr Jaroszyński - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -FILE_LICENCE(GPL2_OR_LATER); - -/** @file - * - * linux_strerror implementation - */ - -#include -#include - -/** Error names from glibc */ -static const char *errors[] = { - "Success", - "Operation not permitted", - "No such file or directory", - "No such process", - "Interrupted system call", - "Input/output error", - "No such device or address", - "Argument list too long", - "Exec format error", - "Bad file descriptor", - "No child processes", - "Resource temporarily unavailable", - "Cannot allocate memory", - "Permission denied", - "Bad address", - "Block device required", - "Device or resource busy", - "File exists", - "Invalid cross-device link", - "No such device", - "Not a directory", - "Is a directory", - "Invalid argument", - "Too many open files in system", - "Too many open files", - "Inappropriate ioctl for device", - "Text file busy", - "File too large", - "No space left on device", - "Illegal seek", - "Read-only file system", - "Too many links", - "Broken pipe", - "Numerical argument out of domain", - "Numerical result out of range", - "Resource deadlock avoided", - "File name too long", - "No locks available", - "Function not implemented", - "Directory not empty", - "Too many levels of symbolic links", - "", - "No message of desired type", - "Identifier removed", - "Channel number out of range", - "Level 2 not synchronized", - "Level 3 halted", - "Level 3 reset", - "Link number out of range", - "Protocol driver not attached", - "No CSI structure available", - "Level 2 halted", - "Invalid exchange", - "Invalid request descriptor", - "Exchange full", - "No anode", - "Invalid request code", - "Invalid slot", - "", - "Bad font file format", - "Device not a stream", - "No data available", - "Timer expired", - "Out of streams resources", - "Machine is not on the network", - "Package not installed", - "Object is remote", - "Link has been severed", - "Advertise error", - "Srmount error", - "Communication error on send", - "Protocol error", - "Multihop attempted", - "RFS specific error", - "Bad message", - "Value too large for defined data type", - "Name not unique on network", - "File descriptor in bad state", - "Remote address changed", - "Can not access a needed shared library", - "Accessing a corrupted shared library", - ".lib section in a.out corrupted", - "Attempting to link in too many shared libraries", - "Cannot exec a shared library directly", - "Invalid or incomplete multibyte or wide character", - "Interrupted system call should be restarted", - "Streams pipe error", - "Too many users", - "Socket operation on non-socket", - "Destination address required", - "Message too long", - "Protocol wrong type for socket", - "Protocol not available", - "Protocol not supported", - "Socket type not supported", - "Operation not supported", - "Protocol family not supported", - "Address family not supported by protocol", - "Address already in use", - "Cannot assign requested address", - "Network is down", - "Network is unreachable", - "Network dropped connection on reset", - "Software caused connection abort", - "Connection reset by peer", - "No buffer space available", - "Transport endpoint is already connected", - "Transport endpoint is not connected", - "Cannot send after transport endpoint shutdown", - "Too many references: cannot splice", - "Connection timed out", - "Connection refused", - "Host is down", - "No route to host", - "Operation already in progress", - "Operation now in progress", - "Stale NFS file handle", - "Structure needs cleaning", - "Not a XENIX named type file", - "No XENIX semaphores available", - "Is a named type file", - "Remote I/O error", - "Disk quota exceeded", - "No medium found", - "Wrong medium type", -}; - -const char *linux_strerror(int errnum) -{ - static char errbuf[64]; - static int errors_size = sizeof(errors) / sizeof(*errors); - - if (errnum >= errors_size || errnum < 0) { - snprintf(errbuf, sizeof(errbuf), "Error %#08x", errnum); - return errbuf; - } else { - return errors[errnum]; - } -} diff --git a/src/arch/x86/include/bits/linux_api_platform.h b/src/arch/x86/include/bits/linux_api_platform.h deleted file mode 100644 index 4a9ced5e2..000000000 --- a/src/arch/x86/include/bits/linux_api_platform.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _LINUX_API_PLATFORM_H -#define _LINUX_API_PLATFORM_H - -extern int linux_errno; - -#endif /* _LINUX_API_PLATFORM_H */ diff --git a/src/arch/x86_64/Makefile.linux b/src/arch/x86_64/Makefile.linux index 154f9d40d..c41ee49df 100644 --- a/src/arch/x86_64/Makefile.linux +++ b/src/arch/x86_64/Makefile.linux @@ -1,6 +1,10 @@ -LDSCRIPT = arch/x86_64/scripts/linux.lds +# -*- makefile -*- : Force emacs to use Makefile mode -SRCDIRS += arch/x86_64/core/linux +# Linker script +# +LDSCRIPT = arch/x86_64/scripts/linux.lds +# Include generic Linux Makefile +# MAKEDEPS += arch/x86/Makefile.linux include arch/x86/Makefile.linux diff --git a/src/arch/x86_64/core/linux/linux_syscall.S b/src/arch/x86_64/core/linux/linux_syscall.S deleted file mode 100644 index d2805f94c..000000000 --- a/src/arch/x86_64/core/linux/linux_syscall.S +++ /dev/null @@ -1,33 +0,0 @@ - - .section ".data" - .globl linux_errno - -linux_errno: .int 0 - - .section ".text" - .code64 - .globl linux_syscall - .type linux_syscall, @function - -linux_syscall: - movq %rdi, %rax // C arg1 -> syscall number - movq %rsi, %rdi // C arg2 -> syscall arg1 - movq %rdx, %rsi // C arg3 -> syscall arg2 - movq %rcx, %rdx // C arg4 -> syscall arg3 - movq %r8, %r10 // C arg5 -> syscall arg4 - movq %r9, %r8 // C arg6 -> syscall arg5 - movq 8(%rsp), %r9 // C arg7 -> syscall arg6 - - syscall - - cmpq $-4095, %rax - jae 1f - ret - -1: - negq %rax - movl %eax, linux_errno - movq $-1, %rax - ret - - .size linux_syscall, . - linux_syscall diff --git a/src/arch/x86_64/core/linux/linuxprefix.S b/src/arch/x86_64/core/linux/linuxprefix.S deleted file mode 100644 index ec8a9decd..000000000 --- a/src/arch/x86_64/core/linux/linuxprefix.S +++ /dev/null @@ -1,25 +0,0 @@ -#include - - .section ".text" - .code64 - .globl _linux_start - .type _linux_start, @function - -_linux_start: - xorq %rbp, %rbp - - popq %rdi // argc -> C arg1 - movq %rsp, %rsi // argv -> C arg2 - - andq $~15, %rsp // 16-byte align the stack - - call save_args - - /* Our main doesn't use any arguments */ - call main - - movq %rax, %rdi // rc -> syscall arg1 - movq $__NR_exit, %rax - syscall - - .size _linux_start, . - _linux_start diff --git a/src/arch/x86_64/include/bits/linux_api.h b/src/arch/x86_64/include/bits/linux_api.h deleted file mode 100644 index 589fb5808..000000000 --- a/src/arch/x86_64/include/bits/linux_api.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _X86_64_LINUX_API_H -#define _X86_64_LINUX_API_H - -#define __SYSCALL_mmap __NR_mmap - -#endif /* _X86_64_LINUX_API_H */ diff --git a/src/drivers/linux/af_packet.c b/src/drivers/linux/af_packet.c index 65aafc5b1..9fa6ef2a5 100644 --- a/src/drivers/linux/af_packet.c +++ b/src/drivers/linux/af_packet.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/drivers/linux/tap.c b/src/drivers/linux/tap.c index db3b7955b..ff1e08bdb 100644 --- a/src/drivers/linux/tap.c +++ b/src/drivers/linux/tap.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/hci/linux_args.c b/src/hci/linux_args.c index 5f903e3b6..12020bd0b 100644 --- a/src/hci/linux_args.c +++ b/src/hci/linux_args.c @@ -18,7 +18,6 @@ FILE_LICENCE(GPL2_OR_LATER); -#include #include #include #include @@ -27,21 +26,8 @@ FILE_LICENCE(GPL2_OR_LATER); #include #include -/** Saved argc */ -static int saved_argc = 0; -/** Saved argv */ -static char ** saved_argv; - -/** - * Save argc and argv for later access. - * - * To be called by linuxprefix - */ -__asmcall void save_args(int argc, char **argv) -{ - saved_argc = argc; - saved_argv = argv; -} +int linux_argc; +char **linux_argv; /** Supported command-line options */ static struct option options[] = { @@ -138,7 +124,7 @@ void linux_args_parse() while (1) { int option_index = 0; - c = getopt_long(saved_argc, saved_argv, "", options, &option_index); + c = getopt_long(linux_argc, linux_argv, "", options, &option_index); if (c == -1) break; diff --git a/src/include/hci/linux_args.h b/src/include/hci/linux_args.h deleted file mode 100644 index ae1ed0526..000000000 --- a/src/include/hci/linux_args.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2010 Piotr Jaroszyński - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _HCI_LINUX_ARGS_H -#define _HCI_LINUX_ARGS_H - -FILE_LICENCE(GPL2_OR_LATER); - -/** - * Save argc and argv for later access. - * - * To be called by linuxprefix - */ -extern __asmcall void save_args(int argc, char **argv); - -#endif /* _HCI_LINUX_ARGS_H */ diff --git a/src/include/ipxe/linux_api.h b/src/include/ipxe/linux_api.h new file mode 100644 index 000000000..ea247a613 --- /dev/null +++ b/src/include/ipxe/linux_api.h @@ -0,0 +1,86 @@ +#ifndef _IPXE_LINUX_API_H +#define _IPXE_LINUX_API_H + +/* + * Copyright (C) 2010 Piotr Jaroszyński . + * Copyright (C) 2021 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/** @file + * + * Linux host API + * + * This file is included from both the iPXE build environment and the + * host build environment. + * + */ + +#if __STDC_HOSTED__ +#define __asmcall +#define FILE_LICENCE(x) +#endif + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +#if ! __STDC_HOSTED__ +#define __KERNEL_STRICT_NAMES +#include +#include +#include +#include +#include +#include +#define MAP_FAILED ( ( void * ) -1 ) +#endif + +struct sockaddr; + +extern int linux_errno; +extern int linux_argc; +extern char **linux_argv; + +extern int __asmcall linux_open ( const char *pathname, int flags, ... ); +extern int __asmcall linux_close ( int fd ); +extern off_t __asmcall linux_lseek ( int fd, off_t offset, int whence ); +extern ssize_t __asmcall linux_read ( int fd, void *buf, size_t count ); +extern ssize_t __asmcall linux_write ( int fd, const void *buf, size_t count ); +extern int __asmcall linux_fcntl ( int fd, int cmd, ... ); +extern int __asmcall linux_ioctl ( int fd, unsigned long request, ... ); +extern int __asmcall linux_poll ( struct pollfd *fds, unsigned int nfds, + int timeout ); +extern int __asmcall linux_nanosleep ( const struct timespec *req, + struct timespec *rem ); +extern int __asmcall linux_usleep ( unsigned int usec ); +extern int __asmcall linux_gettimeofday ( struct timeval *tv, + struct timezone *tz ); +extern void * __asmcall linux_mmap ( void *addr, size_t length, int prot, + int flags, int fd, off_t offset ); +extern void * __asmcall linux_mremap ( void *old_address, size_t old_size, + size_t new_size, int flags, ... ); +extern int __asmcall linux_munmap ( void *addr, size_t length ); +extern int __asmcall linux_socket ( int domain, int type, int protocol ); +extern int __asmcall linux_bind ( int sockfd, const struct sockaddr *addr, + size_t addrlen ); +extern ssize_t __asmcall linux_sendto ( int sockfd, const void *buf, + size_t len, int flags, + const struct sockaddr *dest_addr, + size_t addrlen ); +extern const char * __asmcall linux_strerror ( int linux_errno ); + +#endif /* _IPXE_LINUX_API_H */ diff --git a/src/include/linux_api.h b/src/include/linux_api.h deleted file mode 100644 index fe9fa910f..000000000 --- a/src/include/linux_api.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2010 Piotr Jaroszyński - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _LINUX_API_H -#define _LINUX_API_H - -/** * @file - * - * Linux API prototypes. - * Most of the functions map directly to linux syscalls and are the equivalent - * of POSIX functions with the linux_ prefix removed. - */ - -FILE_LICENCE(GPL2_OR_LATER); - -#include -#include - -#include - -#define __KERNEL_STRICT_NAMES -#include -#include -typedef __kernel_pid_t pid_t; -typedef __kernel_suseconds_t suseconds_t; -typedef __kernel_loff_t loff_t; -#include -#include -#include -#include -#include -typedef unsigned long nfds_t; -typedef uint32_t useconds_t; -typedef uint32_t socklen_t; -struct sockaddr; -#define MAP_FAILED ( ( void * ) -1 ) -#define SEEK_SET 0 - -extern long linux_syscall ( int number, ... ); - -extern int linux_open ( const char *pathname, int flags ); -extern int linux_close ( int fd ); -extern off_t linux_lseek ( int fd, off_t offset, int whence ); -extern __kernel_ssize_t linux_read ( int fd, void *buf, __kernel_size_t count ); -extern __kernel_ssize_t linux_write ( int fd, const void *buf, - __kernel_size_t count ); -extern int linux_fcntl ( int fd, int cmd, ... ); -extern int linux_ioctl ( int fd, int request, ... ); -extern int linux_poll ( struct pollfd *fds, nfds_t nfds, int timeout ); -extern int linux_nanosleep ( const struct timespec *req, struct timespec *rem ); -extern int linux_usleep ( useconds_t usec ); -extern int linux_gettimeofday ( struct timeval *tv, struct timezone *tz ); -extern void * linux_mmap ( void *addr, __kernel_size_t length, int prot, - int flags, int fd, off_t offset ); -extern void * linux_mremap ( void *old_address, __kernel_size_t old_size, - __kernel_size_t new_size, int flags ); -extern int linux_munmap ( void *addr, __kernel_size_t length ); -extern int linux_socket ( int domain, int type_, int protocol ); -extern int linux_bind ( int fd, const struct sockaddr *addr, - socklen_t addrlen ); -extern ssize_t linux_sendto ( int fd, const void *buf, size_t len, int flags, - const struct sockaddr *daddr, socklen_t addrlen ); - -extern const char * linux_strerror ( int errnum ); - -#endif /* _LINUX_API_H */ diff --git a/src/interface/linux/linux_api.c b/src/interface/linux/linux_api.c new file mode 100644 index 000000000..4ab3c6603 --- /dev/null +++ b/src/interface/linux/linux_api.c @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2010 Piotr Jaroszyński . + * Copyright (C) 2021 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Linux host API + * + */ + +/** Construct prefixed symbol name */ +#define _C1( x, y ) x ## y +#define _C2( x, y ) _C1 ( x, y ) + +/** Construct prefixed symbol name for iPXE symbols */ +#define IPXE_SYM( symbol ) _C2 ( SYMBOL_PREFIX, symbol ) + +/** Provide a prefixed symbol alias visible to iPXE code */ +#define PROVIDE_IPXE_SYM( symbol ) \ + extern typeof ( symbol ) IPXE_SYM ( symbol ) \ + __attribute__ (( alias ( #symbol) )) + +/** Most recent system call error */ +int linux_errno __attribute__ (( nocommon )); + +/****************************************************************************** + * + * Host entry point + * + ****************************************************************************** + */ + +extern int IPXE_SYM ( _linux_start ) ( int argc, char **argv ); + +/** + * Main entry point + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Exit status + */ +int main ( int argc, char **argv ) { + + return IPXE_SYM ( _linux_start ) ( argc, argv ); +} + +/****************************************************************************** + * + * System call wrappers + * + ****************************************************************************** + */ + +/** + * Wrap open() + * + */ +int __asmcall linux_open ( const char *pathname, int flags, ... ) { + va_list args; + mode_t mode; + int ret; + + va_start ( args, flags ); + mode = va_arg ( args, mode_t ); + va_end ( args ); + ret = open ( pathname, flags, mode ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap close() + * + */ +int __asmcall linux_close ( int fd ) { + int ret; + + ret = close ( fd ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap lseek() + * + */ +off_t __asmcall linux_lseek ( int fd, off_t offset, int whence ) { + off_t ret; + + ret = lseek ( fd, offset, whence ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap read() + * + */ +ssize_t __asmcall linux_read ( int fd, void *buf, size_t count ) { + ssize_t ret; + + ret = read ( fd, buf, count ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap write() + * + */ +ssize_t __asmcall linux_write ( int fd, const void *buf, size_t count ) { + ssize_t ret; + + ret = write ( fd, buf, count ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap fcntl() + * + */ +int __asmcall linux_fcntl ( int fd, int cmd, ... ) { + va_list args; + long arg; + int ret; + + va_start ( args, cmd ); + arg = va_arg ( args, long ); + va_end ( args ); + ret = fcntl ( fd, cmd, arg ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap ioctl() + * + */ +int __asmcall linux_ioctl ( int fd, unsigned long request, ... ) { + va_list args; + void *arg; + int ret; + + va_start ( args, request ); + arg = va_arg ( args, void * ); + va_end ( args ); + ret = ioctl ( fd, request, arg ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap poll() + * + */ +int __asmcall linux_poll ( struct pollfd *fds, unsigned int nfds, + int timeout ) { + int ret; + + ret = poll ( fds, nfds, timeout ); + if ( ret == -1 ) + linux_errno = errno; +} + +/** + * Wrap nanosleep() + * + */ +int __asmcall linux_nanosleep ( const struct timespec *req, + struct timespec *rem ) { + int ret; + + ret = nanosleep ( req, rem ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap usleep() + * + */ +int __asmcall linux_usleep ( unsigned int usec ) { + int ret; + + ret = usleep ( usec ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap gettimeofday() + * + */ +int __asmcall linux_gettimeofday ( struct timeval *tv, struct timezone *tz ) { + int ret; + + ret = gettimeofday ( tv, tz ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap mmap() + * +*/ +void * __asmcall linux_mmap ( void *addr, size_t length, int prot, int flags, + int fd, off_t offset ) { + void *ret; + + ret = mmap ( addr, length, prot, flags, fd, offset ); + if ( ret == MAP_FAILED ) + linux_errno = errno; + return ret; +} + +/** + * Wrap mremap() + * + */ +void * __asmcall linux_mremap ( void *old_address, size_t old_size, + size_t new_size, int flags, ... ) { + va_list args; + void *new_address; + void *ret; + + va_start ( args, flags ); + new_address = va_arg ( args, void * ); + va_end ( args ); + ret = mremap ( old_address, old_size, new_size, flags, new_address ); + if ( ret == MAP_FAILED ) + linux_errno = errno; + return ret; +} + +/** + * Wrap munmap() + * + */ +int __asmcall linux_munmap ( void *addr, size_t length ) { + int ret; + + ret = munmap ( addr, length ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap socket() + * + */ +int __asmcall linux_socket ( int domain, int type, int protocol ) { + int ret; + + ret = socket ( domain, type, protocol ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap bind() + * + */ +int __asmcall linux_bind ( int sockfd, const struct sockaddr *addr, + size_t addrlen ) { + int ret; + + ret = bind ( sockfd, addr, addrlen ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap sendto() + * + */ +ssize_t __asmcall linux_sendto ( int sockfd, const void *buf, size_t len, + int flags, const struct sockaddr *dest_addr, + size_t addrlen ) { + ssize_t ret; + + ret = sendto ( sockfd, buf, len, flags, dest_addr, addrlen ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/****************************************************************************** + * + * C library wrappers + * + ****************************************************************************** + */ + +/** + * Wrap strerror() + * + */ +const char * __asmcall linux_strerror ( int linux_errno ) { + + return strerror ( linux_errno ); +} + +/****************************************************************************** + * + * Symbol aliases + * + ****************************************************************************** + */ + +PROVIDE_IPXE_SYM ( linux_errno ); +PROVIDE_IPXE_SYM ( linux_open ); +PROVIDE_IPXE_SYM ( linux_close ); +PROVIDE_IPXE_SYM ( linux_lseek ); +PROVIDE_IPXE_SYM ( linux_read ); +PROVIDE_IPXE_SYM ( linux_write ); +PROVIDE_IPXE_SYM ( linux_fcntl ); +PROVIDE_IPXE_SYM ( linux_ioctl ); +PROVIDE_IPXE_SYM ( linux_poll ); +PROVIDE_IPXE_SYM ( linux_nanosleep ); +PROVIDE_IPXE_SYM ( linux_usleep ); +PROVIDE_IPXE_SYM ( linux_gettimeofday ); +PROVIDE_IPXE_SYM ( linux_mmap ); +PROVIDE_IPXE_SYM ( linux_mremap ); +PROVIDE_IPXE_SYM ( linux_munmap ); +PROVIDE_IPXE_SYM ( linux_socket ); +PROVIDE_IPXE_SYM ( linux_bind ); +PROVIDE_IPXE_SYM ( linux_sendto ); +PROVIDE_IPXE_SYM ( linux_strerror ); diff --git a/src/interface/linux/linux_console.c b/src/interface/linux/linux_console.c index 5294fca79..d5415b61c 100644 --- a/src/interface/linux/linux_console.c +++ b/src/interface/linux/linux_console.c @@ -28,7 +28,7 @@ FILE_LICENCE(GPL2_OR_LATER); #include #include -#include +#include #include #include diff --git a/src/interface/linux/linux_entropy.c b/src/interface/linux/linux_entropy.c index 0f8e45d36..257e993a0 100644 --- a/src/interface/linux/linux_entropy.c +++ b/src/interface/linux/linux_entropy.c @@ -31,7 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -#include +#include #include /** Entropy source filename */ diff --git a/src/interface/linux/linux_nap.c b/src/interface/linux/linux_nap.c index f1d3cd962..3e77bc7f1 100644 --- a/src/interface/linux/linux_nap.c +++ b/src/interface/linux/linux_nap.c @@ -21,7 +21,7 @@ FILE_LICENCE(GPL2_OR_LATER); #include -#include +#include /** @file * diff --git a/src/interface/linux/linux_pci.c b/src/interface/linux/linux_pci.c index 0c140cb89..99c629c19 100644 --- a/src/interface/linux/linux_pci.c +++ b/src/interface/linux/linux_pci.c @@ -26,7 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include +#include #include #include diff --git a/src/interface/linux/linux_smbios.c b/src/interface/linux/linux_smbios.c index 6e5174d23..494a60bd9 100644 --- a/src/interface/linux/linux_smbios.c +++ b/src/interface/linux/linux_smbios.c @@ -20,7 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include -#include +#include #include #include diff --git a/src/interface/linux/linux_time.c b/src/interface/linux/linux_time.c index 9e99fe9cd..9d410f8e0 100644 --- a/src/interface/linux/linux_time.c +++ b/src/interface/linux/linux_time.c @@ -32,7 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include +#include #include /** diff --git a/src/interface/linux/linux_timer.c b/src/interface/linux/linux_timer.c index 9c5e96f2b..418fd046a 100644 --- a/src/interface/linux/linux_timer.c +++ b/src/interface/linux/linux_timer.c @@ -21,7 +21,7 @@ FILE_LICENCE(GPL2_OR_LATER); #include #include -#include +#include /** @file * diff --git a/src/interface/linux/linux_umalloc.c b/src/interface/linux/linux_umalloc.c index aa0052c53..a7250fa5b 100644 --- a/src/interface/linux/linux_umalloc.c +++ b/src/interface/linux/linux_umalloc.c @@ -29,7 +29,7 @@ FILE_LICENCE(GPL2_OR_LATER); #include #include -#include +#include /** Special address returned for empty allocations */ #define NOWHERE ((void *)-1) diff --git a/src/interface/linux/linuxprefix.c b/src/interface/linux/linuxprefix.c new file mode 100644 index 000000000..f38236202 --- /dev/null +++ b/src/interface/linux/linuxprefix.c @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2021 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include + +/** + * Linux entry point + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +int __asmcall _linux_start ( int argc, char **argv ) { + + /* Store command-line arguments */ + linux_argc = argc; + linux_argv = argv; + + /* Run iPXE */ + return main(); +} -- cgit v1.2.3-55-g7522 From 2b5d3f582f718ca11488fb6d92ea39dd22b8ffed Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 2 Mar 2021 10:20:55 +0000 Subject: [slirp] Add libslirp driver for Linux Add a driver using libslirp to provide a virtual network interface without requiring root permissions on the host. This simplifies the process of running iPXE as a Linux userspace application with network access. For example: make bin-x86_64-linux/slirp.linux ./bin-x86_64-linux/slirp.linux --net slirp libslirp will provide a built-in emulated DHCP server and NAT router. Settings such as the boot filename may be controlled via command-line options. For example: ./bin-x86_64-linux/slirp.linux \ --net slirp,filename=http://192.168.0.1/boot.ipxe Signed-off-by: Michael Brown --- src/Makefile.linux | 17 +- src/drivers/linux/slirp.c | 552 ++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/errfile.h | 1 + src/include/ipxe/linux_api.h | 19 ++ src/include/ipxe/slirp.h | 155 +++++++++++ src/interface/linux/linux_api.c | 158 ++++++++++++ 6 files changed, 900 insertions(+), 2 deletions(-) create mode 100644 src/drivers/linux/slirp.c create mode 100644 src/include/ipxe/slirp.h (limited to 'src/drivers') diff --git a/src/Makefile.linux b/src/Makefile.linux index 4a7837916..09b2b1577 100644 --- a/src/Makefile.linux +++ b/src/Makefile.linux @@ -26,9 +26,21 @@ NON_AUTO_MEDIA = linux # LINUX_CFLAGS += -Os -idirafter include -DSYMBOL_PREFIX=$(SYMBOL_PREFIX) +# Check for libslirp +# +LIBSLIRP_TEST = $(CC) $(LINUX_CFLAGS) -x c /dev/null -nostartfiles \ + -include slirp/libslirp.h -lslirp \ + -o /dev/null >/dev/null 2>&1 +WITH_LIBSLIRP := $(shell $(LIBSLIRP_TEST) && $(ECHO) yes) +ifneq ($(WITH_LIBSLIRP),) +LINUX_CFLAGS += -DHAVE_LIBSLIRP +LINUX_LDFLAGS += -lslirp +endif + # Host API wrapper # -$(BIN)/linux_api.o : interface/linux/linux_api.c $(MAKEDEPS) +$(BIN)/linux_api.o : interface/linux/linux_api.c include/ipxe/linux_api.h \ + include/ipxe/slirp.h $(MAKEDEPS) $(QM)$(ECHO) " [BUILD] $@" $(Q)$(CC) $(LINUX_CFLAGS) $(WORKAROUND_CFLAGS) -o $@ -c $< @@ -36,4 +48,5 @@ $(BIN)/linux_api.o : interface/linux/linux_api.c $(MAKEDEPS) # $(BIN)/%.linux : $(BIN)/%.linux.tmp $(BIN)/linux_api.o $(QM)$(ECHO) " [FINISH] $@" - $(Q)$(CC) $(LINUX_CFLAGS) $(WORKAROUND_CFLAGS) -o $@ $^ + $(Q)$(CC) $(LINUX_CFLAGS) $(WORKAROUND_CFLAGS) $(LINUX_LDFLAGS) \ + -o $@ $^ diff --git a/src/drivers/linux/slirp.c b/src/drivers/linux/slirp.c new file mode 100644 index 000000000..8341c9676 --- /dev/null +++ b/src/drivers/linux/slirp.c @@ -0,0 +1,552 @@ +/* + * Copyright (C) 2021 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Linux Slirp network driver + * + */ + +/** Maximum number of open file descriptors */ +#define SLIRP_MAX_FDS 128 + +/** A Slirp network interface */ +struct slirp_nic { + /** The libslirp device object */ + struct Slirp *slirp; + /** Polling file descriptor list */ + struct pollfd pollfds[SLIRP_MAX_FDS]; + /** Number of file descriptors */ + unsigned int numfds; +}; + +/** A Slirp alarm timer */ +struct slirp_alarm { + /** Slirp network interface */ + struct slirp_nic *slirp; + /** Retry timer */ + struct retry_timer timer; + /** Callback function */ + void ( __asmcall * callback ) ( void *opaque ); + /** Opaque value for callback function */ + void *opaque; +}; + +/** Default MAC address */ +static const uint8_t slirp_default_mac[ETH_ALEN] = + { 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 }; + +/****************************************************************************** + * + * Slirp interface + * + ****************************************************************************** + */ + +/** + * Send packet + * + * @v buf Data buffer + * @v len Length of data + * @v device Device opaque pointer + * @ret len Consumed length (or negative on error) + */ +static ssize_t __asmcall slirp_send_packet ( const void *buf, size_t len, + void *device ) { + struct net_device *netdev = device; + struct io_buffer *iobuf; + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( len ); + if ( ! iobuf ) + return -1; + + /* Populate I/O buffer */ + memcpy ( iob_put ( iobuf, len ), buf, len ); + + /* Hand off to network stack */ + netdev_rx ( netdev, iobuf ); + + return len; +} + +/** + * Print an error message + * + * @v msg Error message + * @v device Device opaque pointer + */ +static void __asmcall slirp_guest_error ( const char *msg, void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + + DBGC ( slirp, "SLIRP %p error: %s\n", slirp, msg ); +} + +/** + * Get virtual clock + * + * @v device Device opaque pointer + * @ret clock_ns Clock time in nanoseconds + */ +static int64_t __asmcall slirp_clock_get_ns ( void *device __unused ) { + int64_t time; + + time = currticks(); + return ( time * ( 1000000 / TICKS_PER_MS ) ); +} + +/** + * Handle timer expiry + * + * @v timer Retry timer + * @v over Failure indicator + */ +static void slirp_expired ( struct retry_timer *timer, int over __unused ) { + struct slirp_alarm *alarm = + container_of ( timer, struct slirp_alarm, timer ); + struct slirp_nic *slirp = alarm->slirp; + + /* Notify callback */ + DBGC ( slirp, "SLIRP %p timer fired\n", slirp ); + alarm->callback ( alarm->opaque ); +} + +/** + * Create a new timer + * + * @v callback Timer callback + * @v opaque Timer opaque pointer + * @v device Device opaque pointer + * @ret timer Timer + */ +static void * __asmcall +slirp_timer_new ( void ( __asmcall * callback ) ( void *opaque ), + void *opaque, void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + struct slirp_alarm *alarm; + + /* Allocate timer */ + alarm = malloc ( sizeof ( *alarm ) ); + if ( ! alarm ) { + DBGC ( slirp, "SLIRP %p could not allocate timer\n", slirp ); + return NULL; + } + + /* Initialise timer */ + memset ( alarm, 0, sizeof ( *alarm ) ); + alarm->slirp = slirp; + timer_init ( &alarm->timer, slirp_expired, NULL ); + alarm->callback = callback; + alarm->opaque = opaque; + DBGC ( slirp, "SLIRP %p timer %p has callback %p (%p)\n", + slirp, alarm, alarm->callback, alarm->opaque ); + + return alarm; +} + +/** + * Delete a timer + * + * @v timer Timer + * @v device Device opaque pointer + */ +static void __asmcall slirp_timer_free ( void *timer, void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + struct slirp_alarm *alarm = timer; + + /* Ignore timers that failed to allocate */ + if ( ! alarm ) + return; + + /* Stop timer */ + stop_timer ( &alarm->timer ); + + /* Free timer */ + free ( alarm ); + DBGC ( slirp, "SLIRP %p timer %p freed\n", slirp, alarm ); +} + +/** + * Set timer expiry time + * + * @v timer Timer + * @v expire Expiry time + * @v device Device opaque pointer + */ +static void __asmcall slirp_timer_mod ( void *timer, int64_t expire, + void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + struct slirp_alarm *alarm = timer; + int64_t timeout_ms; + unsigned long timeout; + + /* Ignore timers that failed to allocate */ + if ( ! alarm ) + return; + + /* (Re)start timer */ + timeout_ms = ( expire - ( currticks() / TICKS_PER_MS ) ); + if ( timeout_ms < 0 ) + timeout_ms = 0; + timeout = ( timeout_ms * TICKS_PER_MS ); + start_timer_fixed ( &alarm->timer, timeout ); + DBGC ( slirp, "SLIRP %p timer %p set for %ld ticks\n", + slirp, alarm, timeout ); +} + +/** + * Register file descriptor for polling + * + * @v fd File descriptor + * @v device Device opaque pointer + */ +static void __asmcall slirp_register_poll_fd ( int fd, void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + + DBGC ( slirp, "SLIRP %p registered FD %d\n", slirp, fd ); +} + +/** + * Unregister file descriptor + * + * @v fd File descriptor + * @v device Device opaque pointer + */ +static void __asmcall slirp_unregister_poll_fd ( int fd, void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + + DBGC ( slirp, "SLIRP %p unregistered FD %d\n", slirp, fd ); +} + +/** + * Notify that new events are ready + * + * @v device Device opaque pointer + */ +static void __asmcall slirp_notify ( void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + + DBGC2 ( slirp, "SLIRP %p notified\n", slirp ); +} + +/** Slirp callbacks */ +static struct slirp_callbacks slirp_callbacks = { + .send_packet = slirp_send_packet, + .guest_error = slirp_guest_error, + .clock_get_ns = slirp_clock_get_ns, + .timer_new = slirp_timer_new, + .timer_free = slirp_timer_free, + .timer_mod = slirp_timer_mod, + .register_poll_fd = slirp_register_poll_fd, + .unregister_poll_fd = slirp_unregister_poll_fd, + .notify = slirp_notify, +}; + +/****************************************************************************** + * + * Network device interface + * + ****************************************************************************** + */ + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int slirp_open ( struct net_device *netdev ) { + struct slirp_nic *slirp = netdev->priv; + + /* Nothing to do */ + DBGC ( slirp, "SLIRP %p opened\n", slirp ); + + return 0; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void slirp_close ( struct net_device *netdev ) { + struct slirp_nic *slirp = netdev->priv; + + /* Nothing to do */ + DBGC ( slirp, "SLIRP %p closed\n", slirp ); +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int slirp_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct slirp_nic *slirp = netdev->priv; + + /* Transmit packet */ + linux_slirp_input ( slirp->slirp, iobuf->data, iob_len ( iobuf ) ); + netdev_tx_complete ( netdev, iobuf ); + + return 0; +} + +/** + * Add polling file descriptor + * + * @v fd File descriptor + * @v events Events of interest + * @v device Device opaque pointer + * @ret index File descriptor index + */ +static int __asmcall slirp_add_poll ( int fd, int events, void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + struct pollfd *pollfd; + unsigned int index; + + /* Fail if too many descriptors are registered */ + if ( slirp->numfds >= SLIRP_MAX_FDS ) { + DBGC ( slirp, "SLIRP %p too many file descriptors\n", slirp ); + return -1; + } + + /* Populate polling file descriptor */ + index = slirp->numfds++; + pollfd = &slirp->pollfds[index]; + pollfd->fd = fd; + pollfd->events = 0; + if ( events & SLIRP_EVENT_IN ) + pollfd->events |= POLLIN; + if ( events & SLIRP_EVENT_OUT ) + pollfd->events |= POLLOUT; + if ( events & SLIRP_EVENT_PRI ) + pollfd->events |= POLLPRI; + if ( events & SLIRP_EVENT_ERR ) + pollfd->events |= POLLERR; + if ( events & SLIRP_EVENT_HUP ) + pollfd->events |= ( POLLHUP | POLLRDHUP ); + DBGCP ( slirp, "SLIRP %p polling FD %d event mask %#04x(%#04x)\n", + slirp, fd, events, pollfd->events ); + + return index; +} + +/** + * Get returned events for a file descriptor + * + * @v index File descriptor index + * @v device Device opaque pointer + * @ret events Returned events + */ +static int __asmcall slirp_get_revents ( int index, void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + int revents; + int events; + + /* Ignore failed descriptors */ + if ( index < 0 ) + return 0; + + /* Collect events */ + revents = slirp->pollfds[index].revents; + events = 0; + if ( revents & POLLIN ) + events |= SLIRP_EVENT_IN; + if ( revents & POLLOUT ) + events |= SLIRP_EVENT_OUT; + if ( revents & POLLPRI ) + events |= SLIRP_EVENT_PRI; + if ( revents & POLLERR ) + events |= SLIRP_EVENT_ERR; + if ( revents & ( POLLHUP | POLLRDHUP ) ) + events |= SLIRP_EVENT_HUP; + if ( events ) { + DBGC2 ( slirp, "SLIRP %p polled FD %d events %#04x(%#04x)\n", + slirp, slirp->pollfds[index].fd, events, revents ); + } + + return events; +} + +/** + * Poll for completed and received packets + * + * @v netdev Network device + */ +static void slirp_poll ( struct net_device *netdev ) { + struct slirp_nic *slirp = netdev->priv; + uint32_t timeout = 0; + int ready; + int error; + + /* Rebuild polling file descriptor list */ + slirp->numfds = 0; + linux_slirp_pollfds_fill ( slirp->slirp, &timeout, + slirp_add_poll, netdev ); + + /* Poll descriptors */ + ready = linux_poll ( slirp->pollfds, slirp->numfds, 0 ); + error = ( ready == -1 ); + linux_slirp_pollfds_poll ( slirp->slirp, error, slirp_get_revents, + netdev ); + + /* Record polling errors */ + if ( error ) { + DBGC ( slirp, "SLIRP %p poll failed: %s\n", + slirp, linux_strerror ( linux_errno ) ); + netdev_rx_err ( netdev, NULL, -ELINUX ( linux_errno ) ); + } +} + +/** Network device operations */ +static struct net_device_operations slirp_operations = { + .open = slirp_open, + .close = slirp_close, + .transmit = slirp_transmit, + .poll = slirp_poll, +}; + +/****************************************************************************** + * + * Linux driver interface + * + ****************************************************************************** + */ + +/** + * Probe device + * + * @v linux Linux device + * @v request Device creation request + * @ret rc Return status code + */ +static int slirp_probe ( struct linux_device *linux, + struct linux_device_request *request ) { + struct net_device *netdev; + struct slirp_nic *slirp; + struct slirp_config config; + int rc; + + /* Allocate device */ + netdev = alloc_etherdev ( sizeof ( *slirp ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &slirp_operations ); + linux_set_drvdata ( linux, netdev ); + snprintf ( linux->dev.name, sizeof ( linux->dev.name ), "host" ); + netdev->dev = &linux->dev; + memcpy ( netdev->hw_addr, slirp_default_mac, ETH_ALEN ); + slirp = netdev->priv; + memset ( slirp, 0, sizeof ( *slirp ) ); + + /* Apply requested settings */ + linux_apply_settings ( &request->settings, + netdev_settings ( netdev ) ); + + /* Initialise default configuration (matching qemu) */ + memset ( &config, 0, sizeof ( config ) ); + config.version = 1; + config.in_enabled = true; + config.vnetwork.s_addr = htonl ( 0x0a000200 ); /* 10.0.2.0 */ + config.vnetmask.s_addr = htonl ( 0xffffff00 ); /* 255.255.255.0 */ + config.vhost.s_addr = htonl ( 0x0a000202 ); /* 10.0.2.2 */ + config.in6_enabled = true; + config.vdhcp_start.s_addr = htonl ( 0x0a00020f ); /* 10.0.2.15 */ + config.vnameserver.s_addr = htonl ( 0x0a000203 ); /* 10.0.2.3 */ + + /* Instantiate device */ + slirp->slirp = linux_slirp_new ( &config, &slirp_callbacks, netdev ); + if ( ! slirp->slirp ) { + DBGC ( slirp, "SLIRP could not instantiate\n" ); + rc = -ENODEV; + goto err_new; + } + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register; + + /* Set link up since there is no concept of link state */ + netdev_link_up ( netdev ); + + return 0; + + unregister_netdev ( netdev ); + err_register: + linux_slirp_cleanup ( slirp->slirp ); + err_new: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: + return rc; +} + +/** + * Remove device + * + * @v linux Linux device + */ +static void slirp_remove ( struct linux_device *linux ) { + struct net_device *netdev = linux_get_drvdata ( linux ); + struct slirp_nic *slirp = netdev->priv; + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Shut down device */ + linux_slirp_cleanup ( slirp->slirp ); + + /* Free network device */ + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** Slirp driver */ +struct linux_driver slirp_driver __linux_driver = { + .name = "slirp", + .probe = slirp_probe, + .remove = slirp_remove, + .can_probe = 1, +}; diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index e3fc8fa09..b5c5d185e 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -212,6 +212,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_intelxlvf ( ERRFILE_DRIVER | 0x00cd0000 ) #define ERRFILE_usbblk ( ERRFILE_DRIVER | 0x00ce0000 ) #define ERRFILE_iphone ( ERRFILE_DRIVER | 0x00cf0000 ) +#define ERRFILE_slirp ( ERRFILE_DRIVER | 0x00d00000 ) #define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 ) #define ERRFILE_arp ( ERRFILE_NET | 0x00010000 ) diff --git a/src/include/ipxe/linux_api.h b/src/include/ipxe/linux_api.h index ea247a613..040b52f8c 100644 --- a/src/include/ipxe/linux_api.h +++ b/src/include/ipxe/linux_api.h @@ -50,6 +50,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #endif struct sockaddr; +struct slirp_config; +struct slirp_callbacks; +struct Slirp; extern int linux_errno; extern int linux_argc; @@ -82,5 +85,21 @@ extern ssize_t __asmcall linux_sendto ( int sockfd, const void *buf, const struct sockaddr *dest_addr, size_t addrlen ); extern const char * __asmcall linux_strerror ( int linux_errno ); +extern struct Slirp * __asmcall +linux_slirp_new ( const struct slirp_config *config, + const struct slirp_callbacks *callbacks, void *opaque ); +extern void __asmcall linux_slirp_cleanup ( struct Slirp *slirp ); +extern void __asmcall linux_slirp_input ( struct Slirp *slirp, + const uint8_t *pkt, int pkt_len ); +extern void __asmcall +linux_slirp_pollfds_fill ( struct Slirp *slirp, uint32_t *timeout, + int ( __asmcall * add_poll ) ( int fd, int events, + void *opaque ), + void *opaque ); +extern void __asmcall +linux_slirp_pollfds_poll ( struct Slirp *slirp, int select_error, + int ( __asmcall * get_revents ) ( int idx, + void *opaque ), + void *opaque ); #endif /* _IPXE_LINUX_API_H */ diff --git a/src/include/ipxe/slirp.h b/src/include/ipxe/slirp.h new file mode 100644 index 000000000..4fb13b934 --- /dev/null +++ b/src/include/ipxe/slirp.h @@ -0,0 +1,155 @@ +#ifndef _IPXE_SLIRP_H +#define _IPXE_SLIRP_H + +/** @file + * + * Linux Slirp network driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include + +/** Ready to be read */ +#define SLIRP_EVENT_IN 0x01 + +/** Ready to be written */ +#define SLIRP_EVENT_OUT 0x02 + +/** Exceptional condition */ +#define SLIRP_EVENT_PRI 0x04 + +/** Error condition */ +#define SLIRP_EVENT_ERR 0x08 + +/** Hang up */ +#define SLIRP_EVENT_HUP 0x10 + +/** Slirp device configuration */ +struct slirp_config { + /** Configuration version */ + uint32_t version; + /** Restrict to host loopback connections only */ + int restricted; + /** IPv4 is enabled */ + bool in_enabled; + /** IPv4 network */ + struct in_addr vnetwork; + /** IPv4 netmask */ + struct in_addr vnetmask; + /** IPv4 host server address */ + struct in_addr vhost; + /** IPv6 is enabled */ + bool in6_enabled; + /** IPv6 prefix */ + struct in6_addr vprefix_addr6; + /** IPv6 prefix length */ + uint8_t vprefix_len; + /** IPv6 host server address */ + struct in6_addr vhost6; + /** Client hostname */ + const char *vhostname; + /** TFTP server name */ + const char *tftp_server_name; + /** TFTP path prefix */ + const char *tftp_path; + /** Boot filename */ + const char *bootfile; + /** DHCPv4 start address */ + struct in_addr vdhcp_start; + /** DNS IPv4 address */ + struct in_addr vnameserver; + /** DNS IPv6 address */ + struct in_addr vnameserver6; + /** DNS search list */ + const char **vdnssearch; + /** Domain name */ + const char *vdomainname; + /** Interface MTU */ + size_t if_mtu; + /** Interface MRU */ + size_t if_mru; + /** Disable host loopback connections */ + bool disable_host_loopback; + /** Enable emulation (apparently unsafe) */ + bool enable_emu; +}; + +/** Slirp device callbacks */ +struct slirp_callbacks { + /** + * Send packet + * + * @v buf Data buffer + * @v len Length of data + * @v device Device opaque pointer + * @ret len Consumed length (or negative on error) + */ + ssize_t ( __asmcall * send_packet ) ( const void *buf, size_t len, + void *device ); + /** + * Print an error message + * + * @v msg Error message + * @v device Device opaque pointer + */ + void ( __asmcall * guest_error ) ( const char *msg, void *device ); + /** + * Get virtual clock + * + * @v device Device opaque pointer + * @ret clock_ns Clock time in nanoseconds + */ + int64_t ( __asmcall * clock_get_ns ) ( void *device ); + /** + * Create a new timer + * + * @v callback Timer callback + * @v opaque Timer opaque pointer + * @v device Device opaque pointer + * @ret timer Timer + */ + void * ( __asmcall * timer_new ) ( void ( __asmcall * callback ) + ( void *opaque ), + void *opaque, void *device ); + /** + * Delete a timer + * + * @v timer Timer + * @v device Device opaque pointer + */ + void ( __asmcall * timer_free ) ( void *timer, void *device ); + /** + * Set timer expiry time + * + * @v timer Timer + * @v expire Expiry time + * @v device Device opaque pointer + */ + void ( __asmcall * timer_mod ) ( void *timer, int64_t expire, + void *device ); + /** + * Register file descriptor for polling + * + * @v fd File descriptor + * @v device Device opaque pointer + */ + void ( __asmcall * register_poll_fd ) ( int fd, void *device ); + /** + * Unregister file descriptor + * + * @v fd File descriptor + * @v device Device opaque pointer + */ + void ( __asmcall * unregister_poll_fd ) ( int fd, void *device ); + /** + * Notify that new events are ready + * + * @v device Device opaque pointer + */ + void ( __asmcall * notify ) ( void *device ); +}; + +#endif /* _IPXE_SLIRP_H */ diff --git a/src/interface/linux/linux_api.c b/src/interface/linux/linux_api.c index 4ab3c6603..1f44b532b 100644 --- a/src/interface/linux/linux_api.c +++ b/src/interface/linux/linux_api.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,13 @@ #include #include #include +#include #include +#include + +#ifdef HAVE_LIBSLIRP +#include +#endif /** @file * @@ -345,6 +352,152 @@ const char * __asmcall linux_strerror ( int linux_errno ) { return strerror ( linux_errno ); } +/****************************************************************************** + * + * libslirp wrappers + * + ****************************************************************************** + */ + +#ifdef HAVE_LIBSLIRP + +/** + * Wrap slirp_new() + * + */ +struct Slirp * __asmcall +linux_slirp_new ( const struct slirp_config *config, + const struct slirp_callbacks *callbacks, void *opaque ) { + const union { + struct slirp_callbacks callbacks; + SlirpCb cb; + } *u = ( ( typeof ( u ) ) callbacks ); + SlirpConfig cfg; + Slirp *slirp; + + /* Translate configuration */ + memset ( &cfg, 0, sizeof ( cfg ) ); + cfg.version = config->version; + cfg.restricted = config->restricted; + cfg.in_enabled = config->in_enabled; + cfg.vnetwork = config->vnetwork; + cfg.vnetmask = config->vnetmask; + cfg.vhost = config->vhost; + cfg.in6_enabled = config->in6_enabled; + memcpy ( &cfg.vprefix_addr6, &config->vprefix_addr6, + sizeof ( cfg.vprefix_addr6 ) ); + cfg.vprefix_len = config->vprefix_len; + memcpy ( &cfg.vhost6, &config->vhost6, sizeof ( cfg.vhost6 ) ); + cfg.vhostname = config->vhostname; + cfg.tftp_server_name = config->tftp_server_name; + cfg.tftp_path = config->tftp_path; + cfg.bootfile = config->bootfile; + cfg.vdhcp_start = config->vdhcp_start; + cfg.vnameserver = config->vnameserver; + memcpy ( &cfg.vnameserver6, &config->vnameserver6, + sizeof ( cfg.vnameserver6 ) ); + cfg.vdnssearch = config->vdnssearch; + cfg.vdomainname = config->vdomainname; + cfg.if_mtu = config->if_mtu; + cfg.if_mru = config->if_mru; + cfg.disable_host_loopback = config->disable_host_loopback; + cfg.enable_emu = config->enable_emu; + + /* Validate callback structure */ + static_assert ( &u->cb.send_packet == &u->callbacks.send_packet ); + static_assert ( &u->cb.guest_error == &u->callbacks.guest_error ); + static_assert ( &u->cb.clock_get_ns == &u->callbacks.clock_get_ns ); + static_assert ( &u->cb.timer_new == &u->callbacks.timer_new ); + static_assert ( &u->cb.timer_free == &u->callbacks.timer_free ); + static_assert ( &u->cb.timer_mod == &u->callbacks.timer_mod ); + static_assert ( &u->cb.register_poll_fd == + &u->callbacks.register_poll_fd ); + static_assert ( &u->cb.unregister_poll_fd == + &u->callbacks.unregister_poll_fd ); + static_assert ( &u->cb.notify == &u->callbacks.notify ); + + /* Create device */ + slirp = slirp_new ( &cfg, &u->cb, opaque ); + + return slirp; +} + +/** + * Wrap slirp_cleanup() + * + */ +void __asmcall linux_slirp_cleanup ( struct Slirp *slirp ) { + + slirp_cleanup ( slirp ); +} + +/** + * Wrap slirp_input() + * + */ +void __asmcall linux_slirp_input ( struct Slirp *slirp, const uint8_t *pkt, + int pkt_len ) { + + slirp_input ( slirp, pkt, pkt_len ); +} + +/** + * Wrap slirp_pollfds_fill() + * + */ +void __asmcall +linux_slirp_pollfds_fill ( struct Slirp *slirp, uint32_t *timeout, + int ( __asmcall * add_poll ) ( int fd, int events, + void *opaque ), + void *opaque ) { + + slirp_pollfds_fill ( slirp, timeout, add_poll, opaque ); +} + +/** + * Wrap slirp_pollfds_poll() + * + */ +void __asmcall +linux_slirp_pollfds_poll ( struct Slirp *slirp, int select_error, + int ( __asmcall * get_revents ) ( int idx, + void *opaque ), + void *opaque ) { + + slirp_pollfds_poll ( slirp, select_error, get_revents, opaque ); +} + +#else /* HAVE_LIBSLIRP */ + +struct Slirp * __asmcall +linux_slirp_new ( const struct slirp_config *config, + const struct slirp_callbacks *callbacks, void *opaque ) { + return NULL; +} + +void __asmcall linux_slirp_cleanup ( struct Slirp *slirp ) { +} + +void __asmcall linux_slirp_input ( struct Slirp *slirp, const uint8_t *pkt, + int pkt_len ) { +} + +void __asmcall +linux_slirp_pollfds_fill ( struct Slirp *slirp, uint32_t *timeout, + int ( __asmcall * add_poll ) ( int fd, int events, + void *opaque ), + void *opaque ) { +} + +void __asmcall +linux_slirp_pollfds_poll ( struct Slirp *slirp, int select_error, + int ( __asmcall * get_revents ) ( int idx, + void *opaque ), + void *opaque ) { +} + +#endif /* HAVE_LIBSLIRP */ + /****************************************************************************** * * Symbol aliases @@ -371,3 +524,8 @@ PROVIDE_IPXE_SYM ( linux_socket ); PROVIDE_IPXE_SYM ( linux_bind ); PROVIDE_IPXE_SYM ( linux_sendto ); PROVIDE_IPXE_SYM ( linux_strerror ); +PROVIDE_IPXE_SYM ( linux_slirp_new ); +PROVIDE_IPXE_SYM ( linux_slirp_cleanup ); +PROVIDE_IPXE_SYM ( linux_slirp_input ); +PROVIDE_IPXE_SYM ( linux_slirp_pollfds_fill ); +PROVIDE_IPXE_SYM ( linux_slirp_pollfds_poll ); -- cgit v1.2.3-55-g7522 From 7b963310aad3e68663d93ddaa10f8f27ab33d157 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 2 Mar 2021 19:34:16 +0000 Subject: [linux] Allow arbitrary settings to be applied to Linux devices Allow arbitrary settings to be specified on the Linux command line. For example: ./bin-x86_64-linux/slirp.linux \ --net slirp,testserver=qa-test.ipxe.org This can be useful when using the Linux userspace build to test embedded scripts, since it allows arbitrary parameters to be passed directly on the command line. Signed-off-by: Michael Brown --- src/drivers/linux/linux.c | 50 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 13 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/linux/linux.c b/src/drivers/linux/linux.c index 83546b27e..898f50024 100644 --- a/src/drivers/linux/linux.c +++ b/src/drivers/linux/linux.c @@ -130,24 +130,48 @@ struct linux_setting *linux_find_setting(char *name, struct list_head *settings) return result; } -void linux_apply_settings(struct list_head *new_settings, struct settings *settings_block) -{ - struct linux_setting *setting; +/** + * Apply Linux command-line settings + * + * @v list List of command-line settings + * @v settings Settings block + */ +void linux_apply_settings ( struct list_head *list, + struct settings *settings ) { + struct linux_setting *lsetting; + struct settings *ignore; + struct setting setting; int rc; - list_for_each_entry(setting, new_settings, list) { + list_for_each_entry ( lsetting, list, list ) { + /* Skip already applied settings */ - if (setting->applied) + if ( lsetting->applied ) continue; - struct setting *s = find_setting(setting->name); - if (s) { - rc = storef_setting(settings_block, find_setting(setting->name), setting->value); - if (rc != 0) - DBG("linux storing setting '%s' = '%s' failed\n", setting->name, setting->value); - setting->applied = 1; - } else { - DBG("linux unknown setting '%s'\n", setting->name); + /* Parse setting name */ + if ( ( rc = parse_setting_name ( lsetting->name, + find_child_settings, &ignore, + &setting ) ) != 0 ) { + DBGC ( settings, "Linux cannot parse %s: %s\n", + lsetting->name, strerror ( rc ) ); + continue; + } + + /* Apply default type if not specified */ + if ( ! setting.type ) + setting.type = &setting_type_string; + + /* Store setting */ + if ( ( rc = storef_setting ( settings, &setting, + lsetting->value ) ) != 0 ) { + DBGC ( settings, "Linux cannot set %s=\"%s\": %s\n", + lsetting->name, lsetting->value, + strerror ( rc ) ); + continue; } + + /* Mark setting as applied */ + lsetting->applied = 1; } } -- cgit v1.2.3-55-g7522