void efe_mii_notify(void *arg, link_state_t link) { efe_t *efep = arg; mac_link_update(efep->efe_mh, link); }
static void pcn_mii_notify(void *arg, link_state_t link) { pcn_t *pcnp = (pcn_t *)arg; mac_link_update(pcnp->pcn_mh, link); }
/** * 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; }
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); } }
/** * 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; }
/** * 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); }
/* 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); }