Newer
Older
fw_type = NX_P3_CT_ROMIMAGE;
break;
case NX_P3_MN_ROMIMAGE:
fw_type = NX_P3_CT_ROMIMAGE;
break;
case NX_P2_MN_ROMIMAGE:
case NX_P3_CT_ROMIMAGE:
default:
fw_type = NX_FLASH_ROMIMAGE;
break;
}
adapter->fw_type = fw_type;
}
static int
netxen_p3_has_mn(struct netxen_adapter *adapter)
{
u32 capability, flashed_ver;
capability = 0;
netxen_rom_fast_read(adapter,
NX_FW_VERSION_OFFSET, (int *)&flashed_ver);
flashed_ver = NETXEN_DECODE_VERSION(flashed_ver);
if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) {
capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY);
if (capability & NX_PEG_TUNE_MN_PRESENT)
return 1;
}
return 0;
}
void netxen_request_firmware(struct netxen_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
int rc = 0;
adapter->fw_type = NX_UNKNOWN_ROMIMAGE;
next:
nx_get_next_fwtype(adapter);
if (adapter->fw_type == NX_FLASH_ROMIMAGE) {
} else {
rc = request_firmware(&adapter->fw,
fw_name[adapter->fw_type], &pdev->dev);
if (rc != 0)
goto next;
rc = netxen_validate_firmware(adapter);
if (rc != 0) {
release_firmware(adapter->fw);
}
}
}
void
netxen_release_firmware(struct netxen_adapter *adapter)
{
if (adapter->fw)
release_firmware(adapter->fw);
int netxen_init_dummy_dma(struct netxen_adapter *adapter)
if (!NX_IS_REVISION_P2(adapter->ahw.revision_id))
return 0;
adapter->dummy_dma.addr = pci_alloc_consistent(adapter->pdev,
NETXEN_HOST_DUMMY_DMA_SIZE,
&adapter->dummy_dma.phys_addr);
if (adapter->dummy_dma.addr == NULL) {
dev_err(&adapter->pdev->dev,
"ERROR: Could not allocate dummy DMA memory\n");
return -ENOMEM;
}
addr = (uint64_t) adapter->dummy_dma.phys_addr;
hi = (addr >> 32) & 0xffffffff;
lo = addr & 0xffffffff;
NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI, hi);
NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO, lo);
return 0;
}
/*
* NetXen DMA watchdog control:
*
* Bit 0 : enabled => R/O: 1 watchdog active, 0 inactive
* Bit 1 : disable_request => 1 req disable dma watchdog
* Bit 2 : enable_request => 1 req enable dma watchdog
* Bit 3-31 : unused
*/
void netxen_free_dummy_dma(struct netxen_adapter *adapter)
u32 ctrl;
if (!NX_IS_REVISION_P2(adapter->ahw.revision_id))
return;
if (!adapter->dummy_dma.addr)
return;
ctrl = NXRD32(adapter, NETXEN_DMA_WATCHDOG_CTRL);
if ((ctrl & 0x1) != 0) {
NXWR32(adapter, NETXEN_DMA_WATCHDOG_CTRL, (ctrl | 0x2));
while ((ctrl & 0x1) != 0) {
ctrl = NXRD32(adapter, NETXEN_DMA_WATCHDOG_CTRL);
if (--i == 0)
if (i) {
pci_free_consistent(adapter->pdev,
NETXEN_HOST_DUMMY_DMA_SIZE,
adapter->dummy_dma.addr,
adapter->dummy_dma.phys_addr);
adapter->dummy_dma.addr = NULL;
} else
dev_err(&adapter->pdev->dev, "dma_watchdog_shutdown failed\n");
Dhananjay Phadke
committed
int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val)
if (pegtune_val)
return 0;
do {
val = NXRD32(adapter, CRB_CMDPEG_STATE);
Dhananjay Phadke
committed
switch (val) {
case PHAN_INITIALIZE_COMPLETE:
case PHAN_INITIALIZE_ACK:
return 0;
case PHAN_INITIALIZE_FAILED:
goto out_err;
default:
break;
}
Dhananjay Phadke
committed
NXWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
Dhananjay Phadke
committed
out_err:
dev_warn(&adapter->pdev->dev, "firmware init failed\n");
return -EIO;
static int
netxen_receive_peg_ready(struct netxen_adapter *adapter)
{
u32 val = 0;
int retries = 2000;
do {
val = NXRD32(adapter, CRB_RCVPEG_STATE);
if (val == PHAN_PEG_RCV_INITIALIZED)
return 0;
msleep(10);
} while (--retries);
if (!retries) {
printk(KERN_ERR "Receive Peg initialization not "
"complete, state: 0x%x.\n", val);
return -EIO;
}
return 0;
}
int netxen_init_firmware(struct netxen_adapter *adapter)
{
int err;
err = netxen_receive_peg_ready(adapter);
if (err)
return err;
NXWR32(adapter, CRB_NIC_CAPABILITIES_HOST, INTR_SCHEME_PERPORT);
NXWR32(adapter, CRB_NIC_MSI_MODE_HOST, MSI_MODE_MULTIFUNC);
NXWR32(adapter, CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE);
NXWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
static void
netxen_handle_linkevent(struct netxen_adapter *adapter, nx_fw_msg_t *msg)
{
u32 cable_OUI;
u16 cable_len;
u16 link_speed;
u8 link_status, module, duplex, autoneg;
struct net_device *netdev = adapter->netdev;
adapter->has_link_events = 1;
cable_OUI = msg->body[1] & 0xffffffff;
cable_len = (msg->body[1] >> 32) & 0xffff;
link_speed = (msg->body[1] >> 48) & 0xffff;
link_status = msg->body[2] & 0xff;
duplex = (msg->body[2] >> 16) & 0xff;
autoneg = (msg->body[2] >> 24) & 0xff;
module = (msg->body[2] >> 8) & 0xff;
if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE) {
printk(KERN_INFO "%s: unsupported cable: OUI 0x%x, length %d\n",
netdev->name, cable_OUI, cable_len);
} else if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN) {
printk(KERN_INFO "%s: unsupported cable length %d\n",
netdev->name, cable_len);
}
netxen_advert_link_change(adapter, link_status);
/* update link parameters */
if (duplex == LINKEVENT_FULL_DUPLEX)
adapter->link_duplex = DUPLEX_FULL;
else
adapter->link_duplex = DUPLEX_HALF;
adapter->module_type = module;
adapter->link_autoneg = autoneg;
adapter->link_speed = link_speed;
}
static void
netxen_handle_fw_message(int desc_cnt, int index,
struct nx_host_sds_ring *sds_ring)
{
nx_fw_msg_t msg;
struct status_desc *desc;
int i = 0, opcode;
while (desc_cnt > 0 && i < 8) {
desc = &sds_ring->desc_head[index];
msg.words[i++] = le64_to_cpu(desc->status_desc_data[0]);
msg.words[i++] = le64_to_cpu(desc->status_desc_data[1]);
index = get_next_index(index, sds_ring->num_desc);
desc_cnt--;
}
opcode = netxen_get_nic_msg_opcode(msg.body[0]);
switch (opcode) {
case NX_NIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE:
netxen_handle_linkevent(sds_ring->adapter, &msg);
break;
default:
break;
}
}
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
static int
netxen_alloc_rx_skb(struct netxen_adapter *adapter,
struct nx_host_rds_ring *rds_ring,
struct netxen_rx_buffer *buffer)
{
struct sk_buff *skb;
dma_addr_t dma;
struct pci_dev *pdev = adapter->pdev;
buffer->skb = dev_alloc_skb(rds_ring->skb_size);
if (!buffer->skb)
return 1;
skb = buffer->skb;
if (!adapter->ahw.cut_through)
skb_reserve(skb, 2);
dma = pci_map_single(pdev, skb->data,
rds_ring->dma_size, PCI_DMA_FROMDEVICE);
if (pci_dma_mapping_error(pdev, dma)) {
dev_kfree_skb_any(skb);
buffer->skb = NULL;
return 1;
}
buffer->skb = skb;
buffer->dma = dma;
buffer->state = NETXEN_BUFFER_BUSY;
return 0;
}
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
static struct sk_buff *netxen_process_rxbuf(struct netxen_adapter *adapter,
struct nx_host_rds_ring *rds_ring, u16 index, u16 cksum)
{
struct netxen_rx_buffer *buffer;
struct sk_buff *skb;
buffer = &rds_ring->rx_buf_arr[index];
pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size,
PCI_DMA_FROMDEVICE);
skb = buffer->skb;
if (!skb)
goto no_skb;
if (likely(adapter->rx_csum && cksum == STATUS_CKSUM_OK)) {
adapter->stats.csummed++;
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else
skb->ip_summed = CHECKSUM_NONE;
skb->dev = adapter->netdev;
buffer->skb = NULL;
no_skb:
buffer->state = NETXEN_BUFFER_FREE;
return skb;
}
static struct netxen_rx_buffer *
netxen_process_rcv(struct netxen_adapter *adapter,
struct nx_host_sds_ring *sds_ring,
int ring, u64 sts_data0)
struct net_device *netdev = adapter->netdev;
struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
struct netxen_rx_buffer *buffer;
struct sk_buff *skb;
struct nx_host_rds_ring *rds_ring;
int index, length, cksum, pkt_offset;
if (unlikely(ring >= adapter->max_rds_rings))
return NULL;
rds_ring = &recv_ctx->rds_rings[ring];
index = netxen_get_sts_refhandle(sts_data0);
if (unlikely(index >= rds_ring->num_desc))
length = netxen_get_sts_totallength(sts_data0);
cksum = netxen_get_sts_status(sts_data0);
pkt_offset = netxen_get_sts_pkt_offset(sts_data0);
skb = netxen_process_rxbuf(adapter, rds_ring, index, cksum);
if (!skb)
if (length > rds_ring->skb_size)
skb_put(skb, rds_ring->skb_size);
else
skb_put(skb, length);
if (pkt_offset)
skb_pull(skb, pkt_offset);
skb->truesize = skb->len + sizeof(struct sk_buff);
skb->protocol = eth_type_trans(skb, netdev);
napi_gro_receive(&sds_ring->napi, skb);
adapter->stats.rx_pkts++;
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
#define TCP_HDR_SIZE 20
#define TCP_TS_OPTION_SIZE 12
#define TCP_TS_HDR_SIZE (TCP_HDR_SIZE + TCP_TS_OPTION_SIZE)
static struct netxen_rx_buffer *
netxen_process_lro(struct netxen_adapter *adapter,
struct nx_host_sds_ring *sds_ring,
int ring, u64 sts_data0, u64 sts_data1)
{
struct net_device *netdev = adapter->netdev;
struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
struct netxen_rx_buffer *buffer;
struct sk_buff *skb;
struct nx_host_rds_ring *rds_ring;
struct iphdr *iph;
struct tcphdr *th;
bool push, timestamp;
int l2_hdr_offset, l4_hdr_offset;
int index;
u16 lro_length, length, data_offset;
u32 seq_number;
if (unlikely(ring > adapter->max_rds_rings))
return NULL;
rds_ring = &recv_ctx->rds_rings[ring];
index = netxen_get_lro_sts_refhandle(sts_data0);
if (unlikely(index > rds_ring->num_desc))
return NULL;
buffer = &rds_ring->rx_buf_arr[index];
timestamp = netxen_get_lro_sts_timestamp(sts_data0);
lro_length = netxen_get_lro_sts_length(sts_data0);
l2_hdr_offset = netxen_get_lro_sts_l2_hdr_offset(sts_data0);
l4_hdr_offset = netxen_get_lro_sts_l4_hdr_offset(sts_data0);
push = netxen_get_lro_sts_push_flag(sts_data0);
seq_number = netxen_get_lro_sts_seq_number(sts_data1);
skb = netxen_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
if (!skb)
return buffer;
if (timestamp)
data_offset = l4_hdr_offset + TCP_TS_HDR_SIZE;
else
data_offset = l4_hdr_offset + TCP_HDR_SIZE;
skb_put(skb, lro_length + data_offset);
skb->truesize = skb->len + sizeof(struct sk_buff) + skb_headroom(skb);
skb_pull(skb, l2_hdr_offset);
skb->protocol = eth_type_trans(skb, netdev);
iph = (struct iphdr *)skb->data;
th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
iph->tot_len = htons(length);
iph->check = 0;
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
th->psh = push;
th->seq = htonl(seq_number);
length = skb->len;
adapter->stats.lro_pkts++;
adapter->stats.rxbytes += length;
#define netxen_merge_rx_buffers(list, head) \
do { list_splice_tail_init(list, head); } while (0);
netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max)
struct netxen_adapter *adapter = sds_ring->adapter;
struct list_head *cur;
struct netxen_rx_buffer *rxbuf;
u32 consumer = sds_ring->consumer;
u64 sts_data0, sts_data1;
int opcode, ring = 0, desc_cnt;
desc = &sds_ring->desc_head[consumer];
sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
if (!(sts_data0 & STATUS_OWNER_HOST))
desc_cnt = netxen_get_sts_desc_cnt(sts_data0);
opcode = netxen_get_sts_opcode(sts_data0);
switch (opcode) {
case NETXEN_NIC_RXPKT_DESC:
case NETXEN_OLD_RXPKT_DESC:
ring = netxen_get_sts_type(sts_data0);
rxbuf = netxen_process_rcv(adapter, sds_ring,
ring, sts_data0);
break;
case NETXEN_NIC_LRO_DESC:
ring = netxen_get_lro_sts_type(sts_data0);
sts_data1 = le64_to_cpu(desc->status_desc_data[1]);
rxbuf = netxen_process_lro(adapter, sds_ring,
ring, sts_data0, sts_data1);
break;
case NETXEN_NIC_RESPONSE_DESC:
netxen_handle_fw_message(desc_cnt, consumer, sds_ring);
default:
goto skip;
}
WARN_ON(desc_cnt > 1);
if (rxbuf)
list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
skip:
for (; desc_cnt > 0; desc_cnt--) {
desc = &sds_ring->desc_head[consumer];
desc->status_desc_data[0] =
cpu_to_le64(STATUS_OWNER_PHANTOM);
consumer = get_next_index(consumer, sds_ring->num_desc);
}
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
struct nx_host_rds_ring *rds_ring =
&adapter->recv_ctx.rds_rings[ring];
if (!list_empty(&sds_ring->free_list[ring])) {
list_for_each(cur, &sds_ring->free_list[ring]) {
rxbuf = list_entry(cur,
struct netxen_rx_buffer, list);
netxen_alloc_rx_skb(adapter, rds_ring, rxbuf);
}
spin_lock(&rds_ring->lock);
netxen_merge_rx_buffers(&sds_ring->free_list[ring],
&rds_ring->free_list);
spin_unlock(&rds_ring->lock);
}
netxen_post_rx_buffers_nodb(adapter, rds_ring);
}
sds_ring->consumer = consumer;
NXWRIO(adapter, sds_ring->crb_sts_consumer, consumer);
}
return count;
}
/* Process Command status ring */
int netxen_process_cmd_ring(struct netxen_adapter *adapter)
struct pci_dev *pdev = adapter->pdev;
struct net_device *netdev = adapter->netdev;
struct nx_host_tx_ring *tx_ring = adapter->tx_ring;
if (!spin_trylock(&adapter->tx_clean_lock))
return 1;
sw_consumer = tx_ring->sw_consumer;
hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
while (sw_consumer != hw_consumer) {
buffer = &tx_ring->cmd_buf_arr[sw_consumer];
if (buffer->skb) {
frag = &buffer->frag_array[0];
pci_unmap_single(pdev, frag->dma, frag->length,
PCI_DMA_TODEVICE);
Dhananjay Phadke
committed
frag->dma = 0ULL;
for (i = 1; i < buffer->frag_count; i++) {
frag++; /* Get the next frag */
pci_unmap_page(pdev, frag->dma, frag->length,
PCI_DMA_TODEVICE);
Dhananjay Phadke
committed
frag->dma = 0ULL;
dev_kfree_skb_any(buffer->skb);
buffer->skb = NULL;
sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc);
if (++count >= MAX_STATUS_HANDLE)
break;
if (count && netif_running(netdev)) {
tx_ring->sw_consumer = sw_consumer;
if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
__netif_tx_lock(tx_ring->txq, smp_processor_id());
if (netxen_tx_avail(tx_ring) > TX_STOP_THRESH) {
/*
* If everything is freed up to consumer then check if the ring is full
* If the ring is full then check if more needs to be freed and
* schedule the call back again.
*
* This happens when there are 2 CPUs. One could be freeing and the
* other filling it. If the ring is full when we get out of here and
* the card has already interrupted the host then the host can miss the
* interrupt.
*
* There is still a possible race condition and the host could miss an
* interrupt. The card has to take care of this.
*/
hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
done = (sw_consumer == hw_consumer);
spin_unlock(&adapter->tx_clean_lock);
return (done);
netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid,
struct nx_host_rds_ring *rds_ring)
{
struct rcv_desc *pdesc;
struct netxen_rx_buffer *buffer;
int producer, count = 0;
netxen_ctx_msg msg = 0;
spin_lock(&rds_ring->lock);
head = &rds_ring->free_list;
buffer = list_entry(head->next, struct netxen_rx_buffer, list);
if (!buffer->skb) {
if (netxen_alloc_rx_skb(adapter, rds_ring, buffer))
break;
/* make a rcv descriptor */
pdesc = &rds_ring->desc_head[producer];
pdesc->addr_buffer = cpu_to_le64(buffer->dma);
pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
producer = get_next_index(producer, rds_ring->num_desc);
spin_unlock(&rds_ring->lock);
if (count) {
NXWRIO(adapter, rds_ring->crb_rcv_producer,
(producer-1) & (rds_ring->num_desc-1));
if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
/*
* Write a doorbell msg to tell phanmon of change in
* receive ring producer
*/
netxen_set_msg_peg_id(msg, NETXEN_RCV_PEG_DB_ID);
netxen_set_msg_privid(msg);
netxen_set_msg_count(msg,
((producer - 1) &
(rds_ring->num_desc - 1)));
netxen_set_msg_ctxid(msg, adapter->portnum);
netxen_set_msg_opcode(msg, NETXEN_RCV_PRODUCER(ringid));
NXWRIO(adapter, DB_NORMALIZE(adapter,
NETXEN_RCV_PRODUCER_OFFSET), msg);
}
}
netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter,
struct nx_host_rds_ring *rds_ring)
{
struct rcv_desc *pdesc;
struct netxen_rx_buffer *buffer;
int producer, count = 0;
if (!spin_trylock(&rds_ring->lock))
return;
head = &rds_ring->free_list;
while (!list_empty(head)) {
buffer = list_entry(head->next, struct netxen_rx_buffer, list);
if (!buffer->skb) {
if (netxen_alloc_rx_skb(adapter, rds_ring, buffer))
break;
pdesc = &rds_ring->desc_head[producer];
pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
pdesc->addr_buffer = cpu_to_le64(buffer->dma);
producer = get_next_index(producer, rds_ring->num_desc);
NXWRIO(adapter, rds_ring->crb_rcv_producer,
(producer - 1) & (rds_ring->num_desc - 1));
spin_unlock(&rds_ring->lock);
}
void netxen_nic_clear_stats(struct netxen_adapter *adapter)
{
memset(&adapter->stats, 0, sizeof(adapter->stats));