Esempio n. 1
0
/**
 * Attach driver to device
 *
 * @v efidev		EFI device
 * @ret rc		Return status code
 */
int snpnet_start ( struct efi_device *efidev ) {
    EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
    EFI_HANDLE device = efidev->device;
    EFI_SIMPLE_NETWORK_MODE *mode;
    struct net_device *netdev;
    struct snp_nic *snp;
    void *interface;
    EFI_STATUS efirc;
    int rc;

    /* Open SNP protocol */
    if ( ( efirc = bs->OpenProtocol ( device,
                                      &efi_simple_network_protocol_guid,
                                      &interface, efi_image_handle, device,
                                      ( EFI_OPEN_PROTOCOL_BY_DRIVER |
                                        EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0) {
        rc = -EEFI ( efirc );
        DBGC ( device, "SNP %s cannot open SNP protocol: %s\n",
               efi_handle_name ( device ), strerror ( rc ) );
        DBGC_EFI_OPENERS ( device, device,
                           &efi_simple_network_protocol_guid );
        goto err_open_protocol;
    }

    /* Allocate and initialise structure */
    netdev = alloc_etherdev ( sizeof ( *snp ) );
    if ( ! netdev ) {
        rc = -ENOMEM;
        goto err_alloc;
    }
    netdev_init ( netdev, &snpnet_operations );
    snp = netdev->priv;
    snp->efidev = efidev;
    snp->snp = interface;
    mode = snp->snp->Mode;
    efidev_set_drvdata ( efidev, netdev );

    /* Populate underlying device information */
    efi_device_info ( device, "SNP", &snp->dev );
    snp->dev.driver_name = "SNP";
    snp->dev.parent = &efidev->dev;
    list_add ( &snp->dev.siblings, &efidev->dev.children );
    INIT_LIST_HEAD ( &snp->dev.children );
    netdev->dev = &snp->dev;

    /* Bring to the Started state */
    if ( ( mode->State == EfiSimpleNetworkStopped ) &&
            ( ( efirc = snp->snp->Start ( snp->snp ) ) != 0 ) ) {
        rc = -EEFI ( efirc );
        DBGC ( device, "SNP %s could not start: %s\n",
               efi_handle_name ( device ), strerror ( rc ) );
        goto err_start;
    }
    if ( ( mode->State == EfiSimpleNetworkInitialized ) &&
            ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) {
        rc = -EEFI ( efirc );
        DBGC ( device, "SNP %s could not shut down: %s\n",
               efi_handle_name ( device ), strerror ( rc ) );
        goto err_shutdown;
    }

    /* Populate network device parameters */
    if ( mode->HwAddressSize != netdev->ll_protocol->hw_addr_len ) {
        DBGC ( device, "SNP %s has invalid hardware address length "
               "%d\n", efi_handle_name ( device ), mode->HwAddressSize);
        rc = -ENOTSUP;
        goto err_hw_addr_len;
    }
    memcpy ( netdev->hw_addr, &mode->PermanentAddress,
             netdev->ll_protocol->hw_addr_len );
    if ( mode->HwAddressSize != netdev->ll_protocol->ll_addr_len ) {
        DBGC ( device, "SNP %s has invalid link-layer address length "
               "%d\n", efi_handle_name ( device ), mode->HwAddressSize);
        rc = -ENOTSUP;
        goto err_ll_addr_len;
    }
    memcpy ( netdev->ll_addr, &mode->CurrentAddress,
             netdev->ll_protocol->ll_addr_len );
    snp->mtu = ( snp->snp->Mode->MaxPacketSize +
                 snp->snp->Mode->MediaHeaderSize );

    /* Register network device */
    if ( ( rc = register_netdev ( netdev ) ) != 0 )
        goto err_register_netdev;
    DBGC ( device, "SNP %s registered as %s\n",
           efi_handle_name ( device ), netdev->name );

    /* Set initial link state */
    if ( snp->snp->Mode->MediaPresentSupported ) {
        snpnet_check_link ( netdev );
    } else {
        netdev_link_up ( netdev );
    }

    return 0;

    unregister_netdev ( netdev );
err_register_netdev:
err_ll_addr_len:
err_hw_addr_len:
err_shutdown:
err_start:
    list_del ( &snp->dev.siblings );
    netdev_nullify ( netdev );
    netdev_put ( netdev );
err_alloc:
    bs->CloseProtocol ( device, &efi_simple_network_protocol_guid,
                        efi_image_handle, device );
err_open_protocol:
    return rc;
}
Esempio n. 2
0
File: nii.c Progetto: baloo/ipxe
/**
 * Attach driver to device
 *
 * @v efidev		EFI device
 * @ret rc		Return status code
 */
int nii_start ( struct efi_device *efidev ) {
	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
	EFI_HANDLE device = efidev->device;
	struct net_device *netdev;
	struct nii_nic *nii;
	void *interface;
	EFI_STATUS efirc;
	int rc;

	/* Allocate and initialise structure */
	netdev = alloc_netdev ( sizeof ( *nii ) );
	if ( ! netdev ) {
		rc = -ENOMEM;
		goto err_alloc;
	}
	netdev_init ( netdev, &nii_operations );
	nii = netdev->priv;
	nii->efidev = efidev;
	netdev->ll_broadcast = nii->broadcast;
	efidev_set_drvdata ( efidev, netdev );

	/* Populate underlying device information */
	efi_device_info ( device, "NII", &nii->dev );
	nii->dev.driver_name = "NII";
	nii->dev.parent = &efidev->dev;
	list_add ( &nii->dev.siblings, &efidev->dev.children );
	INIT_LIST_HEAD ( &nii->dev.children );
	netdev->dev = &nii->dev;

	/* Open NII protocol */
	if ( ( efirc = bs->OpenProtocol ( device, &efi_nii31_protocol_guid,
					  &interface, efi_image_handle, device,
					  ( EFI_OPEN_PROTOCOL_BY_DRIVER |
					    EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){
		rc = -EEFI ( efirc );
		DBGC ( nii, "NII %s cannot open NII protocol: %s\n",
		       nii->dev.name, strerror ( rc ) );
		DBGC_EFI_OPENERS ( device, device, &efi_nii31_protocol_guid );
		goto err_open_protocol;
	}
	nii->nii = interface;

	/* Locate UNDI and entry point */
	nii->undi = ( ( void * ) ( intptr_t ) nii->nii->Id );
	if ( ! nii->undi ) {
		DBGC ( nii, "NII %s has no UNDI\n", nii->dev.name );
		rc = -ENODEV;
		goto err_no_undi;
	}
	if ( nii->undi->Implementation & PXE_ROMID_IMP_HW_UNDI ) {
		DBGC ( nii, "NII %s is a mythical hardware UNDI\n",
		       nii->dev.name );
		rc = -ENOTSUP;
		goto err_hw_undi;
	}
	if ( nii->undi->Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR ) {
		nii->issue = ( ( void * ) ( intptr_t ) nii->undi->EntryPoint );
	} else {
		nii->issue = ( ( ( void * ) nii->undi ) +
			       nii->undi->EntryPoint );
	}
	DBGC ( nii, "NII %s using UNDI v%x.%x at %p entry %p\n", nii->dev.name,
	       nii->nii->MajorVer, nii->nii->MinorVer, nii->undi, nii->issue );

	/* Open PCI I/O protocols and locate BARs */
	if ( ( rc = nii_pci_open ( nii ) ) != 0 )
		goto err_pci_open;

	/* Start UNDI */
	if ( ( rc = nii_start_undi ( nii ) ) != 0 )
		goto err_start_undi;

	/* Get initialisation information */
	if ( ( rc = nii_get_init_info ( nii, netdev ) ) != 0 )
		goto err_get_init_info;

	/* Get MAC addresses */
	if ( ( rc = nii_get_station_address ( nii, netdev ) ) != 0 )
		goto err_get_station_address;

	/* Register network device */
	if ( ( rc = register_netdev ( netdev ) ) != 0 )
		goto err_register_netdev;
	DBGC ( nii, "NII %s registered as %s for %p %s\n", nii->dev.name,
	       netdev->name, device, efi_handle_name ( device ) );

	/* Set initial link state (if media detection is not supported) */
	if ( ! nii->media )
		netdev_link_up ( netdev );

	return 0;

	unregister_netdev ( netdev );
 err_register_netdev:
 err_get_station_address:
 err_get_init_info:
	nii_stop_undi ( nii );
 err_start_undi:
	nii_pci_close ( nii );
 err_pci_open:
 err_hw_undi:
 err_no_undi:
	bs->CloseProtocol ( device, &efi_nii31_protocol_guid,
			    efi_image_handle, device );
 err_open_protocol:
	list_del ( &nii->dev.siblings );
	netdev_nullify ( netdev );
	netdev_put ( netdev );
 err_alloc:
	return rc;
}