# HG changeset patch # User speer # Date 1172188532 28800 # Node ID e3112ae4a1540d00ec54d6e303409d4ab855f96f # Parent 5340a4d98e0b711fc99a45e8d76f61cb40ff0c05 6504795 Huron NIU driver should support multiple MAC addresses diff -r 5340a4d98e0b -r e3112ae4a154 usr/src/uts/sun4v/io/nxge/npi/npi_mac.c --- a/usr/src/uts/sun4v/io/nxge/npi/npi_mac.c Thu Feb 22 13:40:56 2007 -0800 +++ b/usr/src/uts/sun4v/io/nxge/npi/npi_mac.c Thu Feb 22 15:55:32 2007 -0800 @@ -729,8 +729,8 @@ ASSERT(IS_PORT_NUM_VALID(portn)); if ((portn == XMAC_PORT_0) || (portn == XMAC_PORT_1)) { - ASSERT(addrn < XMAC_MAX_ALT_ADDR_ENTRY); - if (addrn >= XMAC_MAX_ALT_ADDR_ENTRY) { + ASSERT(addrn <= XMAC_MAX_ALT_ADDR_ENTRY); + if (addrn > XMAC_MAX_ALT_ADDR_ENTRY) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_mac_altaddr_enable" " Invalid Input: addrn <0x%x>", @@ -771,8 +771,8 @@ ASSERT(IS_PORT_NUM_VALID(portn)); if ((portn == XMAC_PORT_0) || (portn == XMAC_PORT_1)) { - ASSERT(addrn < XMAC_MAX_ALT_ADDR_ENTRY); - if (addrn >= XMAC_MAX_ALT_ADDR_ENTRY) { + ASSERT(addrn <= XMAC_MAX_ALT_ADDR_ENTRY); + if (addrn > XMAC_MAX_ALT_ADDR_ENTRY) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_mac_altaddr_disable" " Invalid Input: addrn <0x%x>", @@ -811,8 +811,8 @@ ASSERT((op == OP_GET) || (op == OP_SET)); if ((portn == XMAC_PORT_0) || (portn == XMAC_PORT_1)) { - ASSERT(entryn < XMAC_MAX_ALT_ADDR_ENTRY); - if (entryn >= XMAC_MAX_ALT_ADDR_ENTRY) { + ASSERT(entryn <= XMAC_MAX_ALT_ADDR_ENTRY); + if (entryn > XMAC_MAX_ALT_ADDR_ENTRY) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_mac_altaddr_entry" " Invalid Input: entryn <0x%x>", @@ -842,8 +842,8 @@ data->w2 = val2 & 0xFFFF; } } else { - ASSERT(entryn < BMAC_MAX_ALT_ADDR_ENTRY); - if (entryn >= BMAC_MAX_ALT_ADDR_ENTRY) { + ASSERT(entryn <= BMAC_MAX_ALT_ADDR_ENTRY); + if (entryn > BMAC_MAX_ALT_ADDR_ENTRY) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_mac_altaddr_entry" " Invalid Input: entryn <0x%x>", diff -r 5340a4d98e0b -r e3112ae4a154 usr/src/uts/sun4v/io/nxge/nxge_fflp.c --- a/usr/src/uts/sun4v/io/nxge/nxge_fflp.c Thu Feb 22 13:40:56 2007 -0800 +++ b/usr/src/uts/sun4v/io/nxge/nxge_fflp.c Thu Feb 22 15:55:32 2007 -0800 @@ -457,7 +457,7 @@ break; default: NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, - "failed Assign RDC table (invalid funcion #)")); + "failed Assign RDC table (invalid function #)")); return (NXGE_ERROR); } @@ -469,12 +469,17 @@ return (NXGE_OK); } +/* + * Initialize hostinfo registers for alternate MAC addresses and + * multicast MAC address. + */ nxge_status_t -nxge_multicast_mac_assign_rdc_table(p_nxge_t nxgep) +nxge_alt_mcast_mac_assign_rdc_table(p_nxge_t nxgep) { npi_status_t rs = NPI_SUCCESS; hostinfo_t mac_rdc; npi_handle_t handle; + int i; handle = nxgep->npi_reg_handle; mac_rdc.value = 0; @@ -483,13 +488,23 @@ switch (nxgep->function_num) { case 0: case 1: + /* + * Tests indicate that it is OK not to re-initialize the + * hostinfo registers for the XMAC's alternate MAC + * addresses. But that is necessary for BMAC (case 2 + * and case 3 below) + */ rs = npi_mac_hostinfo_entry(handle, OP_SET, nxgep->function_num, XMAC_MULTI_HOST_INFO_ENTRY, &mac_rdc); break; case 2: case 3: - rs = npi_mac_hostinfo_entry(handle, OP_SET, + for (i = 1; i <= BMAC_MAX_ALT_ADDR_ENTRY; i++) + rs |= npi_mac_hostinfo_entry(handle, OP_SET, + nxgep->function_num, i, &mac_rdc); + + rs |= npi_mac_hostinfo_entry(handle, OP_SET, nxgep->function_num, BMAC_MULTI_HOST_INFO_ENTRY, &mac_rdc); break; @@ -512,8 +527,8 @@ { nxge_status_t status = NXGE_OK; - status = nxge_multicast_mac_assign_rdc_table(nxgep); - status = nxge_main_mac_assign_rdc_table(nxgep); + status = nxge_alt_mcast_mac_assign_rdc_table(nxgep); + status |= nxge_main_mac_assign_rdc_table(nxgep); return (status); } @@ -1899,7 +1914,7 @@ return (NXGE_ERROR); } - status = nxge_multicast_mac_assign_rdc_table(nxgep); + status = nxge_alt_mcast_mac_assign_rdc_table(nxgep); if (status != NXGE_OK) { NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_multicast_mac_assign_rdc_table failed")); diff -r 5340a4d98e0b -r e3112ae4a154 usr/src/uts/sun4v/io/nxge/nxge_kstats.c --- a/usr/src/uts/sun4v/io/nxge/nxge_kstats.c Thu Feb 22 13:40:56 2007 -0800 +++ b/usr/src/uts/sun4v/io/nxge/nxge_kstats.c Thu Feb 22 15:55:32 2007 -0800 @@ -493,8 +493,8 @@ } nxge_mmac_stat_index_t; nxge_kstat_index_t nxge_mmac_stats[] = { - {MMAC_MAX_ADDR, KSTAT_DATA_CHAR, "max_mmac_addr"}, - {MMAC_AVAIL_ADDR, KSTAT_DATA_CHAR, "avail_mmac_addr"}, + {MMAC_MAX_ADDR, KSTAT_DATA_UINT64, "max_mmac_addr"}, + {MMAC_AVAIL_ADDR, KSTAT_DATA_UINT64, "avail_mmac_addr"}, {MMAC_ADDR_POOL1, KSTAT_DATA_UINT64, "mmac_addr_1"}, {MMAC_ADDR_POOL2, KSTAT_DATA_UINT64, "mmac_addr_2"}, {MMAC_ADDR_POOL3, KSTAT_DATA_UINT64, "mmac_addr_3"}, diff -r 5340a4d98e0b -r e3112ae4a154 usr/src/uts/sun4v/io/nxge/nxge_mac.c --- a/usr/src/uts/sun4v/io/nxge/nxge_mac.c Thu Feb 22 13:40:56 2007 -0800 +++ b/usr/src/uts/sun4v/io/nxge/nxge_mac.c Thu Feb 22 15:55:32 2007 -0800 @@ -875,7 +875,7 @@ statsp = nxgep->statsp; /* - * Initialise the xcvr statistics. + * Initialize the xcvr statistics. */ statsp->mac_stats.cap_autoneg = 0; statsp->mac_stats.cap_100T4 = 0; @@ -1254,7 +1254,6 @@ uint32_t i; uint16_t hashtab_e; p_hash_filter_t hash_filter; - npi_mac_addr_t altmac_e; nxge_port_t portt; uint8_t portn; npi_handle_t handle; @@ -1310,15 +1309,6 @@ goto fail; nxgep->mac.rx_iconfig = NXGE_XMAC_RX_INTRS; - altmac_e.w0 = 0; - altmac_e.w1 = 0; - altmac_e.w2 = 0; - for (i = 0; i < XMAC_MAX_ALT_ADDR_ENTRY; i++) { - if ((rs = npi_mac_altaddr_entry(handle, OP_SET, portn, - i, (npi_mac_addr_t *)&altmac_e)) != NPI_SUCCESS) - goto fail; - } - (void) nxge_fflp_init_hostinfo(nxgep); xconfig = CFG_XMAC_RX_ERRCHK | CFG_XMAC_RX_CRC_CHK | @@ -1344,15 +1334,6 @@ != NPI_SUCCESS) goto fail; } else { - altmac_e.w0 = 0; - altmac_e.w1 = 0; - altmac_e.w2 = 0; - for (i = 0; i < BMAC_MAX_ALT_ADDR_ENTRY; i++) { - if ((rs = npi_mac_altaddr_entry(handle, OP_SET, portn, - i, (npi_mac_addr_t *)&altmac_e)) != NPI_SUCCESS) - goto fail; - } - (void) nxge_fflp_init_hostinfo(nxgep); if (npi_bmac_rx_iconfig(nxgep->npi_handle, INIT, portn, @@ -1754,7 +1735,7 @@ param_arr[param_anar_10hdx].value = 0; /* - * Initialise the xcvr statistics. + * Initialize the xcvr statistics. */ statsp->mac_stats.cap_autoneg = bmsr.bits.auto_neg_able; statsp->mac_stats.cap_100T4 = bmsr.bits.link_100T4; diff -r 5340a4d98e0b -r e3112ae4a154 usr/src/uts/sun4v/io/nxge/nxge_main.c --- a/usr/src/uts/sun4v/io/nxge/nxge_main.c Thu Feb 22 13:40:56 2007 -0800 +++ b/usr/src/uts/sun4v/io/nxge/nxge_main.c Thu Feb 22 15:55:32 2007 -0800 @@ -182,6 +182,15 @@ static void nxge_m_resources(void *); mblk_t *nxge_m_tx(void *arg, mblk_t *); static nxge_status_t nxge_mac_register(p_nxge_t); +static int nxge_altmac_set(p_nxge_t nxgep, uint8_t *mac_addr, + mac_addr_slot_t slot); +static void nxge_mmac_kstat_update(p_nxge_t nxgep, mac_addr_slot_t slot, + boolean_t factory); +static int nxge_m_mmac_add(void *arg, mac_multi_addr_t *maddr); +static int nxge_m_mmac_reserve(void *arg, mac_multi_addr_t *maddr); +static int nxge_m_mmac_remove(void *arg, mac_addr_slot_t slot); +static int nxge_m_mmac_modify(void *arg, mac_multi_addr_t *maddr); +static int nxge_m_mmac_get(void *arg, mac_multi_addr_t *maddr); #define NXGE_NEPTUNE_MAGIC 0x4E584745UL #define MAX_DUMP_SZ 256 @@ -239,6 +248,7 @@ ddi_device_acc_attr_t *, ddi_dma_attr_t *); extern void nxge_fm_fini(p_nxge_t); +extern npi_status_t npi_mac_altaddr_disable(npi_handle_t, uint8_t, uint8_t); /* * Count used to maintain the number of buffers being used @@ -363,6 +373,7 @@ int status = DDI_SUCCESS; nxge_status_t nxge_status = NXGE_OK; uint8_t portn; + nxge_mmac_t *mmac_info; NXGE_DEBUG_MSG((nxgep, DDI_CTL, "==> nxge_attach")); @@ -455,7 +466,19 @@ nxgep->mac.porttype = PORT_TYPE_XMAC; else nxgep->mac.porttype = PORT_TYPE_BMAC; - + /* + * Neptune has 4 ports, the first 2 ports use XMAC (10G MAC) + * internally, the rest 2 ports use BMAC (1G "Big" MAC). + * The two types of MACs have different characterizations. + */ + mmac_info = &nxgep->nxge_mmac_info; + if (nxgep->function_num < 2) { + mmac_info->num_mmac = XMAC_MAX_ALT_ADDR_ENTRY; + mmac_info->naddrfree = XMAC_MAX_ALT_ADDR_ENTRY; + } else { + mmac_info->num_mmac = BMAC_MAX_ALT_ADDR_ENTRY; + mmac_info->naddrfree = BMAC_MAX_ALT_ADDR_ENTRY; + } /* * Setup the Ndd parameters for the this instance. */ @@ -1056,7 +1079,7 @@ /* * Get the interrupt cookie so the mutexes can be - * Initialised. + * Initialized. */ ddi_status = ddi_get_iblock_cookie(nxgep->dip, 0, &nxgep->interrupt_cookie); @@ -3152,7 +3175,7 @@ MUTEX_ENTER(nxgep->genlock); /* - * CR 6492541 Check to see if the drv_state has been intialized, + * CR 6492541 Check to see if the drv_state has been initialized, * if not * call nxge_init(). */ if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) { @@ -3192,17 +3215,459 @@ NXGE_DEBUG_MSG((nxgep, RX_CTL, "<== nxge_m_resources")); } -/*ARGSUSED*/ +static void +nxge_mmac_kstat_update(p_nxge_t nxgep, mac_addr_slot_t slot, boolean_t factory) +{ + p_nxge_mmac_stats_t mmac_stats; + int i; + nxge_mmac_t *mmac_info; + + mmac_info = &nxgep->nxge_mmac_info; + + mmac_stats = &nxgep->statsp->mmac_stats; + mmac_stats->mmac_max_cnt = mmac_info->num_mmac; + mmac_stats->mmac_avail_cnt = mmac_info->naddrfree; + + for (i = 0; i < ETHERADDRL; i++) { + if (factory) { + mmac_stats->mmac_avail_pool[slot-1].ether_addr_octet[i] + = mmac_info->factory_mac_pool[slot][(ETHERADDRL-1) - i]; + } else { + mmac_stats->mmac_avail_pool[slot-1].ether_addr_octet[i] + = mmac_info->mac_pool[slot].addr[(ETHERADDRL - 1) - i]; + } + } +} + +/* + * nxge_altmac_set() -- Set an alternate MAC address + */ +static int +nxge_altmac_set(p_nxge_t nxgep, uint8_t *maddr, mac_addr_slot_t slot) +{ + uint8_t addrn; + uint8_t portn; + npi_mac_addr_t altmac; + + altmac.w2 = ((uint16_t)maddr[0] << 8) | ((uint16_t)maddr[1] & 0x0ff); + altmac.w1 = ((uint16_t)maddr[2] << 8) | ((uint16_t)maddr[3] & 0x0ff); + altmac.w0 = ((uint16_t)maddr[4] << 8) | ((uint16_t)maddr[5] & 0x0ff); + + portn = nxgep->mac.portnum; + addrn = (uint8_t)slot - 1; + + if (npi_mac_altaddr_entry(nxgep->npi_handle, OP_SET, portn, + addrn, &altmac) != NPI_SUCCESS) + return (EIO); + /* + * Enable comparison with the alternate MAC address. + * While the first alternate addr is enabled by bit 1 of register + * BMAC_ALTAD_CMPEN, it is enabled by bit 0 of register + * XMAC_ADDR_CMPEN, so slot needs to be converted to addrn + * accordingly before calling npi_mac_altaddr_entry. + */ + if (portn == XMAC_PORT_0 || portn == XMAC_PORT_1) + addrn = (uint8_t)slot - 1; + else + addrn = (uint8_t)slot; + + if (npi_mac_altaddr_enable(nxgep->npi_handle, portn, addrn) + != NPI_SUCCESS) + return (EIO); + + return (0); +} + +/* + * nxeg_m_mmac_add() - find an unused address slot, set the address + * value to the one specified, enable the port to start filtering on + * the new MAC address. Returns 0 on success. + */ +static int +nxge_m_mmac_add(void *arg, mac_multi_addr_t *maddr) +{ + p_nxge_t nxgep = arg; + mac_addr_slot_t slot; + nxge_mmac_t *mmac_info; + int err; + nxge_status_t status; + + mutex_enter(nxgep->genlock); + + /* + * Make sure that nxge is initialized, if _start() has + * not been called. + */ + if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) { + status = nxge_init(nxgep); + if (status != NXGE_OK) { + mutex_exit(nxgep->genlock); + return (ENXIO); + } + } + + mmac_info = &nxgep->nxge_mmac_info; + if (mmac_info->naddrfree == 0) { + mutex_exit(nxgep->genlock); + return (ENOSPC); + } + if (!mac_unicst_verify(nxgep->mach, maddr->mma_addr, + maddr->mma_addrlen)) { + mutex_exit(nxgep->genlock); + return (EINVAL); + } + /* + * Search for the first available slot. Because naddrfree + * is not zero, we are guaranteed to find one. + * Slot 0 is for unique (primary) MAC. The first alternate + * MAC slot is slot 1. + * Each of the first two ports of Neptune has 16 alternate + * MAC slots but only the first 7 (of 15) slots have assigned factory + * MAC addresses. We first search among the slots without bundled + * factory MACs. If we fail to find one in that range, then we + * search the slots with bundled factory MACs. A factory MAC + * will be wasted while the slot is used with a user MAC address. + * But the slot could be used by factory MAC again after calling + * nxge_m_mmac_remove and nxge_m_mmac_reserve. + */ + if (mmac_info->num_factory_mmac < mmac_info->num_mmac) { + for (slot = mmac_info->num_factory_mmac + 1; + slot <= mmac_info->num_mmac; slot++) { + if (!(mmac_info->mac_pool[slot].flags & MMAC_SLOT_USED)) + break; + } + if (slot > mmac_info->num_mmac) { + for (slot = 1; slot <= mmac_info->num_factory_mmac; + slot++) { + if (!(mmac_info->mac_pool[slot].flags + & MMAC_SLOT_USED)) + break; + } + } + } else { + for (slot = 1; slot <= mmac_info->num_mmac; slot++) { + if (!(mmac_info->mac_pool[slot].flags & MMAC_SLOT_USED)) + break; + } + } + ASSERT(slot <= mmac_info->num_mmac); + if ((err = nxge_altmac_set(nxgep, maddr->mma_addr, slot)) != 0) { + mutex_exit(nxgep->genlock); + return (err); + } + bcopy(maddr->mma_addr, mmac_info->mac_pool[slot].addr, ETHERADDRL); + mmac_info->mac_pool[slot].flags |= MMAC_SLOT_USED; + mmac_info->mac_pool[slot].flags &= ~MMAC_VENDOR_ADDR; + mmac_info->naddrfree--; + nxge_mmac_kstat_update(nxgep, slot, B_FALSE); + + maddr->mma_slot = slot; + + mutex_exit(nxgep->genlock); + return (0); +} + +/* + * This function reserves an unused slot and programs the slot and the HW + * with a factory mac address. + */ +static int +nxge_m_mmac_reserve(void *arg, mac_multi_addr_t *maddr) +{ + p_nxge_t nxgep = arg; + mac_addr_slot_t slot; + nxge_mmac_t *mmac_info; + int err; + nxge_status_t status; + + mutex_enter(nxgep->genlock); + + /* + * Make sure that nxge is initialized, if _start() has + * not been called. + */ + if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) { + status = nxge_init(nxgep); + if (status != NXGE_OK) { + mutex_exit(nxgep->genlock); + return (ENXIO); + } + } + + mmac_info = &nxgep->nxge_mmac_info; + if (mmac_info->naddrfree == 0) { + mutex_exit(nxgep->genlock); + return (ENOSPC); + } + + slot = maddr->mma_slot; + if (slot == -1) { /* -1: Take the first available slot */ + for (slot = 1; slot <= mmac_info->num_factory_mmac; slot++) { + if (!(mmac_info->mac_pool[slot].flags & MMAC_SLOT_USED)) + break; + } + if (slot > mmac_info->num_factory_mmac) { + mutex_exit(nxgep->genlock); + return (ENOSPC); + } + } + if (slot < 1 || slot > mmac_info->num_factory_mmac) { + /* + * Do not support factory MAC at a slot greater than + * num_factory_mmac even when there are available factory + * MAC addresses because the alternate MACs are bundled with + * slot[1] through slot[num_factory_mmac] + */ + mutex_exit(nxgep->genlock); + return (EINVAL); + } + if (mmac_info->mac_pool[slot].flags & MMAC_SLOT_USED) { + mutex_exit(nxgep->genlock); + return (EBUSY); + } + /* Verify the address to be reserved */ + if (!mac_unicst_verify(nxgep->mach, + mmac_info->factory_mac_pool[slot], ETHERADDRL)) { + mutex_exit(nxgep->genlock); + return (EINVAL); + } + if (err = nxge_altmac_set(nxgep, + mmac_info->factory_mac_pool[slot], slot)) { + mutex_exit(nxgep->genlock); + return (err); + } + bcopy(mmac_info->factory_mac_pool[slot], maddr->mma_addr, ETHERADDRL); + mmac_info->mac_pool[slot].flags |= MMAC_SLOT_USED | MMAC_VENDOR_ADDR; + mmac_info->naddrfree--; + + nxge_mmac_kstat_update(nxgep, slot, B_TRUE); + mutex_exit(nxgep->genlock); + + /* Pass info back to the caller */ + maddr->mma_slot = slot; + maddr->mma_addrlen = ETHERADDRL; + maddr->mma_flags = MMAC_SLOT_USED | MMAC_VENDOR_ADDR; + + return (0); +} + +/* + * Remove the specified mac address and update the HW not to filter + * the mac address anymore. + */ +static int +nxge_m_mmac_remove(void *arg, mac_addr_slot_t slot) +{ + p_nxge_t nxgep = arg; + nxge_mmac_t *mmac_info; + uint8_t addrn; + uint8_t portn; + int err = 0; + nxge_status_t status; + + mutex_enter(nxgep->genlock); + + /* + * Make sure that nxge is initialized, if _start() has + * not been called. + */ + if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) { + status = nxge_init(nxgep); + if (status != NXGE_OK) { + mutex_exit(nxgep->genlock); + return (ENXIO); + } + } + + mmac_info = &nxgep->nxge_mmac_info; + if (slot < 1 || slot > mmac_info->num_mmac) { + mutex_exit(nxgep->genlock); + return (EINVAL); + } + + portn = nxgep->mac.portnum; + if (portn == XMAC_PORT_0 || portn == XMAC_PORT_1) + addrn = (uint8_t)slot - 1; + else + addrn = (uint8_t)slot; + + if (mmac_info->mac_pool[slot].flags & MMAC_SLOT_USED) { + if (npi_mac_altaddr_disable(nxgep->npi_handle, portn, addrn) + == NPI_SUCCESS) { + mmac_info->naddrfree++; + mmac_info->mac_pool[slot].flags &= ~MMAC_SLOT_USED; + /* + * Regardless if the MAC we just stopped filtering + * is a user addr or a facory addr, we must set + * the MMAC_VENDOR_ADDR flag if this slot has an + * associated factory MAC to indicate that a factory + * MAC is available. + */ + if (slot <= mmac_info->num_factory_mmac) { + mmac_info->mac_pool[slot].flags + |= MMAC_VENDOR_ADDR; + } + /* + * Clear mac_pool[slot].addr so that kstat shows 0 + * alternate MAC address if the slot is not used. + * (But nxge_m_mmac_get returns the factory MAC even + * when the slot is not used!) + */ + bzero(mmac_info->mac_pool[slot].addr, ETHERADDRL); + nxge_mmac_kstat_update(nxgep, slot, B_FALSE); + } else { + err = EIO; + } + } else { + err = EINVAL; + } + + mutex_exit(nxgep->genlock); + return (err); +} + + +/* + * Modify a mac address added by nxge_m_mmac_add or nxge_m_mmac_reserve(). + */ +static int +nxge_m_mmac_modify(void *arg, mac_multi_addr_t *maddr) +{ + p_nxge_t nxgep = arg; + mac_addr_slot_t slot; + nxge_mmac_t *mmac_info; + int err = 0; + nxge_status_t status; + + if (!mac_unicst_verify(nxgep->mach, maddr->mma_addr, + maddr->mma_addrlen)) + return (EINVAL); + + slot = maddr->mma_slot; + + mutex_enter(nxgep->genlock); + + /* + * Make sure that nxge is initialized, if _start() has + * not been called. + */ + if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) { + status = nxge_init(nxgep); + if (status != NXGE_OK) { + mutex_exit(nxgep->genlock); + return (ENXIO); + } + } + + mmac_info = &nxgep->nxge_mmac_info; + if (slot < 1 || slot > mmac_info->num_mmac) { + mutex_exit(nxgep->genlock); + return (EINVAL); + } + if (mmac_info->mac_pool[slot].flags & MMAC_SLOT_USED) { + if ((err = nxge_altmac_set(nxgep, maddr->mma_addr, slot)) + != 0) { + bcopy(maddr->mma_addr, mmac_info->mac_pool[slot].addr, + ETHERADDRL); + /* + * Assume that the MAC passed down from the caller + * is not a factory MAC address (The user should + * call mmac_remove followed by mmac_reserve if + * he wants to use the factory MAC for this slot). + */ + mmac_info->mac_pool[slot].flags &= ~MMAC_VENDOR_ADDR; + nxge_mmac_kstat_update(nxgep, slot, B_FALSE); + } + } else { + err = EINVAL; + } + mutex_exit(nxgep->genlock); + return (err); +} + +/* + * nxge_m_mmac_get() - Get the MAC address and other information + * related to the slot. mma_flags should be set to 0 in the call. + * Note: although kstat shows MAC address as zero when a slot is + * not used, Crossbow expects nxge_m_mmac_get to copy factory MAC + * to the caller as long as the slot is not using a user MAC address. + * The following table shows the rules, + * + * USED VENDOR mma_addr + * ------------------------------------------------------------ + * (1) Slot uses a user MAC: yes no user MAC + * (2) Slot uses a factory MAC: yes yes factory MAC + * (3) Slot is not used but is + * factory MAC capable: no yes factory MAC + * (4) Slot is not used and is + * not factory MAC capable: no no 0 + * ------------------------------------------------------------ + */ +static int +nxge_m_mmac_get(void *arg, mac_multi_addr_t *maddr) +{ + nxge_t *nxgep = arg; + mac_addr_slot_t slot; + nxge_mmac_t *mmac_info; + nxge_status_t status; + + slot = maddr->mma_slot; + + mutex_enter(nxgep->genlock); + + /* + * Make sure that nxge is initialized, if _start() has + * not been called. + */ + if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) { + status = nxge_init(nxgep); + if (status != NXGE_OK) { + mutex_exit(nxgep->genlock); + return (ENXIO); + } + } + + mmac_info = &nxgep->nxge_mmac_info; + + if (slot < 1 || slot > mmac_info->num_mmac) { + mutex_exit(nxgep->genlock); + return (EINVAL); + } + maddr->mma_flags = 0; + if (mmac_info->mac_pool[slot].flags & MMAC_SLOT_USED) + maddr->mma_flags |= MMAC_SLOT_USED; + + if (mmac_info->mac_pool[slot].flags & MMAC_VENDOR_ADDR) { + maddr->mma_flags |= MMAC_VENDOR_ADDR; + bcopy(mmac_info->factory_mac_pool[slot], + maddr->mma_addr, ETHERADDRL); + maddr->mma_addrlen = ETHERADDRL; + } else { + if (maddr->mma_flags & MMAC_SLOT_USED) { + bcopy(mmac_info->mac_pool[slot].addr, + maddr->mma_addr, ETHERADDRL); + maddr->mma_addrlen = ETHERADDRL; + } else { + bzero(maddr->mma_addr, ETHERADDRL); + maddr->mma_addrlen = 0; + } + } + mutex_exit(nxgep->genlock); + return (0); +} + + static boolean_t nxge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) { + nxge_t *nxgep = arg; + uint32_t *txflags = cap_data; + multiaddress_capab_t *mmacp = cap_data; + switch (cap) { - case MAC_CAPAB_HCKSUM: { - uint32_t *txflags = cap_data; - + case MAC_CAPAB_HCKSUM: *txflags = HCKSUM_INET_PARTIAL; break; - } case MAC_CAPAB_POLL: /* * There's nothing for us to fill in, simply returning @@ -3210,6 +3675,25 @@ */ break; + case MAC_CAPAB_MULTIADDRESS: + mutex_enter(nxgep->genlock); + + mmacp->maddr_naddr = nxgep->nxge_mmac_info.num_mmac; + mmacp->maddr_naddrfree = nxgep->nxge_mmac_info.naddrfree; + mmacp->maddr_flag = 0; /* 0 is requried by PSARC2006/265 */ + /* + * maddr_handle is driver's private data, passed back to + * entry point functions as arg. + */ + mmacp->maddr_handle = nxgep; + mmacp->maddr_add = nxge_m_mmac_add; + mmacp->maddr_remove = nxge_m_mmac_remove; + mmacp->maddr_modify = nxge_m_mmac_modify; + mmacp->maddr_get = nxge_m_mmac_get; + mmacp->maddr_reserve = nxge_m_mmac_reserve; + + mutex_exit(nxgep->genlock); + break; default: return (B_FALSE); } @@ -3245,14 +3729,14 @@ DEVO_REV, /* devo_rev */ 0, /* devo_refcnt */ nulldev, - nulldev, /* devo_identify */ - nulldev, /* devo_probe */ - nxge_attach, /* devo_attach */ - nxge_detach, /* devo_detach */ - nodev, /* devo_reset */ - &nxge_cb_ops, /* devo_cb_ops */ - (struct bus_ops *)NULL, /* devo_bus_ops */ - ddi_power /* devo_power */ + nulldev, /* devo_identify */ + nulldev, /* devo_probe */ + nxge_attach, /* devo_attach */ + nxge_detach, /* devo_detach */ + nodev, /* devo_reset */ + &nxge_cb_ops, /* devo_cb_ops */ + (struct bus_ops *)NULL, /* devo_bus_ops */ + ddi_power /* devo_power */ }; extern struct mod_ops mod_driverops; diff -r 5340a4d98e0b -r e3112ae4a154 usr/src/uts/sun4v/io/nxge/nxge_virtual.c --- a/usr/src/uts/sun4v/io/nxge/nxge_virtual.c Thu Feb 22 13:40:56 2007 -0800 +++ b/usr/src/uts/sun4v/io/nxge/nxge_virtual.c Thu Feb 22 15:55:32 2007 -0800 @@ -1156,7 +1156,7 @@ * these parameter affect the classification outcome. * these parameters are used to configure the Flow key and * the TCAM key for each of the IP classes. - * Includee here are also the H1 and H2 initial values + * Included here are also the H1 and H2 initial values * which affect the distribution as well as final hash value * (hence the offset into RDC table and FCRAM bucket location) * @@ -1652,8 +1652,8 @@ * Config types: equal: (default) DMA channels, RDC groups, TCAM, FCRAM * are shared equally across all the ports. * - * Fair: DMA channels, RDC groups, TCAM, FCRAM are shared proprtional to - * te port speed. + * Fair: DMA channels, RDC groups, TCAM, FCRAM are shared proportional + * to the port speed. * * * custom: DMA channels, RDC groups, TCAM, FCRAM partition is @@ -3363,7 +3363,7 @@ uint_t prop_len; uint_t i; uint8_t func_num; - uint8_t num_macs; + uint8_t total_factory_macs; NXGE_DEBUG_MSG((nxgep, DDI_CTL, "==> nxge_get_mac_addr_properties ")); @@ -3408,11 +3408,18 @@ func_num = nxgep->function_num; - /* NIU does not need max_num_mmac */ + /* + * total_factory_macs is the total number of MACs the factory assigned + * to the whole Neptune device. NIU does not need this parameter + * because it derives the number of factory MACs for each port from + * the device properties. + */ if (nxgep->niu_type == NEPTUNE || nxgep->niu_type == NEPTUNE_2) { - if (nxge_espc_num_macs_get(nxgep, &num_macs) == NXGE_OK) { - nxgep->nxge_mmac_info.max_num_mmac = num_macs; - } else { + if (nxge_espc_num_macs_get(nxgep, &total_factory_macs) + == NXGE_OK) { + nxgep->nxge_mmac_info.total_factory_macs + = total_factory_macs; + } else { NXGE_ERROR_MSG((NULL, NXGE_ERR_CTL, "nxge_espc_num_macs_get: espc access failed")); return (NXGE_ERROR); @@ -3432,35 +3439,31 @@ * XAUI may have up to 18 MACs, more than the XMAC can * use (1 unique MAC plus 16 alternate MACs) */ - nxgep->nxge_mmac_info.num_mmac = prop_len / 6; - if (nxgep->nxge_mmac_info.num_mmac > - XMAC_MAX_ALT_ADDR_ENTRY + 1) { - nxgep->nxge_mmac_info.num_mmac = - XMAC_MAX_ALT_ADDR_ENTRY + 1; + nxgep->nxge_mmac_info.num_factory_mmac + = prop_len / ETHERADDRL - 1; + if (nxgep->nxge_mmac_info.num_factory_mmac > + XMAC_MAX_ALT_ADDR_ENTRY) { + nxgep->nxge_mmac_info.num_factory_mmac = + XMAC_MAX_ALT_ADDR_ENTRY; } ddi_prop_free(prop_val); } } else { - nxgep->nxge_mmac_info.num_mmac - = nxgep->nxge_mmac_info.max_num_mmac >> - (nxgep->nports >> 1); + /* + * total_factory_macs = 32 + * num_factory_mmac = (32 >> (nports/2)) - 1 + * So if nports = 4, then num_factory_mmac = 7 + * if nports = 2, then num_factory_mmac = 15 + */ + nxgep->nxge_mmac_info.num_factory_mmac + = ((nxgep->nxge_mmac_info.total_factory_macs >> + (nxgep->nports >> 1))) - 1; } - - for (i = 0; i < nxgep->nxge_mmac_info.num_mmac - 1; ++i) { - /* Initialze all mac addr. to "AVAILABLE" state */ - nxgep->nxge_mmac_info.rsv_mmac[i] = B_FALSE; - /* - * XMAC: Disable alter MAC address comparison only (XMAC's - * unique MAC comparison is always enabled. BMAC: (Neptune - * only) Disable both unique and alter MAC address comparison - */ + for (i = 0; i <= nxgep->nxge_mmac_info.num_mmac; i++) { (void) npi_mac_altaddr_disable(nxgep->npi_handle, NXGE_GET_PORT_NUM(func_num), i); } - /* - * Initialize alt. mac addr. in the mac pool - */ (void) nxge_init_mmac(nxgep); return (NXGE_OK); } @@ -3548,7 +3551,7 @@ } /* - * Note: This function assume the following distribution of mac + * Note: This function assumes the following distribution of mac * addresses among 4 ports in neptune: * * ------------- @@ -3587,49 +3590,61 @@ static void nxge_init_mmac(p_nxge_t nxgep) { - int i; + int slot; uint8_t func_num; uint16_t *base_mmac_addr; - uint32_t first_alt_mac_ls4b; + uint32_t alt_mac_ls4b; uint16_t *mmac_addr; - uint32_t base_mac_ls4b; /* least significant 4 bytes */ - nxge_mmac_t *mac_poolp; + uint32_t base_mac_ls4b; /* least significant 4 bytes */ + nxge_mmac_t *mmac_info; npi_mac_addr_t mac_addr; func_num = nxgep->function_num; base_mmac_addr = (uint16_t *)&nxgep->factaddr; - mac_poolp = (nxge_mmac_t *)&nxgep->nxge_mmac_info; + mmac_info = (nxge_mmac_t *)&nxgep->nxge_mmac_info; base_mac_ls4b = ((uint32_t)base_mmac_addr[1]) << 16 | base_mmac_addr[2]; - if (nxgep->niu_type == N2_NIU) - first_alt_mac_ls4b = base_mac_ls4b + 1; - else /* Neptune */ - first_alt_mac_ls4b = base_mac_ls4b + (nxgep->nports - func_num) - + (func_num * (nxgep->nxge_mmac_info.num_mmac - 1)); - - for (i = 0; i < nxgep->nxge_mmac_info.num_mmac - 1; ++i) { + if (nxgep->niu_type == N2_NIU) { + alt_mac_ls4b = base_mac_ls4b + 1; /* ls4b of 1st altmac */ + } else { /* Neptune */ + alt_mac_ls4b = base_mac_ls4b + (nxgep->nports - func_num) + + (func_num * (mmac_info->num_factory_mmac)); + } + + /* Set flags for unique MAC */ + mmac_info->mac_pool[0].flags |= MMAC_SLOT_USED | MMAC_VENDOR_ADDR; + + /* Clear flags of all alternate MAC slots */ + for (slot = 1; slot <= mmac_info->num_mmac; slot++) { + if (slot <= mmac_info->num_factory_mmac) + mmac_info->mac_pool[slot].flags = MMAC_VENDOR_ADDR; + else + mmac_info->mac_pool[slot].flags = 0; + } + + /* Generate and store factory alternate MACs */ + for (slot = 1; slot <= mmac_info->num_factory_mmac; slot++) { + mmac_addr = (uint16_t *)&mmac_info->factory_mac_pool[slot]; + mmac_addr[0] = base_mmac_addr[0]; + mac_addr.w2 = mmac_addr[0]; + + mmac_addr[1] = (alt_mac_ls4b >> 16) & 0x0FFFF; + mac_addr.w1 = mmac_addr[1]; + + mmac_addr[2] = alt_mac_ls4b & 0x0FFFF; + mac_addr.w0 = mmac_addr[2]; /* - * Populate shadow mac pool w/ available mac. so we dont have - * to read the h/w to search for a mac addr. - */ - mmac_addr = (uint16_t *)&mac_poolp->mmac_pool[i]; - mmac_addr[0] = base_mmac_addr[0]; - mac_addr.w0 = mmac_addr[0]; - - mmac_addr[1] = (first_alt_mac_ls4b >> 16) & 0x0FFFF; - mac_addr.w1 = mmac_addr[1]; - - mmac_addr[2] = first_alt_mac_ls4b & 0x0FFFF; - mac_addr.w2 = mmac_addr[2]; - - /* - * Program the h/w alt. mac address, starting from reg1(reg0 - * corr. to unique mac addr) + * slot minus 1 because npi_mac_alraddr_entry expects 0 + * for the first alternate mac address. */ (void) npi_mac_altaddr_entry(nxgep->npi_handle, OP_SET, - NXGE_GET_PORT_NUM(func_num), i, &mac_addr); - first_alt_mac_ls4b++; + NXGE_GET_PORT_NUM(func_num), slot - 1, &mac_addr); + + alt_mac_ls4b++; } + /* Initialize the first two parameters for mmac kstat */ + nxgep->statsp->mmac_stats.mmac_max_cnt = mmac_info->num_mmac; + nxgep->statsp->mmac_stats.mmac_avail_cnt = mmac_info->num_mmac; } diff -r 5340a4d98e0b -r e3112ae4a154 usr/src/uts/sun4v/sys/nxge/nxge_impl.h --- a/usr/src/uts/sun4v/sys/nxge/nxge_impl.h Thu Feb 22 13:40:56 2007 -0800 +++ b/usr/src/uts/sun4v/sys/nxge/nxge_impl.h Thu Feb 22 15:55:32 2007 -0800 @@ -531,16 +531,33 @@ unsigned char *nxge_romp; /* fcode pointer */ } dev_regs_t, *p_dev_regs_t; + +typedef struct _nxge_mac_addr_t { + ether_addr_t addr; + uint_t flags; +} nxge_mac_addr_t; + /* - * Driver alternate mac address structure. + * The hardware supports 1 unique MAC and 16 alternate MACs (num_mmac) + * for each XMAC port and supports 1 unique MAC and 7 alternate MACs + * for each BMAC port. The number of MACs assigned by the factory is + * different and is as follows, + * BMAC port: num_factory_mmac = num_mmac = 7 + * XMAC port on a 2-port NIC: num_factory_mmac = num_mmac - 1 = 15 + * XMAC port on a 4-port NIC: num_factory_mmac = 7 + * So num_factory_mmac is smaller than num_mmac. nxge_m_mmac_add uses + * num_mmac and nxge_m_mmac_reserve uses num_factory_mmac. + * + * total_factory_macs is the total number of factory MACs, including + * the unique MAC, assigned to a Neptune based NIC card, it is 32. */ typedef struct _nxge_mmac_t { - kmutex_t mmac_lock; - uint8_t max_num_mmac; /* Max allocated per card */ - uint8_t num_mmac; /* Mac addr. per function */ - struct ether_addr mmac_pool[16]; /* Mac addr pool per function in s/w */ - boolean_t rsv_mmac[16]; /* Reserved mac addr. in the pool */ - uint8_t num_avail_mmac; /* # of rsv.ed mac addr. in the pool */ + uint8_t total_factory_macs; + uint8_t num_mmac; + uint8_t num_factory_mmac; + nxge_mac_addr_t mac_pool[XMAC_MAX_ADDR_ENTRY]; + ether_addr_t factory_mac_pool[XMAC_MAX_ADDR_ENTRY]; + uint8_t naddrfree; /* number of alt mac addr available */ } nxge_mmac_t; /* diff -r 5340a4d98e0b -r e3112ae4a154 usr/src/uts/sun4v/sys/nxge/nxge_mac_hw.h --- a/usr/src/uts/sun4v/sys/nxge/nxge_mac_hw.h Thu Feb 22 13:40:56 2007 -0800 +++ b/usr/src/uts/sun4v/sys/nxge/nxge_mac_hw.h Thu Feb 22 15:55:32 2007 -0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -815,6 +815,7 @@ #define BMAC_ALT_ADDR_BASE 0x118 #define BMAC_MAX_ALT_ADDR_ENTRY 7 /* 7 alternate MAC addr */ +#define BMAC_MAX_ADDR_ENTRY (BMAC_MAX_ALT_ADDR_ENTRY + 1) /* hash table registers */ #define MAC_MAX_HASH_ENTRY 16 @@ -1051,6 +1052,7 @@ /* Alternate MAC address registers */ #define XMAC_MAX_ALT_ADDR_ENTRY 16 /* 16 alternate MAC addrs */ +#define XMAC_MAX_ADDR_ENTRY (XMAC_MAX_ALT_ADDR_ENTRY + 1) /* Max / Min parameters for Neptune MAC */