/************************************************************************
* s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2005 Neterion Inc.
+ * Copyright(c) 2002-2007 Neterion Inc.
* This software may be used and distributed according to the terms of
* the GNU General Public License (GPL), incorporated herein by reference.
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.17.1"
+#define DRV_VERSION "2.0.23.1"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
("lro_out_of_sequence_pkts"),
("lro_flush_due_to_max_pkts"),
("lro_avg_aggr_pkts"),
+ ("mem_alloc_fail_cnt"),
+ ("watchdog_timer_cnt"),
+ ("mem_allocated"),
+ ("mem_freed"),
+ ("link_up_cnt"),
+ ("link_down_cnt"),
+ ("link_up_time"),
+ ("link_down_time"),
+ ("tx_tcode_buf_abort_cnt"),
+ ("tx_tcode_desc_abort_cnt"),
+ ("tx_tcode_parity_err_cnt"),
+ ("tx_tcode_link_loss_cnt"),
+ ("tx_tcode_list_proc_err_cnt"),
+ ("rx_tcode_parity_err_cnt"),
+ ("rx_tcode_abort_cnt"),
+ ("rx_tcode_parity_abort_cnt"),
+ ("rx_tcode_rda_fail_cnt"),
+ ("rx_tcode_unkn_prot_cnt"),
+ ("rx_tcode_fcs_err_cnt"),
+ ("rx_tcode_buf_size_err_cnt"),
+ ("rx_tcode_rxd_corrupt_cnt"),
+ ("rx_tcode_unkn_err_cnt")
};
#define S2IO_XENA_STAT_LEN sizeof(ethtool_xena_stats_keys)/ ETH_GSTRING_LEN
}
/* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */
-int vlan_strip_flag;
-
-/* Unregister the vlan */
-static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
-{
- struct s2io_nic *nic = dev->priv;
- unsigned long flags;
-
- spin_lock_irqsave(&nic->tx_lock, flags);
- vlan_group_set_device(nic->vlgrp, vid, NULL);
- spin_unlock_irqrestore(&nic->tx_lock, flags);
-}
+static int vlan_strip_flag;
/*
* Constants to be programmed into the Xena's registers, to configure
END_SIGN
};
-MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
MODULE_DEVICE_TABLE(pci, s2io_tbl);
+static struct pci_error_handlers s2io_err_handler = {
+ .error_detected = s2io_io_error_detected,
+ .slot_reset = s2io_io_slot_reset,
+ .resume = s2io_io_resume,
+};
+
static struct pci_driver s2io_driver = {
.name = "S2IO",
.id_table = s2io_tbl,
.probe = s2io_init_nic,
.remove = __devexit_p(s2io_rem_nic),
+ .err_handler = &s2io_err_handler,
};
/* A simplifier macro used both by init and free shared_mem Fns(). */
struct mac_info *mac_control;
struct config_param *config;
+ unsigned long long mem_allocated = 0;
mac_control = &nic->mac_control;
config = &nic->config;
mac_control->fifos[i].list_info = kmalloc(list_holder_size,
GFP_KERNEL);
if (!mac_control->fifos[i].list_info) {
- DBG_PRINT(ERR_DBG,
+ DBG_PRINT(INFO_DBG,
"Malloc failed for list_info\n");
return -ENOMEM;
}
+ mem_allocated += list_holder_size;
memset(mac_control->fifos[i].list_info, 0, list_holder_size);
}
for (i = 0; i < config->tx_fifo_num; i++) {
tmp_v = pci_alloc_consistent(nic->pdev,
PAGE_SIZE, &tmp_p);
if (!tmp_v) {
- DBG_PRINT(ERR_DBG,
+ DBG_PRINT(INFO_DBG,
"pci_alloc_consistent ");
- DBG_PRINT(ERR_DBG, "failed for TxDL\n");
+ DBG_PRINT(INFO_DBG, "failed for TxDL\n");
return -ENOMEM;
}
/* If we got a zero DMA address(can happen on
tmp_v = pci_alloc_consistent(nic->pdev,
PAGE_SIZE, &tmp_p);
if (!tmp_v) {
- DBG_PRINT(ERR_DBG,
+ DBG_PRINT(INFO_DBG,
"pci_alloc_consistent ");
- DBG_PRINT(ERR_DBG, "failed for TxDL\n");
+ DBG_PRINT(INFO_DBG, "failed for TxDL\n");
return -ENOMEM;
}
+ mem_allocated += PAGE_SIZE;
}
while (k < lst_per_page) {
int l = (j * lst_per_page) + k;
nic->ufo_in_band_v = kcalloc(size, sizeof(u64), GFP_KERNEL);
if (!nic->ufo_in_band_v)
return -ENOMEM;
+ mem_allocated += (size * sizeof(u64));
/* Allocation and initialization of RXDs in Rings */
size = 0;
rx_blocks->block_virt_addr = tmp_v_addr;
return -ENOMEM;
}
+ mem_allocated += size;
memset(tmp_v_addr, 0, size);
rx_blocks->block_virt_addr = tmp_v_addr;
rx_blocks->block_dma_addr = tmp_p_addr;
GFP_KERNEL);
if (!rx_blocks->rxds)
return -ENOMEM;
+ mem_allocated +=
+ (sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]);
for (l=0; l<rxd_count[nic->rxd_mode];l++) {
rx_blocks->rxds[l].virt_addr =
rx_blocks->block_virt_addr +
GFP_KERNEL);
if (!mac_control->rings[i].ba)
return -ENOMEM;
+ mem_allocated +=(sizeof(struct buffAdd *) * blk_cnt);
for (j = 0; j < blk_cnt; j++) {
int k = 0;
mac_control->rings[i].ba[j] =
GFP_KERNEL);
if (!mac_control->rings[i].ba[j])
return -ENOMEM;
+ mem_allocated += (sizeof(struct buffAdd) * \
+ (rxd_count[nic->rxd_mode] + 1));
while (k != rxd_count[nic->rxd_mode]) {
ba = &mac_control->rings[i].ba[j][k];
(BUF0_LEN + ALIGN_SIZE, GFP_KERNEL);
if (!ba->ba_0_org)
return -ENOMEM;
+ mem_allocated +=
+ (BUF0_LEN + ALIGN_SIZE);
tmp = (unsigned long)ba->ba_0_org;
tmp += ALIGN_SIZE;
tmp &= ~((unsigned long) ALIGN_SIZE);
(BUF1_LEN + ALIGN_SIZE, GFP_KERNEL);
if (!ba->ba_1_org)
return -ENOMEM;
+ mem_allocated
+ += (BUF1_LEN + ALIGN_SIZE);
tmp = (unsigned long) ba->ba_1_org;
tmp += ALIGN_SIZE;
tmp &= ~((unsigned long) ALIGN_SIZE);
*/
return -ENOMEM;
}
+ mem_allocated += size;
mac_control->stats_mem_sz = size;
tmp_v_addr = mac_control->stats_mem;
memset(tmp_v_addr, 0, size);
DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name,
(unsigned long long) tmp_p_addr);
-
+ mac_control->stats_info->sw_stat.mem_allocated += mem_allocated;
return SUCCESS;
}
static void free_shared_mem(struct s2io_nic *nic)
{
int i, j, blk_cnt, size;
+ u32 ufo_size = 0;
void *tmp_v_addr;
dma_addr_t tmp_p_addr;
struct mac_info *mac_control;
struct config_param *config;
int lst_size, lst_per_page;
struct net_device *dev = nic->dev;
+ int page_num = 0;
if (!nic)
return;
lst_per_page = PAGE_SIZE / lst_size;
for (i = 0; i < config->tx_fifo_num; i++) {
- int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
- lst_per_page);
+ ufo_size += config->tx_cfg[i].fifo_len;
+ page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
+ lst_per_page);
for (j = 0; j < page_num; j++) {
int mem_blks = (j * lst_per_page);
if (!mac_control->fifos[i].list_info)
mac_control->fifos[i].
list_info[mem_blks].
list_phy_addr);
+ nic->mac_control.stats_info->sw_stat.mem_freed
+ += PAGE_SIZE;
}
/* If we got a zero DMA address during allocation,
* free the page now
dev->name);
DBG_PRINT(INIT_DBG, "Virtual address %p\n",
mac_control->zerodma_virt_addr);
+ nic->mac_control.stats_info->sw_stat.mem_freed
+ += PAGE_SIZE;
}
kfree(mac_control->fifos[i].list_info);
+ nic->mac_control.stats_info->sw_stat.mem_freed +=
+ (nic->config.tx_cfg[i].fifo_len *sizeof(struct list_info_hold));
}
size = SIZE_OF_BLOCK;
break;
pci_free_consistent(nic->pdev, size,
tmp_v_addr, tmp_p_addr);
+ nic->mac_control.stats_info->sw_stat.mem_freed += size;
kfree(mac_control->rings[i].rx_blocks[j].rxds);
+ nic->mac_control.stats_info->sw_stat.mem_freed +=
+ ( sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]);
}
}
struct buffAdd *ba =
&mac_control->rings[i].ba[j][k];
kfree(ba->ba_0_org);
+ nic->mac_control.stats_info->sw_stat.\
+ mem_freed += (BUF0_LEN + ALIGN_SIZE);
kfree(ba->ba_1_org);
+ nic->mac_control.stats_info->sw_stat.\
+ mem_freed += (BUF1_LEN + ALIGN_SIZE);
k++;
}
kfree(mac_control->rings[i].ba[j]);
+ nic->mac_control.stats_info->sw_stat.mem_freed += (sizeof(struct buffAdd) *
+ (rxd_count[nic->rxd_mode] + 1));
}
kfree(mac_control->rings[i].ba);
+ nic->mac_control.stats_info->sw_stat.mem_freed +=
+ (sizeof(struct buffAdd *) * blk_cnt);
}
}
mac_control->stats_mem_sz,
mac_control->stats_mem,
mac_control->stats_mem_phy);
+ nic->mac_control.stats_info->sw_stat.mem_freed +=
+ mac_control->stats_mem_sz;
}
- if (nic->ufo_in_band_v)
+ if (nic->ufo_in_band_v) {
kfree(nic->ufo_in_band_v);
+ nic->mac_control.stats_info->sw_stat.mem_freed
+ += (ufo_size * sizeof(u64));
+ }
}
/**
for (i = 0; i < config->tx_fifo_num; i++) {
for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
- txdp = (struct TxD *) mac_control->fifos[i].list_info[j].
- list_virt_addr;
+ txdp = (struct TxD *) \
+ mac_control->fifos[i].list_info[j].list_virt_addr;
skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
if (skb) {
+ nic->mac_control.stats_info->sw_stat.mem_freed
+ += skb->truesize;
dev_kfree_skb(skb);
cnt++;
}
/* skb_shinfo(skb)->frag_list will have L4 data payload */
skb_shinfo(skb)->frag_list = dev_alloc_skb(dev->mtu + ALIGN_SIZE);
if (skb_shinfo(skb)->frag_list == NULL) {
- DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
+ nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
+ DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
return -ENOMEM ;
}
frag_list = skb_shinfo(skb)->frag_list;
skb->truesize += frag_list->truesize;
+ nic->mac_control.stats_info->sw_stat.mem_allocated
+ += frag_list->truesize;
frag_list->next = NULL;
tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1);
frag_list->data = tmp;
- frag_list->tail = tmp;
+ skb_reset_tail_pointer(frag_list);
/* Buffer-2 receives L4 data payload */
((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
struct buffAdd *ba;
unsigned long flags;
struct RxD_t *first_rxdp = NULL;
+ u64 Buffer0_ptr = 0, Buffer1_ptr = 0;
mac_control = &nic->mac_control;
config = &nic->config;
/* allocate skb */
skb = dev_alloc_skb(size);
if(!skb) {
- DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
- DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
+ DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
+ DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n");
if (first_rxdp) {
wmb();
first_rxdp->Control_1 |= RXD_OWN_XENA;
}
+ nic->mac_control.stats_info->sw_stat. \
+ mem_alloc_fail_cnt++;
return -ENOMEM ;
}
+ nic->mac_control.stats_info->sw_stat.mem_allocated
+ += skb->truesize;
if (nic->rxd_mode == RXD_MODE_1) {
/* 1 buffer mode - normal operation mode */
memset(rxdp, 0, sizeof(struct RxD1));
((struct RxD1*)rxdp)->Buffer0_ptr = pci_map_single
(nic->pdev, skb->data, size - NET_IP_ALIGN,
PCI_DMA_FROMDEVICE);
- rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
+ rxdp->Control_2 =
+ SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
} else if (nic->rxd_mode >= RXD_MODE_3A) {
/*
* payload
*/
+ /* save buffer pointers to avoid frequent dma mapping */
+ Buffer0_ptr = ((struct RxD3*)rxdp)->Buffer0_ptr;
+ Buffer1_ptr = ((struct RxD3*)rxdp)->Buffer1_ptr;
memset(rxdp, 0, sizeof(struct RxD3));
+ /* restore the buffer pointers for dma sync*/
+ ((struct RxD3*)rxdp)->Buffer0_ptr = Buffer0_ptr;
+ ((struct RxD3*)rxdp)->Buffer1_ptr = Buffer1_ptr;
+
ba = &mac_control->rings[ring_no].ba[block_no][off];
skb_reserve(skb, BUF0_LEN);
tmp = (u64)(unsigned long) skb->data;
tmp += ALIGN_SIZE;
tmp &= ~ALIGN_SIZE;
skb->data = (void *) (unsigned long)tmp;
- skb->tail = (void *) (unsigned long)tmp;
+ skb_reset_tail_pointer(skb);
if (!(((struct RxD3*)rxdp)->Buffer0_ptr))
((struct RxD3*)rxdp)->Buffer0_ptr =
PCI_DMA_FROMDEVICE);
else
pci_dma_sync_single_for_device(nic->pdev,
- (dma_addr_t) ((struct RxD3*)rxdp)->Buffer0_ptr,
+ (dma_addr_t) ((struct RxD3*)rxdp)->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
if (nic->rxd_mode == RXD_MODE_3B) {
} else {
/* 3 buffer mode */
if (fill_rxd_3buf(nic, rxdp, skb) == -ENOMEM) {
+ nic->mac_control.stats_info->sw_stat.\
+ mem_freed += skb->truesize;
dev_kfree_skb_irq(skb);
if (first_rxdp) {
wmb();
PCI_DMA_FROMDEVICE);
memset(rxdp, 0, sizeof(struct RxD3));
}
+ sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize;
dev_kfree_skb(skb);
atomic_dec(&sp->rx_bufs_left[ring_no]);
}
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(nic, i) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
- DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
+ DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
break;
}
}
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(nic, i) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
- DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
+ DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
break;
}
}
u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
int i;
+ if (pci_channel_offline(nic->pdev))
+ return;
+
disable_irq(dev->irq);
atomic_inc(&nic->isr_cnt);
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(nic, i) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
- DBG_PRINT(ERR_DBG, " in Rx Netpoll!!\n");
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
+ DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n");
break;
}
}
struct tx_curr_get_info get_info, put_info;
struct sk_buff *skb;
struct TxD *txdlp;
+ u8 err_mask;
get_info = fifo_data->tx_curr_get_info;
memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info));
nic->mac_control.stats_info->sw_stat.
parity_err_cnt++;
}
- if ((err >> 48) == 0xA) {
- DBG_PRINT(TX_DBG, "TxD returned due \
- to loss of link\n");
- }
- else {
- DBG_PRINT(ERR_DBG, "***TxD error %llx\n", err);
- }
+
+ /* update t_code statistics */
+ err_mask = err >> 48;
+ switch(err_mask) {
+ case 2:
+ nic->mac_control.stats_info->sw_stat.
+ tx_buf_abort_cnt++;
+ break;
+
+ case 3:
+ nic->mac_control.stats_info->sw_stat.
+ tx_desc_abort_cnt++;
+ break;
+
+ case 7:
+ nic->mac_control.stats_info->sw_stat.
+ tx_parity_err_cnt++;
+ break;
+
+ case 10:
+ nic->mac_control.stats_info->sw_stat.
+ tx_link_loss_cnt++;
+ break;
+
+ case 15:
+ nic->mac_control.stats_info->sw_stat.
+ tx_list_proc_err_cnt++;
+ break;
+ }
}
skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset);
/* Updating the statistics block */
nic->stats.tx_bytes += skb->len;
+ nic->mac_control.stats_info->sw_stat.mem_freed += skb->truesize;
dev_kfree_skb_irq(skb);
get_info.offset++;
int i;
if (atomic_read(&nic->card_state) == CARD_DOWN)
return;
+ if (pci_channel_offline(nic->pdev))
+ return;
nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
/* Handling the XPAK counters update */
if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
u16 subid, pci_cmd;
int i;
u16 val16;
+ unsigned long long up_cnt, down_cnt, up_time, down_time, reset_cnt;
+ unsigned long long mem_alloc_cnt, mem_free_cnt, watchdog_cnt;
+
DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n",
__FUNCTION__, sp->dev->name);
/* Reset device statistics maintained by OS */
memset(&sp->stats, 0, sizeof (struct net_device_stats));
+
+ up_cnt = sp->mac_control.stats_info->sw_stat.link_up_cnt;
+ down_cnt = sp->mac_control.stats_info->sw_stat.link_down_cnt;
+ up_time = sp->mac_control.stats_info->sw_stat.link_up_time;
+ down_time = sp->mac_control.stats_info->sw_stat.link_down_time;
+ reset_cnt = sp->mac_control.stats_info->sw_stat.soft_reset_cnt;
+ mem_alloc_cnt = sp->mac_control.stats_info->sw_stat.mem_allocated;
+ mem_free_cnt = sp->mac_control.stats_info->sw_stat.mem_freed;
+ watchdog_cnt = sp->mac_control.stats_info->sw_stat.watchdog_timer_cnt;
+ /* save link up/down time/cnt, reset/memory/watchdog cnt */
+ memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
+ /* restore link up/down time/cnt, reset/memory/watchdog cnt */
+ sp->mac_control.stats_info->sw_stat.link_up_cnt = up_cnt;
+ sp->mac_control.stats_info->sw_stat.link_down_cnt = down_cnt;
+ sp->mac_control.stats_info->sw_stat.link_up_time = up_time;
+ sp->mac_control.stats_info->sw_stat.link_down_time = down_time;
+ sp->mac_control.stats_info->sw_stat.soft_reset_cnt = reset_cnt;
+ sp->mac_control.stats_info->sw_stat.mem_allocated = mem_alloc_cnt;
+ sp->mac_control.stats_info->sw_stat.mem_freed = mem_free_cnt;
+ sp->mac_control.stats_info->sw_stat.watchdog_timer_cnt = watchdog_cnt;
/* SXE-002: Configure link and activity LED to turn it off */
subid = sp->pdev->subsystem_device;
nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
GFP_KERNEL);
if (nic->entries == NULL) {
- DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
+ DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \
+ __FUNCTION__);
+ nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
return -ENOMEM;
}
- memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
+ nic->mac_control.stats_info->sw_stat.mem_allocated
+ += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
+ memset(nic->entries, 0,MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
nic->s2io_entries =
kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
GFP_KERNEL);
if (nic->s2io_entries == NULL) {
- DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
+ DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n",
+ __FUNCTION__);
+ nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
kfree(nic->entries);
+ nic->mac_control.stats_info->sw_stat.mem_freed
+ += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
return -ENOMEM;
}
+ nic->mac_control.stats_info->sw_stat.mem_allocated
+ += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
memset(nic->s2io_entries, 0,
MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
rx_mat = readq(&bar0->rx_mat);
for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
rx_mat |= RX_MAT_SET(j, msix_indx);
- nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
+ nic->s2io_entries[msix_indx].arg
+ = &nic->mac_control.rings[j];
nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
}
tx_mat = readq(&bar0->tx_mat0_n[7]);
for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
tx_mat |= TX_MAT_SET(i, msix_indx);
- nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
+ nic->s2io_entries[msix_indx].arg
+ = &nic->mac_control.rings[j];
nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
}
if (ret) {
DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
kfree(nic->entries);
+ nic->mac_control.stats_info->sw_stat.mem_freed
+ += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
kfree(nic->s2io_entries);
+ nic->mac_control.stats_info->sw_stat.mem_freed
+ += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
nic->entries = NULL;
nic->s2io_entries = NULL;
nic->avail_msix_vectors = 0;
hw_init_failed:
if (sp->intr_type == MSI_X) {
- if (sp->entries)
+ if (sp->entries) {
kfree(sp->entries);
- if (sp->s2io_entries)
+ sp->mac_control.stats_info->sw_stat.mem_freed
+ += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
+ }
+ if (sp->s2io_entries) {
kfree(sp->s2io_entries);
+ sp->mac_control.stats_info->sw_stat.mem_freed
+ += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
+ }
}
return err;
}
/* Reset card, kill tasklet and free Tx and Rx buffers. */
s2io_card_down(sp);
- sp->device_close_flag = TRUE; /* Device is shut down. */
return 0;
}
config = &sp->config;
DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name);
+
+ if (unlikely(skb->len <= 0)) {
+ DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
+ dev_kfree_skb_any(skb);
+ return 0;
+}
+
spin_lock_irqsave(&sp->tx_lock, flags);
if (atomic_read(&sp->card_state) == CARD_DOWN) {
DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
}
queue = 0;
-
/* Get Fifo number to Transmit based on vlan priority */
if (sp->vlgrp && vlan_tx_tag_present(skb)) {
vlan_tag = vlan_tx_tag_get(skb);
return 0;
}
- /* A buffer with no data will be dropped */
- if (!skb->len) {
- DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
- dev_kfree_skb(skb);
- spin_unlock_irqrestore(&sp->tx_lock, flags);
- return 0;
- }
-
offload_type = s2io_offload_type(skb);
if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
txdp->Control_1 |= TXD_TCP_LSO_EN;
put_off, get_off);
netif_stop_queue(dev);
}
-
+ mac_control->stats_info->sw_stat.mem_allocated += skb->truesize;
dev->trans_start = jiffies;
spin_unlock_irqrestore(&sp->tx_lock, flags);
DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
DBG_PRINT(INTR_DBG, "PANIC levels\n");
if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "Out of memory in %s",
+ DBG_PRINT(INFO_DBG, "Out of memory in %s",
__FUNCTION__);
clear_bit(0, (&sp->tasklet_status));
return -1;
tasklet_schedule(&sp->task);
} else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory", sp->dev->name);
- DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name);
+ DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
}
return 0;
}
struct mac_info *mac_control;
struct config_param *config;
+ /* Pretend we handled any irq's from a disconnected card */
+ if (pci_channel_offline(sp->pdev))
+ return IRQ_NONE;
+
atomic_inc(&sp->isr_cnt);
mac_control = &sp->mac_control;
config = &sp->config;
if (cnt == 5)
break; /* Updt failed */
} while(1);
- } else {
- memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
- }
+ }
}
/**
return 0;
}
+static void s2io_ethtool_gringparam(struct net_device *dev,
+ struct ethtool_ringparam *ering)
+{
+ struct s2io_nic *sp = dev->priv;
+ int i,tx_desc_count=0,rx_desc_count=0;
+
+ if (sp->rxd_mode == RXD_MODE_1)
+ ering->rx_max_pending = MAX_RX_DESC_1;
+ else if (sp->rxd_mode == RXD_MODE_3B)
+ ering->rx_max_pending = MAX_RX_DESC_2;
+ else if (sp->rxd_mode == RXD_MODE_3A)
+ ering->rx_max_pending = MAX_RX_DESC_3;
+
+ ering->tx_max_pending = MAX_TX_DESC;
+ for (i = 0 ; i < sp->config.tx_fifo_num ; i++) {
+ tx_desc_count += sp->config.tx_cfg[i].fifo_len;
+ }
+ DBG_PRINT(INFO_DBG,"\nmax txds : %d\n",sp->config.max_txds);
+ ering->tx_pending = tx_desc_count;
+ rx_desc_count = 0;
+ for (i = 0 ; i < sp->config.rx_ring_num ; i++) {
+ rx_desc_count += sp->config.rx_cfg[i].num_rxd;
+ }
+ ering->rx_pending = rx_desc_count;
+
+ ering->rx_mini_max_pending = 0;
+ ering->rx_mini_pending = 0;
+ if(sp->rxd_mode == RXD_MODE_1)
+ ering->rx_jumbo_max_pending = MAX_RX_DESC_1;
+ else if (sp->rxd_mode == RXD_MODE_3B)
+ ering->rx_jumbo_max_pending = MAX_RX_DESC_2;
+ ering->rx_jumbo_pending = rx_desc_count;
+}
+
/**
* s2io_ethtool_getpause_data -Pause frame frame generation and reception.
* @sp : private member of the device structure, which is a pointer to the
strcpy(nic->serial_num, "NOT AVAILABLE");
vpd_data = kmalloc(256, GFP_KERNEL);
- if (!vpd_data)
+ if (!vpd_data) {
+ nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
return;
+ }
+ nic->mac_control.stats_info->sw_stat.mem_allocated += 256;
for (i = 0; i < 256; i +=4 ) {
pci_write_config_byte(nic->pdev, (vpd_addr + 2), i);
memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
}
kfree(vpd_data);
+ nic->mac_control.stats_info->sw_stat.mem_freed += 256;
}
/**
}
else
tmp_stats[i++] = 0;
+ tmp_stats[i++] = stat_info->sw_stat.mem_alloc_fail_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.watchdog_timer_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.mem_allocated;
+ tmp_stats[i++] = stat_info->sw_stat.mem_freed;
+ tmp_stats[i++] = stat_info->sw_stat.link_up_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.link_down_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.link_up_time;
+ tmp_stats[i++] = stat_info->sw_stat.link_down_time;
+
+ tmp_stats[i++] = stat_info->sw_stat.tx_buf_abort_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.tx_desc_abort_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.tx_parity_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.tx_link_loss_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.tx_list_proc_err_cnt;
+
+ tmp_stats[i++] = stat_info->sw_stat.rx_parity_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rx_abort_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rx_parity_abort_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rx_rda_fail_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rx_unkn_prot_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rx_fcs_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rx_buf_size_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rx_rxd_corrupt_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rx_unkn_err_cnt;
}
static int s2io_ethtool_get_regs_len(struct net_device *dev)
.get_eeprom_len = s2io_get_eeprom_len,
.get_eeprom = s2io_ethtool_geeprom,
.set_eeprom = s2io_ethtool_seeprom,
+ .get_ringparam = s2io_ethtool_gringparam,
.get_pauseparam = s2io_ethtool_getpause_data,
.set_pauseparam = s2io_ethtool_setpause_data,
.get_rx_csum = s2io_ethtool_get_rx_csum,
for (i = 0; i < config->rx_ring_num; i++) {
ret = fill_rx_buffers(sp, i);
if (ret == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s: Out of ",
+ DBG_PRINT(INFO_DBG, "%s: Out of ",
dev->name);
- DBG_PRINT(ERR_DBG, "memory in tasklet\n");
+ DBG_PRINT(INFO_DBG, "memory in tasklet\n");
break;
} else if (ret == -EFILL) {
- DBG_PRINT(ERR_DBG,
+ DBG_PRINT(INFO_DBG,
"%s: Rx Ring %d is full\n",
dev->name, i);
break;
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
- DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
- DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
+ DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
+ DBG_PRINT(INFO_DBG, "memory to allocate ");
+ DBG_PRINT(INFO_DBG, "1 buf mode SKBs\n");
+ sp->mac_control.stats_info->sw_stat. \
+ mem_alloc_fail_cnt++;
return -ENOMEM ;
}
+ sp->mac_control.stats_info->sw_stat.mem_allocated
+ += (*skb)->truesize;
/* storing the mapped addr in a temp variable
* such it will be used for next rxd whose
* Host Control is NULL
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
- DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
- dev->name);
+ DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
+ DBG_PRINT(INFO_DBG, "memory to allocate ");
+ DBG_PRINT(INFO_DBG, "2 buf mode SKBs\n");
+ sp->mac_control.stats_info->sw_stat. \
+ mem_alloc_fail_cnt++;
return -ENOMEM;
}
+ sp->mac_control.stats_info->sw_stat.mem_allocated
+ += (*skb)->truesize;
((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
pci_map_single(sp->pdev, (*skb)->data,
dev->mtu + 4,
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
- DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
- dev->name);
+ DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
+ DBG_PRINT(INFO_DBG, "memory to allocate ");
+ DBG_PRINT(INFO_DBG, "3 buf mode SKBs\n");
+ sp->mac_control.stats_info->sw_stat. \
+ mem_alloc_fail_cnt++;
return -ENOMEM;
}
+ sp->mac_control.stats_info->sw_stat.mem_allocated
+ += (*skb)->truesize;
((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN,
PCI_DMA_FROMDEVICE);
if (skb_shinfo(*skb)->frag_list == NULL) {
DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb \
failed\n ", dev->name);
+ sp->mac_control.stats_info->sw_stat. \
+ mem_alloc_fail_cnt++;
return -ENOMEM ;
}
frag_list = skb_shinfo(*skb)->frag_list;
frag_list->next = NULL;
+ sp->mac_control.stats_info->sw_stat.mem_allocated
+ += frag_list->truesize;
/*
* Buffer-2 receives L4 data payload
*/
} while(cnt < 5);
}
-static void s2io_card_down(struct s2io_nic * sp)
+static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
{
int cnt = 0;
struct XENA_dev_config __iomem *bar0 = sp->bar0;
atomic_set(&sp->card_state, CARD_DOWN);
/* disable Tx and Rx traffic on the NIC */
- stop_nic(sp);
+ if (do_io)
+ stop_nic(sp);
s2io_rem_isr(sp);
tasklet_kill(&sp->task);
/* Check if the device is Quiescent and then Reset the NIC */
- do {
+ while(do_io) {
/* As per the HW requirement we need to replenish the
* receive buffer to avoid the ring bump. Since there is
* no intention of processing the Rx frame at this pointwe are
(unsigned long long) val64);
break;
}
- } while (1);
- s2io_reset(sp);
+ }
+ if (do_io)
+ s2io_reset(sp);
spin_lock_irqsave(&sp->tx_lock, flags);
/* Free all Tx buffers */
clear_bit(0, &(sp->link_state));
}
+static void s2io_card_down(struct s2io_nic * sp)
+{
+ do_s2io_card_down(sp, 1);
+}
+
static int s2io_card_up(struct s2io_nic * sp)
{
int i, ret = 0;
struct s2io_nic *sp = dev->priv;
if (netif_carrier_ok(dev)) {
+ sp->mac_control.stats_info->sw_stat.watchdog_timer_cnt++;
schedule_work(&sp->rst_timer_task);
sp->mac_control.stats_info->sw_stat.soft_reset_cnt++;
}
u16 l3_csum, l4_csum;
unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
struct lro *lro;
+ u8 err_mask;
skb->dev = dev;
if (err & 0x1) {
sp->mac_control.stats_info->sw_stat.parity_err_cnt++;
}
+ err_mask = err >> 48;
+ switch(err_mask) {
+ case 1:
+ sp->mac_control.stats_info->sw_stat.
+ rx_parity_err_cnt++;
+ break;
+
+ case 2:
+ sp->mac_control.stats_info->sw_stat.
+ rx_abort_cnt++;
+ break;
+
+ case 3:
+ sp->mac_control.stats_info->sw_stat.
+ rx_parity_abort_cnt++;
+ break;
+ case 4:
+ sp->mac_control.stats_info->sw_stat.
+ rx_rda_fail_cnt++;
+ break;
+
+ case 5:
+ sp->mac_control.stats_info->sw_stat.
+ rx_unkn_prot_cnt++;
+ break;
+
+ case 6:
+ sp->mac_control.stats_info->sw_stat.
+ rx_fcs_err_cnt++;
+ break;
+
+ case 7:
+ sp->mac_control.stats_info->sw_stat.
+ rx_buf_size_err_cnt++;
+ break;
+
+ case 8:
+ sp->mac_control.stats_info->sw_stat.
+ rx_rxd_corrupt_cnt++;
+ break;
+
+ case 15:
+ sp->mac_control.stats_info->sw_stat.
+ rx_unkn_err_cnt++;
+ break;
+ }
/*
* Drop the packet if bad transfer code. Exception being
* 0x5, which could be due to unsupported IPv6 extension header.
* Note that in this case, since checksum will be incorrect,
* stack will validate the same.
*/
- if (err && ((err >> 48) != 0x5)) {
- DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n",
- dev->name, err);
+ if (err_mask != 0x5) {
+ DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%x\n",
+ dev->name, err_mask);
sp->stats.rx_crc_errors++;
+ sp->mac_control.stats_info->sw_stat.mem_freed
+ += skb->truesize;
dev_kfree_skb(skb);
atomic_dec(&sp->rx_bufs_left[ring_no]);
rxdp->Host_Control = 0;
/* Updating statistics */
rxdp->Host_Control = 0;
- sp->rx_pkt_count++;
- sp->stats.rx_packets++;
if (sp->rxd_mode == RXD_MODE_1) {
int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
} else {
skb->ip_summed = CHECKSUM_NONE;
}
-
+ sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize;
if (!sp->lro) {
skb->protocol = eth_type_trans(skb, dev);
if ((sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2) &&
if (link == LINK_DOWN) {
DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
netif_carrier_off(dev);
+ if(sp->mac_control.stats_info->sw_stat.link_up_cnt)
+ sp->mac_control.stats_info->sw_stat.link_up_time =
+ jiffies - sp->start_time;
+ sp->mac_control.stats_info->sw_stat.link_down_cnt++;
} else {
DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name);
+ if (sp->mac_control.stats_info->sw_stat.link_down_cnt)
+ sp->mac_control.stats_info->sw_stat.link_down_time =
+ jiffies - sp->start_time;
+ sp->mac_control.stats_info->sw_stat.link_up_cnt++;
netif_carrier_on(dev);
}
}
sp->last_link_state = link;
+ sp->start_time = jiffies;
}
/**
SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
dev->vlan_rx_register = s2io_vlan_rx_register;
- dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid;
/*
* will use eth_mac_addr() for dev->set_mac_address
goto register_failed;
}
s2io_vpd_read(sp);
- DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n");
+ DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2007 Neterion Inc.\n");
DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name,
sp->product_name, get_xena_rev_id(sp->pdev));
DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
return;
}
+
+/**
+ * s2io_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct s2io_nic *sp = netdev->priv;
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev)) {
+ /* Bring down the card, while avoiding PCI I/O */
+ do_s2io_card_down(sp, 0);
+ }
+ pci_disable_device(pdev);
+
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * s2io_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ * At this point, the card has exprienced a hard reset,
+ * followed by fixups by BIOS, and has its config space
+ * set up identically to what it was at cold boot.
+ */
+static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct s2io_nic *sp = netdev->priv;
+
+ if (pci_enable_device(pdev)) {
+ printk(KERN_ERR "s2io: "
+ "Cannot re-enable PCI device after reset.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ pci_set_master(pdev);
+ s2io_reset(sp);
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * s2io_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells
+ * us that its OK to resume normal operation.
+ */
+static void s2io_io_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct s2io_nic *sp = netdev->priv;
+
+ if (netif_running(netdev)) {
+ if (s2io_card_up(sp)) {
+ printk(KERN_ERR "s2io: "
+ "Can't bring device back up after reset.\n");
+ return;
+ }
+
+ if (s2io_set_mac_addr(netdev, netdev->dev_addr) == FAILURE) {
+ s2io_card_down(sp);
+ printk(KERN_ERR "s2io: "
+ "Can't resetore mac addr after reset.\n");
+ return;
+ }
+ }
+
+ netif_device_attach(netdev);
+ netif_wake_queue(netdev);
+}