示例#1
0
文件: smcp.c 项目: andreiw/polaris
/*
 * attach(9E) -- Attach a device to the system
 *
 * Called once for each board successfully probed.
 */
static int
SMCG_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
{
	gld_mac_info_t	*macinfo;
	Adapter_Struc	*pAd;
	smcg_t		*smcg;
	int		rc;
	ddi_acc_handle_t pcihandle;

#ifdef	DEBUG
	if (SMCG_debug & SMCGDDI)
		cmn_err(CE_CONT, SMCG_NAME "_attach(0x%p)", (void *)devinfo);
#endif

	if (cmd != DDI_ATTACH)
		return (DDI_FAILURE);

	/*
	 * Allocate gld_mac_info_t and Lower MAC Adapter_Struc structures
	 */
	if ((macinfo = gld_mac_alloc(devinfo)) == NULL)
		return (DDI_FAILURE);
	if ((pAd = kmem_zalloc(sizeof (Adapter_Struc), KM_NOSLEEP)) == NULL) {
		gld_mac_free(macinfo);
		return (DDI_FAILURE);
	}
	if ((smcg = kmem_zalloc(sizeof (smcg_t), KM_NOSLEEP)) == NULL) {
		gld_mac_free(macinfo);
		kmem_free(pAd, sizeof (Adapter_Struc));
		return (DDI_FAILURE);
	}

	pAd->pc_bus = SMCG_PCI_BUS;

	/* create pci handle for UM_PCI_Service */
	if (pci_config_setup(devinfo, (ddi_acc_handle_t *)&pcihandle)
	    != DDI_SUCCESS) {
		goto attach_fail_cleanup;
	}

	/*
	 * Query the LMAC for the device information
	 */
	pAd->pcihandle = (void *) pcihandle;
	rc = LM_GetCnfg(pAd);

	pci_config_teardown((ddi_acc_handle_t *)&pcihandle);
	pAd->pcihandle = NULL;

	if (rc != ADAPTER_AND_CONFIG) {
		cmn_err(CE_WARN,
		    SMCG_NAME "_attach: LM_GetCnfg failed (0x%x)", rc);
		goto attach_fail_cleanup;
	}

	/*
	 * Initialize pointers to device specific functions which will be
	 * used by the generic layer.
	 */
	macinfo->gldm_reset   = SMCG_reset;
	macinfo->gldm_start   = SMCG_start_board;
	macinfo->gldm_stop    = SMCG_stop_board;
	macinfo->gldm_set_mac_addr   = SMCG_set_mac_addr;
	macinfo->gldm_set_multicast = SMCG_set_multicast;
	macinfo->gldm_set_promiscuous = SMCG_set_promiscuous;
	macinfo->gldm_get_stats   = SMCG_get_stats;
	macinfo->gldm_send    = SMCG_send;
	macinfo->gldm_intr    = SMCG_intr;
	macinfo->gldm_ioctl   = NULL;

	/*
	 * Initialize board characteristics needed by the generic layer.
	 */
	macinfo->gldm_ident = SMCG_IDENT;
	macinfo->gldm_type = DL_ETHER;
	macinfo->gldm_minpkt = 0;	/* assumes we pad ourselves */
	macinfo->gldm_maxpkt = SMCGMAXPKT;
	macinfo->gldm_addrlen = ETHERADDRL;
	macinfo->gldm_saplen = -2;
	macinfo->gldm_ppa = ddi_get_instance(devinfo);

	pAd->receive_mask = ACCEPT_BROADCAST;
	pAd->max_packet_size = SMMAXPKT;

	macinfo->gldm_broadcast_addr = SMCG_broadcastaddr;

	/* Get the board's vendor-assigned hardware network address. */
	LM_Get_Addr(pAd);
	macinfo->gldm_vendor_addr = (unsigned char *)pAd->node_address;

	/* Link macinfo, smcg, and LMAC Adapter Structs */
	macinfo->gldm_private = (caddr_t)smcg;
	pAd->sm_private = (void *)smcg;
	smcg->smcg_pAd = pAd;
	smcg->smcg_macinfo = macinfo;

	pAd->ptr_rx_CRC_errors = &smcg->rx_CRC_errors;
	pAd->ptr_rx_too_big = &smcg->rx_too_big;
	pAd->ptr_rx_lost_pkts = &smcg->rx_lost_pkts;
	pAd->ptr_rx_align_errors = &smcg->rx_align_errors;
	pAd->ptr_rx_overruns = &smcg->rx_overruns;
	pAd->ptr_tx_deferred = &smcg->tx_deferred;
	pAd->ptr_tx_total_collisions = &smcg->tx_total_collisions;
	pAd->ptr_tx_max_collisions = &smcg->tx_max_collisions;
	pAd->ptr_tx_one_collision = &smcg->tx_one_collision;
	pAd->ptr_tx_mult_collisions = &smcg->tx_mult_collisions;
	pAd->ptr_tx_ow_collision = &smcg->tx_ow_collision;
	pAd->ptr_tx_CD_heartbeat = &smcg->tx_CD_heartbeat;
	pAd->ptr_tx_carrier_lost = &smcg->tx_carrier_lost;
	pAd->ptr_tx_underruns = &smcg->tx_underruns;
	pAd->ptr_ring_OVW = &smcg->ring_OVW;

	macinfo->gldm_devinfo = smcg->smcg_devinfo = devinfo;

	pAd->num_of_tx_buffs = ddi_getprop(DDI_DEV_T_ANY, devinfo,
	    DDI_PROP_DONTPASS, "num-tx-bufs", SMTRANSMIT_BUFS);
	if (pAd->num_of_tx_buffs > SMCG_MAX_TXDESCS) {
		pAd->num_of_tx_buffs = SMCG_MAX_TXDESCS;
		cmn_err(CE_WARN, SMCG_NAME
		    "Max number_of_tx_buffs is %d", SMCG_MAX_TXDESCS);
	}
	if (pAd->num_of_tx_buffs < 2) {
		pAd->num_of_tx_buffs = 2;
	}
	pAd->num_of_rx_buffs = ddi_getprop(DDI_DEV_T_ANY, devinfo,
	    DDI_PROP_DONTPASS, "num-rx-bufs", SMRECEIVE_BUFS);
	if (pAd->num_of_rx_buffs > SMCG_MAX_RXDESCS) {
		pAd->num_of_rx_buffs = SMCG_MAX_RXDESCS;
		cmn_err(CE_WARN, SMCG_NAME
		    "Max number_of_rx_buffs is %d", SMCG_MAX_RXDESCS);
	}
	if (pAd->num_of_rx_buffs < 2) {
		pAd->num_of_rx_buffs = 2;
	}

	if (ddi_get_iblock_cookie(devinfo, 0, &macinfo->gldm_cookie)
		!= DDI_SUCCESS)
		goto attach_fail_cleanup;

	/*
	 * rbuf_lock	Protects receive data structures
	 * txbuf_lock	Protects transmit data structures
	 * lm_lock	Protects all calls to LMAC layer
	 * rlist_lock	Protects receive buffer list
	 * Note: Locks should be acquired in the above order.
	 */
	mutex_init(&smcg->rbuf_lock, NULL, MUTEX_DRIVER, NULL);
	mutex_init(&smcg->txbuf_lock, NULL, MUTEX_DRIVER, NULL);
	mutex_init(&smcg->lm_lock, NULL, MUTEX_DRIVER, NULL);
	mutex_init(&smcg->rlist_lock, NULL, MUTEX_DRIVER, NULL);

	/*
	 * SMCG_dma_alloc is called before it is possible to get
	 * any interrupts, send or receive packets... Therefore I'm
	 * not going to take rlist_lock for it.
	 */
	if (SMCG_dma_alloc(smcg) != DDI_SUCCESS)
		goto attach_fail_cleanup1;

#ifdef SAFE
	LM_Reset_Adapter(pAd);
#endif
	/* Add the interrupt handler */
	if (ddi_add_intr(devinfo, 0,  NULL, NULL, gld_intr, (caddr_t)macinfo)
	    != DDI_SUCCESS) {
		SMCG_dma_unalloc(smcg);
		goto attach_fail_cleanup1;
	}

	/*
	 * Register ourselves with the GLD interface
	 *
	 * gld_register will:
	 *	link us with the GLD system;
	 *	create the minor node.
	 */
	if (gld_register(devinfo, SMCG_NAME, macinfo) != DDI_SUCCESS) {
		ddi_remove_intr(devinfo, 0, macinfo->gldm_cookie);
		SMCG_dma_unalloc(smcg);
		goto attach_fail_cleanup1;
	}

	return (DDI_SUCCESS);

attach_fail_cleanup1:
	mutex_destroy(&smcg->rbuf_lock);
	mutex_destroy(&smcg->txbuf_lock);
	mutex_destroy(&smcg->lm_lock);
	mutex_destroy(&smcg->rlist_lock);

attach_fail_cleanup:
	kmem_free(pAd, sizeof (Adapter_Struc));
	kmem_free(smcg, sizeof (smcg_t));
	gld_mac_free(macinfo);
	return (DDI_FAILURE);
}
示例#2
0
/**
 * Attach entry point, to attach a device to the system or resume it.
 *
 * @param   pDip            The module structure instance.
 * @param   enmCmd          Operation type (attach/resume).
 *
 * @returns corresponding solaris error code.
 */
