diff options
author | Brice Goglin <brice@myri.com> | 2008-05-08 20:21:10 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-05-30 22:11:46 -0400 |
commit | 779297320d192655c2f95a870c12e9b307612429 (patch) | |
tree | 6fbd2355900d21cb0852109e49890739286a4630 /drivers/net/myri10ge/myri10ge.c | |
parent | a5b17df04c4ad8f25fc598fce37fccb4b387c94c (diff) |
myri10ge: add routines for multislices
Add several routines that multislices support will use.
Signed-off-by: Brice Goglin <brice@myri.com>
Signed-off-by: Andrew Gallatin <gallatin@myri.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/myri10ge/myri10ge.c')
-rw-r--r-- | drivers/net/myri10ge/myri10ge.c | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 36be6efc6398..f3ef9e3c48cd 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c | |||
@@ -1928,6 +1928,76 @@ myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr, | |||
1928 | return 0; | 1928 | return 0; |
1929 | } | 1929 | } |
1930 | 1930 | ||
1931 | #if 0 | ||
1932 | static int myri10ge_get_txrx(struct myri10ge_priv *mgp, int slice) | ||
1933 | { | ||
1934 | struct myri10ge_cmd cmd; | ||
1935 | struct myri10ge_slice_state *ss; | ||
1936 | int status; | ||
1937 | |||
1938 | ss = &mgp->ss[slice]; | ||
1939 | cmd.data0 = 0; /* single slice for now */ | ||
1940 | status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0); | ||
1941 | ss->tx.lanai = (struct mcp_kreq_ether_send __iomem *) | ||
1942 | (mgp->sram + cmd.data0); | ||
1943 | |||
1944 | cmd.data0 = slice; | ||
1945 | status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET, | ||
1946 | &cmd, 0); | ||
1947 | ss->rx_small.lanai = (struct mcp_kreq_ether_recv __iomem *) | ||
1948 | (mgp->sram + cmd.data0); | ||
1949 | |||
1950 | cmd.data0 = slice; | ||
1951 | status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd, 0); | ||
1952 | ss->rx_big.lanai = (struct mcp_kreq_ether_recv __iomem *) | ||
1953 | (mgp->sram + cmd.data0); | ||
1954 | |||
1955 | if (myri10ge_wcfifo && mgp->wc_enabled) { | ||
1956 | ss->tx.wc_fifo = (u8 __iomem *) | ||
1957 | mgp->sram + MXGEFW_ETH_SEND_4 + 64 * slice; | ||
1958 | ss->rx_small.wc_fifo = (u8 __iomem *) | ||
1959 | mgp->sram + MXGEFW_ETH_RECV_SMALL + 64 * slice; | ||
1960 | ss->rx_big.wc_fifo = (u8 __iomem *) | ||
1961 | mgp->sram + MXGEFW_ETH_RECV_BIG + 64 * slice; | ||
1962 | } else { | ||
1963 | ss->tx.wc_fifo = NULL; | ||
1964 | ss->rx_small.wc_fifo = NULL; | ||
1965 | ss->rx_big.wc_fifo = NULL; | ||
1966 | } | ||
1967 | return status; | ||
1968 | |||
1969 | } | ||
1970 | |||
1971 | static int myri10ge_set_stats(struct myri10ge_priv *mgp, int slice) | ||
1972 | { | ||
1973 | struct myri10ge_cmd cmd; | ||
1974 | struct myri10ge_slice_state *ss; | ||
1975 | int status; | ||
1976 | |||
1977 | ss = &mgp->ss[slice]; | ||
1978 | cmd.data0 = MYRI10GE_LOWPART_TO_U32(ss->fw_stats_bus); | ||
1979 | cmd.data1 = MYRI10GE_HIGHPART_TO_U32(ss->fw_stats_bus); | ||
1980 | cmd.data2 = sizeof(struct mcp_irq_data); | ||
1981 | status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0); | ||
1982 | if (status == -ENOSYS) { | ||
1983 | dma_addr_t bus = ss->fw_stats_bus; | ||
1984 | if (slice != 0) | ||
1985 | return -EINVAL; | ||
1986 | bus += offsetof(struct mcp_irq_data, send_done_count); | ||
1987 | cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus); | ||
1988 | cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus); | ||
1989 | status = myri10ge_send_cmd(mgp, | ||
1990 | MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, | ||
1991 | &cmd, 0); | ||
1992 | /* Firmware cannot support multicast without STATS_DMA_V2 */ | ||
1993 | mgp->fw_multicast_support = 0; | ||
1994 | } else { | ||
1995 | mgp->fw_multicast_support = 1; | ||
1996 | } | ||
1997 | return 0; | ||
1998 | } | ||
1999 | #endif | ||
2000 | |||
1931 | static int myri10ge_open(struct net_device *dev) | 2001 | static int myri10ge_open(struct net_device *dev) |
1932 | { | 2002 | { |
1933 | struct myri10ge_priv *mgp = netdev_priv(dev); | 2003 | struct myri10ge_priv *mgp = netdev_priv(dev); |
@@ -3106,6 +3176,192 @@ static void myri10ge_watchdog_timer(unsigned long arg) | |||
3106 | mgp->watchdog_pause = rx_pause_cnt; | 3176 | mgp->watchdog_pause = rx_pause_cnt; |
3107 | } | 3177 | } |
3108 | 3178 | ||
3179 | #if 0 | ||
3180 | static void myri10ge_free_slices(struct myri10ge_priv *mgp) | ||
3181 | { | ||
3182 | struct myri10ge_slice_state *ss; | ||
3183 | struct pci_dev *pdev = mgp->pdev; | ||
3184 | size_t bytes; | ||
3185 | int i; | ||
3186 | |||
3187 | if (mgp->ss == NULL) | ||
3188 | return; | ||
3189 | |||
3190 | for (i = 0; i < mgp->num_slices; i++) { | ||
3191 | ss = &mgp->ss[i]; | ||
3192 | if (ss->rx_done.entry != NULL) { | ||
3193 | bytes = mgp->max_intr_slots * | ||
3194 | sizeof(*ss->rx_done.entry); | ||
3195 | dma_free_coherent(&pdev->dev, bytes, | ||
3196 | ss->rx_done.entry, ss->rx_done.bus); | ||
3197 | ss->rx_done.entry = NULL; | ||
3198 | } | ||
3199 | if (ss->fw_stats != NULL) { | ||
3200 | bytes = sizeof(*ss->fw_stats); | ||
3201 | dma_free_coherent(&pdev->dev, bytes, | ||
3202 | ss->fw_stats, ss->fw_stats_bus); | ||
3203 | ss->fw_stats = NULL; | ||
3204 | } | ||
3205 | } | ||
3206 | kfree(mgp->ss); | ||
3207 | mgp->ss = NULL; | ||
3208 | } | ||
3209 | |||
3210 | static int myri10ge_alloc_slices(struct myri10ge_priv *mgp) | ||
3211 | { | ||
3212 | struct myri10ge_slice_state *ss; | ||
3213 | struct pci_dev *pdev = mgp->pdev; | ||
3214 | size_t bytes; | ||
3215 | int i; | ||
3216 | |||
3217 | bytes = sizeof(*mgp->ss) * mgp->num_slices; | ||
3218 | mgp->ss = kzalloc(bytes, GFP_KERNEL); | ||
3219 | if (mgp->ss == NULL) { | ||
3220 | return -ENOMEM; | ||
3221 | } | ||
3222 | |||
3223 | for (i = 0; i < mgp->num_slices; i++) { | ||
3224 | ss = &mgp->ss[i]; | ||
3225 | bytes = mgp->max_intr_slots * sizeof(*ss->rx_done.entry); | ||
3226 | ss->rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes, | ||
3227 | &ss->rx_done.bus, | ||
3228 | GFP_KERNEL); | ||
3229 | if (ss->rx_done.entry == NULL) | ||
3230 | goto abort; | ||
3231 | memset(ss->rx_done.entry, 0, bytes); | ||
3232 | bytes = sizeof(*ss->fw_stats); | ||
3233 | ss->fw_stats = dma_alloc_coherent(&pdev->dev, bytes, | ||
3234 | &ss->fw_stats_bus, | ||
3235 | GFP_KERNEL); | ||
3236 | if (ss->fw_stats == NULL) | ||
3237 | goto abort; | ||
3238 | ss->mgp = mgp; | ||
3239 | ss->dev = mgp->dev; | ||
3240 | netif_napi_add(ss->dev, &ss->napi, myri10ge_poll, | ||
3241 | myri10ge_napi_weight); | ||
3242 | } | ||
3243 | return 0; | ||
3244 | abort: | ||
3245 | myri10ge_free_slices(mgp); | ||
3246 | return -ENOMEM; | ||
3247 | } | ||
3248 | |||
3249 | /* | ||
3250 | * This function determines the number of slices supported. | ||
3251 | * The number slices is the minumum of the number of CPUS, | ||
3252 | * the number of MSI-X irqs supported, the number of slices | ||
3253 | * supported by the firmware | ||
3254 | */ | ||
3255 | static void myri10ge_probe_slices(struct myri10ge_priv *mgp) | ||
3256 | { | ||
3257 | struct myri10ge_cmd cmd; | ||
3258 | struct pci_dev *pdev = mgp->pdev; | ||
3259 | char *old_fw; | ||
3260 | int i, status, ncpus, msix_cap; | ||
3261 | |||
3262 | mgp->num_slices = 1; | ||
3263 | msix_cap = pci_find_capability(pdev, PCI_CAP_ID_MSIX); | ||
3264 | ncpus = num_online_cpus(); | ||
3265 | |||
3266 | if (myri10ge_max_slices == 1 || msix_cap == 0 || | ||
3267 | (myri10ge_max_slices == -1 && ncpus < 2)) | ||
3268 | return; | ||
3269 | |||
3270 | /* try to load the slice aware rss firmware */ | ||
3271 | old_fw = mgp->fw_name; | ||
3272 | if (old_fw == myri10ge_fw_aligned) | ||
3273 | mgp->fw_name = myri10ge_fw_rss_aligned; | ||
3274 | else | ||
3275 | mgp->fw_name = myri10ge_fw_rss_unaligned; | ||
3276 | status = myri10ge_load_firmware(mgp, 0); | ||
3277 | if (status != 0) { | ||
3278 | dev_info(&pdev->dev, "Rss firmware not found\n"); | ||
3279 | return; | ||
3280 | } | ||
3281 | |||
3282 | /* hit the board with a reset to ensure it is alive */ | ||
3283 | memset(&cmd, 0, sizeof(cmd)); | ||
3284 | status = myri10ge_send_cmd(mgp, MXGEFW_CMD_RESET, &cmd, 0); | ||
3285 | if (status != 0) { | ||
3286 | dev_err(&mgp->pdev->dev, "failed reset\n"); | ||
3287 | goto abort_with_fw; | ||
3288 | return; | ||
3289 | } | ||
3290 | |||
3291 | mgp->max_intr_slots = cmd.data0 / sizeof(struct mcp_slot); | ||
3292 | |||
3293 | /* tell it the size of the interrupt queues */ | ||
3294 | cmd.data0 = mgp->max_intr_slots * sizeof(struct mcp_slot); | ||
3295 | status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0); | ||
3296 | if (status != 0) { | ||
3297 | dev_err(&mgp->pdev->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n"); | ||
3298 | goto abort_with_fw; | ||
3299 | } | ||
3300 | |||
3301 | /* ask the maximum number of slices it supports */ | ||
3302 | status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd, 0); | ||
3303 | if (status != 0) | ||
3304 | goto abort_with_fw; | ||
3305 | else | ||
3306 | mgp->num_slices = cmd.data0; | ||
3307 | |||
3308 | /* Only allow multiple slices if MSI-X is usable */ | ||
3309 | if (!myri10ge_msi) { | ||
3310 | goto abort_with_fw; | ||
3311 | } | ||
3312 | |||
3313 | /* if the admin did not specify a limit to how many | ||
3314 | * slices we should use, cap it automatically to the | ||
3315 | * number of CPUs currently online */ | ||
3316 | if (myri10ge_max_slices == -1) | ||
3317 | myri10ge_max_slices = ncpus; | ||
3318 | |||
3319 | if (mgp->num_slices > myri10ge_max_slices) | ||
3320 | mgp->num_slices = myri10ge_max_slices; | ||
3321 | |||
3322 | /* Now try to allocate as many MSI-X vectors as we have | ||
3323 | * slices. We give up on MSI-X if we can only get a single | ||
3324 | * vector. */ | ||
3325 | |||
3326 | mgp->msix_vectors = kzalloc(mgp->num_slices * | ||
3327 | sizeof(*mgp->msix_vectors), GFP_KERNEL); | ||
3328 | if (mgp->msix_vectors == NULL) | ||
3329 | goto disable_msix; | ||
3330 | for (i = 0; i < mgp->num_slices; i++) { | ||
3331 | mgp->msix_vectors[i].entry = i; | ||
3332 | } | ||
3333 | |||
3334 | while (mgp->num_slices > 1) { | ||
3335 | /* make sure it is a power of two */ | ||
3336 | while (!is_power_of_2(mgp->num_slices)) | ||
3337 | mgp->num_slices--; | ||
3338 | if (mgp->num_slices == 1) | ||
3339 | goto disable_msix; | ||
3340 | status = pci_enable_msix(pdev, mgp->msix_vectors, | ||
3341 | mgp->num_slices); | ||
3342 | if (status == 0) { | ||
3343 | pci_disable_msix(pdev); | ||
3344 | return; | ||
3345 | } | ||
3346 | if (status > 0) | ||
3347 | mgp->num_slices = status; | ||
3348 | else | ||
3349 | goto disable_msix; | ||
3350 | } | ||
3351 | |||
3352 | disable_msix: | ||
3353 | if (mgp->msix_vectors != NULL) { | ||
3354 | kfree(mgp->msix_vectors); | ||
3355 | mgp->msix_vectors = NULL; | ||
3356 | } | ||
3357 | |||
3358 | abort_with_fw: | ||
3359 | mgp->num_slices = 1; | ||
3360 | mgp->fw_name = old_fw; | ||
3361 | myri10ge_load_firmware(mgp, 0); | ||
3362 | } | ||
3363 | #endif | ||
3364 | |||
3109 | static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 3365 | static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
3110 | { | 3366 | { |
3111 | struct net_device *netdev; | 3367 | struct net_device *netdev; |