diff options
author | Brice Goglin <brice@myri.com> | 2006-08-21 17:36:56 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-08-24 00:43:51 -0400 |
commit | 85a7ea1b0a3263f3ad423b789a841d03c9acbb65 (patch) | |
tree | 1bd6e9fca08067157425fee973cf68594c827829 /drivers/net/myri10ge | |
parent | c58ac5caeb32ef17c2e4fc208f7dc93f6de32b7d (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')
-rw-r--r-- | drivers/net/myri10ge/myri10ge.c | 99 | ||||
-rw-r--r-- | drivers/net/myri10ge/myri10ge_mcp.h | 33 |
2 files changed, 124 insertions, 8 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 | ||
2178 | static void myri10ge_set_multicast_list(struct net_device *dev) | 2197 | static 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 | |||
2272 | abort: | ||
2273 | return; | ||
2183 | } | 2274 | } |
2184 | 2275 | ||
2185 | static int myri10ge_set_mac_address(struct net_device *dev, void *addr) | 2276 | static int myri10ge_set_mac_address(struct net_device *dev, void *addr) |
diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h index d7dfaa5f64a2..9519ae7cd5ec 100644 --- a/drivers/net/myri10ge/myri10ge_mcp.h +++ b/drivers/net/myri10ge/myri10ge_mcp.h | |||
@@ -166,7 +166,7 @@ enum myri10ge_mcp_cmd_type { | |||
166 | MXGEFW_CMD_SET_MTU, | 166 | MXGEFW_CMD_SET_MTU, |
167 | MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, /* in microseconds */ | 167 | MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, /* in microseconds */ |
168 | MXGEFW_CMD_SET_STATS_INTERVAL, /* in microseconds */ | 168 | MXGEFW_CMD_SET_STATS_INTERVAL, /* in microseconds */ |
169 | MXGEFW_CMD_SET_STATS_DMA, | 169 | MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, /* replaced by SET_STATS_DMA_V2 */ |
170 | 170 | ||
171 | MXGEFW_ENABLE_PROMISC, | 171 | MXGEFW_ENABLE_PROMISC, |
172 | MXGEFW_DISABLE_PROMISC, | 172 | MXGEFW_DISABLE_PROMISC, |
@@ -180,7 +180,26 @@ enum myri10ge_mcp_cmd_type { | |||
180 | * data2 = RDMA length (MSH), WDMA length (LSH) | 180 | * data2 = RDMA length (MSH), WDMA length (LSH) |
181 | * command return data = repetitions (MSH), 0.5-ms ticks (LSH) | 181 | * command return data = repetitions (MSH), 0.5-ms ticks (LSH) |
182 | */ | 182 | */ |
183 | MXGEFW_DMA_TEST | 183 | MXGEFW_DMA_TEST, |
184 | |||
185 | MXGEFW_ENABLE_ALLMULTI, | ||
186 | MXGEFW_DISABLE_ALLMULTI, | ||
187 | |||
188 | /* returns MXGEFW_CMD_ERROR_MULTICAST | ||
189 | * if there is no room in the cache | ||
190 | * data0,MSH(data1) = multicast group address */ | ||
191 | MXGEFW_JOIN_MULTICAST_GROUP, | ||
192 | /* returns MXGEFW_CMD_ERROR_MULTICAST | ||
193 | * if the address is not in the cache, | ||
194 | * or is equal to FF-FF-FF-FF-FF-FF | ||
195 | * data0,MSH(data1) = multicast group address */ | ||
196 | MXGEFW_LEAVE_MULTICAST_GROUP, | ||
197 | MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, | ||
198 | |||
199 | MXGEFW_CMD_SET_STATS_DMA_V2, | ||
200 | /* data0, data1 = bus addr, | ||
201 | * data2 = sizeof(struct mcp_irq_data) from driver point of view, allows | ||
202 | * adding new stuff to mcp_irq_data without changing the ABI */ | ||
184 | }; | 203 | }; |
185 | 204 | ||
186 | enum myri10ge_mcp_cmd_status { | 205 | enum myri10ge_mcp_cmd_status { |
@@ -192,11 +211,17 @@ enum myri10ge_mcp_cmd_status { | |||
192 | MXGEFW_CMD_ERROR_CLOSED, | 211 | MXGEFW_CMD_ERROR_CLOSED, |
193 | MXGEFW_CMD_ERROR_HASH_ERROR, | 212 | MXGEFW_CMD_ERROR_HASH_ERROR, |
194 | MXGEFW_CMD_ERROR_BAD_PORT, | 213 | MXGEFW_CMD_ERROR_BAD_PORT, |
195 | MXGEFW_CMD_ERROR_RESOURCES | 214 | MXGEFW_CMD_ERROR_RESOURCES, |
215 | MXGEFW_CMD_ERROR_MULTICAST | ||
196 | }; | 216 | }; |
197 | 217 | ||
198 | /* 40 Bytes */ | 218 | #define MXGEFW_OLD_IRQ_DATA_LEN 40 |
219 | |||
199 | struct mcp_irq_data { | 220 | struct mcp_irq_data { |
221 | /* add new counters at the beginning */ | ||
222 | u32 future_use[5]; | ||
223 | u32 dropped_multicast_filtered; | ||
224 | /* 40 Bytes */ | ||
200 | u32 send_done_count; | 225 | u32 send_done_count; |
201 | 226 | ||
202 | u32 link_up; | 227 | u32 link_up; |