static int VBoxNetAdpSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
{
    LogFunc((DEVICE_NAME ":VBoxNetAdpSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd));

    int rc = -1;
    switch (enmCmd)
    {
        case DDI_ATTACH:
        {
            gld_mac_info_t *pMacInfo = gld_mac_alloc(pDip);
            if (pMacInfo)
            {
                vboxnetadp_state_t *pState = RTMemAllocZ(sizeof(vboxnetadp_state_t));
                if (pState)
                {
                    pState->pDip = pDip;

                    /*
                     * Setup GLD MAC layer registration info.
                     */
                    pMacInfo->gldm_reset = vboxNetAdpSolarisStub;
                    pMacInfo->gldm_start = vboxNetAdpSolarisStub;
                    pMacInfo->gldm_stop = vboxNetAdpSolarisStub;
                    pMacInfo->gldm_set_mac_addr = vboxNetAdpSolarisSetMacAddress;
                    pMacInfo->gldm_set_multicast = vboxNetAdpSolarisSetMulticast;
                    pMacInfo->gldm_set_promiscuous = vboxNetAdpSolarisSetPromisc;
                    pMacInfo->gldm_send = vboxNetAdpSolarisSend;
                    pMacInfo->gldm_intr = NULL;
                    pMacInfo->gldm_get_stats = vboxNetAdpSolarisGetStats;
                    pMacInfo->gldm_ioctl = NULL;
                    pMacInfo->gldm_ident = DEVICE_NAME;
                    pMacInfo->gldm_type = DL_ETHER;
                    pMacInfo->gldm_minpkt = 0;
                    pMacInfo->gldm_maxpkt = VBOXNETADP_MTU;
                    pMacInfo->gldm_capabilities = GLD_CAP_LINKSTATE;
                    AssertCompile(sizeof(RTMAC) == ETHERADDRL);

                    pMacInfo->gldm_addrlen = ETHERADDRL;
                    pMacInfo->gldm_saplen = -2;
                    pMacInfo->gldm_broadcast_addr = achBroadcastAddr;
                    pMacInfo->gldm_ppa = ddi_get_instance(pState->pDip);
                    pMacInfo->gldm_devinfo = pState->pDip;
                    pMacInfo->gldm_private = (caddr_t)pState;

                    /*
                     * We use a semi-random MAC addresses similar to a guest NIC's MAC address
                     * as the default factory address of the interface.
                     */
                    rc = vboxNetAdpSolarisGenerateMac(&pState->FactoryMac);
                    if (RT_SUCCESS(rc))
                    {
                        bcopy(&pState->FactoryMac, &pState->CurrentMac, sizeof(RTMAC));
                        pMacInfo->gldm_vendor_addr = (unsigned char *)&pState->FactoryMac;

                        /*
                         * Now try registering our GLD with the MAC layer.
                         * Registration can fail on some S10 versions when the MTU size is more than 1500.
                         * When we implement jumbo frames we should probably retry with MTU 1500 for S10.
                         */
                        rc = gld_register(pDip, (char *)ddi_driver_name(pDip), pMacInfo);
                        if (rc == DDI_SUCCESS)
                        {
                            ddi_report_dev(pDip);
                            gld_linkstate(pMacInfo, GLD_LINKSTATE_UP);
                            return DDI_SUCCESS;
                        }
                        else
                            LogRel((DEVICE_NAME ":VBoxNetAdpSolarisAttach failed to register GLD. rc=%d\n", rc));
                    }
                    else
                        LogRel((DEVICE_NAME ":VBoxNetAdpSolarisAttach failed to generate mac address.rc=%d\n"));

                    RTMemFree(pState);
                }
                else
                    LogRel((DEVICE_NAME ":VBoxNetAdpSolarisAttach failed to alloc state.\n"));

                gld_mac_free(pMacInfo);
            }
            else
                LogRel((DEVICE_NAME ":VBoxNetAdpSolarisAttach failed to alloc mac structure.\n"));
            return DDI_FAILURE;
        }

        case DDI_RESUME:
        {
            /* Nothing to do here... */
            return DDI_SUCCESS;
        }

        /* case DDI_PM_RESUME: */
        default:
            return DDI_FAILURE;
    }
}