Exemple #1
0
void
efe_mii_notify(void *arg, link_state_t link)
{
	efe_t *efep = arg;

	mac_link_update(efep->efe_mh, link);
}
Exemple #2
0
static void
pcn_mii_notify(void *arg, link_state_t link)
{
	pcn_t		*pcnp = (pcn_t *)arg;

	mac_link_update(pcnp->pcn_mh, link);
}
Exemple #3
0
/**
 * Virtio Net device attach rountine.
 *
 * @param pDevice           Pointer to the Virtio device instance.
 *
 * @return corresponding solaris error code.
 */
static int VirtioNetDevAttach(PVIRTIODEVICE pDevice)
{
    LogFlowFunc((VIRTIOLOGNAME ":VirtioNetDevAttach pDevice=%p\n", pDevice));

    virtio_net_t *pNet = pDevice->pvDevice;
    mac_register_t *pMacRegHandle = mac_alloc(MAC_VERSION);
    if (pMacRegHandle)
    {
        pMacRegHandle->m_driver     = pDevice;
        pMacRegHandle->m_dip        = pDevice->pDip;
        pMacRegHandle->m_callbacks  = &g_VirtioNetCallbacks;
        pMacRegHandle->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
        pMacRegHandle->m_min_sdu    = 0;
        pMacRegHandle->m_max_sdu    = 1500;    /* @todo verify */
        /* @todo should we set the margin size? */
        pMacRegHandle->m_src_addr   = pNet->MacAddr.au8;

        /*
         * Get MAC from the host or generate a random MAC address.
         */
        if (pDevice->fHostFeatures & VIRTIO_NET_MAC)
        {
            pDevice->pHyperOps->pfnGet(pDevice, 0 /* offset */, &pNet->MacAddr.au8, sizeof(pNet->MacAddr));
            LogFlow((VIRTIOLOGNAME ":VirtioNetDevAttach: Obtained MAC address from host: %.6Rhxs\n", pNet->MacAddr.au8));
        }
        else
        {
            pNet->MacAddr.au8[0] = 0x08;
            pNet->MacAddr.au8[1] = 0x00;
            pNet->MacAddr.au8[2] = 0x27;
            RTRandBytes(&pNet->MacAddr.au8[3], 3);
            LogFlow((VIRTIOLOGNAME ":VirtioNetDevAttach: Generated MAC address %.6Rhxs\n", pNet->MacAddr.au8));
        }

        int rc = VirtioNetAttachQueues(pDevice);
        if (rc == DDI_SUCCESS)
        {
            rc = mac_register(pMacRegHandle, &pNet->hMac);
            if (rc == 0)
            {
                mac_link_update(pNet->hMac, LINK_STATE_DOWN);
                mac_free(pMacRegHandle);
                LogFlow((VIRTIOLOGNAME ":VirtioNetDevAttach: successfully registered mac.\n"));
                return DDI_SUCCESS;
            }
            else
                LogRel((VIRTIOLOGNAME ":VirtioNetDevAttach: mac_register failed. rc=%d\n", rc));

            VirtioNetDetachQueues(pDevice);
        }
        else
            LogRel((VIRTIOLOGNAME ":VirtioNetDevAttach: VirtioNetAttachQueues failed. rc=%d\n", rc));

        mac_free(pMacRegHandle);
    }
    else
        LogRel((VIRTIOLOGNAME ":VirtioNetDevAttach: mac_alloc failed. Invalid version!?!\n"));

    return DDI_FAILURE;
}
Exemple #4
0
int
oce_start(struct oce_dev *dev)
{
	int qidx = 0;
	struct link_status link = {0};

	/* get link status */
	(void) oce_get_link_status(dev, &link);

	dev->link_status  = (link.logical_link_status == NTWK_LOGICAL_LINK_UP) ?
	    LINK_STATE_UP : LINK_STATE_DOWN;

	dev->link_speed = link.qos_link_speed ? link.qos_link_speed * 10 :
	    pow10[link.mac_speed];

	mac_link_update(dev->mac_handle, dev->link_status);

	for (qidx = 0; qidx < dev->nwqs; qidx++) {
		(void) oce_start_wq(dev->wq[qidx]);
	}
	for (qidx = 0; qidx < dev->nrqs; qidx++) {
		(void) oce_start_rq(dev->rq[qidx]);
	}
	(void) oce_start_mq(dev->mq);
	/* enable interrupts */
	oce_ei(dev);
	/* arm the eqs */
	for (qidx = 0; qidx < dev->neqs; qidx++) {
		oce_arm_eq(dev, dev->eq[qidx]->eq_id, 0, B_TRUE, B_FALSE);
	}
	/* TODO update state */
	return (DDI_SUCCESS);
} /* oce_start */
static uint_t
virtionet_intr(caddr_t arg1, caddr_t arg2)
{
	virtionet_state_t	*sp = (virtionet_state_t *)arg1;
	uint8_t			intr;

	/* Autoclears the ISR */
	intr = VIRTIO_ISR(sp);

	cmn_err(CE_NOTE, "intr=0x%X", (int)intr);

	if (intr) {
		if (intr & VIRTIO_ISR_VQ) {
			/* VQ update */
			intr &= (~VIRTIO_ISR_VQ);
			virtionet_check_vq(sp, sp->rxq);
			virtionet_check_vq(sp, sp->txq);
			virtionet_check_vq(sp, sp->ctlq);
		}
		if (intr & VIRTIO_ISR_CFG) {
			/* Configuration update */
			intr &= (~VIRTIO_ISR_CFG);
			mac_link_update(sp->mh, virtionet_link_status(sp));
		}
		/* Let us know if there is still something interrupting */
		if (intr) {
			cmn_err(CE_WARN, "Unknown interrupt 0x%X", intr);
		}
		return (DDI_INTR_CLAIMED);
	} else {
		return (DDI_INTR_UNCLAIMED);
	}
}
Exemple #6
0
/**
 * Virtio Net Start.
 *
 * @param pvArg             Pointer to private data.
 *
 * @return corresponding solaris error code.
 */
