diff options
Diffstat (limited to 'drivers/net/s2io.c')
-rw-r--r-- | drivers/net/s2io.c | 194 |
1 files changed, 178 insertions, 16 deletions
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 67e0a65fc28c..644d71bfb640 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -3375,6 +3375,9 @@ static void s2io_reset(struct s2io_nic * sp) /* Set swapper to enable I/O register access */ s2io_set_swapper(sp); + /* restore mac_addr entries */ + do_s2io_restore_unicast_mc(sp); + /* Restore the MSIX table entries from local variables */ restore_xmsi_data(sp); @@ -3433,9 +3436,6 @@ static void s2io_reset(struct s2io_nic * sp) writeq(val64, &bar0->pcc_err_reg); } - /* restore the previously assigned mac address */ - do_s2io_prog_unicast(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr); - sp->device_enabled_once = FALSE; } @@ -3920,6 +3920,9 @@ hw_init_failed: static int s2io_close(struct net_device *dev) { struct s2io_nic *sp = dev->priv; + struct config_param *config = &sp->config; + u64 tmp64; + int offset; /* Return if the device is already closed * * Can happen when s2io_card_up failed in change_mtu * @@ -3928,6 +3931,14 @@ static int s2io_close(struct net_device *dev) return 0; netif_stop_queue(dev); + + /* delete all populated mac entries */ + for (offset = 1; offset < config->max_mc_addr; offset++) { + tmp64 = do_s2io_read_unicast_mc(sp, offset); + if (tmp64 != S2IO_DISABLE_MAC_ENTRY) + do_s2io_delete_unicast_mc(sp, tmp64); + } + /* Reset card, kill tasklet and free Tx and Rx buffers. */ s2io_card_down(sp); @@ -4728,8 +4739,9 @@ static void s2io_set_multicast(struct net_device *dev) struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = 0, multi_mac = 0x010203040506ULL, mask = 0xfeffffffffffULL; - u64 dis_addr = 0xffffffffffffULL, mac_addr = 0; + u64 dis_addr = S2IO_DISABLE_MAC_ENTRY, mac_addr = 0; void __iomem *add; + struct config_param *config = &sp->config; if ((dev->flags & IFF_ALLMULTI) && (!sp->m_cast_flg)) { /* Enable all Multicast addresses */ @@ -4739,7 +4751,7 @@ static void s2io_set_multicast(struct net_device *dev) &bar0->rmac_addr_data1_mem); val64 = RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | - RMAC_ADDR_CMD_MEM_OFFSET(MAC_MC_ALL_MC_ADDR_OFFSET); + RMAC_ADDR_CMD_MEM_OFFSET(config->max_mc_addr - 1); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait till command completes */ wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, @@ -4747,7 +4759,7 @@ static void s2io_set_multicast(struct net_device *dev) S2IO_BIT_RESET); sp->m_cast_flg = 1; - sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET; + sp->all_multi_pos = config->max_mc_addr - 1; } else if ((dev->flags & IFF_ALLMULTI) && (sp->m_cast_flg)) { /* Disable all Multicast addresses */ writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr), @@ -4816,7 +4828,7 @@ static void s2io_set_multicast(struct net_device *dev) /* Update individual M_CAST address list */ if ((!sp->m_cast_flg) && dev->mc_count) { if (dev->mc_count > - (MAX_ADDRS_SUPPORTED - MAC_MC_ADDR_START_OFFSET - 1)) { + (config->max_mc_addr - config->max_mac_addr)) { DBG_PRINT(ERR_DBG, "%s: No more Rx filters ", dev->name); DBG_PRINT(ERR_DBG, "can be added, please enable "); @@ -4836,7 +4848,7 @@ static void s2io_set_multicast(struct net_device *dev) val64 = RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | RMAC_ADDR_CMD_MEM_OFFSET - (MAC_MC_ADDR_START_OFFSET + i); + (config->mc_start_offset + i); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait for command completes */ @@ -4868,7 +4880,7 @@ static void s2io_set_multicast(struct net_device *dev) val64 = RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | RMAC_ADDR_CMD_MEM_OFFSET - (i + MAC_MC_ADDR_START_OFFSET); + (i + config->mc_start_offset); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait for command completes */ @@ -4884,8 +4896,78 @@ static void s2io_set_multicast(struct net_device *dev) } } -/* add unicast MAC address to CAM */ -static int do_s2io_add_unicast(struct s2io_nic *sp, u64 addr, int off) +/* read from CAM unicast & multicast addresses and store it in + * def_mac_addr structure + */ +void do_s2io_store_unicast_mc(struct s2io_nic *sp) +{ + int offset; + u64 mac_addr = 0x0; + struct config_param *config = &sp->config; + + /* store unicast & multicast mac addresses */ + for (offset = 0; offset < config->max_mc_addr; offset++) { + mac_addr = do_s2io_read_unicast_mc(sp, offset); + /* if read fails disable the entry */ + if (mac_addr == FAILURE) + mac_addr = S2IO_DISABLE_MAC_ENTRY; + do_s2io_copy_mac_addr(sp, offset, mac_addr); + } +} + +/* restore unicast & multicast MAC to CAM from def_mac_addr structure */ +static void do_s2io_restore_unicast_mc(struct s2io_nic *sp) +{ + int offset; + struct config_param *config = &sp->config; + /* restore unicast mac address */ + for (offset = 0; offset < config->max_mac_addr; offset++) + do_s2io_prog_unicast(sp->dev, + sp->def_mac_addr[offset].mac_addr); + + /* restore multicast mac address */ + for (offset = config->mc_start_offset; + offset < config->max_mc_addr; offset++) + do_s2io_add_mc(sp, sp->def_mac_addr[offset].mac_addr); +} + +/* add a multicast MAC address to CAM */ +static int do_s2io_add_mc(struct s2io_nic *sp, u8 *addr) +{ + int i; + u64 mac_addr = 0; + struct config_param *config = &sp->config; + + for (i = 0; i < ETH_ALEN; i++) { + mac_addr <<= 8; + mac_addr |= addr[i]; + } + if ((0ULL == mac_addr) || (mac_addr == S2IO_DISABLE_MAC_ENTRY)) + return SUCCESS; + + /* check if the multicast mac already preset in CAM */ + for (i = config->mc_start_offset; i < config->max_mc_addr; i++) { + u64 tmp64; + tmp64 = do_s2io_read_unicast_mc(sp, i); + if (tmp64 == S2IO_DISABLE_MAC_ENTRY) /* CAM entry is empty */ + break; + + if (tmp64 == mac_addr) + return SUCCESS; + } + if (i == config->max_mc_addr) { + DBG_PRINT(ERR_DBG, + "CAM full no space left for multicast MAC\n"); + return FAILURE; + } + /* Update the internal structure with this new mac address */ + do_s2io_copy_mac_addr(sp, i, mac_addr); + + return (do_s2io_add_mac(sp, mac_addr, i)); +} + +/* add MAC address to CAM */ +static int do_s2io_add_mac(struct s2io_nic *sp, u64 addr, int off) { u64 val64; struct XENA_dev_config __iomem *bar0 = sp->bar0; @@ -4902,15 +4984,62 @@ static int do_s2io_add_unicast(struct s2io_nic *sp, u64 addr, int off) if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET)) { - DBG_PRINT(INFO_DBG, "add_mac_addr failed\n"); + DBG_PRINT(INFO_DBG, "do_s2io_add_mac failed\n"); return FAILURE; } return SUCCESS; } +/* deletes a specified unicast/multicast mac entry from CAM */ +static int do_s2io_delete_unicast_mc(struct s2io_nic *sp, u64 addr) +{ + int offset; + u64 dis_addr = S2IO_DISABLE_MAC_ENTRY, tmp64; + struct config_param *config = &sp->config; + + for (offset = 1; + offset < config->max_mc_addr; offset++) { + tmp64 = do_s2io_read_unicast_mc(sp, offset); + if (tmp64 == addr) { + /* disable the entry by writing 0xffffffffffffULL */ + if (do_s2io_add_mac(sp, dis_addr, offset) == FAILURE) + return FAILURE; + /* store the new mac list from CAM */ + do_s2io_store_unicast_mc(sp); + return SUCCESS; + } + } + DBG_PRINT(ERR_DBG, "MAC address 0x%llx not found in CAM\n", + (unsigned long long)addr); + return FAILURE; +} + +/* read mac entries from CAM */ +static u64 do_s2io_read_unicast_mc(struct s2io_nic *sp, int offset) +{ + u64 tmp64 = 0xffffffffffff0000ULL, val64; + struct XENA_dev_config __iomem *bar0 = sp->bar0; + + /* read mac addr */ + val64 = + RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | + RMAC_ADDR_CMD_MEM_OFFSET(offset); + writeq(val64, &bar0->rmac_addr_cmd_mem); + + /* Wait till command completes */ + if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET)) { + DBG_PRINT(INFO_DBG, "do_s2io_read_unicast_mc failed\n"); + return FAILURE; + } + tmp64 = readq(&bar0->rmac_addr_data0_mem); + return (tmp64 >> 16); +} /** * s2io_set_mac_addr driver entry point */ + static int s2io_set_mac_addr(struct net_device *dev, void *p) { struct sockaddr *addr = p; @@ -4923,7 +5052,6 @@ static int s2io_set_mac_addr(struct net_device *dev, void *p) /* store the MAC address in CAM */ return (do_s2io_prog_unicast(dev, dev->dev_addr)); } - /** * do_s2io_prog_unicast - Programs the Xframe mac address * @dev : pointer to the device structure. @@ -4933,11 +5061,14 @@ static int s2io_set_mac_addr(struct net_device *dev, void *p) * Return value: SUCCESS on success and an appropriate (-)ve integer * as defined in errno.h file on failure. */ + static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) { struct s2io_nic *sp = dev->priv; register u64 mac_addr = 0, perm_addr = 0; int i; + u64 tmp64; + struct config_param *config = &sp->config; /* * Set the new MAC address as the new unicast filter and reflect this @@ -4955,9 +5086,26 @@ static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) if (mac_addr == perm_addr) return SUCCESS; + /* check if the mac already preset in CAM */ + for (i = 1; i < config->max_mac_addr; i++) { + tmp64 = do_s2io_read_unicast_mc(sp, i); + if (tmp64 == S2IO_DISABLE_MAC_ENTRY) /* CAM entry is empty */ + break; + + if (tmp64 == mac_addr) { + DBG_PRINT(INFO_DBG, + "MAC addr:0x%llx already present in CAM\n", + (unsigned long long)mac_addr); + return SUCCESS; + } + } + if (i == config->max_mac_addr) { + DBG_PRINT(ERR_DBG, "CAM full no space left for Unicast MAC\n"); + return FAILURE; + } /* Update the internal structure with this new mac address */ - do_s2io_copy_mac_addr(sp, 0, mac_addr); - return (do_s2io_add_unicast(sp, mac_addr, 0)); + do_s2io_copy_mac_addr(sp, i, mac_addr); + return (do_s2io_add_mac(sp, mac_addr, i)); } /** @@ -7651,7 +7799,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) */ bar0 = sp->bar0; val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | - RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET); + RMAC_ADDR_CMD_MEM_OFFSET(0 + S2IO_MAC_ADDR_START_OFFSET); writeq(val64, &bar0->rmac_addr_cmd_mem); wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET); @@ -7671,6 +7819,20 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN); memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN); + /* initialize number of multicast & unicast MAC entries variables */ + if (sp->device_type == XFRAME_I_DEVICE) { + config->max_mc_addr = S2IO_XENA_MAX_MC_ADDRESSES; + config->max_mac_addr = S2IO_XENA_MAX_MAC_ADDRESSES; + config->mc_start_offset = S2IO_XENA_MC_ADDR_START_OFFSET; + } else if (sp->device_type == XFRAME_II_DEVICE) { + config->max_mc_addr = S2IO_HERC_MAX_MC_ADDRESSES; + config->max_mac_addr = S2IO_HERC_MAX_MAC_ADDRESSES; + config->mc_start_offset = S2IO_HERC_MC_ADDR_START_OFFSET; + } + + /* store mac addresses from CAM to s2io_nic structure */ + do_s2io_store_unicast_mc(sp); + /* Store the values of the MSIX table in the s2io_nic structure */ store_xmsi_data(sp); /* reset Nic and bring it to known state */ |