aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/myri10ge/myri10ge.c
diff options
context:
space:
mode:
authorBrice Goglin <brice@myri.com>2006-08-21 17:36:56 -0400
committerJeff Garzik <jeff@garzik.org>2006-08-24 00:43:51 -0400
commit85a7ea1b0a3263f3ad423b789a841d03c9acbb65 (patch)
tree1bd6e9fca08067157425fee973cf68594c827829 /drivers/net/myri10ge/myri10ge.c
parentc58ac5caeb32ef17c2e4fc208f7dc93f6de32b7d (diff)
[PATCH] myri10ge: use multicast support in the firmware
Some recent myri10ge firmwares support multicast filtering as well as an extended mcp_irq_data structure (64 instead of 40 bytes). The new command MXGEFW_CMD_SET_STATS_DMA_V2 is used to check whether the firmware support those. mgp->fw_multicast_support is defined accordingly. When fw_multicast_support is set, some new multicast filtering commands is passed to the board in myri10ge_set_multicast_list(). Signed-off-by: Brice Goglin <brice@myri.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/myri10ge/myri10ge.c')
-rw-r--r--drivers/net/myri10ge/myri10ge.c99
1 files changed, 95 insertions, 4 deletions
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index a79afe2134ba..e2346e8a4d52 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -187,6 +187,7 @@ struct myri10ge_priv {
187 u8 mac_addr[6]; /* eeprom mac address */ 187 u8 mac_addr[6]; /* eeprom mac address */
188 unsigned long serial_number; 188 unsigned long serial_number;
189 int vendor_specific_offset; 189 int vendor_specific_offset;
190 int fw_multicast_support;
190 u32 devctl; 191 u32 devctl;
191 u16 msi_flags; 192 u16 msi_flags;
192 u32 read_dma; 193 u32 read_dma;
@@ -328,6 +329,8 @@ myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd,
328 if (result == 0) { 329 if (result == 0) {
329 data->data0 = value; 330 data->data0 = value;
330 return 0; 331 return 0;
332 } else if (result == MXGEFW_CMD_UNKNOWN) {
333 return -ENOSYS;
331 } else { 334 } else {
332 dev_err(&mgp->pdev->dev, 335 dev_err(&mgp->pdev->dev,
333 "command %d failed, result = %d\n", 336 "command %d failed, result = %d\n",
@@ -1309,8 +1312,8 @@ static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
1309 "tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt", 1312 "tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt",
1310 "wake_queue", "stop_queue", "watchdog_resets", "tx_linearized", 1313 "wake_queue", "stop_queue", "watchdog_resets", "tx_linearized",
1311 "link_changes", "link_up", "dropped_link_overflow", 1314 "link_changes", "link_up", "dropped_link_overflow",
1312 "dropped_link_error_or_filtered", "dropped_runt", 1315 "dropped_link_error_or_filtered", "dropped_multicast_filtered",
1313 "dropped_overrun", "dropped_no_small_buffer", 1316 "dropped_runt", "dropped_overrun", "dropped_no_small_buffer",
1314 "dropped_no_big_buffer" 1317 "dropped_no_big_buffer"
1315}; 1318};
1316 1319
@@ -1366,6 +1369,8 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
1366 data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_link_overflow); 1369 data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_link_overflow);
1367 data[i++] = 1370 data[i++] =
1368 (unsigned int)ntohl(mgp->fw_stats->dropped_link_error_or_filtered); 1371 (unsigned int)ntohl(mgp->fw_stats->dropped_link_error_or_filtered);
1372 data[i++] =
1373 (unsigned int)ntohl(mgp->fw_stats->dropped_multicast_filtered);
1369 data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_runt); 1374 data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_runt);
1370 data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_overrun); 1375 data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_overrun);
1371 data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_small_buffer); 1376 data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_small_buffer);
@@ -1722,7 +1727,21 @@ static int myri10ge_open(struct net_device *dev)
1722 1727
1723 cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->fw_stats_bus); 1728 cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->fw_stats_bus);
1724 cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->fw_stats_bus); 1729 cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->fw_stats_bus);
1725 status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA, &cmd, 0); 1730 cmd.data2 = sizeof(struct mcp_irq_data);
1731 status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0);
1732 if (status == -ENOSYS) {
1733 dma_addr_t bus = mgp->fw_stats_bus;
1734 bus += offsetof(struct mcp_irq_data, send_done_count);
1735 cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus);
1736 cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus);
1737 status = myri10ge_send_cmd(mgp,
1738 MXGEFW_CMD_SET_STATS_DMA_OBSOLETE,
1739 &cmd, 0);
1740 /* Firmware cannot support multicast without STATS_DMA_V2 */
1741 mgp->fw_multicast_support = 0;
1742 } else {
1743 mgp->fw_multicast_support = 1;
1744 }
1726 if (status) { 1745 if (status) {
1727 printk(KERN_ERR "myri10ge: %s: Couldn't set stats DMA\n", 1746 printk(KERN_ERR "myri10ge: %s: Couldn't set stats DMA\n",
1728 dev->name); 1747 dev->name);
@@ -2177,9 +2196,81 @@ static struct net_device_stats *myri10ge_get_stats(struct net_device *dev)
2177 2196
2178static void myri10ge_set_multicast_list(struct net_device *dev) 2197static void myri10ge_set_multicast_list(struct net_device *dev)
2179{ 2198{
2199 struct myri10ge_cmd cmd;
2200 struct myri10ge_priv *mgp;
2201 struct dev_mc_list *mc_list;
2202 int err;
2203
2204 mgp = netdev_priv(dev);
2180 /* can be called from atomic contexts, 2205 /* can be called from atomic contexts,
2181 * pass 1 to force atomicity in myri10ge_send_cmd() */ 2206 * pass 1 to force atomicity in myri10ge_send_cmd() */
2182 myri10ge_change_promisc(netdev_priv(dev), dev->flags & IFF_PROMISC, 1); 2207 myri10ge_change_promisc(mgp, dev->flags & IFF_PROMISC, 1);
2208
2209 /* This firmware is known to not support multicast */
2210 if (!mgp->fw_multicast_support)
2211 return;
2212
2213 /* Disable multicast filtering */
2214
2215 err = myri10ge_send_cmd(mgp, MXGEFW_ENABLE_ALLMULTI, &cmd, 1);
2216 if (err != 0) {
2217 printk(KERN_ERR "myri10ge: %s: Failed MXGEFW_ENABLE_ALLMULTI,"
2218 " error status: %d\n", dev->name, err);
2219 goto abort;
2220 }
2221
2222 if (dev->flags & IFF_ALLMULTI) {
2223 /* request to disable multicast filtering, so quit here */
2224 return;
2225 }
2226
2227 /* Flush the filters */
2228
2229 err = myri10ge_send_cmd(mgp, MXGEFW_LEAVE_ALL_MULTICAST_GROUPS,
2230 &cmd, 1);
2231 if (err != 0) {
2232 printk(KERN_ERR
2233 "myri10ge: %s: Failed MXGEFW_LEAVE_ALL_MULTICAST_GROUPS"
2234 ", error status: %d\n", dev->name, err);
2235 goto abort;
2236 }
2237
2238 /* Walk the multicast list, and add each address */
2239 for (mc_list = dev->mc_list; mc_list != NULL; mc_list = mc_list->next) {
2240 memcpy(&cmd.data0, &mc_list->dmi_addr, 4);
2241 memcpy(&cmd.data1, ((char *)&mc_list->dmi_addr) + 4, 2);
2242 cmd.data0 = htonl(cmd.data0);
2243 cmd.data1 = htonl(cmd.data1);
2244 err = myri10ge_send_cmd(mgp, MXGEFW_JOIN_MULTICAST_GROUP,
2245 &cmd, 1);
2246
2247 if (err != 0) {
2248 printk(KERN_ERR "myri10ge: %s: Failed "
2249 "MXGEFW_JOIN_MULTICAST_GROUP, error status:"
2250 "%d\t", dev->name, err);
2251 printk(KERN_ERR "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
2252 ((unsigned char *)&mc_list->dmi_addr)[0],
2253 ((unsigned char *)&mc_list->dmi_addr)[1],
2254 ((unsigned char *)&mc_list->dmi_addr)[2],
2255 ((unsigned char *)&mc_list->dmi_addr)[3],
2256 ((unsigned char *)&mc_list->dmi_addr)[4],
2257 ((unsigned char *)&mc_list->dmi_addr)[5]
2258 );
2259 goto abort;
2260 }
2261 }
2262 /* Enable multicast filtering */
2263 err = myri10ge_send_cmd(mgp, MXGEFW_DISABLE_ALLMULTI, &cmd, 1);
2264 if (err != 0) {
2265 printk(KERN_ERR "myri10ge: %s: Failed MXGEFW_DISABLE_ALLMULTI,"
2266 "error status: %d\n", dev->name, err);
2267 goto abort;
2268 }
2269
2270 return;
2271
2272abort:
2273 return;
2183} 2274}
2184 2275
2185static int myri10ge_set_mac_address(struct net_device *dev, void *addr) 2276static int myri10ge_set_mac_address(struct net_device *dev, void *addr)