static int VirtioNetStart(void *pvArg)
{
    PVIRTIODEVICE pDevice = pvArg;
    virtio_net_t *pNet = pDevice->pvDevice;
    mac_link_update(pNet->hMac, LINK_STATE_UP);

    pDevice->pHyperOps->pfnSetStatus(pDevice, VIRTIO_PCI_STATUS_DRV_OK);
    return 0;
}
Exemple #7
0
/**
 * Virtio Net Stop.
 *
 * @param pvArg             Pointer to private data.
 */
static void VirtioNetStop(void *pvArg)
{
    PVIRTIODEVICE pDevice = pvArg;
    virtio_net_t *pNet = pDevice->pvDevice;
    mac_link_update(pNet->hMac, LINK_STATE_DOWN);

    /*
     * I don't think we should set status here as the host checks the status on every Xmit. This means pending Xmits
     * would also be dropped.
     * @todo: Not sure what's the best way to signal connect/disconnect of the link to the host. Figure it out.
     */
}
static int
virtionet_start(void *arg)
{
	virtionet_state_t	*sp = arg;

	cmn_err(CE_CONT, "virtionet_start\n");

	VIRTIO_DEV_DRIVER_OK(sp);

	mac_link_update(sp->mh, virtionet_link_status(sp));

	return (0);
}
Exemple #9
0
/* called with Tx/Rx comp locks held */
void
oce_stop(struct oce_dev *dev)
{
	int qidx;
	/* disable interrupts */
	oce_di(dev);
	for (qidx = 0; qidx < dev->nwqs; qidx++) {
		mutex_enter(&dev->wq[qidx]->tx_lock);
	}
	mutex_enter(&dev->mq->lock);
	/* complete the pending Tx */
	for (qidx = 0; qidx < dev->nwqs; qidx++)
		oce_clean_wq(dev->wq[qidx]);
	/* Release all the locks */
	mutex_exit(&dev->mq->lock);
	for (qidx = 0; qidx < dev->nwqs; qidx++)
		mutex_exit(&dev->wq[qidx]->tx_lock);
	if (dev->link_status == LINK_STATE_UP) {
		dev->link_status = LINK_STATE_UNKNOWN;
		mac_link_update(dev->mac_handle, dev->link_status);
	}

} /* oce_stop */
static void
vnic_notify_cb(void *arg, mac_notify_type_t type)
{
	vnic_t *vnic = arg;

	/*
	 * Do not deliver notifications if the vnic is not fully initialized
	 * or is in process of being torn down.
	 */
	if (!vnic->vn_enabled)
		return;

	switch (type) {
	case MAC_NOTE_UNICST:
		/*
		 * Only the VLAN VNIC needs to be notified with primary MAC
		 * address change.
		 */
		if (vnic->vn_addr_type != VNIC_MAC_ADDR_TYPE_PRIMARY)
			return;

		/*  the unicast MAC address value */
		mac_unicast_primary_get(vnic->vn_lower_mh, vnic->vn_addr);

		/* notify its upper layer MAC about MAC address change */
		mac_unicst_update(vnic->vn_mh, (const uint8_t *)vnic->vn_addr);
		break;

	case MAC_NOTE_LINK:
		mac_link_update(vnic->vn_mh,
		    mac_client_stat_get(vnic->vn_mch, MAC_STAT_LINK_STATE));
		break;

	default:
		break;
	}
}
/* ARGSUSED */
int
vnic_dev_create(datalink_id_t vnic_id, datalink_id_t linkid,
    vnic_mac_addr_type_t *vnic_addr_type, int *mac_len, uchar_t *mac_addr,
    int *mac_slot, uint_t mac_prefix_len, uint16_t vid, vrid_t vrid,
    int af, mac_resource_props_t *mrp, uint32_t flags, vnic_ioc_diag_t *diag,
    cred_t *credp)
{
	vnic_t *vnic;
	mac_register_t *mac;
	int err;
	boolean_t is_anchor = ((flags & VNIC_IOC_CREATE_ANCHOR) != 0);
	char vnic_name[MAXNAMELEN];
	const mac_info_t *minfop;
	uint32_t req_hwgrp_flag = B_FALSE;

	*diag = VNIC_IOC_DIAG_NONE;

	rw_enter(&vnic_lock, RW_WRITER);

	/* does a VNIC with the same id already exist? */
	err = mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id),
	    (mod_hash_val_t *)&vnic);
	if (err == 0) {
		rw_exit(&vnic_lock);
		return (EEXIST);
	}

	vnic = kmem_cache_alloc(vnic_cache, KM_NOSLEEP);
	if (vnic == NULL) {
		rw_exit(&vnic_lock);
		return (ENOMEM);
	}

	bzero(vnic, sizeof (*vnic));

	vnic->vn_id = vnic_id;
	vnic->vn_link_id = linkid;
	vnic->vn_vrid = vrid;
	vnic->vn_af = af;

	if (!is_anchor) {
		if (linkid == DATALINK_INVALID_LINKID) {
			err = EINVAL;
			goto bail;
		}

		/*
		 * Open the lower MAC and assign its initial bandwidth and
		 * MAC address. We do this here during VNIC creation and
		 * do not wait until the upper MAC client open so that we
		 * can validate the VNIC creation parameters (bandwidth,
		 * MAC address, etc) and reserve a factory MAC address if
		 * one was requested.
		 */
		err = mac_open_by_linkid(linkid, &vnic->vn_lower_mh);
		if (err != 0)
			goto bail;

		/*
		 * VNIC(vlan) over VNICs(vlans) is not supported.
		 */
		if (mac_is_vnic(vnic->vn_lower_mh)) {
			err = EINVAL;
			goto bail;
		}

		/* only ethernet support for now */
		minfop = mac_info(vnic->vn_lower_mh);
		if (minfop->mi_nativemedia != DL_ETHER) {
			err = ENOTSUP;
			goto bail;
		}

		(void) dls_mgmt_get_linkinfo(vnic_id, vnic_name, NULL, NULL,
		    NULL);
		err = mac_client_open(vnic->vn_lower_mh, &vnic->vn_mch,
		    vnic_name, MAC_OPEN_FLAGS_IS_VNIC);
		if (err != 0)
			goto bail;

		/* assign a MAC address to the VNIC */

		err = vnic_unicast_add(vnic, *vnic_addr_type, mac_slot,
		    mac_prefix_len, mac_len, mac_addr, flags, diag, vid,
		    req_hwgrp_flag);
		if (err != 0) {
			vnic->vn_muh = NULL;
			if (diag != NULL && req_hwgrp_flag)
				*diag = VNIC_IOC_DIAG_NO_HWRINGS;
			goto bail;
		}

		/* register to receive notification from underlying MAC */
		vnic->vn_mnh = mac_notify_add(vnic->vn_lower_mh, vnic_notify_cb,
		    vnic);

		*vnic_addr_type = vnic->vn_addr_type;
		vnic->vn_addr_len = *mac_len;
		vnic->vn_vid = vid;

		bcopy(mac_addr, vnic->vn_addr, vnic->vn_addr_len);

		if (vnic->vn_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY)
			vnic->vn_slot_id = *mac_slot;

		/*
		 * Set the initial VNIC capabilities. If the VNIC is created
		 * over MACs which does not support nactive vlan, disable
		 * VNIC's hardware checksum capability if its VID is not 0,
		 * since the underlying MAC would get the hardware checksum
		 * offset wrong in case of VLAN packets.
		 */
		if (vid == 0 || !mac_capab_get(vnic->vn_lower_mh,
		    MAC_CAPAB_NO_NATIVEVLAN, NULL)) {
			if (!mac_capab_get(vnic->vn_lower_mh, MAC_CAPAB_HCKSUM,
			    &vnic->vn_hcksum_txflags))
				vnic->vn_hcksum_txflags = 0;
		} else {
			vnic->vn_hcksum_txflags = 0;
		}
	}

	/* register with the MAC module */
	if ((mac = mac_alloc(MAC_VERSION)) == NULL)
		goto bail;

	mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
	mac->m_driver = vnic;
	mac->m_dip = vnic_get_dip();
	mac->m_instance = (uint_t)-1;
	mac->m_src_addr = vnic->vn_addr;
	mac->m_callbacks = &vnic_m_callbacks;

	if (!is_anchor) {
		/*
		 * If this is a VNIC based VLAN, then we check for the
		 * margin unless it has been created with the force
		 * flag. If we are configuring a VLAN over an etherstub,
		 * we don't check the margin even if force is not set.
		 */
		if (vid == 0 || (flags & VNIC_IOC_CREATE_FORCE) != 0) {
			if (vid != VLAN_ID_NONE)
				vnic->vn_force = B_TRUE;
			/*
			 * As the current margin size of the underlying mac is
			 * used to determine the margin size of the VNIC
			 * itself, request the underlying mac not to change
			 * to a smaller margin size.
			 */
			err = mac_margin_add(vnic->vn_lower_mh,
			    &vnic->vn_margin, B_TRUE);
			ASSERT(err == 0);
		} else {
			vnic->vn_margin = VLAN_TAGSZ;
			err = mac_margin_add(vnic->vn_lower_mh,
			    &vnic->vn_margin, B_FALSE);
			if (err != 0) {
				mac_free(mac);
				if (diag != NULL)
					*diag = VNIC_IOC_DIAG_MACMARGIN_INVALID;
				goto bail;
			}
		}

		mac_sdu_get(vnic->vn_lower_mh, &mac->m_min_sdu,
		    &mac->m_max_sdu);
		err = mac_mtu_add(vnic->vn_lower_mh, &mac->m_max_sdu, B_FALSE);
		if (err != 0) {
			VERIFY(mac_margin_remove(vnic->vn_lower_mh,
			    vnic->vn_margin) == 0);
			mac_free(mac);
			if (diag != NULL)
				*diag = VNIC_IOC_DIAG_MACMTU_INVALID;
			goto bail;
		}
		vnic->vn_mtu = mac->m_max_sdu;
	} else {
		vnic->vn_margin = VLAN_TAGSZ;
		mac->m_min_sdu = 1;
		mac->m_max_sdu = ANCHOR_VNIC_MAX_MTU;
		vnic->vn_mtu = ANCHOR_VNIC_MAX_MTU;
	}

	mac->m_margin = vnic->vn_margin;

	err = mac_register(mac, &vnic->vn_mh);
	mac_free(mac);
	if (err != 0) {
		if (!is_anchor) {
			VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
			    vnic->vn_mtu) == 0);
			VERIFY(mac_margin_remove(vnic->vn_lower_mh,
			    vnic->vn_margin) == 0);
		}
		goto bail;
	}

	/* Set the VNIC's MAC in the client */
	if (!is_anchor) {
		mac_set_upper_mac(vnic->vn_mch, vnic->vn_mh, mrp);

		if (mrp != NULL) {
			if ((mrp->mrp_mask & MRP_RX_RINGS) != 0 ||
			    (mrp->mrp_mask & MRP_TX_RINGS) != 0) {
				req_hwgrp_flag = B_TRUE;
			}
			err = mac_client_set_resources(vnic->vn_mch, mrp);
			if (err != 0) {
				VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
				    vnic->vn_mtu) == 0);
				VERIFY(mac_margin_remove(vnic->vn_lower_mh,
				    vnic->vn_margin) == 0);
				(void) mac_unregister(vnic->vn_mh);
				goto bail;
			}
		}
	}

	err = dls_devnet_create(vnic->vn_mh, vnic->vn_id, crgetzoneid(credp));
	if (err != 0) {
		VERIFY(is_anchor || mac_margin_remove(vnic->vn_lower_mh,
		    vnic->vn_margin) == 0);
		if (!is_anchor) {
			VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
			    vnic->vn_mtu) == 0);
			VERIFY(mac_margin_remove(vnic->vn_lower_mh,
			    vnic->vn_margin) == 0);
		}
		(void) mac_unregister(vnic->vn_mh);
		goto bail;
	}

	/* add new VNIC to hash table */
	err = mod_hash_insert(vnic_hash, VNIC_HASH_KEY(vnic_id),
	    (mod_hash_val_t)vnic);
	ASSERT(err == 0);
	vnic_count++;

	/*
	 * Now that we've enabled this VNIC, we should go through and update the
	 * link state by setting it to our parents.
	 */
	vnic->vn_enabled = B_TRUE;

	if (is_anchor) {
		mac_link_update(vnic->vn_mh, LINK_STATE_UP);
	} else {
		mac_link_update(vnic->vn_mh,
		    mac_client_stat_get(vnic->vn_mch, MAC_STAT_LINK_STATE));
	}

	rw_exit(&vnic_lock);

	return (0);

