diff options
Diffstat (limited to 'drivers/net/s2io.c')
| -rw-r--r-- | drivers/net/s2io.c | 314 |
1 files changed, 124 insertions, 190 deletions
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 18bc5b718bbb..df0d2c8ecc09 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c | |||
| @@ -38,8 +38,6 @@ | |||
| 38 | * Tx descriptors that can be associated with each corresponding FIFO. | 38 | * Tx descriptors that can be associated with each corresponding FIFO. |
| 39 | * intr_type: This defines the type of interrupt. The values can be 0(INTA), | 39 | * intr_type: This defines the type of interrupt. The values can be 0(INTA), |
| 40 | * 2(MSI_X). Default value is '2(MSI_X)' | 40 | * 2(MSI_X). Default value is '2(MSI_X)' |
| 41 | * lro: Specifies whether to enable Large Receive Offload (LRO) or not. | ||
| 42 | * Possible values '1' for enable '0' for disable. Default is '0' | ||
| 43 | * lro_max_pkts: This parameter defines maximum number of packets can be | 41 | * lro_max_pkts: This parameter defines maximum number of packets can be |
| 44 | * aggregated as a single large packet | 42 | * aggregated as a single large packet |
| 45 | * napi: This parameter used to enable/disable NAPI (polling Rx) | 43 | * napi: This parameter used to enable/disable NAPI (polling Rx) |
| @@ -80,6 +78,7 @@ | |||
| 80 | #include <linux/uaccess.h> | 78 | #include <linux/uaccess.h> |
| 81 | #include <linux/io.h> | 79 | #include <linux/io.h> |
| 82 | #include <linux/slab.h> | 80 | #include <linux/slab.h> |
| 81 | #include <linux/prefetch.h> | ||
| 83 | #include <net/tcp.h> | 82 | #include <net/tcp.h> |
| 84 | 83 | ||
| 85 | #include <asm/system.h> | 84 | #include <asm/system.h> |
| @@ -90,14 +89,14 @@ | |||
| 90 | #include "s2io.h" | 89 | #include "s2io.h" |
| 91 | #include "s2io-regs.h" | 90 | #include "s2io-regs.h" |
| 92 | 91 | ||
| 93 | #define DRV_VERSION "2.0.26.26" | 92 | #define DRV_VERSION "2.0.26.28" |
| 94 | 93 | ||
| 95 | /* S2io Driver name & version. */ | 94 | /* S2io Driver name & version. */ |
| 96 | static char s2io_driver_name[] = "Neterion"; | 95 | static const char s2io_driver_name[] = "Neterion"; |
| 97 | static char s2io_driver_version[] = DRV_VERSION; | 96 | static const char s2io_driver_version[] = DRV_VERSION; |
| 98 | 97 | ||
| 99 | static int rxd_size[2] = {32, 48}; | 98 | static const int rxd_size[2] = {32, 48}; |
| 100 | static int rxd_count[2] = {127, 85}; | 99 | static const int rxd_count[2] = {127, 85}; |
| 101 | 100 | ||
| 102 | static inline int RXD_IS_UP2DT(struct RxD_t *rxdp) | 101 | static inline int RXD_IS_UP2DT(struct RxD_t *rxdp) |
| 103 | { | 102 | { |
| @@ -496,8 +495,6 @@ S2IO_PARM_INT(rxsync_frequency, 3); | |||
| 496 | /* Interrupt type. Values can be 0(INTA), 2(MSI_X) */ | 495 | /* Interrupt type. Values can be 0(INTA), 2(MSI_X) */ |
| 497 | S2IO_PARM_INT(intr_type, 2); | 496 | S2IO_PARM_INT(intr_type, 2); |
| 498 | /* Large receive offload feature */ | 497 | /* Large receive offload feature */ |
| 499 | static unsigned int lro_enable = 1; | ||
| 500 | module_param_named(lro, lro_enable, uint, 0); | ||
| 501 | 498 | ||
| 502 | /* Max pkts to be aggregated by LRO at one time. If not specified, | 499 | /* Max pkts to be aggregated by LRO at one time. If not specified, |
| 503 | * aggregation happens until we hit max IP pkt size(64K) | 500 | * aggregation happens until we hit max IP pkt size(64K) |
| @@ -2248,13 +2245,12 @@ static int verify_xena_quiescence(struct s2io_nic *sp) | |||
| 2248 | static void fix_mac_address(struct s2io_nic *sp) | 2245 | static void fix_mac_address(struct s2io_nic *sp) |
| 2249 | { | 2246 | { |
| 2250 | struct XENA_dev_config __iomem *bar0 = sp->bar0; | 2247 | struct XENA_dev_config __iomem *bar0 = sp->bar0; |
| 2251 | u64 val64; | ||
| 2252 | int i = 0; | 2248 | int i = 0; |
| 2253 | 2249 | ||
| 2254 | while (fix_mac[i] != END_SIGN) { | 2250 | while (fix_mac[i] != END_SIGN) { |
| 2255 | writeq(fix_mac[i++], &bar0->gpio_control); | 2251 | writeq(fix_mac[i++], &bar0->gpio_control); |
| 2256 | udelay(10); | 2252 | udelay(10); |
| 2257 | val64 = readq(&bar0->gpio_control); | 2253 | (void) readq(&bar0->gpio_control); |
| 2258 | } | 2254 | } |
| 2259 | } | 2255 | } |
| 2260 | 2256 | ||
| @@ -2357,7 +2353,7 @@ static int start_nic(struct s2io_nic *nic) | |||
| 2357 | 2353 | ||
| 2358 | if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) { | 2354 | if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) { |
| 2359 | /* | 2355 | /* |
| 2360 | * Dont see link state interrupts initally on some switches, | 2356 | * Dont see link state interrupts initially on some switches, |
| 2361 | * so directly scheduling the link state task here. | 2357 | * so directly scheduling the link state task here. |
| 2362 | */ | 2358 | */ |
| 2363 | schedule_work(&nic->set_link_task); | 2359 | schedule_work(&nic->set_link_task); |
| @@ -2731,7 +2727,6 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) | |||
| 2731 | int j; | 2727 | int j; |
| 2732 | struct sk_buff *skb; | 2728 | struct sk_buff *skb; |
| 2733 | struct RxD_t *rxdp; | 2729 | struct RxD_t *rxdp; |
| 2734 | struct buffAdd *ba; | ||
| 2735 | struct RxD1 *rxdp1; | 2730 | struct RxD1 *rxdp1; |
| 2736 | struct RxD3 *rxdp3; | 2731 | struct RxD3 *rxdp3; |
| 2737 | struct mac_info *mac_control = &sp->mac_control; | 2732 | struct mac_info *mac_control = &sp->mac_control; |
| @@ -2755,7 +2750,6 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) | |||
| 2755 | memset(rxdp, 0, sizeof(struct RxD1)); | 2750 | memset(rxdp, 0, sizeof(struct RxD1)); |
| 2756 | } else if (sp->rxd_mode == RXD_MODE_3B) { | 2751 | } else if (sp->rxd_mode == RXD_MODE_3B) { |
| 2757 | rxdp3 = (struct RxD3 *)rxdp; | 2752 | rxdp3 = (struct RxD3 *)rxdp; |
| 2758 | ba = &mac_control->rings[ring_no].ba[blk][j]; | ||
| 2759 | pci_unmap_single(sp->pdev, | 2753 | pci_unmap_single(sp->pdev, |
| 2760 | (dma_addr_t)rxdp3->Buffer0_ptr, | 2754 | (dma_addr_t)rxdp3->Buffer0_ptr, |
| 2761 | BUF0_LEN, | 2755 | BUF0_LEN, |
| @@ -3567,7 +3561,7 @@ static void s2io_reset(struct s2io_nic *sp) | |||
| 3567 | } | 3561 | } |
| 3568 | 3562 | ||
| 3569 | /* | 3563 | /* |
| 3570 | * Clear spurious ECC interrupts that would have occured on | 3564 | * Clear spurious ECC interrupts that would have occurred on |
| 3571 | * XFRAME II cards after reset. | 3565 | * XFRAME II cards after reset. |
| 3572 | */ | 3566 | */ |
| 3573 | if (sp->device_type == XFRAME_II_DEVICE) { | 3567 | if (sp->device_type == XFRAME_II_DEVICE) { |
| @@ -3602,10 +3596,12 @@ static int s2io_set_swapper(struct s2io_nic *sp) | |||
| 3602 | val64 = readq(&bar0->pif_rd_swapper_fb); | 3596 | val64 = readq(&bar0->pif_rd_swapper_fb); |
| 3603 | if (val64 != 0x0123456789ABCDEFULL) { | 3597 | if (val64 != 0x0123456789ABCDEFULL) { |
| 3604 | int i = 0; | 3598 | int i = 0; |
| 3605 | u64 value[] = { 0xC30000C3C30000C3ULL, /* FE=1, SE=1 */ | 3599 | static const u64 value[] = { |
| 3606 | 0x8100008181000081ULL, /* FE=1, SE=0 */ | 3600 | 0xC30000C3C30000C3ULL, /* FE=1, SE=1 */ |
| 3607 | 0x4200004242000042ULL, /* FE=0, SE=1 */ | 3601 | 0x8100008181000081ULL, /* FE=1, SE=0 */ |
| 3608 | 0}; /* FE=0, SE=0 */ | 3602 | 0x4200004242000042ULL, /* FE=0, SE=1 */ |
| 3603 | 0 /* FE=0, SE=0 */ | ||
| 3604 | }; | ||
| 3609 | 3605 | ||
| 3610 | while (i < 4) { | 3606 | while (i < 4) { |
| 3611 | writeq(value[i], &bar0->swapper_ctrl); | 3607 | writeq(value[i], &bar0->swapper_ctrl); |
| @@ -3631,10 +3627,12 @@ static int s2io_set_swapper(struct s2io_nic *sp) | |||
| 3631 | 3627 | ||
| 3632 | if (val64 != valt) { | 3628 | if (val64 != valt) { |
| 3633 | int i = 0; | 3629 | int i = 0; |
| 3634 | u64 value[] = { 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */ | 3630 | static const u64 value[] = { |
| 3635 | 0x0081810000818100ULL, /* FE=1, SE=0 */ | 3631 | 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */ |
| 3636 | 0x0042420000424200ULL, /* FE=0, SE=1 */ | 3632 | 0x0081810000818100ULL, /* FE=1, SE=0 */ |
| 3637 | 0}; /* FE=0, SE=0 */ | 3633 | 0x0042420000424200ULL, /* FE=0, SE=1 */ |
| 3634 | 0 /* FE=0, SE=0 */ | ||
| 3635 | }; | ||
| 3638 | 3636 | ||
| 3639 | while (i < 4) { | 3637 | while (i < 4) { |
| 3640 | writeq((value[i] | valr), &bar0->swapper_ctrl); | 3638 | writeq((value[i] | valr), &bar0->swapper_ctrl); |
| @@ -4065,7 +4063,7 @@ static int s2io_close(struct net_device *dev) | |||
| 4065 | * Description : | 4063 | * Description : |
| 4066 | * This function is the Tx entry point of the driver. S2IO NIC supports | 4064 | * This function is the Tx entry point of the driver. S2IO NIC supports |
| 4067 | * certain protocol assist features on Tx side, namely CSO, S/G, LSO. | 4065 | * certain protocol assist features on Tx side, namely CSO, S/G, LSO. |
| 4068 | * NOTE: when device cant queue the pkt,just the trans_start variable will | 4066 | * NOTE: when device can't queue the pkt,just the trans_start variable will |
| 4069 | * not be upadted. | 4067 | * not be upadted. |
| 4070 | * Return value: | 4068 | * Return value: |
| 4071 | * 0 on success & 1 on failure. | 4069 | * 0 on success & 1 on failure. |
| @@ -4105,7 +4103,7 @@ static netdev_tx_t s2io_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 4105 | } | 4103 | } |
| 4106 | 4104 | ||
| 4107 | queue = 0; | 4105 | queue = 0; |
| 4108 | if (sp->vlgrp && vlan_tx_tag_present(skb)) | 4106 | if (vlan_tx_tag_present(skb)) |
| 4109 | vlan_tag = vlan_tx_tag_get(skb); | 4107 | vlan_tag = vlan_tx_tag_get(skb); |
| 4110 | if (sp->config.tx_steering_type == TX_DEFAULT_STEERING) { | 4108 | if (sp->config.tx_steering_type == TX_DEFAULT_STEERING) { |
| 4111 | if (skb->protocol == htons(ETH_P_IP)) { | 4109 | if (skb->protocol == htons(ETH_P_IP)) { |
| @@ -5124,8 +5122,6 @@ static void s2io_set_multicast(struct net_device *dev) | |||
| 5124 | /* Create the new Rx filter list and update the same in H/W. */ | 5122 | /* Create the new Rx filter list and update the same in H/W. */ |
| 5125 | i = 0; | 5123 | i = 0; |
| 5126 | netdev_for_each_mc_addr(ha, dev) { | 5124 | netdev_for_each_mc_addr(ha, dev) { |
| 5127 | memcpy(sp->usr_addrs[i].addr, ha->addr, | ||
| 5128 | ETH_ALEN); | ||
| 5129 | mac_addr = 0; | 5125 | mac_addr = 0; |
| 5130 | for (j = 0; j < ETH_ALEN; j++) { | 5126 | for (j = 0; j < ETH_ALEN; j++) { |
| 5131 | mac_addr |= ha->addr[j]; | 5127 | mac_addr |= ha->addr[j]; |
| @@ -5385,7 +5381,7 @@ static int s2io_ethtool_sset(struct net_device *dev, | |||
| 5385 | { | 5381 | { |
| 5386 | struct s2io_nic *sp = netdev_priv(dev); | 5382 | struct s2io_nic *sp = netdev_priv(dev); |
| 5387 | if ((info->autoneg == AUTONEG_ENABLE) || | 5383 | if ((info->autoneg == AUTONEG_ENABLE) || |
| 5388 | (info->speed != SPEED_10000) || | 5384 | (ethtool_cmd_speed(info) != SPEED_10000) || |
| 5389 | (info->duplex != DUPLEX_FULL)) | 5385 | (info->duplex != DUPLEX_FULL)) |
| 5390 | return -EINVAL; | 5386 | return -EINVAL; |
| 5391 | else { | 5387 | else { |
| @@ -5419,10 +5415,10 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) | |||
| 5419 | info->transceiver = XCVR_EXTERNAL; | 5415 | info->transceiver = XCVR_EXTERNAL; |
| 5420 | 5416 | ||
| 5421 | if (netif_carrier_ok(sp->dev)) { | 5417 | if (netif_carrier_ok(sp->dev)) { |
| 5422 | info->speed = 10000; | 5418 | ethtool_cmd_speed_set(info, SPEED_10000); |
| 5423 | info->duplex = DUPLEX_FULL; | 5419 | info->duplex = DUPLEX_FULL; |
| 5424 | } else { | 5420 | } else { |
| 5425 | info->speed = -1; | 5421 | ethtool_cmd_speed_set(info, -1); |
| 5426 | info->duplex = -1; | 5422 | info->duplex = -1; |
| 5427 | } | 5423 | } |
| 5428 | 5424 | ||
| @@ -5486,83 +5482,79 @@ static void s2io_ethtool_gregs(struct net_device *dev, | |||
| 5486 | } | 5482 | } |
| 5487 | } | 5483 | } |
| 5488 | 5484 | ||
| 5489 | /** | 5485 | /* |
| 5490 | * s2io_phy_id - timer function that alternates adapter LED. | 5486 | * s2io_set_led - control NIC led |
| 5491 | * @data : address of the private member of the device structure, which | ||
| 5492 | * is a pointer to the s2io_nic structure, provided as an u32. | ||
| 5493 | * Description: This is actually the timer function that alternates the | ||
| 5494 | * adapter LED bit of the adapter control bit to set/reset every time on | ||
| 5495 | * invocation. The timer is set for 1/2 a second, hence tha NIC blinks | ||
| 5496 | * once every second. | ||
| 5497 | */ | 5487 | */ |
| 5498 | static void s2io_phy_id(unsigned long data) | 5488 | static void s2io_set_led(struct s2io_nic *sp, bool on) |
| 5499 | { | 5489 | { |
| 5500 | struct s2io_nic *sp = (struct s2io_nic *)data; | ||
| 5501 | struct XENA_dev_config __iomem *bar0 = sp->bar0; | 5490 | struct XENA_dev_config __iomem *bar0 = sp->bar0; |
| 5502 | u64 val64 = 0; | 5491 | u16 subid = sp->pdev->subsystem_device; |
| 5503 | u16 subid; | 5492 | u64 val64; |
| 5504 | 5493 | ||
| 5505 | subid = sp->pdev->subsystem_device; | ||
| 5506 | if ((sp->device_type == XFRAME_II_DEVICE) || | 5494 | if ((sp->device_type == XFRAME_II_DEVICE) || |
| 5507 | ((subid & 0xFF) >= 0x07)) { | 5495 | ((subid & 0xFF) >= 0x07)) { |
| 5508 | val64 = readq(&bar0->gpio_control); | 5496 | val64 = readq(&bar0->gpio_control); |
| 5509 | val64 ^= GPIO_CTRL_GPIO_0; | 5497 | if (on) |
| 5498 | val64 |= GPIO_CTRL_GPIO_0; | ||
| 5499 | else | ||
| 5500 | val64 &= ~GPIO_CTRL_GPIO_0; | ||
| 5501 | |||
| 5510 | writeq(val64, &bar0->gpio_control); | 5502 | writeq(val64, &bar0->gpio_control); |
| 5511 | } else { | 5503 | } else { |
| 5512 | val64 = readq(&bar0->adapter_control); | 5504 | val64 = readq(&bar0->adapter_control); |
| 5513 | val64 ^= ADAPTER_LED_ON; | 5505 | if (on) |
| 5506 | val64 |= ADAPTER_LED_ON; | ||
| 5507 | else | ||
| 5508 | val64 &= ~ADAPTER_LED_ON; | ||
| 5509 | |||
| 5514 | writeq(val64, &bar0->adapter_control); | 5510 | writeq(val64, &bar0->adapter_control); |
| 5515 | } | 5511 | } |
| 5516 | 5512 | ||
| 5517 | mod_timer(&sp->id_timer, jiffies + HZ / 2); | ||
| 5518 | } | 5513 | } |
| 5519 | 5514 | ||
| 5520 | /** | 5515 | /** |
| 5521 | * s2io_ethtool_idnic - To physically identify the nic on the system. | 5516 | * s2io_ethtool_set_led - To physically identify the nic on the system. |
| 5522 | * @sp : private member of the device structure, which is a pointer to the | 5517 | * @dev : network device |
| 5523 | * s2io_nic structure. | 5518 | * @state: led setting |
| 5524 | * @id : pointer to the structure with identification parameters given by | 5519 | * |
| 5525 | * ethtool. | ||
| 5526 | * Description: Used to physically identify the NIC on the system. | 5520 | * Description: Used to physically identify the NIC on the system. |
| 5527 | * The Link LED will blink for a time specified by the user for | 5521 | * The Link LED will blink for a time specified by the user for |
| 5528 | * identification. | 5522 | * identification. |
| 5529 | * NOTE: The Link has to be Up to be able to blink the LED. Hence | 5523 | * NOTE: The Link has to be Up to be able to blink the LED. Hence |
| 5530 | * identification is possible only if it's link is up. | 5524 | * identification is possible only if it's link is up. |
| 5531 | * Return value: | ||
| 5532 | * int , returns 0 on success | ||
| 5533 | */ | 5525 | */ |
| 5534 | 5526 | ||
| 5535 | static int s2io_ethtool_idnic(struct net_device *dev, u32 data) | 5527 | static int s2io_ethtool_set_led(struct net_device *dev, |
| 5528 | enum ethtool_phys_id_state state) | ||
| 5536 | { | 5529 | { |
| 5537 | u64 val64 = 0, last_gpio_ctrl_val; | ||
| 5538 | struct s2io_nic *sp = netdev_priv(dev); | 5530 | struct s2io_nic *sp = netdev_priv(dev); |
| 5539 | struct XENA_dev_config __iomem *bar0 = sp->bar0; | 5531 | struct XENA_dev_config __iomem *bar0 = sp->bar0; |
| 5540 | u16 subid; | 5532 | u16 subid = sp->pdev->subsystem_device; |
| 5541 | 5533 | ||
| 5542 | subid = sp->pdev->subsystem_device; | ||
| 5543 | last_gpio_ctrl_val = readq(&bar0->gpio_control); | ||
| 5544 | if ((sp->device_type == XFRAME_I_DEVICE) && ((subid & 0xFF) < 0x07)) { | 5534 | if ((sp->device_type == XFRAME_I_DEVICE) && ((subid & 0xFF) < 0x07)) { |
| 5545 | val64 = readq(&bar0->adapter_control); | 5535 | u64 val64 = readq(&bar0->adapter_control); |
| 5546 | if (!(val64 & ADAPTER_CNTL_EN)) { | 5536 | if (!(val64 & ADAPTER_CNTL_EN)) { |
| 5547 | pr_err("Adapter Link down, cannot blink LED\n"); | 5537 | pr_err("Adapter Link down, cannot blink LED\n"); |
| 5548 | return -EFAULT; | 5538 | return -EAGAIN; |
| 5549 | } | 5539 | } |
| 5550 | } | 5540 | } |
| 5551 | if (sp->id_timer.function == NULL) { | ||
| 5552 | init_timer(&sp->id_timer); | ||
| 5553 | sp->id_timer.function = s2io_phy_id; | ||
| 5554 | sp->id_timer.data = (unsigned long)sp; | ||
| 5555 | } | ||
| 5556 | mod_timer(&sp->id_timer, jiffies); | ||
| 5557 | if (data) | ||
| 5558 | msleep_interruptible(data * HZ); | ||
| 5559 | else | ||
| 5560 | msleep_interruptible(MAX_FLICKER_TIME); | ||
| 5561 | del_timer_sync(&sp->id_timer); | ||
| 5562 | 5541 | ||
| 5563 | if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) { | 5542 | switch (state) { |
| 5564 | writeq(last_gpio_ctrl_val, &bar0->gpio_control); | 5543 | case ETHTOOL_ID_ACTIVE: |
| 5565 | last_gpio_ctrl_val = readq(&bar0->gpio_control); | 5544 | sp->adapt_ctrl_org = readq(&bar0->gpio_control); |
| 5545 | return 1; /* cycle on/off once per second */ | ||
| 5546 | |||
| 5547 | case ETHTOOL_ID_ON: | ||
| 5548 | s2io_set_led(sp, true); | ||
| 5549 | break; | ||
| 5550 | |||
| 5551 | case ETHTOOL_ID_OFF: | ||
| 5552 | s2io_set_led(sp, false); | ||
| 5553 | break; | ||
| 5554 | |||
| 5555 | case ETHTOOL_ID_INACTIVE: | ||
| 5556 | if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) | ||
| 5557 | writeq(sp->adapt_ctrl_org, &bar0->gpio_control); | ||
| 5566 | } | 5558 | } |
| 5567 | 5559 | ||
| 5568 | return 0; | 5560 | return 0; |
| @@ -5574,30 +5566,27 @@ static void s2io_ethtool_gringparam(struct net_device *dev, | |||
| 5574 | struct s2io_nic *sp = netdev_priv(dev); | 5566 | struct s2io_nic *sp = netdev_priv(dev); |
| 5575 | int i, tx_desc_count = 0, rx_desc_count = 0; | 5567 | int i, tx_desc_count = 0, rx_desc_count = 0; |
| 5576 | 5568 | ||
| 5577 | if (sp->rxd_mode == RXD_MODE_1) | 5569 | if (sp->rxd_mode == RXD_MODE_1) { |
| 5578 | ering->rx_max_pending = MAX_RX_DESC_1; | 5570 | ering->rx_max_pending = MAX_RX_DESC_1; |
| 5579 | else if (sp->rxd_mode == RXD_MODE_3B) | 5571 | ering->rx_jumbo_max_pending = MAX_RX_DESC_1; |
| 5572 | } else { | ||
| 5580 | ering->rx_max_pending = MAX_RX_DESC_2; | 5573 | ering->rx_max_pending = MAX_RX_DESC_2; |
| 5574 | ering->rx_jumbo_max_pending = MAX_RX_DESC_2; | ||
| 5575 | } | ||
| 5581 | 5576 | ||
| 5577 | ering->rx_mini_max_pending = 0; | ||
| 5582 | ering->tx_max_pending = MAX_TX_DESC; | 5578 | ering->tx_max_pending = MAX_TX_DESC; |
| 5583 | for (i = 0 ; i < sp->config.tx_fifo_num ; i++) | ||
| 5584 | tx_desc_count += sp->config.tx_cfg[i].fifo_len; | ||
| 5585 | 5579 | ||
| 5586 | DBG_PRINT(INFO_DBG, "max txds: %d\n", sp->config.max_txds); | 5580 | for (i = 0; i < sp->config.rx_ring_num; i++) |
| 5587 | ering->tx_pending = tx_desc_count; | ||
| 5588 | rx_desc_count = 0; | ||
| 5589 | for (i = 0 ; i < sp->config.rx_ring_num ; i++) | ||
| 5590 | rx_desc_count += sp->config.rx_cfg[i].num_rxd; | 5581 | rx_desc_count += sp->config.rx_cfg[i].num_rxd; |
| 5591 | |||
| 5592 | ering->rx_pending = rx_desc_count; | 5582 | ering->rx_pending = rx_desc_count; |
| 5593 | |||
| 5594 | ering->rx_mini_max_pending = 0; | ||
| 5595 | ering->rx_mini_pending = 0; | ||
| 5596 | if (sp->rxd_mode == RXD_MODE_1) | ||
| 5597 | ering->rx_jumbo_max_pending = MAX_RX_DESC_1; | ||
| 5598 | else if (sp->rxd_mode == RXD_MODE_3B) | ||
| 5599 | ering->rx_jumbo_max_pending = MAX_RX_DESC_2; | ||
| 5600 | ering->rx_jumbo_pending = rx_desc_count; | 5583 | ering->rx_jumbo_pending = rx_desc_count; |
| 5584 | ering->rx_mini_pending = 0; | ||
| 5585 | |||
| 5586 | for (i = 0; i < sp->config.tx_fifo_num; i++) | ||
| 5587 | tx_desc_count += sp->config.tx_cfg[i].fifo_len; | ||
| 5588 | ering->tx_pending = tx_desc_count; | ||
| 5589 | DBG_PRINT(INFO_DBG, "max txds: %d\n", sp->config.max_txds); | ||
| 5601 | } | 5590 | } |
| 5602 | 5591 | ||
| 5603 | /** | 5592 | /** |
| @@ -6630,25 +6619,6 @@ static int s2io_ethtool_get_regs_len(struct net_device *dev) | |||
| 6630 | } | 6619 | } |
| 6631 | 6620 | ||
| 6632 | 6621 | ||
| 6633 | static u32 s2io_ethtool_get_rx_csum(struct net_device *dev) | ||
| 6634 | { | ||
| 6635 | struct s2io_nic *sp = netdev_priv(dev); | ||
| 6636 | |||
| 6637 | return sp->rx_csum; | ||
| 6638 | } | ||
| 6639 | |||
| 6640 | static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) | ||
| 6641 | { | ||
| 6642 | struct s2io_nic *sp = netdev_priv(dev); | ||
| 6643 | |||
| 6644 | if (data) | ||
| 6645 | sp->rx_csum = 1; | ||
| 6646 | else | ||
| 6647 | sp->rx_csum = 0; | ||
| 6648 | |||
| 6649 | return 0; | ||
| 6650 | } | ||
| 6651 | |||
| 6652 | static int s2io_get_eeprom_len(struct net_device *dev) | 6622 | static int s2io_get_eeprom_len(struct net_device *dev) |
| 6653 | { | 6623 | { |
| 6654 | return XENA_EEPROM_SPACE; | 6624 | return XENA_EEPROM_SPACE; |
| @@ -6700,65 +6670,27 @@ static void s2io_ethtool_get_strings(struct net_device *dev, | |||
| 6700 | } | 6670 | } |
| 6701 | } | 6671 | } |
| 6702 | 6672 | ||
| 6703 | static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data) | 6673 | static int s2io_set_features(struct net_device *dev, u32 features) |
| 6704 | { | ||
| 6705 | if (data) | ||
| 6706 | dev->features |= NETIF_F_IP_CSUM; | ||
| 6707 | else | ||
| 6708 | dev->features &= ~NETIF_F_IP_CSUM; | ||
| 6709 | |||
| 6710 | return 0; | ||
| 6711 | } | ||
| 6712 | |||
| 6713 | static u32 s2io_ethtool_op_get_tso(struct net_device *dev) | ||
| 6714 | { | ||
| 6715 | return (dev->features & NETIF_F_TSO) != 0; | ||
| 6716 | } | ||
| 6717 | |||
| 6718 | static int s2io_ethtool_op_set_tso(struct net_device *dev, u32 data) | ||
| 6719 | { | ||
| 6720 | if (data) | ||
| 6721 | dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); | ||
| 6722 | else | ||
| 6723 | dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); | ||
| 6724 | |||
| 6725 | return 0; | ||
| 6726 | } | ||
| 6727 | |||
| 6728 | static int s2io_ethtool_set_flags(struct net_device *dev, u32 data) | ||
| 6729 | { | 6674 | { |
| 6730 | struct s2io_nic *sp = netdev_priv(dev); | 6675 | struct s2io_nic *sp = netdev_priv(dev); |
| 6731 | int rc = 0; | 6676 | u32 changed = (features ^ dev->features) & NETIF_F_LRO; |
| 6732 | int changed = 0; | ||
| 6733 | |||
| 6734 | if (data & ~ETH_FLAG_LRO) | ||
| 6735 | return -EINVAL; | ||
| 6736 | |||
| 6737 | if (data & ETH_FLAG_LRO) { | ||
| 6738 | if (lro_enable) { | ||
| 6739 | if (!(dev->features & NETIF_F_LRO)) { | ||
| 6740 | dev->features |= NETIF_F_LRO; | ||
| 6741 | changed = 1; | ||
| 6742 | } | ||
| 6743 | } else | ||
| 6744 | rc = -EINVAL; | ||
| 6745 | } else if (dev->features & NETIF_F_LRO) { | ||
| 6746 | dev->features &= ~NETIF_F_LRO; | ||
| 6747 | changed = 1; | ||
| 6748 | } | ||
| 6749 | 6677 | ||
| 6750 | if (changed && netif_running(dev)) { | 6678 | if (changed && netif_running(dev)) { |
| 6679 | int rc; | ||
| 6680 | |||
| 6751 | s2io_stop_all_tx_queue(sp); | 6681 | s2io_stop_all_tx_queue(sp); |
| 6752 | s2io_card_down(sp); | 6682 | s2io_card_down(sp); |
| 6753 | sp->lro = !!(dev->features & NETIF_F_LRO); | 6683 | dev->features = features; |
| 6754 | rc = s2io_card_up(sp); | 6684 | rc = s2io_card_up(sp); |
| 6755 | if (rc) | 6685 | if (rc) |
| 6756 | s2io_reset(sp); | 6686 | s2io_reset(sp); |
| 6757 | else | 6687 | else |
| 6758 | s2io_start_all_tx_queue(sp); | 6688 | s2io_start_all_tx_queue(sp); |
| 6689 | |||
| 6690 | return rc ? rc : 1; | ||
| 6759 | } | 6691 | } |
| 6760 | 6692 | ||
| 6761 | return rc; | 6693 | return 0; |
| 6762 | } | 6694 | } |
| 6763 | 6695 | ||
| 6764 | static const struct ethtool_ops netdev_ethtool_ops = { | 6696 | static const struct ethtool_ops netdev_ethtool_ops = { |
| @@ -6774,18 +6706,9 @@ static const struct ethtool_ops netdev_ethtool_ops = { | |||
| 6774 | .get_ringparam = s2io_ethtool_gringparam, | 6706 | .get_ringparam = s2io_ethtool_gringparam, |
| 6775 | .get_pauseparam = s2io_ethtool_getpause_data, | 6707 | .get_pauseparam = s2io_ethtool_getpause_data, |
| 6776 | .set_pauseparam = s2io_ethtool_setpause_data, | 6708 | .set_pauseparam = s2io_ethtool_setpause_data, |
| 6777 | .get_rx_csum = s2io_ethtool_get_rx_csum, | ||
| 6778 | .set_rx_csum = s2io_ethtool_set_rx_csum, | ||
| 6779 | .set_tx_csum = s2io_ethtool_op_set_tx_csum, | ||
| 6780 | .set_flags = s2io_ethtool_set_flags, | ||
| 6781 | .get_flags = ethtool_op_get_flags, | ||
| 6782 | .set_sg = ethtool_op_set_sg, | ||
| 6783 | .get_tso = s2io_ethtool_op_get_tso, | ||
| 6784 | .set_tso = s2io_ethtool_op_set_tso, | ||
| 6785 | .set_ufo = ethtool_op_set_ufo, | ||
| 6786 | .self_test = s2io_ethtool_test, | 6709 | .self_test = s2io_ethtool_test, |
| 6787 | .get_strings = s2io_ethtool_get_strings, | 6710 | .get_strings = s2io_ethtool_get_strings, |
| 6788 | .phys_id = s2io_ethtool_idnic, | 6711 | .set_phys_id = s2io_ethtool_set_led, |
| 6789 | .get_ethtool_stats = s2io_get_ethtool_stats, | 6712 | .get_ethtool_stats = s2io_get_ethtool_stats, |
| 6790 | .get_sset_count = s2io_get_sset_count, | 6713 | .get_sset_count = s2io_get_sset_count, |
| 6791 | }; | 6714 | }; |
| @@ -7240,7 +7163,7 @@ static void do_s2io_card_down(struct s2io_nic *sp, int do_io) | |||
| 7240 | /* As per the HW requirement we need to replenish the | 7163 | /* As per the HW requirement we need to replenish the |
| 7241 | * receive buffer to avoid the ring bump. Since there is | 7164 | * receive buffer to avoid the ring bump. Since there is |
| 7242 | * no intention of processing the Rx frame at this pointwe are | 7165 | * no intention of processing the Rx frame at this pointwe are |
| 7243 | * just settting the ownership bit of rxd in Each Rx | 7166 | * just setting the ownership bit of rxd in Each Rx |
| 7244 | * ring to HW and set the appropriate buffer size | 7167 | * ring to HW and set the appropriate buffer size |
| 7245 | * based on the ring mode | 7168 | * based on the ring mode |
| 7246 | */ | 7169 | */ |
| @@ -7307,7 +7230,7 @@ static int s2io_card_up(struct s2io_nic *sp) | |||
| 7307 | struct ring_info *ring = &mac_control->rings[i]; | 7230 | struct ring_info *ring = &mac_control->rings[i]; |
| 7308 | 7231 | ||
| 7309 | ring->mtu = dev->mtu; | 7232 | ring->mtu = dev->mtu; |
| 7310 | ring->lro = sp->lro; | 7233 | ring->lro = !!(dev->features & NETIF_F_LRO); |
| 7311 | ret = fill_rx_buffers(sp, ring, 1); | 7234 | ret = fill_rx_buffers(sp, ring, 1); |
| 7312 | if (ret) { | 7235 | if (ret) { |
| 7313 | DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n", | 7236 | DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n", |
| @@ -7341,7 +7264,7 @@ static int s2io_card_up(struct s2io_nic *sp) | |||
| 7341 | /* Setting its receive mode */ | 7264 | /* Setting its receive mode */ |
| 7342 | s2io_set_multicast(dev); | 7265 | s2io_set_multicast(dev); |
| 7343 | 7266 | ||
| 7344 | if (sp->lro) { | 7267 | if (dev->features & NETIF_F_LRO) { |
| 7345 | /* Initialize max aggregatable pkts per session based on MTU */ | 7268 | /* Initialize max aggregatable pkts per session based on MTU */ |
| 7346 | sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu; | 7269 | sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu; |
| 7347 | /* Check if we can use (if specified) user provided value */ | 7270 | /* Check if we can use (if specified) user provided value */ |
| @@ -7554,7 +7477,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) | |||
| 7554 | if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && | 7477 | if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && |
| 7555 | ((!ring_data->lro) || | 7478 | ((!ring_data->lro) || |
| 7556 | (ring_data->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) && | 7479 | (ring_data->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) && |
| 7557 | (sp->rx_csum)) { | 7480 | (dev->features & NETIF_F_RXCSUM)) { |
| 7558 | l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1); | 7481 | l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1); |
| 7559 | l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1); | 7482 | l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1); |
| 7560 | if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) { | 7483 | if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) { |
| @@ -7565,7 +7488,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) | |||
| 7565 | */ | 7488 | */ |
| 7566 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 7489 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| 7567 | if (ring_data->lro) { | 7490 | if (ring_data->lro) { |
| 7568 | u32 tcp_len; | 7491 | u32 tcp_len = 0; |
| 7569 | u8 *tcp; | 7492 | u8 *tcp; |
| 7570 | int ret = 0; | 7493 | int ret = 0; |
| 7571 | 7494 | ||
| @@ -7613,10 +7536,10 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) | |||
| 7613 | * Packet with erroneous checksum, let the | 7536 | * Packet with erroneous checksum, let the |
| 7614 | * upper layers deal with it. | 7537 | * upper layers deal with it. |
| 7615 | */ | 7538 | */ |
| 7616 | skb->ip_summed = CHECKSUM_NONE; | 7539 | skb_checksum_none_assert(skb); |
| 7617 | } | 7540 | } |
| 7618 | } else | 7541 | } else |
| 7619 | skb->ip_summed = CHECKSUM_NONE; | 7542 | skb_checksum_none_assert(skb); |
| 7620 | 7543 | ||
| 7621 | swstats->mem_freed += skb->truesize; | 7544 | swstats->mem_freed += skb->truesize; |
| 7622 | send_up: | 7545 | send_up: |
| @@ -7702,6 +7625,8 @@ static void s2io_init_pci(struct s2io_nic *sp) | |||
| 7702 | static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, | 7625 | static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, |
| 7703 | u8 *dev_multiq) | 7626 | u8 *dev_multiq) |
| 7704 | { | 7627 | { |
| 7628 | int i; | ||
| 7629 | |||
| 7705 | if ((tx_fifo_num > MAX_TX_FIFOS) || (tx_fifo_num < 1)) { | 7630 | if ((tx_fifo_num > MAX_TX_FIFOS) || (tx_fifo_num < 1)) { |
| 7706 | DBG_PRINT(ERR_DBG, "Requested number of tx fifos " | 7631 | DBG_PRINT(ERR_DBG, "Requested number of tx fifos " |
| 7707 | "(%d) not supported\n", tx_fifo_num); | 7632 | "(%d) not supported\n", tx_fifo_num); |
| @@ -7760,6 +7685,15 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, | |||
| 7760 | DBG_PRINT(ERR_DBG, "Defaulting to 1-buffer mode\n"); | 7685 | DBG_PRINT(ERR_DBG, "Defaulting to 1-buffer mode\n"); |
| 7761 | rx_ring_mode = 1; | 7686 | rx_ring_mode = 1; |
| 7762 | } | 7687 | } |
| 7688 | |||
| 7689 | for (i = 0; i < MAX_RX_RINGS; i++) | ||
| 7690 | if (rx_ring_sz[i] > MAX_RX_BLOCKS_PER_RING) { | ||
| 7691 | DBG_PRINT(ERR_DBG, "Requested rx ring size not " | ||
| 7692 | "supported\nDefaulting to %d\n", | ||
| 7693 | MAX_RX_BLOCKS_PER_RING); | ||
| 7694 | rx_ring_sz[i] = MAX_RX_BLOCKS_PER_RING; | ||
| 7695 | } | ||
| 7696 | |||
| 7763 | return SUCCESS; | 7697 | return SUCCESS; |
| 7764 | } | 7698 | } |
| 7765 | 7699 | ||
| @@ -7804,6 +7738,7 @@ static const struct net_device_ops s2io_netdev_ops = { | |||
| 7804 | .ndo_do_ioctl = s2io_ioctl, | 7738 | .ndo_do_ioctl = s2io_ioctl, |
| 7805 | .ndo_set_mac_address = s2io_set_mac_addr, | 7739 | .ndo_set_mac_address = s2io_set_mac_addr, |
| 7806 | .ndo_change_mtu = s2io_change_mtu, | 7740 | .ndo_change_mtu = s2io_change_mtu, |
| 7741 | .ndo_set_features = s2io_set_features, | ||
| 7807 | .ndo_vlan_rx_register = s2io_vlan_rx_register, | 7742 | .ndo_vlan_rx_register = s2io_vlan_rx_register, |
| 7808 | .ndo_vlan_rx_kill_vid = s2io_vlan_rx_kill_vid, | 7743 | .ndo_vlan_rx_kill_vid = s2io_vlan_rx_kill_vid, |
| 7809 | .ndo_tx_timeout = s2io_tx_watchdog, | 7744 | .ndo_tx_timeout = s2io_tx_watchdog, |
| @@ -7911,7 +7846,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
| 7911 | else | 7846 | else |
| 7912 | sp->device_type = XFRAME_I_DEVICE; | 7847 | sp->device_type = XFRAME_I_DEVICE; |
| 7913 | 7848 | ||
| 7914 | sp->lro = lro_enable; | ||
| 7915 | 7849 | ||
| 7916 | /* Initialize some PCI/PCI-X fields of the NIC. */ | 7850 | /* Initialize some PCI/PCI-X fields of the NIC. */ |
| 7917 | s2io_init_pci(sp); | 7851 | s2io_init_pci(sp); |
| @@ -8046,18 +7980,18 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
| 8046 | /* Driver entry points */ | 7980 | /* Driver entry points */ |
| 8047 | dev->netdev_ops = &s2io_netdev_ops; | 7981 | dev->netdev_ops = &s2io_netdev_ops; |
| 8048 | SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); | 7982 | SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); |
| 8049 | dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; | 7983 | dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | |
| 8050 | if (lro_enable) | 7984 | NETIF_F_TSO | NETIF_F_TSO6 | |
| 8051 | dev->features |= NETIF_F_LRO; | 7985 | NETIF_F_RXCSUM | NETIF_F_LRO; |
| 8052 | dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; | 7986 | dev->features |= dev->hw_features | |
| 7987 | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; | ||
| 7988 | if (sp->device_type & XFRAME_II_DEVICE) { | ||
| 7989 | dev->hw_features |= NETIF_F_UFO; | ||
| 7990 | if (ufo) | ||
| 7991 | dev->features |= NETIF_F_UFO; | ||
| 7992 | } | ||
| 8053 | if (sp->high_dma_flag == true) | 7993 | if (sp->high_dma_flag == true) |
| 8054 | dev->features |= NETIF_F_HIGHDMA; | 7994 | dev->features |= NETIF_F_HIGHDMA; |
| 8055 | dev->features |= NETIF_F_TSO; | ||
| 8056 | dev->features |= NETIF_F_TSO6; | ||
| 8057 | if ((sp->device_type & XFRAME_II_DEVICE) && (ufo)) { | ||
| 8058 | dev->features |= NETIF_F_UFO; | ||
| 8059 | dev->features |= NETIF_F_HW_CSUM; | ||
| 8060 | } | ||
| 8061 | dev->watchdog_timeo = WATCH_DOG_TIMEOUT; | 7995 | dev->watchdog_timeo = WATCH_DOG_TIMEOUT; |
| 8062 | INIT_WORK(&sp->rst_timer_task, s2io_restart_nic); | 7996 | INIT_WORK(&sp->rst_timer_task, s2io_restart_nic); |
| 8063 | INIT_WORK(&sp->set_link_task, s2io_set_link); | 7997 | INIT_WORK(&sp->set_link_task, s2io_set_link); |
| @@ -8283,9 +8217,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
| 8283 | dev->name); | 8217 | dev->name); |
| 8284 | } | 8218 | } |
| 8285 | 8219 | ||
| 8286 | if (sp->lro) | 8220 | DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n", |
| 8287 | DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n", | 8221 | dev->name); |
| 8288 | dev->name); | ||
| 8289 | if (ufo) | 8222 | if (ufo) |
| 8290 | DBG_PRINT(ERR_DBG, | 8223 | DBG_PRINT(ERR_DBG, |
| 8291 | "%s: UDP Fragmentation Offload(UFO) enabled\n", | 8224 | "%s: UDP Fragmentation Offload(UFO) enabled\n", |
| @@ -8334,8 +8267,7 @@ mem_alloc_failed: | |||
| 8334 | 8267 | ||
| 8335 | static void __devexit s2io_rem_nic(struct pci_dev *pdev) | 8268 | static void __devexit s2io_rem_nic(struct pci_dev *pdev) |
| 8336 | { | 8269 | { |
| 8337 | struct net_device *dev = | 8270 | struct net_device *dev = pci_get_drvdata(pdev); |
| 8338 | (struct net_device *)pci_get_drvdata(pdev); | ||
| 8339 | struct s2io_nic *sp; | 8271 | struct s2io_nic *sp; |
| 8340 | 8272 | ||
| 8341 | if (dev == NULL) { | 8273 | if (dev == NULL) { |
| @@ -8343,9 +8275,11 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev) | |||
| 8343 | return; | 8275 | return; |
| 8344 | } | 8276 | } |
| 8345 | 8277 | ||
| 8346 | flush_scheduled_work(); | ||
| 8347 | |||
| 8348 | sp = netdev_priv(dev); | 8278 | sp = netdev_priv(dev); |
| 8279 | |||
| 8280 | cancel_work_sync(&sp->rst_timer_task); | ||
| 8281 | cancel_work_sync(&sp->set_link_task); | ||
| 8282 | |||
| 8349 | unregister_netdev(dev); | 8283 | unregister_netdev(dev); |
| 8350 | 8284 | ||
| 8351 | free_shared_mem(sp); | 8285 | free_shared_mem(sp); |