bail:
	rw_exit(&vnic_lock);
	if (!is_anchor) {
		if (vnic->vn_mnh != NULL)
			(void) mac_notify_remove(vnic->vn_mnh, B_TRUE);
		if (vnic->vn_muh != NULL)
			(void) mac_unicast_remove(vnic->vn_mch, vnic->vn_muh);
		if (vnic->vn_mch != NULL)
			mac_client_close(vnic->vn_mch, MAC_CLOSE_FLAGS_IS_VNIC);
		if (vnic->vn_lower_mh != NULL)
			mac_close(vnic->vn_lower_mh);
	}

	kmem_cache_free(vnic_cache, vnic);
	return (err);
}
uint_t
rge_chip_factotum(caddr_t arg1, caddr_t arg2)
{
	rge_t *rgep;
	uint_t result;
	boolean_t error;
	boolean_t linkchg;

	rgep = (rge_t *)arg1;
	_NOTE(ARGUNUSED(arg2))

	if (rgep->factotum_flag == 0)
		return (DDI_INTR_UNCLAIMED);

	rgep->factotum_flag = 0;
	result = DDI_INTR_CLAIMED;
	error = B_FALSE;
	linkchg = B_FALSE;

	mutex_enter(rgep->genlock);
	switch (rgep->rge_chip_state) {
	default:
		break;

	case RGE_CHIP_RUNNING:
		linkchg = rge_factotum_link_check(rgep);
		error = rge_factotum_stall_check(rgep);
		break;

	case RGE_CHIP_ERROR:
		error = B_TRUE;
		break;

	case RGE_CHIP_FAULT:
		/*
		 * Fault detected, time to reset ...
		 */
		if (rge_autorecover) {
			RGE_REPORT((rgep, "automatic recovery activated"));
			rge_restart(rgep);
		}
		break;
	}

	/*
	 * If an error is detected, stop the chip now, marking it as
	 * faulty, so that it will be reset next time through ...
	 */
	if (error)
		rge_chip_stop(rgep, B_TRUE);
	mutex_exit(rgep->genlock);

	/*
	 * If the link state changed, tell the world about it.
	 * Note: can't do this while still holding the mutex.
	 */
	if (linkchg)
		mac_link_update(rgep->mh, rgep->param_link_up);

	return (result);
}